W-20 item (3): ratify SI-32 as A27 — filesystem attacker model (ADR 0008 ACCEPTED, spec v0.10) - #50
Conversation
Founding case: the PR #50 SI-32 candidate, where a self-administered battery collapsed into one subagent let an external review find 5 gaps it should have killed (a code-fact claim contradicting source, three filing-named deliverables dropped, a phantom appendix, a wrong-base branch). Fix, per the repo's own G9 remedy: make the battery a required artifact plus a mechanical lane, not a thing the author remembers. - scripts/check-doc-hygiene: dependency-free POSIX shell, three repo-state checks (doc/ADR ref resolution; ordered-list numbering; named-"..."-appendix section existence). Two-sided via --self-test (checks fire on broken fixtures, pass on good + a false-positive guard). roadmap.md exempt from file-existence refs (forward-looking). - scripts/ci: new `hygiene` lane, wired into run_test so it runs in contracts/test/required/full/all and in GitHub Actions' `test` step. - docs/review-battery.md: the doctrine — the three tiers, the structural rule (enumeration -> tables, adversary -> findings, never bundled), the PR-context checks, and the running order. - CLAUDE.md / AGENTS.md: binding paragraph next to G9. Mutation testing N/A (shell enforcement, not Rust — the two-sided contract discipline's stated escape hatch); the --self-test is the two-sided evidence. No Rust touched. Co-authored-by: XVVH <admin@fent.quest> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ROPOSED) Three-tier attacker model + candidate rules A27.1-A27.4, grounded in a complete publication-site inventory. Spec untouched; SI-32 stays open; authorizes no implementation. Queued for operator ratification. - T1 offline tampering: content-address verification for substitution/corruption/truncation; A23 (global_seq + anchor) for rollback; keys and the R7 unsigned-index gap are the carve-outs - T2 same-uid active writer: no pathname check wins — W-4 containment; every T2 claim labeled "COOP now; W-4 at G-ADVERSARIAL". Super-user out of scope (trust boundary = the Unix account, P7) - T3 human edit: not an attack; M8 + A24/R14 attribution - A27.1 staged-bytes (ratifies RF-20); A27.2 verify-on-read-back, tier-labeled, three read classes; A27.3 per-kind incl. hardlinks; A27.4 containment sentence - Surfaces one genuine T1 gap (R7: unsigned fabric.db meta store-paths trusted while sibling events signed; feeds broker authority via substrate_span) -> proposed RF-41, posture-bounded under SU - One uniformity correction (R3: sync_store fs walk omits .git exclusion + no-follow) - Seven ratification choices enumerated Passed the four-audit battery + an internal adversarial pre-review (7 findings, one blocking: the first draft wrongly folded T1-rollback into content-addressing when A23 owns it -- fixed, promoted to a decision point). Ledger mirrors: spec-issues SI-32 candidate note, roadmap W-20 progress. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Applied via the codified review battery (PR #51): completeness table from the SI-32 filing deliverables drove the fold, every code-fact verified at source, Tier-1 hygiene green, Tier-3 internal adversarial pre-review (2 LOW nits, no new soundness hole, ready for challenge pass). - F1 T3 active-publication-window edit: T3 is orthogonal not cumulative; a human write during a live promotion/revert is overwritten with no capture/drift (the item ADR 0007 R14 deferred here) -> decision point, protocol-class, not designed - F2 T1 rollback precise domain: layer 1 detects only rollback inconsistent vs a surviving expected terminal; coherent whole-DB suffix regression is layer 2's (was imprecise "partial rollback") - F3 trust-root unsound: keys/KEK/credentials split; substitution is an SI-27/RF-14 residual (self-consistent forged home; auth-as-other- account), not "degrades to signature failure"; out-of-scope splits root (out) from unprivileged different-uid (defended by perms) - F4 capture_sqlite follows symlinks for registered stores (only fabric.db is checked) -> RF-42 - F5 directory/kind semantics carried from A24/R25 + R24, per operation - F6 G-PUBLISH conditional-publication decision point (the filing's explicit ask, previously dropped) - F7 real inventory appendix with file:line anchors; R3 no-follow recast (capture_fs rejects symlinks via a check, not O_NOFOLLOW) - F8 SHA cite -> PR #48; wrong-base scope fixed by rebase onto main Decision points now 10; SI-32 stays open, no implementation authorized. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
f60b7ca to
22d6e2b
Compare
…ions D32-1..D32-10 ADR 0008 ACCEPTED with the ratification addendum. Spec v0.10 gains the A27 bullet family in section 5.3 (three adversary tiers with the rollback/trust-root/unsigned-index carve-outs, staged-bytes and verify-on-read-back normative, per-kind entry rules, the standing T2 containment sentence), cross-refs in sections 1 and 9, and the changelog. Filings: SI-40 (active-publication-window edit; topology arm foreclosed by D32-4, preservation protocol leading candidate, substrate-assisted CoW-snapshot direction recorded from the operator), RF-41/RF-42/RF-43 with carriers, P29 and the G-PUBLISH gate entry, G14 negatives. Internal adversarial pre-review before the external round: 14 findings (4 medium), all applied and recorded in the addendum. Per the stopping rule (PR #52): one delta-scoped external round next. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…orrection, SI-40 snapshot-timing fix External delta round returned REQUEST CHANGES; all five findings folded. Blocking: A27.1 regains its ratified holds-against-T1 label (D32-5); the candidate body's "layer 2's job (external anchor / caller-pinned expected head)" is corrected in the D32-2 addendum - caller pins are layer 1's completeness tier, only the external anchor is layer 2. Non-blocking: the SI-40 substrate-assisted paragraph no longer claims a gate-acquisition snapshot closes the window (the in-window edit postdates it); the preserving variant is outgoing-state retention at swap plus diff/CAS-ingest/attribute. Lows: A27.4 label variants in preserved candidate text normalized; v0.9 stamps in CLAUDE.md and the spec status line bumped to v0.10. Round record in ADR 0008's addendum. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Delta-round fold (commit eff73b2). The external round returned REQUEST CHANGES with five findings; all folded:
Round recorded in ADR 0008's addendum. Per the stopping rule, whether the cycle closes here (both blockers had reviewer-prescribed remedies, applied verbatim) or buys a confirming delta round is the operator's gate decision. 🤖 Generated with Claude Code |
… commit Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ings folded No blocking findings from the confirming delta round - the cycle closes under the stopping rule. Folded: SI-40's per-file clone variant now requires atomic clone-and-swap semantics (separate clone->rename re-opens the window in miniature; dataset-level retain-and-swap is the sound variant), and the roadmap's branch-local SHA citation replaced per the citation rule. Cycle records in ADR 0008's addendum and the roadmap: one internal pre-review (14 findings) + two external delta rounds (5 + 2), against PR #48's seven rounds. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Cycle closed. The confirming round returned no blocking findings — per the stopping rule the review cycle for this ratification is complete. Its two non-blocking findings are folded (SI-40's per-file clone variant now requires atomic clone-and-swap semantics; the roadmap's branch-local SHA citation replaced per the citation rule). Full cycle cost: one internal adversarial pre-review (14 findings) + two delta-scoped external rounds (5 + 2 findings). PR is ready for the operator's merge decision; W-20 closes at merge per the close-out filed in PR #52. 🤖 Generated with Claude Code |
Two resolutions: the W-20 progress paragraph keeps the full item-(3) narrative (candidate -> ratified -> cycle closed) followed by PR #52's canonical close-out decision, dropping the branch's abbreviated duplicate and the superseded "Next: item (3)" line; the posture ledger keeps both new rows in order (P28 staged consumption from PR #52, P29 apply-window edit from the ratification), count updated to 29, both follow-up notes retained chronologically. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
What this is
The ratification candidate for SI-32 (W-20 item 3) — the filesystem attacker model that RF-20→RF-40 kept re-deriving. PROPOSED, not a spec amendment: spec untouched, SI-32 open, no implementation authorized. Input to the operator's challenge-pass session (the role ADR 0006 played for SI-25).
Now revised: filed → internal adversarial pre-review (caught a blocking T1-rollback hole) → external review round 1 (8 findings), all folded → Tier-3 pre-review of the fold (2 LOW nits, no new soundness hole, ready for challenge pass). Built through the codified review battery (PR #51); rebased onto current
mainso the diff is exactly the 3 SI-32 files.Tier-2 completeness table — the SI-32 filing's named deliverables
capture_fspath_is_symlink) + SQLite (fabric.dbchecked; registered stores = RF-42 gap)All six closed or surfaced as an explicit fork — no filing deliverable dropped (the round-1 misses: directory rules, G-PUBLISH, active-window — all now closed).
Tier-2 code-fact table (every as-built claim verified at source)
write_atomic_verifiedis the gold-standard publishersnapshot.rs:534/543— full guard setsnapshot.rs:152,payload.rs:122,kernel.rs:816/833stores/substrate_spanread from unsigned meta;substrate_spanfeeds broker authoritykernel.rs:505–530capture_sqlitefollows symlinks; onlyfabric.dbis symlink-checkedsnapshot.rs:268(is_file/open/read),kernel.rs:328kernel.rs:1015,:705,:766→snapshot.rs:700sync_storeomits.gitexclusion;capture_fsrejects symlinks via a check notO_NOFOLLOWsnapshot.rs:608vs:215/221asf-schema-spec.md§5.3Ten ratification decision points
Tier count + root/uid boundary · T1-rollback carve-out + precise layer-1 domain · trust-root residual vs verifier-key · active-window edit (topology vs protocol, protocol-class) · staged-bytes normativity · RF-41/RF-42 file-vs-fold · A27.4 containment wording · G-PUBLISH conditional publication · R3 correction now-vs-later · spec placement. Each a real fork with a recommendation and its alternative.
Gaps surfaced (proposed, gated behind ratification)
fabric.dbmeta rows (incl.substrate_span) trusted while sibling events are signedcapture_sqlitefollows symlinks for registered SQLite storessync_store.gituniformity; mechanism follow-upEvidence scoping
Docs-only; 3 files; SI-32 stays open. This is the ratification input, not for merge — the amendment (A27), the SI-32 resolution block, and any filed RF-41/RF-42 get written at the challenge pass, the way A24–A26 were.
🤖 Generated with Claude Code
Ratification fold (2026-07-15) — this PR is now the ratification PR
The operator session ran the challenge pass over the round-1-folded candidate. Determinations D32-1…D32-10 are in ADR 0008's addendum; the "not for merge" note above is superseded — this PR now carries the full A27 ratification, the way PR #47/#48 carried A23/A24–A26.
Declared scope (fold commit)
docs/adr/0008-filesystem-attacker-model.md(ACCEPTED + addendum),docs/asf-schema-spec.md(v0.10, A27 §5.3 + §1/§9 cross-refs + changelog),docs/spec-issues.md(SI-32 resolved; SI-40 filed),docs/review-findings.md(RF-41/RF-42/RF-43),docs/posture-assumptions.md(P29; G-PUBLISH T2 gate entry),docs/testing-theory.md(G14),docs/roadmap.md(item-3 stamp + close-out cross-ref),CLAUDE.md(preamble) — nothing else.Completeness table (decision point → determination → artifact)
Code-fact table (new claims in the fold; candidate-inherited anchors were verified at round 1)
kernel.rs:505metastores/substrate_spanread unsigned (RF-41)snapshot.rs:268capture_sqlitesymlink-following;kernel.rs:328fabric.db-only check (RF-42)snapshot.rs:608sync_storewalk omits.gitexclusion (RF-43)cas_get_rehashes…,row_substitution…,w14_reopen_rejects…) exist; two baseline-unregistered, one under STATE-COMMITBattery evidence
Tier 1 green (
scripts/ci hygiene+ fullrequiredlane at push). Tier 3 internal adversarial pre-review: 14 findings (4 medium), all applied before push, recorded in the ADR addendum — the substantive catch: the SI-40 draft routed a preserving refusal through A24's ordinary-failure rollback, which restoresbeforeuncaptured (the capture record exists only on the crash path); corrected to capture-before-rollback or fail-like-a-crash. Per the stopping rule (adopted 2026-07-15, PR #52): one delta-scoped external round on this fold; continuation only on blocking findings.