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).
62 KiB
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:
alkgitat the root'ssrc/,alkgit-substrateundersubstrate/), the crate manifests reworked per the placement table (backend.md §crate and feature model:alkgit'ssha256off-by- default;alkgit-substrate'ssqliteon,postgres/lfsper 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) andStorageError(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/PushOptionsand theRepoRecordserde 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: falseon 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; therepo: &RepoRecordparameter 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-
donerounds (acknowledgmentssection, NAK + flush, neverready), the statelessdoneround with done-closure generation,common_havesdriving the ack check behind the seam. GitPackGenover 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.updatespoint); the function is crate-public so the interim is not dead code — additive pre-publish, the gate confirms the placement. - The
common_havescontract 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
generatecall site); the shared semaphore is constructed by the serving entries fromLimits::max_concurrent_blocking_tasks. - The stateless serving entry includes the advertisement emission for
the door's future
info/refsroute (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_failedreason 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
Limitsfield, the partial-header-is-malformed rule. GitPackIngestover doubles — prepare/apply split (the single CAS home inGitRefs::apply_updates), CAS timing per ADR-013 §7's observed order,atomicsemantics, 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
preparesignature 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 preparedRefUpdatelist 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 addsupdates: Vec<RefUpdate>afterrepo(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 asPreparedPush.updates(ADR-018 §5's "the transport consumesPreparedPush.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
quietandagent(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
Limitsflowing intoprepareas 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-daemonConnectionon the alkcallBiStreamcompat halves;connect_directrides ADR-016's request-line preamble,open_via_channelsrides the open-op params;ls_refs/fetch(full ack-loop negotiation client-side) and the hand-rolledpush(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 thinOperationSpec+ handler pairs overArc<dyn GitRegistryStore>; the PATCH semantics (review 002 R-3), the error-code table with the N-2 collapse rule (unauthorized= unknown ≡ unauthorized;already_existscreate-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_channelsdialing responsibility (the session branch's one shape call): ADR-016 §4's "sends the same{repo, service}params schema" is ambiguous between the constructor dialingchannels/git/subitself and the constructor accepting the post-openBiStream(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 newLimitsfields (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 becausegit/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-transportpin confirmation) folds intocore/w4-session-constructionas 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 ofLimits(a post-freezeLimitsfield 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 positiveACKs — 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
Limitsand 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 namedLimitsfield 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_entryconverted 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, neverErr, matching the impl-side defense posture the wave-3 gate confirmed). Wave 8's realGitPackIngestinherits 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,sha256over it,--all-features), CHANGELOG/README, publish dry-run, then the publish ofalkgit 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 namedLimitsfield 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 barev0.1.0would 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
sqliteon /postgresoff /lfson per ADR-025;alkgitpinned by version, never a path). - References + the git-object tables: refs row tables + row-CAS
apply_updates(ADR-019 §2 — one transaction per call; theatomicrealization POC-O validated); theput_repo-seeds-HEAD rule (substrate.md §refs —HEAD → refs/heads/mainin 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
opsfeature 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 — theopsfeature'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::Findshapes, location legs empty, constructed once with per-session views. GitPackGen+common_havesreal 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
MemObjectsdouble 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
sinkis 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 substrategenerateimplement; 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
PackHousekeepingconsumer 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) andgit clone/fetchagainst the substrate-backed server, plus the replication loop throughGitSession(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
GitRefsimplement because the wire layer reaches the backend only throughGitRefs::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 newLimitsfield (ADR-009's no-new-kinds rule). - The replication-loop task is test-consumer posture: ADR-023's
replicator is an embedder assembly (a
GitSessionclient + 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'stwo_process.rsshape — 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 —
lfsbatch/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-lfsclient 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/statthrough anOperationContext— 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 alkhttplfsdoor 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
lfssurface 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
lfsfeature 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 reallfs.locksAPI 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 (
sqliteon,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 ofalkgit-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_registrydisposition (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-
pubsiblingtestutil.rsvs 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/lfsfeatures 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 validateafter 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
Limitsread 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 againstpush-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
stableon green. The publish itself iscore/w5-publishover 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).