docs(adr): ADR 009 gives merged notices a covered range, one shared notice log, and a clock per process (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:
committed by
Edward Langley
parent
5e94255c21
commit
353352f89d
@@ -3,7 +3,7 @@
|
||||
**Status:** proposed. ·
|
||||
**Ticket:** improvise-felo.4 (the record of this ADR; implementation goes to its own
|
||||
epic) ·
|
||||
**Relates to:** ADR 003, ADR 005, ADR 007, ADR 008
|
||||
**Relates to:** ADR 003, ADR 005, ADR 006, ADR 007, ADR 008
|
||||
|
||||
## Problem
|
||||
|
||||
@@ -25,7 +25,8 @@ equal today's eager results exactly.
|
||||
A problem-agnostic workspace crate with no dependencies beyond `std` (so it is
|
||||
wasm32-clean and serde-free). It provides:
|
||||
- `ZSet<K>`, a map from `K: Ord` to a non-zero `i64` weight, which is an abelian group;
|
||||
- a synchronous, single-threaded `Circuit`, with `delay`, `integrate`, `differentiate`,
|
||||
- a synchronous, single-threaded `Circuit` per process, with `delay`, `integrate`,
|
||||
`differentiate`,
|
||||
`map`, `filter`, `flat_map`, `index_by`, the bilinear delta join `join_indexed`,
|
||||
`distinct` and `aggregate`;
|
||||
- resumable rebuilds: building an operator from a snapshot is a `step(deadline)`, so it
|
||||
@@ -208,12 +209,18 @@ an **edge adapter**. So every edge has the same semantics:
|
||||
- **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.
|
||||
- **One clock per process.** Each process runs its own synchronous sub-circuit. Across a
|
||||
hop, the stamped batches are the clock.
|
||||
- **Ordering and backpressure.** An edge delivers in order. A slow edge coalesces
|
||||
exactly: deltas are summed, and notices merged.
|
||||
exactly: deltas are summed, and notices merged. A merged notice carries the range of
|
||||
publications it covers, `(from, to]`, so a downstream side sees no gap where nothing
|
||||
was lost.
|
||||
- **No long-lived stream assumed.** An edge may be carried as a series of requests and
|
||||
responses, for example several HTTP requests on one connection, as well as a socket.
|
||||
So each edge keeps an ordered log, every request can be retried, and a resync from a
|
||||
publication stamp is idempotent.
|
||||
Every request can be retried, and a resync from a publication stamp is idempotent. A
|
||||
client asks for "notices since n", and the host answers from **one shared, bounded log
|
||||
of published notices**: a single log, not one per edge or client. A request older than
|
||||
the log's start is answered "refetch".
|
||||
- **Failure is local to a hop.** A hop may be a socket or a series of requests, and it is
|
||||
alive while its next message or request succeeds. Each hop keeps alive in both
|
||||
directions. A side that hears nothing within the timeout, or whose request fails,
|
||||
@@ -221,7 +228,7 @@ an **edge adapter**. So every edge has the same semantics:
|
||||
path, and the host answers from current state.
|
||||
|
||||
Aggregation stays on the model side (ADR 008), so the operators that aggregate run on
|
||||
the host. Which other edges cross a wire is a deployment choice. The engine's
|
||||
the model side, which may itself span a hop. Which other edges cross a wire is a deployment choice. The engine's
|
||||
invalidation signal, which ADR 006's replay trigger relies on, is the change notice and
|
||||
the refetch rule below, followed from a displayed cell's key back to the model.
|
||||
|
||||
@@ -260,13 +267,13 @@ A notice whose key lists exceed a fixed size carries "refetch" instead.
|
||||
maintained key, so it maps member keys through its own remap first. It then refetches
|
||||
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. Because the wire is lossless, outputs keep the
|
||||
cannot read. A slow client may merge pending notices: the union of keys, the covered
|
||||
range of publications, 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
|
||||
state. `GridExtent` is derived by the client, and in records mode the record count is
|
||||
state, only the shared notice log. `GridExtent` is derived by the client, and in records mode the record count is
|
||||
fetched.
|
||||
|
||||
**Edge adapters at the client.** Toward the circuit, a client's adapter is a sink for
|
||||
@@ -287,8 +294,8 @@ come out through clause 7's overlay. Numeric widths stay with ADR 008's view-lay
|
||||
- **Rollback.** The circuit's state joins the snapshot `Host::mutating_frame` takes. An
|
||||
inverse delta is not a rewind, because `delay` and `differentiate` keep history.
|
||||
- **Memory.** Resident state beside the store is the per-cell `Seq`, the multisets,
|
||||
`ExactSum` per summed group, occupancy per live shape, the successor-query index and
|
||||
the width histograms. The store itself is the integrated base and is never copied. It
|
||||
`ExactSum` per summed group, occupancy per live shape, the successor-query index, the
|
||||
width histograms and the bounded notice log. The store itself is the integrated base and is never copied. It
|
||||
is measured at ADR 008's fixture before the store-memory work begins.
|
||||
|
||||
## Alternatives rejected
|
||||
|
||||
Reference in New Issue
Block a user