From 11ceead6fd023f74e8a6527d28c892ce05b2d74f Mon Sep 17 00:00:00 2001 From: "glm-5.3-flash" Date: Wed, 30 Sep 2026 04:19:37 +0000 Subject: [PATCH] =?UTF-8?q?docs(architecture):=20N-4=20+=20N-5=20=E2=80=94?= =?UTF-8?q?=20push-options=20trait=20param,=20unborn-HEAD=20rider?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - N-4: GitPackIngest's prepare binding carries push_options: Option<&PushOptions> (parsed (key, value) pairs, verbatim and un-interpreted; None until the config gate opens) — pinned in ADR-013 §11 and backend.md's trait description so opening the config gate later is value-additive, not a trait redesign - N-5: ls-refs=unborn verification recorded as a rider in transport.md §ls-refs + tracker task tasks/architecture/ n5-unborn-head-rider.md (unborn fixture, real client, both substrates; drop the token if it cannot be served — ADR-003) - review 001: N-4, N-5 marked resolved verification: cargo test, clippy -D warnings, fmt --check, doc — clean --- docs/architecture/backend.md | 7 ++- .../013-receive-pack-state-machine.md | 7 ++- docs/architecture/transport.md | 8 +++ ...1-architecture-pre-decomposition-review.md | 4 +- tasks/architecture/n5-unborn-head-rider.md | 58 +++++++++++++++++++ 5 files changed, 80 insertions(+), 4 deletions(-) create mode 100644 tasks/architecture/n5-unborn-head-rider.md diff --git a/docs/architecture/backend.md b/docs/architecture/backend.md index 4e7f63f..d73521c 100644 --- a/docs/architecture/backend.md +++ b/docs/architecture/backend.md @@ -51,7 +51,12 @@ gix types: `.keep` guard; missing objects → `unpack ng`. It *prepares* the validated ref updates; the transaction itself is applied by `GitRefs` (single CAS home — ingest validates, refs commits; one transaction per - push is what makes `atomic` correct — ADR-013 §7). Budgeted (ADR-009 + push is what makes `atomic` correct — ADR-013 §7). The prepare binding + carries `push_options: Option<&PushOptions>` (ADR-013 §11, review 001 + N-4): the parsed per-push metadata, present only when `push-options` + was negotiated — `None` until the config gate opens; alkgit parses and + forwards the option pairs verbatim, never interprets them (their + meaning is the caller's policy domain). Budgeted (ADR-009 max pack size); the impl runs its blocking work off the async executor (concurrency model below). diff --git a/docs/architecture/decisions/013-receive-pack-state-machine.md b/docs/architecture/decisions/013-receive-pack-state-machine.md index 9e699ab..a009170 100644 --- a/docs/architecture/decisions/013-receive-pack-state-machine.md +++ b/docs/architecture/decisions/013-receive-pack-state-machine.md @@ -186,7 +186,12 @@ verification of the ingestion composition. Captures are recorded in 11. **Push-options**: negotiated (`push-options` advertised only when the assembler enables it; default off in v1), request section parsed (bare pkt-lines between the command flush and the pack) and surfaced - to the ingest/refs seam as per-push metadata. Rejection of specific + to the ingest/refs seam as per-push metadata: the prepared binding + carries `push_options: Option<&PushOptions>` — the parsed + `(key, value)` pair list, verbatim and un-interpreted — present only + when `push-options` was negotiated (`None` until the config gate + opens; review 001 N-4's additive-signature pin, so opening the gate + later is a value change, not a trait redesign). Rejection of specific options is `ng `; the section's absence when not negotiated must not be parsed as commands (the flush boundary is authoritative). diff --git a/docs/architecture/transport.md b/docs/architecture/transport.md index daa6f3a..5055502 100644 --- a/docs/architecture/transport.md +++ b/docs/architecture/transport.md @@ -68,6 +68,14 @@ substrate property (per-request state), not a protocol fork. - Parse `command=ls-refs` (peel, symrefs, ref-prefix), stream ref lines from the backend's listing, flush. `ref-prefix` filtering is client-driven. +- **Unborn-HEAD rider** (review 001 N-5): `ls-refs=unborn` is advertised + (POC-1 validated the *capability token* was accepted, but serving an + unborn HEAD's symref line was never exercised against real git — the + only advertised promise without capture evidence). Implementation-phase + verification: an ls-refs round against an unborn repo, real client, + both substrates (the unborn repo fixture in the POC set has refs — + a new one without any). If it cannot be served correctly, the honest + move per ADR-003 is dropping the token. ### fetch diff --git a/docs/reviews/001-architecture-pre-decomposition-review.md b/docs/reviews/001-architecture-pre-decomposition-review.md index e583a68..2268698 100644 --- a/docs/reviews/001-architecture-pre-decomposition-review.md +++ b/docs/reviews/001-architecture-pre-decomposition-review.md @@ -770,8 +770,8 @@ criticals are ADR-writing work, not code): | N-1 | ref-cap breach behavior | one fail-closed clause in transport.md | trivial | none | **resolved** — ref cap fail-closed clause in transport.md §Limits (breach is an error, never truncation) | | N-2 | unknown ≡ unauthorized at wire mapping | one sentence in transport.md error taxonomy | trivial | none | **resolved** — collapse rule stated at the variant→wire mapping in transport.md §error taxonomy | | N-3 | schemas unpinned | backend.md types/schemas section | small | freeze inventory | open | -| N-4 | push-options seam | pin additive parameter shape | trivial | none | open | -| N-5 | `ls-refs=unborn` unverified | implementation-phase test rider (record in transport.md or a task) | trivial | none | open | +| N-4 | push-options seam | pin additive parameter shape | trivial | none | **resolved** — `GitPackIngest`'s prepare binding carries `push_options: Option<&PushOptions>` (parsed `(key, value)` pairs, verbatim and un-interpreted; `None` until the config gate opens) — pinned in ADR-013 §11 + backend.md trait description, so opening the gate is value-additive, not a trait redesign | +| N-5 | `ls-refs=unborn` unverified | implementation-phase test rider (record in transport.md or a task) | trivial | none | **resolved (rider)** — unborn-HEAD verification recorded in transport.md §ls-refs and tracker task `tasks/architecture/n5-unborn-head-rider.md` (unborn fixture, real client, both substrates; drop the token if it cannot be served — ADR-003) | Suggested sequencing: (1) **A-2 + A-6** together (one trait-surface amendment set + manifest change — they are the same signature surface); diff --git a/tasks/architecture/n5-unborn-head-rider.md b/tasks/architecture/n5-unborn-head-rider.md new file mode 100644 index 0000000..9414c32 --- /dev/null +++ b/tasks/architecture/n5-unborn-head-rider.md @@ -0,0 +1,58 @@ +--- +id: architecture/n5-unborn-head-rider +name: Verify ls-refs=unborn serving (unborn-HEAD fixture, both substrates) +status: pending +depends_on: [] +scope: narrow +risk: low +impact: wire-claim +level: implementation +tags: [verification-rider, advertisement-honesty] +--- + +## Description + +Review 001 N-5: `ls-refs=unborn` is advertised (transport.md §advertisement, +ADR-003), and POC-1 validated real git accepting the capability *token* — +but serving an unborn HEAD's symref line was never exercised against a +real client (every POC fixture had refs). This is the only advertised +promise in the corpus without capture evidence. The rider is the +verification that closes it. + +## Work + +Implementation-phase test (lands with the ls-refs workstream): + +1. Fixture: an unborn repo — registry record exists, `git init`-equivalent + storage with no refs (the POC set's unborn repo has refs; a new one + without any is needed). +2. V2 ls-refs against it over the duplex substrate with a real git client + (`git -c protocol.version=2 ls-remote`), asserting the unborn HEAD + symref line appears per the ls-refs grammar + (` HEAD symref-target:refs/heads/` unpeeled). +3. Same over the stateless (smart-http-shape) substrate. +4. Backend seam: the refs listing must expose the unborn symref for an + empty repo — verify the `GitRefs` trait shape carries it (a + `symref-target` with no oid); adjust the trait surface if the gix + listing cannot produce it. + +If it cannot be served correctly: drop the `ls-refs=unborn` token from +the advertisement (the honest move per ADR-003 — decline by omission) +and record the drop in transport.md §advertisement. + +## Verification + +- Real `git ls-remote` (V2) against an unborn repo lists the unborn HEAD + symref line, both substrates. +- The full advertisement suite still passes against repos with refs + (the token must not change the served behavior there). + +## Out of scope + +- Unborn-HEAD push (an unborn repo's first push is ordinary ref creation + — ADR-013; not this rider). +- Any capability beyond the token's existing grammar. + +## Summary + +> Filled on completion. \ No newline at end of file