Skip to content

W-20 item (3): ratify SI-32 as A27 — filesystem attacker model (ADR 0008 ACCEPTED, spec v0.10) - #50

Merged
XVVH merged 7 commits into
mainfrom
docs/w20-si32-candidate
Jul 15, 2026
Merged

XVVH merged 7 commits into
mainfrom
docs/w20-si32-candidate

Conversation

@XVVH

@XVVH XVVH commented Jul 15, 2026 •

Copy link
Copy Markdown
Owner

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 main so the diff is exactly the 3 SI-32 files.

Tier-2 completeness table — the SI-32 filing's named deliverables

Filing deliverable Closed by
Three-tier attacker model + per-guarantee tier labels T1/T2/T3 sections; every residue row + read-back class carries a tier label
Staged-bytes rule normative A27.1
Symlink rules per store kind A27.3 fs-tree (capture_fs path_is_symlink) + SQLite (fabric.db checked; registered stores = RF-42 gap)
Hardlink rules per store kind A27.3 hardlink clause (captured by content; publication defeats write-through; pre-plant is T2/W-4)
Directory-entry rules per store kind A27.3 fs-tree → A24/R25 tagged path-state domain + A24/R24 kind-complete scan
Which claims need containment before G-PUBLISH Decision point 8 (conditional-publish + posture-ledger G-PUBLISH row)

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)

Claim Verified
write_atomic_verified is the gold-standard publisher snapshot.rs:534/543 — full guard set
CAS/payload read-backs rehash; journal verifies signature snapshot.rs:152, payload.rs:122, kernel.rs:816/833
R7: stores/substrate_span read from unsigned meta; substrate_span feeds broker authority kernel.rs:505–530
RF-42: capture_sqlite follows symlinks; only fabric.db is symlink-checked snapshot.rs:268 (is_file/open/read), kernel.rs:328
T3 active-window: gate lock is cross-process, not vs a human editor; capture-before guard then apply kernel.rs:1015, :705, :766→snapshot.rs:700
R3: sync_store omits .git exclusion; capture_fs rejects symlinks via a check not O_NOFOLLOW snapshot.rs:608 vs :215/221
A24/R25/R24 cross-refs accurate ratified asf-schema-spec.md §5.3

Ten 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)

  • RF-41 — unsigned fabric.db meta rows (incl. substrate_span) trusted while sibling events are signed
  • RF-42 — capture_sqlite follows symlinks for registered SQLite stores
  • Active-window T3 edit — protocol-class; spawns an SI at ratification (the item ADR 0007 R14 deferred here)
  • R3 — sync_store .git uniformity; mechanism follow-up

Evidence 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)

# Decision point Determination Filed at
1 Tier count; root-vs-uid boundary Three tiers; confidentiality cross-referenced (P17/RF-15), not re-tiered; root out of scope, other-uid defended D32-1; spec §5.3 A27 bullet
2 T1-rollback carve-out domain Ratified as drafted; seam kept inside the model D32-2; spec §5.3
3 Trust-root substitution SI-27/RF-14 residual accepted; verifier-key scoping rejected as aspirational D32-3; spec §5.3
4 Active-publication window Topology arm FORECLOSED (shared state is the product thesis); SI-40 filed, preservation protocol leading candidate + operator's substrate-assisted (CoW snapshot) direction recorded; P29 bounds D32-4; SI-40; P29
5 Staged-bytes normativity Normative D32-5; spec A27.1
6 RF-41/RF-42 file-or-fold Filed now; carriers W-15a/b (PR #52 split) and the RF-40 mechanical lane D32-6; RF-41/RF-42
7 A27.4 wording Standing sentence on every T2 claim D32-7; spec A27.4
8 G-PUBLISH mapping Conditional publication with labels; gate entry added D32-8; posture ledger G-PUBLISH
9 R3 correction Filed as RF-43, rides the mechanical lane D32-9; RF-43
10 Spec placement §5.3 bullet family + §1/§9 cross-refs D32-10; spec v0.10

Code-fact table (new claims in the fold; candidate-inherited anchors were verified at round 1)

Claim Verified
kernel.rs:505 meta stores/substrate_span read unsigned (RF-41) Inherited from candidate appendix (round-1 verified); unchanged
snapshot.rs:268 capture_sqlite symlink-following; kernel.rs:328 fabric.db-only check (RF-42) Inherited from candidate appendix (round-1 verified); unchanged
snapshot.rs:608 sync_store walk omits .git exclusion (RF-43) Inherited from candidate appendix; unchanged
G14's three existing tests (cas_get_rehashes…, row_substitution…, w14_reopen_rejects…) exist; two baseline-unregistered, one under STATE-COMMIT Verified at source by the internal pre-review (its finding 11 corrected the "family exists" phrasing)

Battery evidence

Tier 1 green (scripts/ci hygiene + full required lane 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 restores before uncaptured (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.

XVVH added a commit that referenced this pull request Jul 15, 2026
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>
XVVH and others added 2 commits July 15, 2026 09:41
…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>
…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>
@XVVH XVVH changed the title W-20 item (3): SI-32 filesystem-attacker-model candidate (ADR 0008, PROPOSED) W-20 item (3): ratify SI-32 as A27 — filesystem attacker model (ADR 0008 ACCEPTED, spec v0.10) Jul 15, 2026
…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>
@XVVH

XVVH commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

Delta-round fold (commit eff73b2). The external round returned REQUEST CHANGES with five findings; all folded:

  1. A27.1 T1 label (blocking) — restored in the spec text: "Holds against T1 — the write-boundary complement of A27.2's read-back rule (D32-5)."
  2. Caller-pin layer misclass (blocking) — corrected in the D32-2 addendum per the prescribed remedy: caller-pinned expected heads are layer 1's completeness tier (§6.2); only the external monotonic anchor is layer 2. The preserved candidate body's sentence is marked as the error; the addendum wins.
  3. SI-40 snapshot-timing over-claim (non-blocking medium) — the substrate-assisted paragraph no longer claims a gate-acquisition snapshot closes the window (the in-window edit postdates it by definition); the preserving variant is outgoing-state retention at swap, with the diff/CAS-ingest/attribute reconciliation costs now stated.
  4. A27.4 label variants (low) — the two candidate-body shorthands and the spec-issues candidate paragraph normalized to the exact ratified sentence.
  5. v0.9 stamps (low) — CLAUDE.md's "constitution" pointer and the spec status line bumped to v0.10 (status line also gains an A27 provenance clause).

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

XVVH and others added 2 commits July 15, 2026 14:42
… 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>
@XVVH

XVVH commented Jul 15, 2026

Copy link
Copy Markdown
Owner Author

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>
@XVVH
XVVH marked this pull request as ready for review July 15, 2026 19:49
@XVVH
XVVH merged commit 5e241ff into main Jul 15, 2026
6 checks passed
@XVVH
XVVH deleted the docs/w20-si32-candidate branch July 15, 2026 19:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant