Skip to content

Commit 7fe5e88

Browse files
lxsaahclaude
andauthored
Design 039: no_std typed migrations (lift std gate from migratable) (#164)
* docs: add design 039 — no_std typed migrations (lift std gate from migratable) The migratable feature of aimdb-data-contracts is gated on std, but an audit shows nothing in the migration engine needs it: the std gate is an artifact of a locally-declared serde_json dependency with default features. Design 039 describes the change set to make migration_chain! work on no_std + alloc targets: adopt the workspace serde_json dep, re-plumb the feature to alloc, add $crate::__private macro hygiene, and extend the existing no_std CI lanes. Includes a follow-up proposal for a Value-free version probe to cut peak heap on MCUs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6pVffxk1yU9sspKjUumAc * docs: add design 040 — WASM SingleLatest fresh-subscriber parity The WASM adapter is the only runtime where a fresh SingleLatest subscriber does not observe the buffer's current value (it waits for the next push), diverging from Tokio (mark_changed) and Embassy (native watch seen-ID) semantics. Design 040 pins the root cause to the reader initialization in WasmBuffer::subscribe, specifies the one-line fix plus the missing peek() override, adds host-run regression tests (the buffer module is pure core+alloc, no browser needed), and proposes codifying the fresh-subscriber rule in core docs plus a shared cross-adapter buffer contract suite mirroring executor.rs test_support. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6pVffxk1yU9sspKjUumAc * docs: update design 039 — clarify PR structure and no_std compatibility details * docs: design 039 review fixes — correct criterion 3, PR sequencing table, test ordering Apply review findings on the updated 039: acceptance criterion 3 no longer asserts serde_json is absent from the dependency graph (it stays transitive via aimdb-data-contracts by design; verify the direct edge and std feature via cargo tree -i instead); the round-trip test suite moves into PR 1/W3 so the PR 2 proc-macro rewrite lands against pre-existing green tests; generated helpers get collision-safe const- block emission; the risk table's stale W4 pointer now references the PR 3 probe; aimdb-derive's own 0.2.0 release-ordering requirement is recorded; and the probe is promoted to an explicit PR 3 with a hand-off sequencing table in the status header. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V6pVffxk1yU9sspKjUumAc * feat(data-contracts): lift std gate from migratable (design 039 W1) migratable now requires only alloc + serde_json instead of std: serde_json switches to the workspace pin (default-features = false, features = ["alloc"]), and std gains serde_json?/std as a weak dependency feature so std builds keep serde_json's std impl without forcing the dependency on. No source change — migratable.rs has no std:: path today; the gate existed only in Cargo.toml. Bumps aimdb-data-contracts to 0.2.0 (breaking: a consumer that enabled only migratable and relied on it transitively activating std must now enable std explicitly) and updates the two versioned consumer pins (aimdb-wasm-adapter, aimdb-websocket-connector) so the workspace still resolves. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * refactor(data-contracts): route migration_chain! through $crate::__private (design 039 W2) The macro_rules! expansion referenced bare serde_json:: and alloc:: paths, which resolve in the *caller's* namespace — every consumer had to depend on serde_json directly and declare extern crate alloc, and a caller's own plain `serde_json = "1"` would silently re-enable std via feature unification, breaking no_std targets. Route the expansion through $crate::__private::{serde_json, alloc} (re-exported from lib.rs, defining crate) instead. Pure hygiene — expansion behavior is identical, and existing callers keep working (their own serde_json dep becomes unnecessary rather than wrong). Drops the now-redundant `extern crate alloc;` from the module-doc example, which no longer needs it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * test(data-contracts): no_std CI lanes + migration round-trip suite (design 039 W3) Extend the Makefile build/test/clippy lanes to cover alloc,linkable,migratable (no dev-dependency serde_json to unify to std there, unlike the plain `test` lane), and add thumbv7em-none-eabihf target-check lines for aimdb-data-contracts and weather-mesh-common (the latter goes fully green once W5 drops its own serde_json default-std dep). Add tests/migration_roundtrip.rs: 1-, 2-, and 3-step chains (matching the three hand-unrolled macro_rules arities), each upgrading from every historical version and downgrading to every target version, plus the error paths (MissingVersion, VersionTooNew, VersionTooOld, malformed JSON). Lives under tests/ (a separate crate) rather than a #[cfg(test)] module inside src/migratable.rs, since PR2's proc-macro rewrite will emit absolute ::aimdb_data_contracts::... paths that only resolve from outside the defining crate — this suite is the regression pin that rewrite must reproduce unchanged. Also fixes a latent no_std bug the new linkable+migratable lane surfaces: Linkable::from_bytes/to_bytes used bare String/Vec, which only resolved under std (via the automatic std prelude) — linkable was never actually exercised under no_std before (serde_json/std was always pulled in transitively, masking it). Qualify both as alloc::string::String / alloc::vec::Vec. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * docs: note migratable's no_std support (design 039 W4) lib.rs's SchemaType compatibility-rules doc now notes migration_chain! only needs alloc and works identically on std and no_std targets. README's capability-trait table gains a Runtimes column, same std/no_std notation the connector table already uses further down the page. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(weather-mesh-common): drop consumer serde_json dep, fix no_std linkable (design 039 W5) migratable = ["aimdb-data-contracts/migratable"] — the macro no longer needs a consumer serde_json dep after W2's $crate::__private routing. serde_json itself switches to the workspace pin (alloc, no default std), which also fixes the linkable feature for no_std as a side effect (it silently dragged serde_json/std along before). That side effect exposed the same latent bug W3 found and fixed in aimdb-data-contracts's own Linkable trait: GpsLocation's and Humidity's hand-written Linkable impls called bare `e.to_string()`, which only resolves under std's automatic prelude. temperature.rs and dew_point.rs already fully-qualified this (alloc::string::ToString::to_string); apply the same fix here so `cargo check -p weather-mesh-common --no-default-features --features linkable --target thumbv7em-none-eabihf` — PR1 acceptance criterion 4 — actually compiles. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * feat(derive): variable-arity migration_chain! proc-macro (design 039 W6) Adds #[proc_macro] migration_chain in aimdb-derive: a custom syn::parse::Parse impl reads the existing grammar (unchanged) into a Vec<StepDef>, then generates, for arbitrary N: - the same const-assertion validation the old macro_rules produced per hand-unrolled arity (steps increment by 1, are sequential, start at 1, end at Current::VERSION); - one __up_k / __down_k free function per step (k = FROM_VERSION), each applying its step and recursing into __up_{k+1}/__down_{k+1} — O(N) generated code, not O(N²) (no arm re-inlines the full chain walk); and - the MigrationChain impl, with one O(1) match arm per historical version calling the matching helper. Everything (asserts, helpers, impl) lands in a single `const _: () = { ... };` block, the serde-derive collision-avoidance pattern, so multiple chains in one module can't collide on helper names. Generated code hardcodes absolute ::aimdb_data_contracts::... paths (matching the RecordKey -> aimdb_core precedent already in this crate — a proc-macro has no $crate, and aimdb-derive still doesn't depend on aimdb-data-contracts, no cycle). Not yet wired up: aimdb-data-contracts still exports the old macro_rules; the cutover is next. Bumps aimdb-derive to 0.2.0 (new public proc-macro) and aimdb-core's version requirement on it to match. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * refactor(data-contracts): cut over migration_chain! to the aimdb-derive proc-macro (design 039 W7) migratable = ["alloc", "serde_json", "dep:aimdb-derive"] — build-time only, no target/runtime/no_std impact, no cycle (aimdb-derive emits token paths to this crate but doesn't depend on it, same as RecordKey -> aimdb_core). lib.rs re-exports aimdb_derive::migration_chain, so the aimdb_data_contracts::migration_chain! call path and grammar are unchanged for every existing caller. Deletes the old macro_rules from migratable.rs; MigrationStep/MigrationChain/MigrationError stay hand-written and untouched. The full W3 round-trip suite (1/2/3-step chains, error paths) passes unchanged against the new proc-macro — the regression gate for this rewrite. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * test(data-contracts): prove migration_chain! arity is unbounded (design 039 W8) Extends tests/migration_roundtrip.rs with 4-step (Sprocket, 5 versions) and 5-step (Doohickey, 6 versions) chains — the pre-existing 1/2/3-step cases (Widget/Gadget/Gizmo) pass unchanged, pinning the rewrite's behavior across the old 3-step ceiling. Adds an on-target arity proof: cargo check --target thumbv7em-none-eabihf can't compile tests/*.rs at all (no std test harness on a bare-metal target), so a 4-step chain compiling there needs to live in src/ instead. migratable.rs gains an internal, non-test-gated `arity_check` module (a 5-version/4-step fixture, #[allow(dead_code)], never executed — runtime correctness is proven on host by the tests/ suite). Since it invokes migration_chain! from inside this crate, and the macro hardcodes absolute ::aimdb_data_contracts::... paths, lib.rs adds `extern crate self as aimdb_data_contracts;` (RFC 2126) so that self-reference resolves; this reuses the existing no_std/linkable/migratable thumbv7em check lane from W3, no new Makefile line needed. Adds trybuild as a dev-dependency and tests/compile-fail/*.rs + tests/compile_fail.rs: the four malformed-chain shapes (gap, wrong start, non-sequential, wrong end) still fail at compile time with the existing assertion messages. chain_non_sequential.rs is deliberately built so the step *types* still chain correctly (only the declared FROM_VERSION/TO_VERSION disagree) — otherwise it would also hit a mismatched-types error ahead of the intended const-eval assertion, polluting the pinned stderr snapshot. cargo expand confirms the O(N) codegen shape: one __up_k/__down_k helper per step (each a single call plus one recursive call), not the O(N²) a naive per-arm unroll would produce. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * docs: note migration_chain! now lives in aimdb-derive, arity unbounded (design 039 W9) migratable.rs's module doc now describes migration_chain! as a proc-macro (defined in aimdb-derive, re-exported here) rather than the deleted declarative macro, and notes the generated MigrationChain impl is O(N) in code size for a chain of any length. Also de-links two now-broken intra-doc references to `migration_chain!` (it's no longer defined in this module, so `[`migration_chain!`]` doesn't resolve — cargo doc confirmed clean after this fix). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * perf(derive): tree-free version probe for migrate_from_bytes (design 039 PR3) migrate_from_bytes previously parsed the whole payload into a serde_json::Value tree just to read one integer field, then converted into the matched concrete type with from_value — peak allocation O(payload tree). Replace it with a two-pass, tree-free scan: a private #[derive(serde::Deserialize)] probe struct reads only the version field (pass 1), then the matched arm's serde_json::from_slice parses the same bytes directly into the concrete Older/Current type (pass 2). Peak allocation drops to O(concrete struct). serde_json::Error::is_data() distinguishes "well-formed JSON, missing/wrong-type version field" (MissingVersion) from "malformed JSON" (DeserializationFailed), matching the old Value-based behavior exactly — confirmed by the full migration_roundtrip suite (1-5 step chains + error paths) passing unchanged, and by the compile-fail suite (const-eval happens before migrate_from_bytes's body is relevant, so those snapshots are untouched). This rewrites the same migrate_from_bytes body PR2 relocated into the proc-macro, so it lands after PR2 rather than against the old macro_rules, per the design doc's sequencing note. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * bench(bench): record migrate_from_bytes allocation baseline (design 039 PR3) New b0_alloc_migration bench, following the b0_alloc_tokio.rs shape (own CountingAllocator<System>, warm up, reset, batch, snapshot, write_reports). Fixture is a 2-version schema with a label: String field — an all-primitive struct would parse allocation-free regardless of version-scan strategy and wouldn't show anything, so this keeps the bench representative of real contracts (e.g. weather-mesh-common's TemperatureV1.unit). Measured: 1 alloc/msg, 15 B/msg (the label field only) — confirms the PR3 probe rewrite is genuinely O(concrete struct), not O(payload tree); a regression back to Value-tree parsing would show up here as more than one allocation per call. aimdb-data-contracts (alloc, migratable) joins aimdb-bench's std-gated dependency set, same treatment as criterion/serde_json — the no_std lane the stm32h5 B3 rig depends on is untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> * fix(migration-chain): handle error for source version too old in migration logic * docs(changelog): record design 039 no_std migrations + VersionTooOld fix Add a Design 039 aggregate subsection to the root changelog (matching the Design 038 pattern) and a Fixed entry to aimdb-derive for the migrate_from_bytes VersionTooOld classification correction. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore: update changelogs and comments for clarity and consistency * Claude/design doc 40 wasm parity impl (#165) * fix(wasm): deliver current value to fresh SingleLatest subscribers (design 040) WASM's SingleLatest buffer diverged from tokio/embassy: a subscriber created after a value was published observed nothing until the next push, so a browser dashboard subscribing to config after publish rendered blank until the next change. WasmBuffer::subscribe() now starts the reader as never-having-seen a value (last_seen_version: 0), so an already-published value is delivered once — matching the documented cross-runtime contract. Alongside the fix: - Add WasmBuffer DynBuffer::peek() (SingleLatest value / Mailbox slot / None for SpmcRing), the buffer-native read AimX record.get relies on; it previously returned None on WASM. - Add host-run WASM buffer unit tests plus a shared aimdb-core buffer::test_support conformance suite exercised by all three adapters (tokio #[tokio::test], embassy/wasm block_on), so buffer parity is enforced in CI rather than left to per-adapter discipline. - Document the fresh-subscriber rule on Buffer::subscribe and BufferCfg::SingleLatest (was folklore in a tokio comment). - Wire the WASM host lib test lane into `make test` (it was never run in CI) and add a wasm32-excluded `futures` dev-dep for the async suite. - Bump aimdb-wasm-adapter 0.2.0 -> 0.3.0 with a changelog entry. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012JRUMZWyUJ7PHLPCmrbnY1 * format --------- Co-authored-by: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 4b8aaa4 commit 7fe5e88

41 files changed

Lines changed: 2793 additions & 493 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,29 @@ library crates with no capability loss. Breaking changes and migrations:
8080
"issue #133", "pre-W8") rewritten to state the invariant directly; history lives in git
8181
blame and docs/design/.
8282

83+
### Changed — no_std typed migrations
84+
85+
Schema migration is the last capability trait freed from `std`, so a versioned
86+
contract can migrate old payloads on a bare-metal target (e.g. Embassy on an MCU),
87+
not just under `std`. Verified on `thumbv7em-none-eabihf` in CI, with a
88+
multi-step migration round-trip suite and a trybuild compile-fail harness.
89+
90+
- **`migratable` no longer requires `std` (breaking).** The feature is now
91+
`["alloc", "serde_json", "dep:aimdb-derive"]` (was `["std", "serde_json"]`), and
92+
the crate's `serde_json` follows the workspace pin (`default-features = false`,
93+
`features = ["alloc"]`). `migration_chain!` and the `Linkable`-with-migration
94+
patterns now compile on `no_std + alloc`. *Migration:* a crate that enabled only
95+
`migratable` and relied on it transitively activating `std` must now enable `std`
96+
explicitly; in-repo consumers default to `std` and are unaffected.
97+
([aimdb-data-contracts](aimdb-data-contracts/CHANGELOG.md))
98+
- **`migration_chain!` moves to an `aimdb-derive` proc-macro.** The 3-arm
99+
`macro_rules!` is replaced by a variable-arity proc-macro (re-exported unchanged as
100+
`aimdb_data_contracts::migration_chain!`) with `O(N)`-in-code-size dispatch and a
101+
tree-free version probe in `migrate_from_bytes` (peak allocation O(concrete struct),
102+
not O(payload tree)). A below-`MIN_VERSION` source version now reports `VersionTooOld`
103+
instead of the contradictory `VersionTooNew`.
104+
([aimdb-derive](aimdb-derive/CHANGELOG.md))
105+
83106
### Added
84107

85108
- **Design 034 Phase 3 — sans-io KNX/IP tunneling engine shared by both transports (Issue #135, [review doc §3.7](docs/design/034-technical-debt-review.md)).** The entire tunneling lifecycle — CONNECT_REQUEST/RESPONSE handshake, TUNNELING_REQUEST/ACK sequence + pending-ACK bookkeeping, keepalive (CONNECTIONSTATE_REQUEST) scheduling, ACK-timeout sweeps, and reconnect-with-backoff — now lives **once**, in the new runtime-neutral `aimdb_knx_connector::tunnel` module (`no_std + alloc`, no tokio/embassy imports), driven as a poll-based state machine (events in, `Action`s out, `next_deadline()` for timer arming). `tokio_client.rs` (988 → ~530 lines incl. a new fake-gateway integration test) and `embassy_client.rs` (1,055 → ~450 lines) are reduced to socket shims; the previously untestable handshake/ACK/keepalive/reconnect paths now have 15 host-run unit tests plus a scripted localhost-UDP roundtrip test. Behavioral unifications: Embassy gains the 5 s CONNECT_RESPONSE timeout (previously waited forever), both shims reconnect on fatal socket errors, and the dead tokio-only per-publish ACK oneshot is dropped (it was always `None`); the CONNECT_REQUEST HPAI stays per-transport (`LocalEndpoint`: tokio = real bound address, Embassy = NAT mode). ([aimdb-knx-connector](aimdb-knx-connector/CHANGELOG.md))

Cargo.lock

Lines changed: 103 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,8 @@ build:
6666
cargo build --package aimdb-data-contracts --features "std,simulatable,migratable,observable"
6767
@printf "$(YELLOW) → Building aimdb-data-contracts (no_std)$(NC)\n"
6868
cargo build --package aimdb-data-contracts --no-default-features --features alloc
69+
@printf "$(YELLOW) → Building aimdb-data-contracts (no_std + linkable + migratable)$(NC)\n"
70+
cargo build --package aimdb-data-contracts --no-default-features --features alloc,linkable,migratable
6971
@printf "$(YELLOW) → Building aimdb-core (no_std + alloc)$(NC)\n"
7072
cargo build --package aimdb-core --no-default-features --features alloc
7173
@printf "$(YELLOW) → Building aimdb-core (std platform)$(NC)\n"
@@ -109,6 +111,8 @@ test:
109111
@printf "$(GREEN)Running all tests (valid combinations)...$(NC)\n"
110112
@printf "$(YELLOW) → Testing aimdb-data-contracts (std)$(NC)\n"
111113
cargo test --package aimdb-data-contracts --features "std,simulatable,migratable,observable"
114+
@printf "$(YELLOW) → Testing aimdb-data-contracts (no_std + alloc + migratable)$(NC)\n"
115+
cargo test --package aimdb-data-contracts --no-default-features --features alloc,migratable
112116
@printf "$(YELLOW) → Testing aimdb-core (no_std + alloc)$(NC)\n"
113117
cargo test --package aimdb-core --no-default-features --features alloc
114118
@printf "$(YELLOW) → Testing aimdb-core (std platform)$(NC)\n"
@@ -135,6 +139,8 @@ test:
135139
cargo test --package aimdb-tokio-adapter --features "tokio-runtime,tracing,observability"
136140
@printf "$(YELLOW) → Testing embassy adapter (host, no executor: buffers, join-queue, connector spine, doctests)$(NC)\n"
137141
cargo test --package aimdb-embassy-adapter --no-default-features --features "alloc,embassy-sync,embassy-time,connectors"
142+
@printf "$(YELLOW) → Testing WASM adapter (host lib: buffer semantics + shared contract suite; browser layer runs via wasm-test)$(NC)\n"
143+
cargo test --package aimdb-wasm-adapter --no-default-features --lib
138144
@printf "$(YELLOW) → Testing sync wrapper$(NC)\n"
139145
cargo test --package aimdb-sync
140146
@printf "$(YELLOW) → Testing codegen library$(NC)\n"
@@ -196,6 +202,8 @@ clippy:
196202
cargo clippy --package aimdb-data-contracts --features "std,simulatable,migratable,observable" --all-targets -- -D warnings
197203
@printf "$(YELLOW) → Clippy on aimdb-data-contracts (no_std + alloc)$(NC)\n"
198204
cargo clippy --package aimdb-data-contracts --no-default-features --features alloc -- -D warnings
205+
@printf "$(YELLOW) → Clippy on aimdb-data-contracts (no_std + alloc + linkable + migratable)$(NC)\n"
206+
cargo clippy --package aimdb-data-contracts --no-default-features --features alloc,linkable,migratable -- -D warnings
199207
@printf "$(YELLOW) → Clippy on aimdb-core (no_std + alloc)$(NC)\n"
200208
cargo clippy --package aimdb-core --no-default-features --features alloc --all-targets -- -D warnings
201209
@printf "$(YELLOW) → Clippy on aimdb-core (no_std + alloc + remote)$(NC)\n"
@@ -306,6 +314,10 @@ test-embedded:
306314
@printf "$(BLUE)Testing embedded/MCU cross-compilation compatibility...$(NC)\n"
307315
@printf "$(YELLOW) → Checking aimdb-data-contracts (no_std + alloc) on thumbv7em-none-eabihf target$(NC)\n"
308316
cargo check --package aimdb-data-contracts --target thumbv7em-none-eabihf --target-dir $(EMBEDDED_CHECK_TARGET_DIR) --no-default-features --features alloc
317+
@printf "$(YELLOW) → Checking aimdb-data-contracts (no_std + alloc + linkable + migratable) on thumbv7em-none-eabihf target$(NC)\n"
318+
cargo check --package aimdb-data-contracts --target thumbv7em-none-eabihf --target-dir $(EMBEDDED_CHECK_TARGET_DIR) --no-default-features --features alloc,linkable,migratable
319+
@printf "$(YELLOW) → Checking weather-mesh-common (no_std migratable, real TemperatureV1ToV2 chain, no direct serde_json dep) on thumbv7em-none-eabihf target$(NC)\n"
320+
cargo check --package weather-mesh-common --target thumbv7em-none-eabihf --target-dir $(EMBEDDED_CHECK_TARGET_DIR) --no-default-features --features migratable
309321
@printf "$(YELLOW) → Checking aimdb-core (no_std minimal) on thumbv7em-none-eabihf target$(NC)\n"
310322
cargo check --package aimdb-core --target thumbv7em-none-eabihf --target-dir $(EMBEDDED_CHECK_TARGET_DIR) --no-default-features --features alloc
311323
@printf "$(YELLOW) → Checking aimdb-core (no_std + alloc + remote) on thumbv7em-none-eabihf target$(NC)\n"

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,12 @@ docker compose up
130130

131131
**Four capability traits** — opt-in, type-checked:
132132

133-
| Trait | What it unlocks |
134-
| --- | --- |
135-
| [`Streamable`](https://aimdb.dev/blog/streamable-crossing-boundaries) | Crossing WASM / WebSocket / CLI boundaries |
136-
| [`Migratable`](https://aimdb.dev/blog/schema-migration-without-ceremony) | Typed schema evolution across deployed fleets |
137-
| `Observable` | Automatic per-record metrics |
138-
| [`Linkable`](https://aimdb.dev/blog/connectors-where-aimdb-meets-the-real-world) | Wire-format connectors |
133+
| Trait | What it unlocks | Runtimes |
134+
| --- | --- | --- |
135+
| [`Streamable`](https://aimdb.dev/blog/streamable-crossing-boundaries) | Crossing WASM / WebSocket / CLI boundaries | std, no_std |
136+
| [`Migratable`](https://aimdb.dev/blog/schema-migration-without-ceremony) | Typed schema evolution across deployed fleets | std, no_std |
137+
| `Observable` | Automatic per-record metrics | std, no_std |
138+
| [`Linkable`](https://aimdb.dev/blog/connectors-where-aimdb-meets-the-real-world) | Wire-format connectors | std, no_std |
139139

140140
**One async API across runtimes.** Tokio, Embassy, WASM — swap the runtime adapter, keep the code. → [How the runtime abstraction works](https://aimdb.dev/blog/building-aimdb-one-async-api)
141141

aimdb-bench/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ harness = false
3636
name = "b1_b2_embassy"
3737
harness = false
3838

39+
[[bench]]
40+
name = "b0_alloc_migration"
41+
harness = false
42+
3943
[features]
4044
default = ["std"]
4145
# Gates `profiles`/`reports`/`harness` and their criterion/serde_json/
@@ -49,6 +53,7 @@ std = [
4953
"dep:serde_json",
5054
"dep:criterion",
5155
"dep:futures",
56+
"dep:aimdb-data-contracts",
5257
"aimdb-core/std",
5358
]
5459

@@ -80,6 +85,13 @@ tokio = { workspace = true, optional = true }
8085
serde = { workspace = true, optional = true }
8186
serde_json = { workspace = true, optional = true }
8287

88+
# migration_chain! for the b0_alloc_migration bench — std-gated like
89+
# criterion/serde_json above, since that's the only bench that needs it.
90+
aimdb-data-contracts = { path = "../aimdb-data-contracts", default-features = false, features = [
91+
"alloc",
92+
"migratable",
93+
], optional = true }
94+
8395
# Statistical benchmarking for B1/B2 — `harness::bench_spsc` (design 039
8496
# F13) references `criterion::Criterion` in its public signature, so this
8597
# must be a regular (if optional/std-gated) dependency, not a dev-dependency:

0 commit comments

Comments
 (0)