Skip to content

refactor(core): 034 Phase 1 — mechanical debt cleanup (#129, #132)#136

Merged
lxsaah merged 9 commits into
mainfrom
refactor/034-phase1-debt
Jun 10, 2026
Merged

refactor(core): 034 Phase 1 — mechanical debt cleanup (#129, #132)#136
lxsaah merged 9 commits into
mainfrom
refactor/034-phase1-debt

Conversation

@lxsaah

@lxsaah lxsaah commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 1 of the 034 technical-debt review — the mechanical, zero-behavior-change cleanup. One PR for the whole phase (per the "one PR per phase" plan), structured as one commit per work item so it reviews cleanly. Breaking changes are accepted (decision 2026-06-09).

Closes #129. Closes #132.

Net: +177 / −638 lines across core, adapters, and the MQTT/KNX connectors.

Commits (one per work item)

Commit Item
delete dead Database wrapper, adapter aliases, .link() §3.8 — Database<A>, TokioDatabase/EmbassyDatabase, deprecated RecordRegistrar::link() (all zero-user)
unify DbError on alloc::String (#129) §3.1.1 — one variant shape on every target; thiserror derives Display/Error unconditionally; no_std numeric-code Display table deleted
unify std/alloc imports; merge RuntimeContext impls §3.1.2 — dual use std::… / use alloc::… pairs → one use alloc::…; duplicated RuntimeContext impl blocks merged
crate-private log_*! macros replace tracing gates §3.1.3 — 62 per-site #[cfg(feature = "tracing")] gates → log_debug!/log_info!/log_warn!/log_error!
struct-ify OutboundRoute §3.10 — 5-tuple alias → struct with named fields
flatten subscribe_any; O(1) by_key lookup §3.8/§3.10 — subscribe_any infallible; O(n) keys().find() → O(1) get_key_value
drop vestigial tokio dependency §3.1.3 — std no longer pulls tokio into every build (tests cover it via dev-deps)
changelog entries Keep-a-Changelog entries (root + 5 crates)
import ToString in buffer traits test module no_std test-build fixup

Breaking changes (accepted)

  • no_std DbError: _field: () placeholders become the real String fields; Display now prints full messages instead of Error 0xNNNN codes; DbError now implements core::error::Error. Std variant shapes/messages unchanged.
  • Removed: Database<A>, TokioDatabase, EmbassyDatabase, RecordRegistrar::link().
  • ConsumerTrait::subscribe_any returns Box<dyn AnyReader> (was DbResult<…>).
  • OutboundRoute is a struct, not a 5-tuple.
  • aimdb-core's std feature no longer enables a tokio dependency; thiserror is now a mandatory (no_std) dependency; DbError::{runtime_error, permission_denied, record_key_not_found} are now pub (+ new missing_configuration).

Verification

  • make check — fmt, clippy (full feature matrix), test, test-embedded (thumbv7em-none-eabihf), test-wasm, denyall pass
  • make examples — all example crates build
  • Acceptance greps from both issues: no _field: () placeholders, no use std::{ dual imports, no tracing gates outside src/log.rs, cargo tree shows no tokio in normal deps, no Database/.link() references.

Out of scope (other issues)

#130 (builder de-Any, registrar lifetimes), #131 (R removal), #133 (panic-free validation), #134 (MQTT knobs out of core).

🤖 Generated with Claude Code

lxsaah and others added 9 commits June 9, 2026 21:14
…cated .link()

Database<A> was a thin wrapper over AimDb referenced only by the
TokioDatabase/EmbassyDatabase type aliases, which themselves had no
users in the workspace. RecordRegistrar::link() has been deprecated
since 0.2.0 with zero remaining callers.

Part of docs/design/034 Phase 1 (#132, task 3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every DbError variant now has one shape on all targets: context fields
are alloc::string::String unconditionally (the crate already requires
alloc everywhere), and Display/Error derive from thiserror on every
target (thiserror 2.x is no_std-capable). This deletes:

- all #[cfg]-gated dual fields (field: String vs _field: ()) and the
  _field: () placeholders
- the hand-written no_std Display impl (numeric-code table) — no_std
  builds now produce the same error messages as std builds
- every dual construction branch in builder.rs, typed_record.rs,
  graph.rs, time.rs, connector.rs, the adapters, and the MQTT/KNX
  connectors

Helper constructors (runtime_error, permission_denied,
record_key_not_found, new missing_configuration) are un-gated, single
body, and public. thiserror moves from optional (remote-access) to a
mandatory no_std dependency.

BREAKING (no_std only): field renames _key: () -> key: String etc.;
no_std Display output changed from 'Error 0xNNNN' codes to full
messages.

Closes #129

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ocks

std::sync::Arc, std::boxed::Box etc. are re-exports of the alloc types,
and the crate has an unconditional crate-root 'extern crate alloc'. One
unconditional 'use alloc::...' therefore works on every target:

- replace all dual #[cfg(feature = "std")]/#[cfg(not(...))] import
  pairs in builder.rs, router.rs, typed_record.rs, record_id.rs and
  buffer/{traits,writer,cfg}.rs
- drop the redundant per-module 'extern crate alloc;' declarations
  (the ones inside ext_macros.rs expansions stay: they expand into
  other crates)
- context.rs: collapse the character-for-character duplicated std /
  no_std RuntimeContext impl blocks and the dual Arc field type into
  one alloc-based impl; un-gate from_runtime/create_runtime_context
  and the runtime() getter

The std::sync::Mutex vs spin::Mutex alias in typed_record.rs and the
std::io import in error.rs stay gated — those are real platform
differences.

Part of docs/design/034 Phase 1 (#132, task 1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…gates

New #[macro_use] mod log defines log_debug!/log_info!/log_warn!/
log_error!: they forward to the matching tracing event macro when the
'tracing' feature is on and expand to a no-op that borrows the
arguments otherwise, so call sites compile identically under every
feature combination. All 62 per-call-site #[cfg(feature = "tracing")]
gates are gone; the only remaining gate is inside src/log.rs itself.

defmt is deliberately not folded into the macro: most call sites use
{:?} with types that don't implement defmt::Format, and adding defmt
output would be a behavior change. router.rs keeps its explicit
paired defmt gates.

Structural collapses: transform/join.rs now computes output_key/
input_keys unconditionally (build-time one-shot allocations) instead
of cfg-gated shadow variables; builder.rs inlines builder.scheme()
into the macro args; remote/stream.rs drops tracing's structured-field
syntax (record = %key) for plain format args, which the shim macro
(and defmt, if ever) can express.

Part of docs/design/034 Phase 1 (#132, task 2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The 5-tuple type alias forced every consumer to destructure
positionally. OutboundRoute is now a struct with named fields (topic,
consumer, serializer, config, topic_provider); construction in
collect_outbound_routes and the two consumers (session/client.rs,
session/pump.rs) use field names.

Part of docs/design/034 Phase 1 (#132, task 5).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ConsumerTrait::subscribe_any has been infallible since M14 — the
DbResult wrapper only existed 'so connector code stays unchanged'.
The future now resolves to Box<dyn AnyReader> directly and the two
callers (session/pump.rs, session/client.rs) lose their dead Err arms.

build() looked up each topo-order key with an O(n) scan over
by_key.keys() and then resolved the same key again for its RecordId.
StringKey implements Borrow<str> with content-based Hash, so a single
get_key_value(key_str) returns both in O(1) — the unreachable
RecordKeyNotFound branch goes away with it.

The O(n) records.iter().position() in configure() is intentionally
left alone: it is build-time-only over small N, and the builder
internals are restructured by #130/#133.

Part of docs/design/034 Phase 1 (#132, task 6).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Since the session-engine refactor (030/033) the only tokio:: references
in aimdb-core/src are inside #[cfg(test)] modules and doc comments. The
optional [dependencies] tokio (net, io-util, sync, time) enabled by the
std feature pulled tokio into every std build of a crate that
advertises runtime neutrality. The dev-dependency gains 'sync' (used by
tests/session_engine.rs, previously satisfied by feature unification
with the optional dependency).

Part of docs/design/034 Phase 1 (#132, task 4).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…st builds

Fallout from the DbError unification: the mock reader's
'mock'.to_string() needs alloc::string::ToString in scope when the
test harness builds with --no-default-features --features alloc.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@lxsaah lxsaah self-assigned this Jun 9, 2026
@lxsaah lxsaah added the enhancement New feature or request label Jun 9, 2026
@lxsaah lxsaah merged commit f3c0140 into main Jun 10, 2026
9 checks passed
@lxsaah lxsaah deleted the refactor/034-phase1-debt branch June 10, 2026 03:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

1 participant