docs(adr): ADR 009 requires a lossless edge wire form with round-trip tests (improvise-felo.4)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Claude (adr9-steward)
2026-10-09 21:22:50 -07:00
committed by Edward Langley
parent f3a54d34e0
commit 5e94255c21
+18 -2
View File
@@ -189,6 +189,22 @@ an **edge adapter**. So every edge has the same semantics:
defined in `improvise-protocol`. The adapter converts to and from it, and `zset` stays
free of serde. `CellKey` is not `Serialize`, so on the wire a cell is named by its
tuple of ids, its position or an ADR 002 surrogate.
- **The wire form is lossless.** Nothing is lost in transport, numeric precision above
all:
- a number never crosses as a JSON or JS double. A `numtower` `Num` crosses as its
canonical text (ADR 005). An f64 crosses as its exact bits, which keeps `-0.0` and
NaN payloads. That conflicts with today's `wire_f64` and with `numtower`'s `nan`
token, which both drop the payload, so the edge carries bits for every non-finite
value;
- integers wider than 2⁵³, including positions and counts, cross as strings;
- text crosses byte-exact, with no normalisation;
- the delta is the unit that crosses, never `ExactSum`'s limbs. A receiver that needs
a sum gets the host's exact read or rebuilds it from the exact deltas.
The stamp rule detects lost messages, but nothing would detect a lossy encoding. So
every element type has a round-trip property test, where encoding then decoding is
the identity for every value, including `-0.0`, NaN payloads, 28-digit decimals and
`i128`-wide fractions.
- **Stamps compose end to end.** The host stamps each published batch (below), and an
intermediate edge forwards the stamp unchanged. So a loss anywhere on the path shows up
downstream as a gap.
@@ -245,8 +261,8 @@ maintained key, so it maps member keys through its own remap first. It then refe
what moved. It refetches everything when it sees a publication gap, a new
`document_generation` or host instance, its shape in the eviction list, or a notice it
cannot read. A slow client may merge pending notices: the union of keys, the latest
stamp, and axis changes kept in order. Outputs are consolidated under the wire's value
identity, so every NaN counts as one value, because the wire spells every NaN `"nan"`.
stamp, and axis changes kept in order. Because the wire is lossless, outputs keep the
circuit's bit identity end to end.
**What this replaces.** Today's per-session mirrors and pushed diffs (`Sessions`,
`ClientSession`, `grid_updates`, `Projection`, `Dirty`). The host keeps no per-client