Files
alkgit/docs/plans/implementation.md
T
glm-5.3-flash 70694708ee docs(architecture): the wave-10 release gate — green; substrate/lfs flip stable
The substrate release gate (substrate/review-wave-10) verdict, landed:
- OQ-21 outcome confirmed (posture evidenced; build deferral stands
  verbatim; OQ-03's substrate publish-side blocker stays dropped)
- the substrate-side OQ-03 freeze inventory settled and reconciled
  against the crate root's actual re-export list (recorded for
  w10-publish to freeze)
- the release-readiness surface verified (docs, matrix incl. the three
  off-matrix clippies, CHANGELOG/README, dry-run re-run; F-w10-B4/B5
  + N-3 dispositions confirmed)
- all flagged recorded interpretations confirmed (O-g future work,
  the through-store probe stamp, mem_registry removal, testutil home,
  LIVE_GATE stay)
- the test evidence read green; review 006 R-1..R-7 verified absorbed

Inline findings fixed in-session:
- D-1: the architecture README's status-index cells were stale since
  the wave-5 flip; made truthful with the substrate.md/lfs.md
  `stable` flips
- D-2/D-3: two task-record slips (the test-evidence Summary's
  O-b/O-c cross-reference; the placement task's unticked ACs)
- D-4: DEFAULT_SCHEMA + LOCKED_OUT_RETRY_SECS promoted to the
  crate-root re-export list (both module-path-public, never root
  re-exported — the freeze authority byte-exact; additive pre-freeze)

Verification: cargo test (376/186), --all-features 379, the live-pg
harness run 212 passed 0 skips, the fuzz corpus gate 13 targets,
fmt + five clippy passes (-D warnings), cargo doc 0 warnings,
publish dry-run green, taskgraph validate (90 tasks).
2026-10-24 21:54:12 +00:00

62 KiB
Raw Permalink Blame History

status, last_updated
status last_updated
draft 2026-10-24 (**alkgit 0.1.0 published** — commit 0dd5721, tag alkgit-v0.1.0, crates.io; the track-A gate is lifted. Wave 6 decomposed + implemented + gated green. Wave 7 decomposed + implemented + gated green (the wave-7 gate's O-b/O-c observations booked into wave 8's entry task). Wave 8 decomposed + implemented + gated green (the gate's O-e live-pg flake watch and O-g/O-a bookings ride wave 10). Wave 9 decomposed + implemented + **gated green** (the wave-9 gate's B1–B7 bookings ride wave 10; the gate's blocker-class epoch-discipline finding and eight should-fixes landed inline). Review 006 (the post-wave-9 general review) green — no remediation wave; its R-1..R-7 booked as wave-10 material. Wave 10 decomposed + implemented + **gated green** — the wave-10 gate (the substrate release gate) verified the OQ-21 outcome, settled the substrate-side OQ-03 freeze inventory, and flipped substrate.md/lfs.md to `stable`; `substrate/w10-publish` unblocks.)

alkgit — Implementation plan

Wave-based decomposition of the architecture (docs/architecture/) into units of implementable work. This is a deliberate deviation from the SDD process's decompose-everything-upfront step, adopting the sibling pattern proven on alkstore and alkblobs (the ADR-025 consequence naming the precedent): the architecture is large, early waves change the shape of later ones (wave 1's seam types and trait signatures are what every later task implements against; wave 2's fetch machines are what wave 3's receive-pack composes beside), and decomposing only the next wave at a time keeps each session's task set reviewable and lets later decompositions absorb earlier waves' course corrections — reviews sometimes change things, and tasks downstream then have to be edited, so decomposing too far ahead is paid rework.

Rhythm: decompose a wave → implement it → review gate → decompose the next wave. Task files live in tasks/implementation/ (frontmatter carries the categorical estimates; the DAG ordering keeps parallel branches from stepping on each other). Wave boundaries are also review boundaries. Each wave's section here carries a decomposition record added when that wave actually decomposes (not written upfront).

Scope authority: v0.1.0 publishes both crates — the protocol core alkgit (complete: wire layer, state machines, the five-trait seam, GitSession, ops) and the composition alkgit-substrate (ADR-019's entirety, LFS included — LFS is v1 scope per ADR-022). Doors stay out of these waves: the alkhttp git/lfs features land in the alkhttp repo after the core's first publish (doors.md sequencing; POC-3/POC-L's reference implementations cover the interim), and alkssh is entirely future. An assembly of both published crates plus the native path is the complete v1 deliverable.

The waves

Two tracks, staggered on ADR-025's anchored-basis posture: the protocol core decomposes, completes, and publishes first — the substrate track builds against a published anchor rather than a sibling in flux, and its waves do not decompose until the core's release gate lifts.

Dependency logic in one line: seam → (fetch machines ∥ wire transport) → receive-pack → consumer half + ops → [wire validations ∥ fuzzing] → core release → substrate foundation → objects → ingestion → LFS → substrate release.

Track A — the protocol core (alkgit)

Wave Contents Depends on Status
1 Workspace conversion; error model; seam types + record schemas; the five trait signatures; Limits; session substrate types; test convention — decomposed
2 Native transport + preamble; stateless substrate; V2 advertisement + ls-refs; negotiation ack loop; GitPackGen over doubles; ACL + authorize wave 1 decomposed
3 V0 push advertisement; push state machine; bounded packless peek; GitPackIngest over doubles; status report framing wave 2 decomposed
4 GitSession (construction wrapper, ls_refs/fetch/push); the git/repo/* op family + gate wave 3 decomposed
5 OQ-19 wire-validation sessions; fuzzing; crate docs; feature matrix; the core's publish wave 4 decomposed

Track B — the shipped composition (alkgit-substrate)

The gate is lifted (core/w5-publish completed 2026-10-23 — alkgit 0.1.0 live at crates.io, commit 0dd5721, tag alkgit-v0.1.0): wave 6 decomposes against the published anchor. The sketches below are pre-decomposition commitments in the plan, not task material.

Wave Contents Depends on Status
6 Substrate scaffold + alkgit version pin; migrations (ADR-024, day-one LFS refcount); refs row tables + row CAS; the registry adapter family + reactive halves core published (wave 5) decomposed
7 alkblobs git-object-family wiring; the substrate Find front; GitPackGen/common_haves real impls (+ OQ-19 rider (b)'s substrate facet) wave 6 decomposed
8 GitPackIngest: unpack-to-loose, pin bridge + pending-pin registry, connectivity walk; end-to-end push/fetch against real git wave 7 decomposed
9 Reference rows + day-one refcount; liveness wiring; ops composition; batch adapter wave 8 decomposed
10 OQ-21 composition-validation POC; docs; feature matrix; the substrate's publish wave 9 decomposed

Wave 1 — The seam

The contract surface in code, engine-blind: everything later waves implement against, and nothing that needs a backend to test. The alkgit analog of alkblobs' foundations wave.

  • Workspace conversion — ADR-025's manifest surgery from the first commit: the root manifest becomes the workspace (two members: alkgit at the root's src/, alkgit-substrate under substrate/), the crate manifests reworked per the placement table (backend.md §crate and feature model: alkgit's sha256 off-by- default; alkgit-substrate's sqlite on, postgres/lfs per ADR-025's defaults), the pinned-version rule over path deps (alkblobs 0.2, the alkstore family 0.1, alkcall 0.10 — never sibling-checkout paths).
  • Error model — RegistryError (the registry family's five variants, ADR-012 §1 as re-scoped by ADR-018 §7) and StorageError (the object-storage family, ADR-018 §7); the wire-mapping table is transport-layer business; no catch-alls anywhere.
  • Seam types (ADR-018 §5) — RefLine/RefUpdate/RefOutcome/ PreparedPush/PushOptions and the RepoRecord serde schemas (backend.md §registry types — the N-3 draft: no path fields, the ADR-015 three-action grant shape, the opaque grant-key rule, additionalProperties: false on op inputs); the repo-id grammar (review 002 R-5, pinned once — backend.md §repo-id grammar).
  • The five trait signatures (ADR-018 §4) — the #[async_trait] family exactly as pinned; the repo: &RepoRecord parameter rule (§2 as amended on the substrate baseline — record carries no path).
  • Limits (ADR-009 + ADR-020 §1's new bounded-peek field; name pinned at implementation) — the budget model declared from the first commit, every session carries it.
  • Session substrate types (ADR-005) — the duplex + stateless machinery shapes, pkt-line framings under them.
  • Test convention — the in-memory backend doubles (the contract-reference analog of alkblobs' mem engine): the doubles implementing the five traits in-crate for the protocol waves' conformance work; every protocol wave's gate runs its machines against them. The convention (row/stamp discipline adapted from the sibling crates) is established here even though the harness compiles with wave 2's first machines.

The wave-1 review gate is the cheap-place gate: the seam types and trait signatures are one-way doors (they enter OQ-03's freeze inventory at the core's first publish — convention 9). A shape error found at this gate costs a task revision; found after the machine waves implement against them it costs signature churn across five workstreams. The gate reads the seam against ADR-018 §2–7 line by line, amended-status text included.

Decomposition record (2026-10-20): wave 1 decomposed into ten task files under tasks/implementation/core/ (track-A tasks live under tasks/implementation/core/; track B gets tasks/implementation/substrate/ when it decomposes). Shape: core/w1-workspace-conversion first (the ADR-025 manifest surgery everything lands inside); then four independent seam tasks — core/w1-error-model, core/w1-seam-types, core/w1-repo-record (record schema + repo-id grammar), core/w1-limits (the peek field's name pins here); core/w1-trait-signatures over those four; the substrate machinery as core/w1-substrate-duplex (framing primitives + error taxonomy) with core/w1-substrate-stateless building on it; core/w1-test-doubles over the trait signatures; and core/review-wave-1 (the one-way-door gate) depending on all nine. Interpretation recorded: wave 1 lands the substrate machinery shapes and pkt-line framings (ADR-005 §1–2); the serving entry points, service-selection wiring, and state machines are wave 2's transport work.

Wave 2 — The wire serves fetch (dependency-free)

The first machines, chosen so the whole fetch story is provable with zero substrate dependencies (in-memory doubles only):

  • Native transport + preamble (ADR-002/016) — GitAdapter, the git-daemon request-line grammar, the {repo, service} open-op params, the channels open op (register_openable), the authorized-repo marker flowing past the ADR-007 check.
  • Stateless substrate (ADR-005) — the stateless request/response entry point the http door will mount.
  • V2 advertisement + capabilities (ADR-003's honest list) + ls-refs (peel/symrefs/ref-prefix arguments; the unborn symref line shape).
  • Negotiation ack loop (ADR-014) — no-done rounds (acknowledgments section, NAK + flush, never ready), the stateless done round with done-closure generation, common_haves driving the ack check behind the seam.
  • GitPackGen over doubles — ADR-004's pipeline composed against the doubles' Find; missing-object aborts; the generation budget.
  • ACL + authorize (ADR-007 before any advertisement/ref line; ADR-011/015's policy function — public+read anonymous-first-class, write always authenticated+granted; unknown-repo ≡ unauthorized).
  • Ref-name validation + deny-list (ADR-013 §9's transport-side home, wired where the machines consume PreparedPush.updates).

Wave 2 decomposes after the wave-1 gate, absorbing whatever it corrects.

Decomposition record (2026-10-21): wave 2 decomposed into nine task files under tasks/implementation/core/ (the wave-1 gate is green — core/review-wave-1's verdict; nothing needed absorbing). Shape: three independent foundations first — core/w2-authorize (the ADR-011/015 policy function + the authorized-repo marker type, the gate surface every entry consumes), core/w2-refname-validation (the ADR-013 §9 transport-side home), and core/w2-packgen-doubles (the doubles' generate wired to ADR-004's real pipeline over the mem Find — the done round's provability); then the two substrate-agnostic machines in parallel — core/w2-v2-advertisement (advertisement + ls-refs) and core/w2-negotiation (the ack loop + done round, over the wired doubles); then the two serving entries in parallel — core/w2-duplex-serving (advertisement-once + command loop + wall clock) and core/w2-stateless-serving (the per-POST entry the http door mounts); then core/w2-native-transport (GitAdapter + the request-line grammar + the channels open op) over the duplex entry; and core/review-wave-2 (the capture-level gate) depending on all eight.

Interpretations recorded:

  • The machines are substrate-agnostic (both serving entries feed them, ADR-005 §3); the serving entries own ordering (ACL-first via the marker), budgets (wall clock, rounds, the concurrency semaphore's construction), and error mapping — the machines stay pure protocol.
  • The ref-name-validation home lands in wave 2 as the plan places it, with its consumption wiring in wave 3's push machine (the PreparedPush.updates point); the function is crate-public so the interim is not dead code — additive pre-publish, the gate confirms the placement.
  • The common_haves contract reads as exists + is-commit per ADR-014 §5 and backend.md §trait-family bullet 4; backend.md's pinned-signatures sentence ("existence is the operative predicate here — the is-commit refinement is the wire layer's ACK-line rule") reads as the done-round-subtraction note — flagged for the wave-2 gate to confirm or fix as docs drift.
  • The pipeline-concurrency permit (ADR-009's enforcement point) lands with the negotiation machine (the first generate call site); the shared semaphore is constructed by the serving entries from Limits::max_concurrent_blocking_tasks.
  • The stateless serving entry includes the advertisement emission for the door's future info/refs route (the capability dump as a stateless response) — the door itself stays out of these waves.
  • The channels establisher maps resolution and authorization failures to one channel:open_failed reason with a generic message (ADR-008's indistinguishability rule outranks the alktty vocabulary's unknown-resource/ACL-denial split at this gate) — flagged for the wave-2 gate to confirm.

Wave 3 — receive-pack

The push machine (ADR-013 as amended by ADR-020, all against doubles):

  • V0 push advertisement — caps NUL-attached on the first ref line, the capabilities^{} sentinel for empty repos, the served set per ADR-013 §2, private repos advertise nothing (ACL first).
  • Request parsing — command lines, shallow rejection up front v1, push-options section (gated off v1), deletes/creates zero-id shapes.
  • The bounded packless peek (ADR-020 §1) — duplex scoping, the four ordering rules verbatim, the named Limits field, the partial-header-is-malformed rule.
  • GitPackIngest over doubles — prepare/apply split (the single CAS home in GitRefs::apply_updates), CAS timing per ADR-013 §7's observed order, atomic semantics, thin-pack default acceptance.
  • Status report framing (ADR-013 §8) — band-1-wrapped with its inner flush when sideband was selected; bare otherwise; the substrate-owns-the-framing rule (handlers cannot get it wrong).

The wave-3 gate reads the landed machine against push-captures.md and the ADR-020 amendments line by line (the packless-report capture and the ~40 ms datum's shape are the capture-level acceptance).

Decomposition record (2026-10-22): wave 3 decomposed into ten task files under tasks/implementation/core/ (the wave-2 gate is green — core/review-wave-2's verdict; its findings were records, not absorptions: the alkcall early-arrival race is patched upstream, the include-tag rider is booked on OQ-19 for wave 5). Shape: the seam amendment first — core/w3-prepare-updates-seam (the ADR-018 §4 signature gains the command-derived updates; see the interpretation below — everything in the wave composes against it); then core/w3-pack-ingest-doubles (the doubles' real prepare: index with thin bases from the mem Find, unpack-to-loose into the mem store, the tips-based connectivity walk); three independent tasks in parallel — core/w3-push-grammar (the request parse: commands, caps selection, shallow rejection, the nothing-to-do shape), core/w3-v0-advertisement (the V0 ref advertisement + the stateless GET emission), and core/w3-pack-source (the raw-tail escape on both substrates + the async→blocking pack bridge + the wire-side size budget); then core/w3-push-report (the ADR-013 §8 framing — over the advertisement task, the shared-module ordering on src/v0.rs); then core/w3-push-machine (the orchestration: the bounded peek's four rules, prepare under the permit, name validation, the single CAS home, the report) over the grammar, the report, the pack source, and the doubles; then the two serving entries in parallel — core/ w3-duplex-serving (the V0 advertisement + one-request service + the ingest-handle threading through the native transport) and core/ w3-stateless-serving (the push POST path + the advertisement GET); and core/review-wave-3 (the capture-level gate) depending on all nine.

Interpretations recorded:

  • The prepare-seam amendment (the wave's one spec-level call, flagged for the wave-3 gate to confirm): ADR-018 §4's pinned prepare signature cannot express the pinned composition — the impl needs the command-derived updates (the connectivity walk runs "from the pushed tips", ADR-020 §2; the pin-custody correlation keys on "the prepared RefUpdate list it produced", substrate.md §object storage; ADR-013 §6's "prepares validated updates" must be executable) and the pinned signature hands it only the pack stream. The amendment adds updates: Vec<RefUpdate> after repo (the POC-O-validated parameter order — POC-O ran exactly this shape end-to-end against real git); the impl validates and returns the list verbatim as PreparedPush.updates (ADR-018 §5's "the transport consumes PreparedPush.updates" unchanged; the wire layer keeps command parsing — shallow rejection stays up-front, ADR-013 §4). Pre-publish draft shape (the OQ-03 freeze happens at the core's publish); the amendment note lands on ADR-018 with the task.
  • Unknown request capabilities fail closed (the fetch parse's posture); the accepted set is the advertised set plus quiet and agent (honored by omission — we never send progress; upstream clients select quiet habitually).
  • Duplicate ref commands in one push fail closed (upstream rejects multiple updates for one ref; not capture-pinned — flagged for the gate).
  • No-oid ref lines (the unborn-HEAD symref row) are filtered from the V0 advertisement — a V0 line has no symref shape; the OQ-19 rider (a) covers the ls-refs side, this covers the push side (flagged for the gate).
  • A client selecting no report capability gets no report (the captures always select report-status-v2; the honest grammar sends only what was negotiated — flagged for the gate).
  • The pack tail crosses the pkt-line→raw boundary through a substrate escape (the demand-driven pkt-line iterator is positioned exactly after the terminating flush; the no-byte-loss proof is a required test on both substrates).
  • The pack-size budget is enforced wire-side by the relay (fail-closed, the client-fault class — 413-mapped at the door on stateless), with Limits flowing into prepare as the impl-side defense (the POC's counting-reader posture).

General review (2026-10-22, post-wave-3 whole-surface pass — docs/reviews/004): the findings volume sat inside the inline bar — S-1/S-2/C-1/D-1 (the duplex request Readers' missing per-request budget, the O(n²) fetch dedup, the advertisement GET's unbounded listing, the unused tracing dep) fixed and stamped in the review session, tests added, all gates green. Recorded for later waves: R-1 (the wave-4 manifest read for the dead-until-then gix-protocol/gix-transport pins), R-2 (originally a wave-8 booking; re-booked pre-publish 2026-10-23 — the bound decision + the doubles' guard are wave-5 work, before the OQ-03 freeze; wave 8's impl inherits the decision — the size-bomb class), N-1 (the permit-through- stalled-relay observation — read at the wave-5 gate), N-2 (the substrate manifest's wave-6 read). No remediation wave.

Wave 4 — Consumer half + ops

  • GitSession (ADR-017, construction simplified per ADR-023 §2) — the wrapper over gix-transport's git-daemon Connection on the alkcall BiStream compat halves; connect_direct rides ADR-016's request-line preamble, open_via_channels rides the open-op params; ls_refs/fetch (full ack-loop negotiation client-side) and the hand-rolled push (mirror of ADR-013's server shapes); the client riders: packless push holds the write side open until the report (ADR-020 §3) and the RST read-your-request discipline (ADR-023 §5). Below-Negotiate/RefMap is the POC-X-validated structure (ADR-023 §6's recorded scope).
  • The op family (ADR-012 §3/§5, gate per ADR-015) — git/repo/{create,delete,update,get} as thin OperationSpec + handler pairs over Arc<dyn GitRegistryStore>; the PATCH semantics (review 002 R-3), the error-code table with the N-2 collapse rule (unauthorized = unknown ≡ unauthorized; already_exists create-side only — review 002 R-6's posture), create seeding the caller's {read, write, manage} grants.

Wave 4 may decompose as one wave or split (git-session ∥ op family are near-independent bodies of work sharing only the seam) — the decomposition decides with the task sizing in hand.

Decomposition record (2026-10-23): wave 4 decomposed into six task files under tasks/implementation/core/ (the wave-3 gate is green — core/review-wave-3's verdict; nothing needed absorbing). The near-independence read confirmed: the session branch and the op branch share only the seam, so the wave decomposes as two parallel branches under one wave (not a split — one gate). Shape: the construction first on the session branch — core/w4-session-construction (the ADR-017 §2-as-amended wrapper over the gix-transport git-daemon Connection on the BiStream compat halves; both constructors; the Limits wiring; the no-credentials posture) — then the two client machines in parallel over it, core/w4-session-fetch (ls_refs + the client-side ack loop, below-Negotiate/RefMap per ADR-023 §6) and core/w4-session-push (the hand-rolled send-pack mirror of ADR-013's shapes + the two client riders); the op branch runs core/w4-ops-gate (the ADR-015 §3 two-tier function, pure, no dependencies) with core/w4-repo-ops (the four spec+handler pairs + registration + the wire schemas/error table) over it; and core/review-wave-4 (the capture-level gate) depending on all five.

Interpretations recorded (flagged for the wave-4 gate):

  • The open_via_channels dialing responsibility (the session branch's one shape call): ADR-016 §4's "sends the same {repo, service} params schema" is ambiguous between the constructor dialing channels/git/sub itself and the constructor accepting the post-open BiStream (the POC-X shape — the transport writes nothing, the preamble rode the open-op). The task pins the decision against alkcall's client API and records it; the contract either way is that the params are sent by whoever dials.
  • The client-side response-pack budget maps to Limits::max_pack_size (the same budget kind, client-side direction) — no new Limits fields (ADR-009's no-new-kinds rule, the wave-3 gate's confirmed posture). Flagged for the gate to confirm the mapping reads honestly (a fetch response pack and a push report are both "response" directions of the same budget).
  • The ownership mint is required in v1's op family (the registration takes Arc<dyn OwnershipStore>): ADR-015 §Neutral records the mint could become optional for embedders that don't want spawn-tracking, but v1 keeps it ("kept in v1 because git/repo/* ops are family-shared and the record is cheap"); the optional-downgrade is a future additive change, not this wave's.
  • Review 004's dispositions are followed, not re-litigated: R-1 (the gix-protocol/gix-transport pin confirmation) folds into core/w4-session-construction as an acceptance criterion — the review's own recommendation ("a checklist item, not a task"), executed at that task's first commit where the deps become live code. R-2 is re-booked pre-publish (2026-10-23, operator review of the decomposition): the bound decision + the doubles' guard are wave-5 work — the original wave-8 booking would have placed the shape decision after the OQ-03 freeze of Limits (a post-freeze Limits field is semver surface on a published crate) and left the doubles — the reference ingest composition the wave-8 task is written against — unguarded through the core's publish; wave 8's impl inherits the decision. N-1 reads at the wave-5 gate, N-2 at the wave-6 manifest read; S-1/S-2/C-1/D-1 are landed — the wave-4 machines compose against the request-budget semantics as fixed.

General review (2026-10-23, post-wave-4 whole-surface pass — docs/reviews/005): the review-004 precedent's five code-quality dimensions (not a spec-compliance pass — the wave-4 gate's ADR verdict stands). The findings volume sat inside the inline bar — D-1/D-2 (the request-line wire reader's malformed-frame coverage gap, fixed with two byte-level tests — preamble 85→96%; the lib.rs crate-root changelog doc, rewritten module-oriented) fixed and stamped in the review session, full verification set green, coverage at 93.52% lines. Booked for wave 5: R-1 (the session.rs split — three clean-seamed workstreams, flat siblings per convention 14, zero public-API change, two in-file helper dedups folded in — the recommended first task of the wave, ahead of the fuzz harnesses: refactor → fuzz → docs → publish), and R-5 (the per-ingress coverage table — wave 5's fuzz-target inventory's input; the coverage disposition is review-time evidence, per-gate). R-2/R-3/R-4 are duplication keeps with rationale recorded (the client-mirror grammar shares nothing by design). No remediation wave.

Wave 5 — Core validation & release

The wave that lifts track B's gate. Three workstreams:

  • OQ-19's wire validations (tasks/architecture/ oq-19-wire-validations.md) — rider (a): the unborn-HEAD symref line against a real client on both substrates (the seeded-HEAD fixture from substrate.md §refs makes a dangling-HEAD repo trivial once the doubles provide one). Rider (b): the ack loop emitting positive ACKs — validated against the doubles' Find here; its substrate-odb facet re-runs in track B wave 7 against the real Find before the substrate crate's freeze (the OQ entry's wording covers both runs). Either ride's honest-retraction outcome stays inside this wave (ADR-003: serve or retract before publish).
  • Fuzzing — the family standing rule (anything worth fuzzing gets fuzzed), on the core's ingress surfaces: the pkt-line framing parsers, the git-daemon request-line grammar, the negotiation command/state ingress, the repo-id grammar, the preamble open-op params (the alkgit-owned post-schema ingress; the JSON schema gate itself is alkcall's surface, family-fuzzed there — the alkblobs finding). The fuzz/ sidecar convention (detached runner, corpus gate joining the verification list).
  • The size-bomb bound (review 004 R-2, re-booked here pre-publish 2026-10-23 — the original wave-8 booking would have decided the shape after the OQ-03 freeze of Limits and left the doubles unguarded through the publish): the decompressed-size/expansion cap for pack ingestion decided and landed before the freeze — the shape call (a named Limits field is the recommended posture, per the ADR-009 budget model where embedders tune budgets; a fixed fsck-style multiple is the alternative), the doubles' inflate_entry converted to incremental reading under the cap (no pre-allocation of the pack-declared size), and a hostile-declared-size regression test (the breach maps to the unpack-ng leg — the outcome class, never Err, matching the impl-side defense posture the wave-3 gate confirmed). Wave 8's real GitPackIngest inherits the decision and lands the incremental inflate in the substrate impl.
  • Release readiness for the core — crate docs (public-API rustdoc warning-free; docs honesty), the feature matrix (default, sha256 over it, --all-features), CHANGELOG/README, publish dry-run, then the publish of alkgit 0.1 — the gate review that unblocks track B's decomposition. OQ-03's core-side freeze inventory is settled here.

Decomposition record (2026-10-23): wave 5 decomposed into eight task files under tasks/implementation/core/ (the wave-4 gate is green — core/review-wave-4's verdict — and review 005's dispositions are absorbed; no remediation wave). Shape: the review-005 refactor first — core/w5-session-split (R-1: the flat-sibling split per convention 14 + the two in-file helper dedups + R-3's two cheap constants; zero public-API change) — with three independent tasks parallel to it: core/w5-size-bomb-bound (review-004 R-2: the decompressed-size cap decided and landed before the OQ-03 freeze — a named Limits field is the recommended posture; the doubles' incremental inflate; the hostile-declared-size regression), and the OQ-19 riders — core/w5-oq19-positive-acks (rider 2: positive ACKs over the doubles' Find; the substrate facet re-runs in wave 7) and core/w5-oq19-real-client-tokens (rider 3: the wave-2-gate-booked include-tag/session-id round — the survivable-decline validation + the per-token honor-by-omission/retraction decision); rider 1 (the unborn-HEAD symref) executes in-wave as the existing architecture/n5-unborn-head-rider task (the OQ-19 tracker's depends_on now spans all three riders). Then core/w5-fuzz-harness (the fuzz/ sidecar + targets over the plan's ingress inventory with R-5's table as the starting data + the corpus gate joining the verification list) over the split (targets pin the final module paths); core/w5-release-readiness (crate docs, the feature matrix, CHANGELOG/README creation, the publish dry-run) over all five; core/review-wave-5 (the release gate: the OQ-19 dispositions, the fuzz corpus gate, the size-bomb disposition, the counting-reader decision, N-1's read, the freeze inventory; flips the docs to stable) over everything; and core/w5-publish (the publish checklist: manifest sanity + the 0.1.0 bump, tests, CHANGELOG check, dry-run, the alkgit-v0.1.0 tag, cargo publish) over the gate — the gate stays a pure review; the publish is its own task.

Interpretations recorded (flagged for the wave-5 gate):

  • The size-bomb cap shape (core/w5-size-bomb-bound's one spec-level call): a named Limits field is the recommended posture (ADR-009's embedder-tuned budget model); the fixed fsck-style multiple is the alternative. The field lands pre-publish (additive — the freeze happens at the publish); wave 8's impl inherits the decision.
  • The rider-3 token dispositions (core/w5-oq19-real-client-tokens): per token (include-tag, session-id=, the rest of the modern-client inventory), honor-by-omission vs honest retraction — decided in the task, confirmed or corrected at the gate.
  • The counting-reader decision (the wave-4 gate's recorded residual — gix's V2 handshake buffers the peer's capability advertisement internally): read at the gate — accept the wall-clock-only bound (peer servers are authenticated alk nodes) or land the read-half wrapper; recorded for the OQ-03 inventory either way.
  • Review 004 N-1 (the permit-through-stalled-relay observation) reads at the gate, per its booking.
  • The tag convention (core/w5-publish): crate-qualified tags (alkgit-v0.1.0) — two crates publish from this repo over the plan's life; a bare v0.1.0 would be ambiguous at the substrate's publish. Pinned at the publish task; flagged for the gate to confirm.

Wave 6 — Substrate foundation

Track B's seam-side foundation (against the published alkgit):

  • Substrate scaffold + alkgit version pin — the crate manifest (features sqlite on / postgres off / lfs on per ADR-025; alkgit pinned by version, never a path).
  • References + the git-object tables: refs row tables + row-CAS apply_updates (ADR-019 §2 — one transaction per call; the atomic realization POC-O validated); the put_repo-seeds-HEAD rule (substrate.md §refs — HEAD → refs/heads/main in the record transaction, this wave's implementation home).
  • Migrations (ADR-024) — construction-run, version-stamped, additive-first; the LFS refcount column ships day-one in the initial schema; the in-memory adapter stamp-free.
  • The registry adapter family + reactive halves (ADR-019 §3–5) — the family adapter pattern (read-side cached provider, write-side seq-bumping transactions + post-commit announce), publish/notify/ enqueue, the reconcile sweep, the per-push mutation marker; the in-memory default adapter; the sqlite twin (default) and postgres twin (feature).

The wave-6 gate reads the landed tables/adapters against ADR-019/024 and the POC-R evidence (the coherence contract's staleness bounds, the reconcile-closure recipe).

Decomposition record (2026-10-23): wave 6 decomposed into eight task files under tasks/implementation/substrate/ (track-B tasks live there per the wave-1 record; the gate is lifted — alkgit 0.1.0 published, commit 0dd5721). Shape: the scaffold first — substrate/w6-scaffold-manifest (the N-2 manifest read: the pins re-spected against gitoxide.md, the gix-ref → gix-validate swap, the tracing D-1-style decision, the alkblobs ops enablement decision; the module skeleton + the fallible-constructor error surface) — then two independent foundations in parallel: substrate/w6-registry-family (the adapter trait pair + the in-memory default adapter + the cached read provider + the alkgit registry-pair impls) and substrate/w6-migrations (the ADR-024 machinery + the initial co-tenant schema as the sqlite step set + the co-tenant connection handle shape); then three tasks over those — substrate/w6-refs-rows (the CAS-semantics reference impl in-memory + the sqlite one-transaction row-CAS twin + the table-layer name validation) over the migrations, substrate/w6-reactive-halves (the reactor: announce/wake-runner/stream-consumer/reconcile + the construction wiring) over the family, and substrate/w6-registry-sqlite (the sqlite twin: constructor + the seq-bumping write side + put_repo-seeds-HEAD + the marker write + the announce composition) over family + migrations + reactive; substrate/w6-registry-postgres (the postgres twin under the postgres feature: the same logical schema in pg steps, the LISTEN/NOTIFY leg, the live-pg harness tests) parallel to the sqlite twin; and substrate/review-wave-6 (the evidence-level gate) depending on all seven.

Interpretations recorded (flagged for the wave-6 gate):

  • The GC chain's placement: the reactive halves' enqueue (the producer side) lands in wave 6; the chain's consumer side (schedule → queue → worker claim → leader TTL lock → sweep dispatch) and the ref-table-closure liveness source land in wave 7 with the substrate Find — the sweep payload needs a registered liveness source (alkblobs' sweep aborts without one), and the Find is wave 7's. The plan's wave-6 bullets name enqueue + reconcile only; this reading keeps the wave honest to them.
  • The single composition entry (substrate.md §public API — "construction wired by a single composition entry that takes the substrate engine handles") lands in wave 8, the first wave where all five trait impls exist (the entry constructs the complete backend); wave 6 lands the per-piece constructors (adapter constructors, the reactor wiring) the entry will unify. The assembly-shape exercises stay wave 10.
  • The alkblobs ops feature enablement (substrate.md's feature-pin note says the manifest enables it "when those land"): the wave-6 reading is that the reactive halves are alkstore machinery and consume nothing from alkblobs' alkcall surface — the ops feature's real consumer is the LFS byte paths (wave 9's pre-keyed put / ranged fetch ride alkblobs' marked-pub-put contract, alkblobs ADR-014), so the enablement lands in wave 9 unless the scaffold task's surface check finds otherwise. Flagged for the gate.
  • The live-pg harness: the postgres twin's live tests ride the family harness container (localhost:15432, the alkblobs env-gated convention — skip with a clear message when absent); the env names are the postgres task's to pin.

Wave 7 — Objects & generation

  • alkblobs git-object-family wiring — loose objects under the derivation family (alkblobs ADR-018), the odb layer owning the header it writes, stat = preimage length.
  • The substrate Find/odb front (SubstrateOdb-class) — gix_object::Find/Exists + gix_pack::Find shapes, location legs empty, constructed once with per-session views.
  • GitPackGen + common_haves real impls — ADR-004's pipeline over the real Find; both serving shapes (direct + through-store); OQ-19 rider (b)'s substrate facet re-validation runs here (positive acks over the real substrate Find) and closes the rider alongside wave 5's machinery-side run.

Plus the wave-6 gate's riders, booked into this wave by the gate: the GC chain's consumer side + the ref-table-closure liveness source (the recorded wave-6 interpretation), the wake-runner supervision (N-b), and the pg GitRefs row-CAS twin (N-c).

Decomposition record (2026-10-23): wave 7 decomposed into seven task files under tasks/implementation/substrate/ (the wave-6 gate is green — substrate/review-wave-6's verdict; its two riding obligations N-b/N-c are booked as task material below). Shape: the foundation first — substrate/w7-odb-front (the alkblobs git-object-family wiring + the SubstrateOdb-class Find front + the one-place sync/async bridge rule) — then two parallel branches over it: substrate/w7-packgen (the real GitPackGen + common_haves; both serving shapes) with substrate/w7-oq19-substrate-acks (rider (b)'s substrate facet — the positive-ack capture over the real Find, closing the both-runs wording) over it; and substrate/w7-liveness-source (the ref-table-closure LivenessSource over the Find + the wave-6 refs rows) feeding substrate/w7-gc-chain (the maintenance chain's consumer side — schedule/claim/leader-lock/sweep-dispatch — plus the N-b wake-runner supervision and the reconcile tick's driving); substrate/w7-refs-postgres (N-c: the pg row-CAS twin, the mechanical translation over the shared cas_decide core) parallel to everything from the start; and substrate/review-wave-7 (the evidence-level gate) depending on all six.

Interpretations recorded (flagged for the wave-7 gate):

  • The object pool is global, not per-repo-namespaced: git oids are global by git's own design (the alkblobs ADR-017 global-pool caveat, accepted for git objects in ADR-019's neutral consequences); the store's git-object family carries no per-repo namespace rows — per-repo coverage is liveness-decided (the ref-table closure), and repo deletion is a GC consequence. The core's MemObjects double namespaces per repo for test isolation; the real store does not — the Find front reads the family directly. Flagged so the implementation does not inherit the double's namespace shape.
  • The through-store mode selection is the substrate impl's internal posture: the trait's sink is the wire's sideband end either way (the wire layer is unchanged — the frozen signature carries no mode parameter), so both serving shapes live inside the substrate generate implement; the selection mechanism (a constructor-level posture vs a per-call decision) is the task's to pin, flagged for the gate.
  • The liveness memo's invalidation is the task's design point: the wave-6 refs tables carry no version counter (POC-O's memoized-by- version shape used a POC-local one), so the mechanism (an in-process version bump on the refs writes, a TTL, a durable marker) is pinned in-task — with the fleet shape's cross-process ref-write invalidation answered honestly. Flagged for the gate.
  • The reconcile tick's driving mechanism (part of N-b) and the PackHousekeeping consumer action are pinned in-task (the wave-6 interpretation books the tick's driving with the chain; the pack cache's release path is the natural housekeeping consumer) — flagged for the gate.

Wave 8 — receive-pack ingestion

The ADR-020 composition, for real:

  • GitPackIngest: budgeted index into the host working area (thin bases via the substrate Find), unpack-to-loose under verification-on-put, the pin bridge + pending-pin registry (substrate.md §object storage's pinned custody rules: content- addressed correlation, post-CAS guard commits, stale-entry pruning, GC-decreed recovery), the full-graph connectivity walk (parents included), working-area discard. The inflate path reads incrementally under the wave-5-pinned decompressed-size bound (review 004 R-2's implementation half — the decision and the doubles' guard landed pre-publish in wave 5; this wave's decomposition record names the inherited cap).
  • End-to-end against real git — git push (ordinary, thin, packless-delete, atomic) and git clone/fetch against the substrate-backed server, plus the replication loop through GitSession (ADR-023's POC-X gates re-landed on the real code).

Plus the wave-7 gate's riders booked to this wave: O-b (the dead chain_stop arm — the composition entry's run wiring decides wire-or- drop) and O-c (the dead pg live forwarder — folded into the entry's pg touch). O-a (the FleetTable materialization) stays with wave 10's assembly-shape exercises per the gate's booking.

Decomposition record (2026-10-23): wave 8 decomposed into six task files under tasks/implementation/substrate/ (the wave-7 gate is green — substrate/review-wave-7's verdict; its riders O-b/O-c are booked as task material above). Shape: the custody seam first — substrate/w8-pin-registry (the pending-pin registry + the composition-internal GitRefs implement carrying the receive flow's commit side: stale-prune → CAS → drain-only-after-commit, then the marker + announce legs, fail-soft) — then substrate/w8-pack-ingest (the GitPackIngest implement: budgeted index into the host working area, thin bases through the substrate Find; unpack-to-loose into the family store with guards into the registry; the full-graph connectivity walk from the pushed tips; working-area discard; the inherited cap) over it; substrate/w8-composition-entry (the substrate.md §public-API entry — the complete backend per assembly (mem/sqlite/pg), the O-b/O-c riders) over both; then the two end-to-end tasks in parallel over the entry — substrate/w8-e2e-real-git (POC-O's gates re-landed: real push ordinary/thin/packless-delete/ atomic + real clone/fetch, the core's real-client door shapes over the substrate backend) and substrate/w8-e2e-replication (the POC-X gates re-landed: the two-node mirror converges on real code, the recipe's riders, the recorded HEAD posture); and substrate/review-wave-8 (the evidence-level gate) depending on all five.

Interpretations recorded (flagged for the wave-8 gate):

  • The custody split: the pending-pin registry + the committed-ref side land as their own task ahead of the ingest implement — the custody semantics are what ADR-020 §2/substrate.md pin, and they are testable in isolation (the ingest implement composes against a test-pinned seam instead of carrying the semantics in-line). The marker + announce legs ride the same composition-internal GitRefs implement because the wire layer reaches the backend only through GitRefs::apply_updates — the receive flow's post-CAS steps have exactly that one seam to hang from; substrate.md §the receive-pack flow's composed order is realized inside it.
  • The inherited cap: Limits::max_object_size (the 2026-10-23 pre-publish decision — 512 MB default, the ADR-009 budget model's field; the wave-5 doubles' guard the acceptance shape). The enforcement mechanism through gix's own index/inflate machinery is the ingest task's design point and this decomposition's named inheritance — the wave-8 section's promised line (the POC-O reference shape, Bundle::write_to_directory + the odb handle, predates the cap decision and is not mechanically sufficient as-is).
  • The working-area posture: the root is a constructor-level knob (no env vars), one process-scoped directory per push, cleanup on every path; the disk shadow is ≈ the pack budget (the working area holds the temp index + pack) — sized off Limits::max_pack_size, no new Limits field (ADR-009's no-new-kinds rule).
  • The replication-loop task is test-consumer posture: ADR-023's replicator is an embedder assembly (a GitSession client + the registry stream consumer) — no new public surface, the OQ/ADR text untouched; the loop is built in test code over the published pieces. The cross-process rider stays out (POC-X's two_process.rs shape — flagged to the gate for a wave-10 booking or an in-wave decision).
  • The e2e door shapes ride the core's real-client test doors (tests/real_client.rs's duplex-TCP + smart-http-stub patterns, mirrored in substrate tests — the core's test helpers are not importable; the duplication keeps the crates seam-separated, the w7-packgen byte-identity note's posture). git is a test client only (the serving path spawns nothing — convention 7).

Wave 9 — LFS

ADR-022's surface on the landed stack:

  • Reference rows + day-one refcount (the ADR-024 column) — repo-lifetime scoping v1 (OQ-20 stands deferred), the media-re-protected-while-any-row-remains sweep contract.
  • Liveness wiring — the LFS media rows as the second alkgit-owned liveness source; register/remove with push and ops.
  • The batch adapter + ops composition — lfs batch/checking over the ops control plane, the pre-keyed put / ranged fetch byte paths, wired ownership providers (the POC-L door's seam evidence as the regression posture).
  • Real git-lfs client round trips against the composition (the POC-L gates re-landed).

Decomposition record (2026-10-24): wave 9 decomposed into five task files under tasks/implementation/substrate/ (the wave-8 gate is green — substrate/review-wave-8's verdict; its observations O-e/O-g/O-a ride wave 10 per the gate's own bookings, nothing absorbed here). The lfs_objects table already ships day-one in both engine step sets (wave 6's initial schema, refcount column included — ADR-024 §5), so the wave lands the consumption of what the schema pre-committed. Shape: the durable state first — substrate/w9-lfs-rows (the pointer-lifecycle row store: the row-op surface, the refcount semantics — the task's named design point, the mem + sqlite + pg implements, the repo-deletion removal legs) — then two parallel branches over it: substrate/w9-lfs-liveness (the media rows as the second alkgit-owned liveness source + the fail-safe registration wiring at the composition entry + the sweep contract) and substrate/w9-lfs-adapter (the substrate-side batch/transfer mapping: the batch/checking adapter over the ops control plane, the pre-keyed put / ranged fetch byte paths, the wired ownership providers, the manifest's alkblobs/ops enablement — the wave-6-flagged decision landing); then substrate/w9-e2e-real-lfs (the POC-L gates re-landed: real git-lfs 3.7.0 through a test door over the composition + the ops plane, the engine matrix, the GC sweep rows) over both; and substrate/review-wave-9 (the evidence-level gate) depending on all four.

Interpretations recorded (flagged for the wave-9 gate):

  • The adapter's binding shape (the wave's one spec-level call): the substrate-side batch/transfer mapping composes batch/checking over the ops control plane (blobs/stat through an OperationContext — the POC-L DirectOps posture as a substrate surface) with the byte paths the pre-keyed put / ranged fetch, and the wired ownership providers (never the static fallback — the gateway-gap regression posture). ADR-025's neutral consequence records the door-side batch mapping as riding alkblobs directly — the split between what the future alkhttp lfs door consumes from this surface and what rides alkblobs directly (the row assertion is the composition-owned piece only this surface carries) is the adapter task's to pin and the gate's to confirm.
  • The "register/remove with push and ops" bullet read as: register = the liveness source's registration wired at the composition entry (the fail-safe default, ADR-022 §6); remove = the rows leaving with repo removal (the record-removal legs, same removal as refs/registry). Rows are asserted by the batch surface at check/upload time — never by push: pointer blobs are ordinary git blobs and the git path stays LFS-unaware (ADR-022's model).
  • The refcount's consumption mechanism (what bumps/decrements/reads the day-one column) is the rows task's named design point — the contract it serves is ADR-022 §4's re-protect-while-any-row-remains; the mechanism is flagged for the gate.
  • The removal legs' feature placement: the suggested posture is an unconditional DELETE (the table ships unconditionally; the rows only exist when the lfs surface wrote them; a mixed deployment that turned the feature off must not leak) — pinned in-task, flagged.
  • The liveness source's memoization posture: the mark consult is a row read, not a graph walk (media is unstructured content) — rebuild-per-mark is the simple honest shape; the fingerprint+write-counter machinery only if the arbitration discipline needs it. Pinned in-task, flagged for the gate.
  • The e2e binding matrix: DirectOps primary (the recommended embedded form — POC-L's measured ~25 ms vs ~80 ms loopback); the loopback binding's row coverage pinned in-task, flagged. The test door mirrors POC-L's reference door shape (the alkhttp lfs feature stays family infrastructure — doors.md sequencing; the wave-8 e2e posture).

Gate record (2026-10-24, substrate/review-wave-9 — green after inline remediation): the gate's one blocker-class finding — the liveness epoch discipline's soundness argument inverted (bump-before-commit + load-after-read let an in-flight assert's bump pair with a rows read that missed the uncommitted commit; the poisoned memo answers exact-dead for just-referenced media; the same flaw pre-existed in the wave-7 RefClosure) — plus eight should-fixes landed inline (the discipline flipped to bump-after-commit + load-before-read on both sources with straddle regression tests; the mem rows store exact under one lock; the pg removal leg added to the row-store advisory lock; the adapter's whole-span oid verification + resolved-span ceiling; the fleet custody arm confirming immediately; three e2e guards/order fixes; the transfers door duty recorded). All recorded interpretations confirmed or corrected (F-B1's mechanism correction is the gate's one spec-level call); OQ-20 re-confirmed deferred; the OQ-03 substrate-side inventory grown with the wave-9 names. Booked to wave 10 (substrate/review-wave-9's F-w10-B1..B7): the big-media/ceiling e2e rows (door 413/404 paths asserted by no row), the per-piece twin assemblies' raw lfs_rows() parity, the fleet arm's live-pg battery coverage, the dead fetch_max_total_bytes disposition, the ADR-022/lfs.md verification-wording pass, the engine-less combo's clippy residual, and the pre-existing compose flake (w9-lfs-rows' booking).

General review (2026-10-24, post-wave-9 whole-surface pass — docs/reviews/006; the review-005 precedent's five dimensions plus the substrate-specific twin-parity and assembly-shape-parity ones, inserted between the gate and wave 10's decomposition): the findings volume sat inside the inline bar — S-1 (the pg registry's put/remove legs touched git_refs without the advisory lock the CAS twins hold for their whole call — the F-S2 sibling that didn't get the fix; an orphan-row window under multi-instance co-tenancy) and S-2 (the live-pg silence-probe gate promoted shared; the compose entry's announced-write live tests take it) fixed and stamped in the review session alongside D-1..D-5 (the crate-root doc rewrite — the review-005 D-2 analog — and four doc/hygiene items), the full verification set green after (the live-pg run 208, 0 skips). Booked as the head-of-wave-10 recommendations: R-1 (the postgres.rs placement split — the machinery re-home to migrations.rs), R-2 (the impl helper dedups), R-3 (the test-harness consolidation), R-4 (the mem_registry disposal — the freeze inventory settles it), R-5 (the coverage table — F-w10-B1's input; coverage stays review-time evidence), R-6 (the per-piece parity class F-w10-B2 absorbs), R-7 (the engine-less combo joins F-w10-B6's feature hygiene). N-1..N-4 observations recorded. No remediation wave.

Wave 10 — Substrate validation & release

  • OQ-21's composition-validation POC (tasks/architecture/ oq-21-lfs-lock-validation.md) — the real lfs.locks API flows over the substrate stack (alkstore's named-TTL locks, lock rows co-tenant on the shared engine, sqlite contention measured); both outcomes are wins (posture evidenced / gaps surfaced upstream-cheap). The build stays deferred on the first client need.
  • Release readiness for the substrate — crate docs, the feature matrix (sqlite on, postgres, lfs, combos: pg-pure, lfs without postgres, --all-features), the three assembly shapes (substrate.md §assembly shapes) exercised in tests, CHANGELOG/ README/docs honesty, publish dry-run, then the publish of alkgit-substrate 0.1 — the release gate that closes the plan.

Decomposition record (2026-10-24): wave 10 decomposed into nine task files under tasks/implementation/substrate/ (the wave-9 gate is green and review-006's verdict is in — no remediation wave; the R-1..R-7 recommendations and the F-w10-B1..B7 / O-e/O-g/O-a bookings are the decomposition's inputs, organized per the review's Part D order). Shape: the review-006 refactors first — substrate/w10-postgres-placement (R-1 + R-2 folded: the pg machinery re-home to migrations.rs + the three helper dedups; zero public-API change) with substrate/w10-oq21-lock-poc (the OQ-21 composition-validation POC — branch mode, parallel to the refactors: it walks the landed stack and is independent of them) — then substrate/w10-test-harness (R-3: the testutil home + the LIVE_GATE re-home) over the placement; substrate/w10-parity-surfaces (R-6 + F-w10-B2 + R-4's execution: the LFS twins carry the wrap, the through-store cache posture, the mem_registry disposition) over the harness; substrate/w10-test-evidence (F-w10-B1/B3 + O-a's FleetTable + O-g's decision + F-w10-B7's flake fix + O-e's watch; R-5's coverage table the starting inventory) over the parity surfaces; substrate/w10-feature-hygiene (R-7 + F-w10-B6: the one-pass off-matrix combo fix) over the harness; then substrate/w10-release-readiness (crate docs, the feature matrix, CHANGELOG/README creation, the F-w10-B4/F-w10-B5 dispositions, N-3's optional core-doc sweep, the dry-run) over the POC, the evidence, and the hygiene; substrate/review-wave-10 (the release gate: the OQ-21 outcome, the freeze inventory settled, the dispositions confirmed; flips the substrate-era docs to stable) over it; and substrate/w10-publish (the publish checklist: the 0.1.0 bump, the tag alkgit-substrate-v0.1.0, cargo publish) over the gate — the gate stays a pure review; the publish is its own task.

Interpretations recorded (flagged for the wave-10 gate):

  • The OQ-21 POC runs branch mode (it builds on the landed composition — the object under test; POC code never merges — findings land in lfs.md §Lock server + the OQ-21 entry, the branch dropped).
  • The O-g cross-process rider is the test-evidence task's in-wave decision (the POC-X two-process row re-lands, or the in-process evidence stands with the rider recorded as future work) — flagged.
  • The mem_registry disposition (remove vs doc-stamp) executes in the parity task; the gate confirms the OQ-03 inventory entry.
  • The through-store cache posture (explicit cache vs documented probe surface) is the parity task's call — flagged.
  • F-w10-B4's disposition (drop the dead knob vs wire the budget through it) lands at the release-readiness docs/manifest read — flagged.
  • The testutil home's placement (a non-pub sibling testutil.rs vs a #[cfg(test)] shared module) and the LIVE_GATE home are the harness task's calls — flagged.
  • N-2's conditional parity test (the tripled in-SQL removal legs) stays recorded-only — no schema work enters wave 10; the guard is owed only if that changes. N-3's core-doc sweep is the release-readiness task's optional ride.

Gate record (2026-10-24, substrate/review-wave-10 — green after inline remediation): the OQ-21 composition-validation outcome read and confirmed (posture evidenced — the plain-row mapping over the measured machinery gap; the build deferral stands; OQ-03's substrate publish-side blocker dropped); the substrate-side OQ-03 freeze inventory settled and reconciled against the crate root's actual re-export list (all flagged recorded interpretations confirmed: O-g as recorded future work, the through-store probe stamp, the mem_registry removal, the testutil sibling home, the LIVE_GATE stay); the release-readiness surface verified (docs, matrix incl. the three off-matrix clippies, CHANGELOG/README, the dry-run re-run; F-w10-B4's drop, F-w10-B5's wording pass, N-3's sweep confirmed); the test evidence read green (F-w10-B1/B3/B7, O-a's FleetTable, O-e's watch; review 006 R-1..R-7 all verified absorbed). Four inline findings fixed in-session: the stale architecture-README status-index cells (the wave-5 flip missed them), two task-record slips (the test-evidence Summary's O-b/O-c cross-reference, the placement task's unticked ACs), and the freeze-precision re-export (DEFAULT_SCHEMA + LOCKED_OUT_RETRY_SECS promoted to the crate-root list — both were module-path-public; additive pre-freeze). Full verification set green re-run at the gate tree (376/186/379, the live-pg run 212 with 0 skips, the fuzz corpus gate 13, fmt + five clippy passes, doc, dry-run). substrate.md and lfs.md flipped to stable (the architecture README's index cells made truthful with them); substrate/w10-publish unblocks — the plan's final task.

Decided points

  • Wave-based decomposition (ADR-025 consequence; operator-endorsed 2026-10-20): the SDD decompose-everything-upfront step is replaced by the alkstore/alkblobs rhythm — decompose the next wave after the previous wave's review gate; later decompositions absorb earlier outcomes. Renumbering is a guide, not a contract: remediation waves discovered by whole-surface reviews get inserted and the later waves renumbered (the alkblobs 8–10 precedent).
  • Two-track stagger on the publish gate (ADR-025's anchored-basis posture): the core publishes before the substrate track decomposes or implements. The substrate builds against a published anchor; the inter-crate version pin is enforced from wave 6's first commit.
  • Fuzzing embedded in wave 5 (operator, 2026-10-20): "5 is great for now and we'll move it later if needed" — the core's ingress fuzzing runs inside the core-validation wave rather than as its own wave; if the ingress inventory found at decomposition says it wants more room, it splits and the numbering follows.
  • Scope authority (operator, 2026-10-20): v0.1 publishes both crates with LFS in scope (ADR-022); doors stay out of this plan — the alkhttp git/lfs features land in that repo after the core's publish (doors.md sequencing), alkssh stays future.
  • OQ-19 reclassified deferred(scope) (review-003, 2026-10-20): blocked on the booked wave item; rider (a) runs in wave 5, rider (b)'s machinery-side run in wave 5 and its substrate facet in wave 7 — both must pass before the respective crate's freeze (OQ-03).
  • W-2/W-3 decisions recorded in-line (review-003, 2026-10-20): the pending-pin registry (substrate.md §object storage) and the put_repo-seeds-HEAD rule (substrate.md §refs; ADR-023 §4's stated limitation) are composition-internal pins, not ADRs.
  • Taskgraph DAG discipline: task files live under tasks/implementation/ with the frontmatter enums (AGENTS.md task rules), decomposed one wave at a time; taskgraph validate after every write; parallel branches are ordered by the graph so independent workstreams don't step on each other.

Review gates

Each wave ends in a review task (review-wave-N) before the next wave decomposes. The wave's gate reads the landed surface against the pinned ADR text line by line (the alkblobs gate discipline):

  • Wave 1 review — the one-way-door gate: seam types, trait signatures, and Limits read against ADR-018 (as amended) and the N-3 schemas; a shape error here is a task revision.
  • Waves 2–4 reviews — capture-level: the fetch machine against negotiation-captures.md/ADR-014, the push machine against push-captures.md/ADR-020, GitSession/ops against the ADR-016/ 017/023 shapes and the POC-X evidence.
  • Wave 5 review — the core release gate: OQ-19's disposition (all three riders served or retracted), the fuzz corpus gate, the size-bomb bound's disposition (the cap landed, the doubles guarded — R-2 closed pre-publish), the counting-reader decision (the wave-4 gate's residual) and review 004 N-1's read, the feature matrix, the publish dry-run, the OQ-03 core-side freeze inventory settled; flips transport/overview/backend to stable on green. The publish itself is core/w5-publish over the gate (the gate stays a pure review).
  • Waves 6–9 reviews — evidence-level: landed composition vs ADR-019/020/022/024 and the four POC findings' measured datums.
  • Wave 10 review — the substrate release gate: OQ-21's POC outcome recorded, the substrate-side freeze inventory settled; flips substrate/lfs/substrate-era backend sections to stable.

Remediation waves, when a review's findings exceed the inline bar, insert before fuzzing/release of the affected track and renumber (the alkblobs rule: the original numbering was a guide, not a contract; older pre-renumbering records read as their current numbers).