Background
The record-value codec today is hard-wired to serde_json::Value. The capability trait RemoteSerialize and the type-erased JsonCodec<T> / SerdeJsonCodec (aimdb-core/src/codec.rs) only model "T ↔ serde_json::Value". The wire envelope, by contrast, is already cleanly pluggable: EnvelopeCodec (aimdb-core/src/session/mod.rs:392) operates on opaque Payload = Arc<[u8]>, with the NDJSON specifics contained in AimxCodec (aimdb-core/src/session/aimx/codec.rs).
So the envelope can be swapped, but the value model cannot — there is no Codec<T, Repr>, JSON is the type. Design doc docs/design/032-M16-aimx-json-codec.md explicitly lists "Custom (non-JSON) AimX wire formats" as out of scope.
Proposal
Generalize the layer-2 record-value codec from "T ↔ serde_json::Value" to a byte-oriented, pluggable Codec<T> (T ↔ bytes), so the serialization format becomes a codec impl behind one seam. Payload = Arc<[u8]> already flows everywhere, so the boundary type is unchanged.
Once the seam exists, bincode becomes a codec impl for compact, fast, schema-stable serialization — usable on interfaces where both peers share the typed contract.
The critical constraint — type-aware interfaces only
bincode is non-self-describing: you cannot decode its bytes without already knowing the exact target type (and its field order/versions). AimDB's interfaces are not uniform:
- Type-aware — data-plane links between peers that share a
Streamable / Linkable data contract; both ends know T. ✅ bincode fits here.
- Type-agnostic — AimX remote introspection, the MCP server, the dashboard; the peer has no
T. ❌ bincode here reintroduces "opaque bytes at the erased boundary" and destroys the typed-edge model.
So this is not "bincode at the interfaces" wholesale — it is "bincode on the interfaces where a shared contract already lives." The self-describing paths must keep a self-describing codec (JSON today; possibly CBOR — see related issue).
Why it's interesting
- It is the more architecturally meaningful of the two ideas: once the byte-oriented seam exists, JSON, CBOR, and bincode are all just codec impls — self-describing formats on the erased/introspection paths, bincode on the contract-sharing data plane.
- Compact + fast binary serialization for high-volume, known-type data flows.
Constraints / risks
- Requires defining where the type-aware boundary is and ensuring bincode is only reachable there (a known-
T codec selection, not the type-erased dyn AnyRecord JSON methods).
- Schema/version coupling: both peers must agree on
T's layout — a contract change the JSON path does not impose.
- Touches the codec capability trait (
RemoteSerialize / JsonCodec) and with_remote_access config-time capture.
Scope
Investigation + decision capture only. A design document (next number after 036) will follow if/when this is picked up.
Suggested sequencing
This seam is the enabler. Land it first; the self-describing-IR choice (related issue) then becomes "pick the default self-describing codec impl" rather than a separate rewrite.
Background
The record-value codec today is hard-wired to
serde_json::Value. The capability traitRemoteSerializeand the type-erasedJsonCodec<T>/SerdeJsonCodec(aimdb-core/src/codec.rs) only model "T ↔serde_json::Value". The wire envelope, by contrast, is already cleanly pluggable:EnvelopeCodec(aimdb-core/src/session/mod.rs:392) operates on opaquePayload = Arc<[u8]>, with the NDJSON specifics contained inAimxCodec(aimdb-core/src/session/aimx/codec.rs).So the envelope can be swapped, but the value model cannot — there is no
Codec<T, Repr>, JSON is the type. Design docdocs/design/032-M16-aimx-json-codec.mdexplicitly lists "Custom (non-JSON) AimX wire formats" as out of scope.Proposal
Generalize the layer-2 record-value codec from "T ↔
serde_json::Value" to a byte-oriented, pluggableCodec<T>(T ↔ bytes), so the serialization format becomes a codec impl behind one seam.Payload = Arc<[u8]>already flows everywhere, so the boundary type is unchanged.Once the seam exists, bincode becomes a codec impl for compact, fast, schema-stable serialization — usable on interfaces where both peers share the typed contract.
The critical constraint — type-aware interfaces only
bincode is non-self-describing: you cannot decode its bytes without already knowing the exact target type (and its field order/versions). AimDB's interfaces are not uniform:
Streamable/Linkabledata contract; both ends knowT. ✅ bincode fits here.T. ❌ bincode here reintroduces "opaque bytes at the erased boundary" and destroys the typed-edge model.So this is not "bincode at the interfaces" wholesale — it is "bincode on the interfaces where a shared contract already lives." The self-describing paths must keep a self-describing codec (JSON today; possibly CBOR — see related issue).
Why it's interesting
Constraints / risks
Tcodec selection, not the type-eraseddyn AnyRecordJSON methods).T's layout — a contract change the JSON path does not impose.RemoteSerialize/JsonCodec) andwith_remote_accessconfig-time capture.Scope
Investigation + decision capture only. A design document (next number after 036) will follow if/when this is picked up.
Suggested sequencing
This seam is the enabler. Land it first; the self-describing-IR choice (related issue) then becomes "pick the default self-describing codec impl" rather than a separate rewrite.