diff --git a/docs/architecture/README.md b/docs/architecture/README.md index cc92b8f..e573523 100644 --- a/docs/architecture/README.md +++ b/docs/architecture/README.md @@ -1,6 +1,6 @@ --- status: draft -last_updated: 2026-09-25 +last_updated: 2026-09-30 --- # alkgit Architecture @@ -16,29 +16,31 @@ to a POC finding or research doc, or is flagged as an open question. Phase 1, architecture committed to the pure-protocol-crate shape (ADR-010; OQ-09 resolved). POC-1/2/3 validated the git protocol half end-to-end against real git 2.43. Previous cycles settled the auth/backend theme -(ADR-011, ADR-012). This cycle settled the wire surface against +(ADR-011, ADR-012). Past cycles settled the wire surface against real-client captures: the receive-pack push state machine (ADR-013, OQ-04) and the V2 multi-round negotiation ack loop (ADR-014, OQ-02). All -wire-layer design is now capture-grounded; the remaining open questions -are the publish-freeze timing (OQ-03, a release decision), sha256 -policy (OQ-05, deferred on ecosystem need), and the grant-key identity -namespace (OQ-16, deferred on the first cross-assembly deployment — -blocks nothing in v1). ADR-015 resolved -review 001's A-1 (the repo-op gate) with the `manage` grant tier; ADR-016 -resolved its A-3 (the native session preamble — `{repo, service}` -open-op params, the git-daemon request line on the direct path, and the -service dimension in the session tuple); ADR-017 resolved its A-5 (the -consumer half: `GitSession` is a real typed fetch/push client in v1 — -the direct-connection primitive for the p2p replicator deployment). +wire-layer design is now capture-grounded. Reviews 001 and 002 have run; +all findings from both are resolved, and decomposition into +implementation tasks may begin (see the lifecycle gate note in the +Document Lifecycle section). Review 001's resolution produced ADR-015 +(the repo-op gate, `manage` grant tier), ADR-016 (the native session +preamble — `{repo, service}` open-op params, the git-daemon request +line on the direct path, and the service dimension in the session +tuple), and ADR-017 (the consumer half: `GitSession` is a real typed +fetch/push client in v1 — the direct-connection primitive for the p2p +replicator deployment). Review 002's resolution produced ADR-018 (the +object-storage trait signatures and the `StorageError` model — the last +unpinned backend-seam shapes) plus the op-surface pins in backend.md +(update PATCH semantics, repo-id grammar, the `already_exists` posture). ## Architecture Documents | Doc | Area | Status | |---|---|---| -| [overview.md](overview.md) | Cross-cutting: crate shape, halves, security invariants | draft | -| [transport.md](transport.md) | Wire layer: substrates, V2 state machines, upload/receive-pack | draft | -| [backend.md](backend.md) | Backend traits + feature-gated gix implementation | draft | -| [doors.md](doors.md) | Door mappings: alkhttp `git` feature, alkssh requirement, native path | draft | +| [overview.md](overview.md) | Cross-cutting: crate shape, halves, security invariants | reviewed | +| [transport.md](transport.md) | Wire layer: substrates, V2 state machines, upload/receive-pack | reviewed | +| [backend.md](backend.md) | Backend traits + feature-gated gix implementation | reviewed | +| [doors.md](doors.md) | Door mappings: alkhttp `git` feature, alkssh requirement, native path | reviewed | | [open-questions.md](open-questions.md) | Centralized OQ tracker | — | ## ADRs @@ -62,6 +64,7 @@ the direct-connection primitive for the p2p replicator deployment). | [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant tier + repo-op gate (admin scope OR manage grant) | Accepted | | [016](decisions/016-native-session-preamble.md) | Native session preamble (`{repo, service}` params, request line, service in tuple) | Accepted | | [017](decisions/017-consumer-half-git-session.md) | Consumer half — `GitSession` typed fetch/push client (custom alkcall Transport + gix-protocol, hand-rolled push) | Accepted | +| [018](decisions/018-backend-trait-signatures-and-storage-error-model.md) | Backend trait signatures + storage error model (`StorageError` for traits 3–5) | Accepted | ## Open Questions @@ -71,13 +74,14 @@ with stable OQ-IDs, priorities, and cross-references. Remaining: OQ-03 timing), OQ-05 (sha256, deferred on ecosystem need), and OQ-16 (grant-key identity namespace, deferred on the first cross-assembly record-sharing deployment). The wire-layer -questions (OQ-02, OQ-04) resolved this cycle with ADR-014/ADR-013. +questions (OQ-02, OQ-04) resolved with ADR-014/ADR-013; the registry/ +op-surface questions (OQ-06/07/08) with ADR-011/012/015. ## Document Lifecycle | Status | Meaning | Transitions | |---|---|---| -| `draft` | Under active development; may change significantly | → `reviewed` when its OQs are resolved | +| `draft` | Under active development; may change significantly | → `reviewed` when its OQs are resolved *or* every unresolved OQ is a properly-tracked deferral with a concrete non-circular blocker (the gate review's standard — review 001 finding D-1's remediation cycle and review 002 set this precedent; deferred-on-release-timing OQs like OQ-03 do not hold specs in draft) | | `reviewed` | Architecture final; implementation may begin; changes need review | → `stable` when implementation verified | | `stable` | Locked; changes require review, may warrant an ADR | → `deprecated` when superseded | | `deprecated` | Superseded; kept for reference | Removed when no longer referenced | \ No newline at end of file diff --git a/docs/architecture/open-questions.md b/docs/architecture/open-questions.md index acbe894..3905eb4 100644 --- a/docs/architecture/open-questions.md +++ b/docs/architecture/open-questions.md @@ -1,6 +1,6 @@ --- -status: draft -last_updated: 2026-09-25 +status: reviewed +last_updated: 2026-09-30 --- # Open Questions @@ -75,7 +75,11 @@ resolved in earlier cycles. OQ-16 is deferred but blocks nothing in v1 grammar — the last native-path wire surface); ADR-017 added the `GitSession` public API; the registry types/schemas draft (backend.md §"Registry types and schemas", review 001 N-3) pinned - `RepoRecord`, `RegistryError`, and the `git/repo/*` op schemas. + `RepoRecord`, `RegistryError`, and the `git/repo/*` op schemas; + ADR-018 pinned the object-storage trait signatures, the shared + backend-seam types (`RefLine`/`RefUpdate`/`RefOutcome`/ + `PreparedPush`/`PushOptions`), and `StorageError` — the backend-seam + inventory is complete. - **Door type**: one-way (API freeze is registry-visible to dependents) - **Priority**: medium - **Impacts**: blocks the first publish only, not implementation. @@ -86,7 +90,7 @@ resolved in earlier cycles. OQ-16 is deferred but blocks nothing in v1 (`GitPackIngest` binding, `GitPackGen::common_haves`) to the freeze inventory; ADR-016 added the native preamble wire shapes. - **Cross-references**: ADR-010, ADR-002, ADR-012, ADR-013, ADR-014, - ADR-016, backend.md, transport.md + ADR-016, ADR-018, backend.md, transport.md ## Theme: transport / protocol diff --git a/docs/architecture/overview.md b/docs/architecture/overview.md index 7952679..a0726f4 100644 --- a/docs/architecture/overview.md +++ b/docs/architecture/overview.md @@ -1,6 +1,6 @@ --- -status: draft -last_updated: 2026-09-25 +status: reviewed +last_updated: 2026-09-30 --- # Overview: alkgit @@ -32,8 +32,8 @@ Single crate `alkgit`: | Producer | `GitAdapter` (`alk/git` ALPN via alkcall `ProtocolHandler`; parses the ADR-016 request-line preamble), channels `register_openable` (`channels/git/sub` — open-op params `{repo, service}`, the negotiation + service selector + ACL point; ADR-016) | POC-1 verbatim | | Consumer | `GitSession` typed client (`connect_direct`, `open_via_channels`) — ADR-017: `ls_refs`/`fetch`/`push`; fetch via gitoxide client machinery over a custom alkcall Transport, push hand-rolled to ADR-013's shapes; the replication/mirroring primitive for alknet | new, specified (grammar capture-grounded: ADR-013/014 + captures) | | Substrate | duplex session + stateless request/response layer (ADR-005); wire framing, V2 state machines (ADR-003) | POC-1, POC-3 | -| Backends | `GitRegistry` (+ write supertrait), `GitRefs`, `GitPackGen`, `GitPackIngest` traits; impls behind the default-on `gix` (engine) and `registry-file` (records) features | POC-2 (gix impl) | -| Management ops | `git/repo/*` call ops over `GitRegistryStore` (ADR-012 §3) — the JSON half alongside the `alk/git` open op (first dual-kind payload; ADR-012 §5) | thin over the store trait | +| Backends | `GitRegistry` (+ write supertrait), `GitRefs`, `GitPackGen`, `GitPackIngest` traits (signatures pinned: ADR-018); impls behind the default-on `gix` (engine) and `registry-file` (records) features | POC-2 (gix impl) | +| Management ops | `git/repo/*` call ops over `GitRegistryStore` (ADR-012 §3) — the JSON half alongside the `alk/git` open op (first dual-kind payload; ADR-012 §5); types/schemas pinned in backend.md §"Registry types and schemas" | thin over the store trait | Feature model: `gix` (engine impls) and `registry-file` (record store + ops) are independent default-on seams (ADR-012 §4); @@ -95,6 +95,7 @@ multi-round negotiation are design-complete against real-client captures | [015](decisions/015-manage-grant-and-op-gate.md) | Manage grant + op gate | `manage` tier, admin-OR-manage gate, create seeds manage | | [016](decisions/016-native-session-preamble.md) | Native session preamble | `{repo, service}` open-op params, request-line preamble, service in the tuple | | [017](decisions/017-consumer-half-git-session.md) | Consumer half | `GitSession` typed client, custom alkcall Transport + gix-protocol fetch, hand-rolled push | +| [018](decisions/018-backend-trait-signatures-and-storage-error-model.md) | Trait signatures + storage errors | object-storage trait signatures pinned, `StorageError` for traits 3–5, `&RepoRecord` repo param | ## Open Questions @@ -105,7 +106,8 @@ Key questions tracked in [open-questions.md](open-questions.md): the ADR-015 three-action grant shape must land in it; the ADR-016 native preamble wire shapes — `{repo, service}` params schema and the request-line grammar — entered it; ADR-017's `GitSession` public API - enters it). + enters it; ADR-018's trait signatures + shared types + `StorageError` + complete the backend-seam inventory). - **OQ-05**: sha256 policy (deferred(scope), low). - **OQ-16**: grant-key identity namespace (deferred(scope); blocks nothing in v1 — ADR-015 §7). diff --git a/docs/architecture/transport.md b/docs/architecture/transport.md index 5055502..90ab679 100644 --- a/docs/architecture/transport.md +++ b/docs/architecture/transport.md @@ -1,6 +1,6 @@ --- -status: draft -last_updated: 2026-09-29 +status: reviewed +last_updated: 2026-09-30 --- # alkgit: Git Smart Protocol (wire layer) @@ -184,6 +184,7 @@ the feature. Publish-freeze point: **OQ-03**. | [014](decisions/014-v2-negotiation-ack-loop.md) | Negotiation | ack loop, no `ready`, wait-for-done stays | | [016](decisions/016-native-session-preamble.md) | Native session preamble | `{repo, service}` open-op params, request-line preamble, service in the tuple | | [017](decisions/017-consumer-half-git-session.md) | Consumer half | `GitSession` typed client (`ls_refs`/`fetch`/`push`), custom alkcall Transport + gix-protocol, hand-rolled push | +| [018](decisions/018-backend-trait-signatures-and-storage-error-model.md) | Trait signatures + storage errors | the seam shapes transport calls (`generate`/`prepare`/`apply_updates` signatures, `StorageError`, boxed-stream ownership) | ## Open Questions diff --git a/docs/reviews/002-post-remediation-review.md b/docs/reviews/002-post-remediation-review.md new file mode 100644 index 0000000..f117eec --- /dev/null +++ b/docs/reviews/002-post-remediation-review.md @@ -0,0 +1,301 @@ +--- +status: resolved +last_updated: 2026-09-30 +reviewed_artifacts: + - docs/architecture/README.md + - docs/architecture/overview.md + - docs/architecture/transport.md + - docs/architecture/backend.md + - docs/architecture/doors.md + - docs/architecture/open-questions.md + - docs/architecture/decisions/ (ADR-001..017, post-review-001 amendments) + - Cargo.toml + - tasks/architecture/ (all seven tracker/rider tasks) +tool: manual full-corpus re-read post-remediation + sibling-crate + re-verification (alkcall spec.rs/registry surface, alktty channels + establisher) + gitoxide reference-clone checks (gix-transport + async traits, gix-protocol Cargo) + four-config compile probes on + the amended manifest + MSRV 1.88 check/clippy +reviewer: architecture pre-decomposition re-review (fix-verification + + residual-gap pass over review 001's remediated corpus) +scope_note: gate re-review — verifies every review 001 finding landed + correctly, then hunts the residuals the fixes created at the new + seams. Same standard as 001: could a decomposition agent and an + implementation agent proceed without inventing divergent answers? +--- + +# Review 002 — Post-Remediation Re-Review + +## Purpose + +Review 001 gated phase 1 on its remediation. This review verifies that +remediation (all 14 findings, A–D–N) landed correctly and completely, +then re-runs the contradiction/gap/staleness pass over the amended +corpus. Same methodology class as 001: full-corpus read, sibling-source +cross-checks, and compile probes — this time *after* the fix round, on +the amended manifest (which gained `async-trait = "0.1"` and +`async-client` on `gix-protocol`/`gix-transport`). + +## Verification Baseline + +All commands on the post-remediation tree (commit `11ceead` + the N-3 +commit `b6040d3`, clean): + +- `cargo test`: **passes** (0 tests — still the skeleton). +- `cargo clippy --all-targets -- -D warnings`: **clean**. +- `cargo fmt --check`: **clean**. +- `cargo doc --no-deps`: **0 warnings**. +- All four feature configurations check clean: default, + `--no-default-features`, `--features sha256`, `--all-features` — + the manifest grew `async-trait` and the `async-client` features + without breaking the wire-layer-without-gix claim (ADR-012 §4 still + true). +- `cargo +1.88 check` and `cargo +1.88 clippy --all-targets -- -D + warnings`: **clean** — the new dep configuration holds at the pinned + MSRV. +- `cargo publish --dry-run --allow-dirty`: **completes**. +- Sibling re-verification: alkcall `AccessControl` still AND-composes + as ADR-015 routes around (spec.rs:67–72); `AuthContext.identity` is + `Option` — anonymous-public fetch through the channels + establisher (ADR-016's open-time `authorize`) is expressible as + specified; `ChannelOpenSpec`/`ErrorDefinition`/`OperationSpec` + match backend.md's op-schema citations; alktty's + `channels/tty/sub` establisher template matches ADR-016's + `channels/git/sub` claims (including the per-call `AuthContext` + identity the establisher reads); gix-transport's async client + traits are `#[async_trait(?Send)]` exactly as ADR-017 §2 states; + gix-protocol's `async-client` feature exists and pulls + `async-trait` (both rust-version 1.88 — manifest alignment + verified). + +## Remediation Verification (Part A — all 14 findings) + +Each verified at file level, not from the remediation table's claim: + +- **A-1 → ADR-015**: the two-tier op gate is re-expressed as + admin-scope-OR-`manage`-grant, handler-evaluated; ADR-012 §3's table + carries the amendment note; backend.md §"The two op kinds" restates + the mechanism; `create` keeps its static scope gate. The AND- + composition premise re-verified against alkcall source. +- **A-2**: `#[async_trait]` amendment on ADR-012 §1's signatures with + the desugared boxed form pinned into OQ-03's freeze inventory; + `async-trait = "0.1"` in the manifest with provenance comment. +- **A-3 → ADR-016**: `{repo, service}` open-op params + (`additionalProperties: false`), the git-daemon request line + (verified verbatim against poc-1-findings §2), service in both + substrate tuples, ADR-002/005/010 amendment notes all present. +- **A-4**: ADR-014 §2's amendment clause (recognized-subset boundary + via `common_haves`, ack rule ≡ subtraction rule) + the same rule in + transport.md §fetch. +- **A-5 → ADR-017**: consumer half specified as a real typed client + (superseding the review's thin-wrapper recommendation with grounded + use cases); manifest deps carry purpose comments; the + `#[async_trait(?Send)]` claim verified against gix-transport source. +- **A-6**: backend.md's concurrency model commits to the trait-level + permit / impl-internal `spawn_blocking` split; ADR-009's + enforcement-point consequence updated; transport.md rephrased. +- **D-1/D-2/D-3, N-1..N-5**: supersession notes in vision.md + + alk-stack.md + AGENTS.md OQ list (now OQ-03/05/16); ADR-007 step-3 + amendment; authorized-repo marker in transport tuples + backend API + list; fail-closed ref-cap clause; unknown ≡ unauthorized at the + variant→wire mapping; N-3 schemas section; `push_options` param on + the prepare binding; unborn-HEAD rider task + transport.md note. + +**Remediation verdict: complete and faithful.** No fix landed in a way +that contradicts its finding or another decision. + +## Findings (Part B — residuals at the fixed seams) + +Severity: the corpus no longer has criticals. The majors are one +backend.md section each; the minors are one-sentence fixes. + +### R-1 [major] — Traits 3–5 have no pinned signatures; ADR-012 §1 (as amended by A-2) covers only the registry pair + +**Files**: ADR-012 §1 (the A-2 amendment claims "all five traits' +signatures" are pinned there — only traits 1–2 are); backend.md +§"The trait family" (prose descriptions only); review 001's remediation +row for A-2 ("all five traits `#[async_trait]`, signatures per ADR-012 +§1" — over-claims its own fix). + +**Problem**: `GitRefs`, `GitPackGen`, `GitPackIngest` — the traits the +`gix` feature exists to implement — have no method names, no parameter +shapes, and no shared type definitions anywhere in the corpus. Sharpest +fork: `(repo, wants, haves, limits)`'s `repo` parameter — the wire +layer (backend-trait-only per ADR-010) holds only the resolved repo +id, while the gix impl needs the `storage_root` to open the odb +(`gix-odb::Store::at`), and traits 3–5 are speced as independent seams +from `GitRegistry`, so they cannot lean on the resolve path. Is `repo` +a `&str` id, a `PathBuf`, a registry-derived handle? Equally unpinned: +the `GitPackIngest`→`GitRefs` prepared-updates handoff (the mechanism +`atomic` correctness depends on — ADR-013 §7), and the object-id +representation. Two workstreams (wire layer, gix impl) would invent +incompatible answers, and the invented shapes are OQ-03 freeze +surface. This is review 001 A-2's own failure mode surviving at the +three traits whose signatures were never written. + +**Resolution — ADR-018 §2, §4, §5**: signatures pinned for all three +traits; `repo` is `&RepoRecord` (the wire layer resolves once per +ADR-007 and the record carries `storage_root`; no handle type, no +second lookup); shared types pinned (`RefLine` with the unborn-symref +`oid: None` shape for the N-5 rider, `RefUpdate`, `RefOutcome`, +`PreparedPush`, `PushOptions`); object ids are `gix_hash::ObjectId` +(always-on in the manifest, hash-parameterized internally — OQ-05-safe); +parameter ownership is boxed-`Send` streams/owned vecs so the A-6 +execution model (impl-internal `spawn_blocking`) has mechanical +support. + +### R-2 [major] — backend.md's `RegistryError` pin over-claims: "every failure the trait family can produce" + +**Files**: backend.md §`RegistryError` (the "no catch-all, every +failure the trait family can produce" sentence); ADR-013 §7–8 (CAS +outcomes are *business results*, reasons client-displayed). + +**Problem**: the five-variant set genuinely covers the registry pair — +but not the object-storage traits' characteristic failures. CAS-stale +is a per-ref *outcome* of receive-pack with its own report semantics +(ADR-013 gives it a server-chosen reason shown to the client); fsck/ +unpack failures and missing-object aborts are report legs and aborts +with dedicated wire mappings (ADR-004, ADR-013 §8). Forcing those into +`Io(String)` or `Invalid` contradicts the structural-errors rationale +the variant set exists for, or breaks the "session survives" report +semantics. + +**Resolution — ADR-018 §7**: `RegistryError` is re-scoped to the +registry family (the backend.md sentence corrected); traits 3–5 get +`StorageError` (`ObjectMissing { oid }` — the ADR-004 abort; +`Invalid(String)`; `Io(String)` with `RegistryError::Io`'s stability +rule), with the report-vs-error separation stated explicitly (CAS and +fsck outcomes are `RefOutcome`/`PreparedPush.unpack` values, not +variants — which keeps the no-catch-all claim true for both types). + +### R-3 [minor] — `git/repo/update` PATCH-vs-PUT ambiguity + +**Files**: backend.md §op schemas (`{repo_id, visibility?, grants?}` — +"both optional, full-record replace of the provided fields"). + +**Problem**: "optional" reads PATCH; "full-record replace" reads PUT +(omitted = cleared). The wrong reading is destructive: a +visibility-only update that clears grants locks the grant-holder out +of the repo via the op they legitimately called. + +**Resolution**: PATCH pinned in backend.md — omitted fields left +unchanged; present fields replaced wholesale (`grants` present = +whole-map replace; partial grant edits are caller-side +read-modify-write); the response echo (already specified) is the +confirmation surface. The table cell wording aligned. + +### R-4 [minor] — doors.md's alkssh hand-off tuple predates both amendment rounds + +**Files**: doors.md §alkssh ("hand (identity, repo, post-auth stream, +limits)"). + +**Problem**: missing the `service` dimension (ADR-016) and the +authorized-repo marker (review 001 D-3, whose fix swept transport.md +and backend.md but not this third tuple site) — the exact miss D-3 +itself warned about ("the first session-tuple task will fix the +signature"). + +**Resolution**: the tuple now reads `(identity, repo, service, +authorized-repo marker, post-auth stream, limits)` with the exec +command named as the service selector per ADR-016. + +### R-5 [minor] — Repo-id grammar unpinned; the N-3 example implies a two-segment id the http route shape doesn't express + +**Files**: backend.md §`RepoRecord` (example `"alkdev/alkgit"`), §op +schemas (`invalid` for "empty repo id" implies charset rules exist); +doors.md (single-placeholder routes `/{repo}/…`). + +**Problem**: two-segment ids need a two-placeholder http route shape no +doc pins; the `Invalid` variant's empty-id check implies a grammar that +is nowhere stated; the `registry-file` store's record-file naming +derives from the id (a slash in the id forces nested dirs or encoding — +an on-disk layout decision that is freeze-adjacent per ADR-012 §2). + +**Resolution**: grammar pinned in backend.md §"Repo-id grammar" — +`owner/name` shape (lowercase alphanumerics + `-_`, ≤100 bytes, one +segment allowed), rejection-only parsing (never decomposition — +ADR-008 governs), error mapping (grammar-invalid = the collapsed +denial on serving paths, `invalid` on op paths), +percent-encoded flat record-file naming for `registry-file`, and an +explicit note that the http door pins its own route grammar +(`/{owner}/{repo}/…`) when the alkhttp `git` feature lands. + +### R-6 [observation] — `already_exists` on create is an existence oracle to create-scope holders probing arbitrary ids + +**Files**: backend.md §op error codes (the disclosure rationale reasons +only about "the caller knows the id"). + +**Problem**: a `git:repo:create`-scoped identity can probe ids it +didn't choose and learn which exist. Defensible (trusted, scope-gated, +low-population surface; upstream gitea behaves the same), but the +position was unstated — a later agent might "fix" the disclosure and +break an upstream-compatible error clients rely on. + +**Resolution**: the disclosure posture is recorded explicitly in +backend.md (accepted: id-probing at create-scope is inside the trust +boundary the scope grants; resolve-side disclosure stays collapsed per +ADR-008/N-2) so the position survives personnel changes. + +### R-7 [minor] — Lifecycle gate ambiguity: docs cannot reach `reviewed` while release-timing OQs are deferred by design + +**Files**: docs/architecture/README.md §Document Lifecycle +("→ `reviewed` when its OQs are resolved") vs open-questions.md (OQ-03 +partially resolved, OQ-05/OQ-16 deferred(scope) — the deferrals are +correct and non-circular); review 001's remediation note ("the spec +docs are candidates for `reviewed` status per the lifecycle +definition" — which the letter of the definition forbids). + +**Problem**: as written, the `draft → reviewed` transition requires +resolved OQs, but the remaining OQs resolve only at first publish / +ecosystem events. An implementer following the letter is blocked; one +following the review's intent is not. Also caught in this pass: stale +`last_updated` frontmatter (2026-09-25) on README/overview/ +open-questions/doors despite 09-29/30 edits. + +**Resolution**: README's transition definition extended — docs reach +`reviewed` when their OQs are resolved *or* every unresolved OQ is a +properly-tracked deferral with a concrete non-circular blocker (which +is the state review 001's own deferral-hygiene check certified). +All four spec docs flipped to `reviewed` (this review is the gate); +frontmatter timestamps refreshed. + +### R-8 [cosmetic] — ADR-016 text glitches + +**Files**: ADR-016 §2 ("freeze␣␣␣␣inventory" — collapsed multiple +spaces), §4 (code span broken across a line break: `` `open_via_ +channels` `` renders as a broken identifier). + +**Resolution**: both fixed; no semantic change. + +## Summary Statistics + +| Severity | Count | IDs | +|----------|------:|-----| +| Major | 2 | R-1, R-2 | +| Minor | 4 | R-3, R-4, R-5, R-7 | +| Observation | 1 | R-6 | +| Cosmetic | 1 | R-8 | + +All resolved in this cycle (ADR-018 + the backend.md/doors.md/README +doc batch). No finding questions the architecture's direction; no +criticals. The corpus is now fully pinned at every seam a decomposer +cuts: session tuples, preamble wire shapes, op schemas, registry types, +trait signatures, error models, concurrency model, and freeze-inventory +entries. + +## Verification (post-fix battery) + +Re-run after the R-1..R-8 fixes land (see the commit series): four +config compile probes, MSRV check + clippy, full test/clippy/fmt/doc ++ publish dry-run — all expected clean (no code changed; docs-only + +manifest-already-verified). + +## References + +- Review 001 (the gate this re-review verifies the remediation of) — + `docs/reviews/001-architecture-pre-decomposition-review.md` +- ADR-015/016/017 (review 001's resolution ADRs), ADR-018 (this + review's R-1/R-2 resolution) +- backend.md §"Pinned signatures", §"Registry types and schemas" + (re-scoped), §"Repo-id grammar" (new), §op-surface notes +- Phase-1 gate verdict: **decomposition may begin** \ No newline at end of file