docs(architecture): ADR-010/011 — I/O seams, GC-state home, vocabulary; pre-decomposition consistency round

ADR-010 (new): the Backend trait's I/O seams pinned before any code —
'get' returns a crate-internal read cursor (kv engines materialize;
'local' pread loop; pg-lo lo_get windows), 'put' has two named forms
(whole-value kv / staged-put large); GC state is store-core-owned via
a crate-internal contract-tested engine-state seam on the SQL-backed
engines (backends never learn liveness — ADR-005 verbatim); the store
core holds the joint entry+pin transaction (corrects ADR-009 §2's
ownership statement); kv-tier fleet-validity rule added (mirror of
ADR-008 §3); ops pin-token TTL race resolved (the token IS the pin;
renewal rides have/re-put; pause-past-TTL falls to delete-then-recover);
feature graph pinned (pg-lo does not imply postgres).

ADR-011 (new): vocabulary pinned — tier (contract, exactly two) vs
engine (concrete impl, exactly five); store instance / node / fleet
split (fleet = pool-sharing, not node count — fixes requirements.md's
self-contradiction with REQ-2); mem demoted from 'backend'/'testing
tier' to the kv tier's third engine (contract-reference engine);
fs tier renamed 'large' including the feature name (last free moment
before code exists); constructor modes pinned (dual-tier default,
kv-only, mem-only) plus the composite fleet-validity predicate.

Consistency round across all specs and ADR-003/004/007/008/009: stale
pg-lo passages resolved per ADR-009's supersession; ADR-008 owner
'node id' → store-instance id; threshold wording corrected (conservative
edge, not midpoint, of the 128-256 KiB crossover zone); SweepReport
shape specced; mem classification unified; 008/009 ADR files renamed to
match the tier rename; README deferral-policy recap aligned (third
category = decided-but-sequenced work, not a parking kind); POC crate
list completed.

Verification: two independent architecture review rounds (the first
found 4 criticals — unpinned trait I/O shapes, missing fleet-state
seam, node/fleet self-contradiction, pin-token/TTL conflict — all
resolved; final round: zero criticals); all markdown links resolve;
ADR tables complete (11 ADRs).
This commit is contained in:
glm-5.3-flash committed 2026-10-03 05:55:20 +00:00
1 parent 9bbe6f3ad9
commit abf8c5ae9c
18 files changed
+1137 -336

No files matched your search

+39 -7
View File
@@ -1,6 +1,6 @@
---
status: draft
last_updated: 2026-10-03
last_updated: 2026-10-03 (pin-token renewal contract pinned per ADR-010 §4)
---
# Ops surface (alkcall-backed network operations)
@@ -96,8 +96,11 @@ the server. The hand-over contract:
1. the put lands pinned (ADR-005) — the entry cannot be swept while
the handler holds the pin;
2. the `blobs/put` response returns a **pin token** (opaque handle);
the putter can later confirm its registration landed by observing
2. the `blobs/put` response returns a **pin token** (opaque handle —
minted by the ops layer over the pin row the put committed; the
token↔(key, owner) mapping is ops-layer state, not durable state —
the durable state is the pin row itself, ADR-010 §4); the putter
can later confirm its registration landed by observing
the digest present via `blobs/have`;
3. the embedder's registered liveness source is the *actual* root of
record: the contract on the embedder (documented on the ops module)
@@ -112,6 +115,32 @@ the server. The hand-over contract:
conversion on the server side (token → registered liveness source)
is the mechanism the embedder plugs its registry into.
**Token renewal (ADR-010 §4 — the fleet-TTL race, resolved): the
token *is* the pin — there is no second pin state.** The server-side
handler's in-process `Pin` guard drops when the `blobs/put` response
completes (if it never dropped, the TTL machinery would be dead on
the ops path — the pin row's expiry, not the guard's presence, is the
fleet liveness signal). Under fleet
engines the put's pin is an expiry-carrying row (ADR-008: TTL 60 s
default, renewed every TTL/3). The remote putter holding a token is
the row's owner and renews by the ops it already speaks: a
`blobs/have` probe **presenting the token alongside the digest** (the
handler verifies the token maps to the digest's pin row and calls the
crate-internal `pin_renew` via the ops module's store-core access —
the ops module is in-crate and crosses the seam by construction, the
same way the put handler holds the `Pin` guard; `has` itself remains
a pure existence probe per ADR-008 — renewal is a token-authenticated
act on the pin row, not a `has` semantic), or a re-put of the same
digest (CAS dedup renews the row). **A putter may pause past the
TTL/3 mark (20 s at the default TTL) only if it renews before expiry;
a putter pausing past TTL lets the row expire** — the sweeper reaps
it (ADR-008) and delete-then-recover (ADR-005) is the backstop: the
putter re-offers the digest; CAS makes the re-put idempotent. The
race resolves to a re-put, never to silent loss. For non-fleet
(`local`-engine) serving nodes the token is the in-process guard —
nothing expires; the process-crash case is ADR-005's in-flight-put
loss with the same backstop.
Placement of the op *registration* (which embedders wire where they
want them exposed) matches the alkgit ops pattern (its
`git/repo/*` call ops): the module exports spec/handler pairs; the
@@ -143,10 +172,11 @@ handlers call `put`; both honor pins and delete windows. There is no
ops-internal path around the store facade (ADR-001 §Consequences —
this is what makes "re-homing the ops surface later loses nothing"
true). One fleet topology additionally rides this module: **re-routing
(ADR-008)** — a fleet whose nodes do not share fs media routes
(ADR-008)** — a fleet whose nodes do not share large-tier media routes
large-blob access through a single storage node via these ops, with
client nodes' fs tiers serving only node-private content. The module
supports this shape without change; no fleet-specific op exists.
client nodes' constructors in kv-only mode (ADR-011 §4) for pool
content. The module supports this shape without change; no
fleet-specific op exists.
## Design Decisions
@@ -154,7 +184,9 @@ supports this shape without change; no fleet-specific op exists.
|---|---|---|
| [001](decisions/001-substrate-posture-and-ops-placement.md) | Substrate posture & placement | alkcall-backed, feature-gated ops module; conformance-not-deviation rationale |
| [006](decisions/006-verification-posture-and-transfer-encoding.md) | Verification | verified-fetch via carried digests; no chunk trees |
| [008](decisions/008-trait-size-probe-fleet-gc-and-fs-engines.md) | Fleet re-routing topology | non-shared-media fleets route large-blob access through a storage node via these ops; no new ops |
| [008](decisions/008-trait-size-probe-fleet-gc-and-large-engines.md) | Fleet re-routing topology | non-shared-media fleets route large-blob access through a storage node via these ops; no new ops |
| [010](decisions/010-backend-io-seams-and-fleet-state-home.md) | Pin-token renewal | the token is the pin; renewal rides have/re-put; TTL expiry falls to delete-then-recover |
| [011](decisions/011-vocabulary-tiers-engines-and-fleet-state.md) | Vocabulary + modes | instance/node/fleet split; kv-only mode named (the re-routing posture's client shape) |
## Open Questions