diff --git a/.harness-hash b/.harness-hash index 12b4446991..f68ac1822d 100644 --- a/.harness-hash +++ b/.harness-hash @@ -1,12 +1,14 @@ -7c51b2422a2578ab34c9415f1bcb9456bf2ca0c6f6dbe6d828c35d2dbd7dc8b4 000-docs/000-INDEX.md +bcfa54f647187b02bfc8caa23e2e89672e52ef877b988d7705c6c02b86c114a8 000-docs/000-INDEX.md a95f7d4b328f506d53ccc028486f80e79cd7854b7985e838ec6913af21a47f33 000-docs/001-PP-PLAN-buzz-adoption-master-blueprint.md def765bd4f637f1b2cfe5abdb508837e3247b771c8530d0ef394a587c6adc250 000-docs/002-DR-DECR-buzz-adoption-decision-record.md 5030aaf8545985489095cc6f48badee6981f4f2db7b2ba9879877f4bb6bfb755 000-docs/003-OD-DEPL-deploy-posture-public.md 9bcad2b30288a04687745e989a9779823ed16891c1e3c5fa8ae544fa3d814ca7 000-docs/004-DR-DECR-fork-gate-wiring.md 75b5b1253248fd4f04aebfae36efeb2ce48323a567d4ca63d59e0d67667789f6 000-docs/005-DR-DECR-dedicated-vps-topology.md 27bf0d046df299a1662b8c86b4b8a9da1e0c8e14e98c0919d2873014c1080b47 000-docs/006-DR-STND-authoritative-naming-and-boundaries.md +d47f82f7f176ad3fbd87d6e6d6acd8248a2347439de6df6ed3d16f643669088f 000-docs/007-AA-AUDR-fork-contract-breach-2026-08-03.md +fbeaab57a0f6fe0ab1cb876154b1b356e69e88f2803440eeeeb26689723eafdf 000-docs/008-AA-AUDR-fork-allowlist-lockstep-2026-08-08.md d1c85ad5bafc4b6eb1f78ec888746f66f45e87cb9fd9d84122cfdd59994821c4 FORK.md 43f3750a570e82cfa0c0cdef6ff51d962f7dbd98f892b590c0a30955043c0ab4 TEST_AUDIT.md da2d266381d9209da59fcc6b06ca351e8eaf0b56470b5353557cc5eb48354761 lefthook-local.yml -fa65f444d630a5eb6db9aa2e306bb389aefd08837a6c696793dc29579369b03c scripts/fork-gates/check-additive-only.sh +f7a59e4016e8ebecf175be942fd2a021327641b8834ed59af4568896a82fb214 scripts/fork-gates/check-additive-only.sh 5fce5778878475c456ad90fdd1a0d559b5b9bc44cfa583dddd7a783f09397930 scripts/fork-gates/check-must-survive.sh diff --git a/000-docs/000-INDEX.md b/000-docs/000-INDEX.md index 3edd76688d..f0fa8142ab 100644 --- a/000-docs/000-INDEX.md +++ b/000-docs/000-INDEX.md @@ -13,3 +13,4 @@ This directory is an Intent Solutions **addition** to the fork — upstream | 005 | [DR-DECR — Dedicated production VPS topology](005-DR-DECR-dedicated-vps-topology.md) | Owner decision (2026-07-29): production on a dedicated VPS; the shared-host stack becomes permanent staging. Supersedes the one-server answer in `001`/`003`. | | 006 | [DR-STND — Authoritative naming & boundaries](006-DR-STND-authoritative-naming-and-boundaries.md) | **CANONICAL** (owner amendment 2026-07-29, FINAL): the six Buzz assets, the host-vs-repo disambiguation rule, the four-plane flow, and the two gates (contribution vs deployment). Any doc naming a Buzz asset defers to this. | | 007 | [AA-AUDR — Fork-contract breach audit 2026-08-03](007-AA-AUDR-fork-contract-breach-2026-08-03.md) | PR #16 merged 14 upstream-owned paths onto fork `main` (process breach only; prod untouched). Divergence inventory, causal chain (gates never in CI), remediation: revert → repair-branch sync → upstream via the contribution lane → gates as a required CI check. | +| 008 | [AA-AUDR — Fork allowlist lockstep audit 2026-08-08](008-AA-AUDR-fork-allowlist-lockstep-2026-08-08.md) | The `ALLOW` array granted `.gitleaksignore`, a path `FORK.md` never declared, that does not exist and that no tool uses. Removed rather than documented, per `decision-log/048` D170/D171 — removal fails closed. No breach, no divergence change. | diff --git a/000-docs/008-AA-AUDR-fork-allowlist-lockstep-2026-08-08.md b/000-docs/008-AA-AUDR-fork-allowlist-lockstep-2026-08-08.md new file mode 100644 index 0000000000..dbf1676008 --- /dev/null +++ b/000-docs/008-AA-AUDR-fork-allowlist-lockstep-2026-08-08.md @@ -0,0 +1,108 @@ +# 008 — AUDIT: the fork allowlist granted a path the contract never declared + +**Date:** 2026-08-08 +**Type:** Audit record (AA-AUDR) +**Trigger:** A handover readiness pass on the Buzz documentation set. Carter Gray is taking over Buzz +management, so `FORK.md` was re-read as the contract a new maintainer is handed, and checked against +the code that enforces it rather than accepted as written. +**Severity:** Low. No breach, no divergence, no production impact. Recorded because the defect class +— the human contract and its machine form disagreeing — is exactly what `007` cost us. +**Status:** Fixed in this change. + +--- + +## 1. The claim under test + +`scripts/fork-gates/check-additive-only.sh`, immediately above the `ALLOW` array: + +> ```text +> # The fork allowlist — every path prefix this fork is allowed to differ on. +> # Keep in lockstep with the FORK.md must-survive table (that table is the +> # human contract; this array is its machine form). +> ``` + +Two artifacts, one asserted to be the other's machine form. That assertion is testable, and nothing +tests it — `check-must-survive.sh` asserts the *paths exist*, not that the two lists agree. + +## 2. Finding — one entry in `ALLOW` has no row in `FORK.md` + +Comparing the 13 `ALLOW` entries against the 10 path rows of `FORK.md` § *Must-survive set*: + +| `ALLOW` entry | `FORK.md` row | +|---|---| +| `FORK.md`, `TEST_AUDIT.md`, `000-docs/`, `.beads/` | present | +| `scripts/fork-gates/`, `scripts/audit-harness`, `.audit-harness/` | present | +| `.harness-hash`, `.harness-hash-extra-patterns`, `lefthook-local.yml` | present | +| `CLAUDE.md`, `.github/workflows/fork-gates.yml` | present (declared divergences) | +| **`.gitleaksignore`** | **absent** | + +Three further facts settle what to do about it: + +- **The file does not exist.** Not in the worktree, not in `git diff upstream/main...HEAD`. +- **Nothing would use it.** `gitleaks` does not run anywhere in this repository — the only workflow + is `fork-gates.yml`, whose two steps are the additive-only and must-survive checks. The single + occurrence of the string `gitleaks` in the entire repo was that `ALLOW` entry. +- **It is a permission, not a claim.** `ALLOW` means *"if this path differs from upstream, that is + allowed"*. So the entry was standing permission for a file nobody needs, that no gate would + notice appearing. + +## 3. Why removal, rather than adding a row to `FORK.md` + +Both fixes restore lockstep. Adding a `FORK.md` row would have documented a file that does not +exist — and `decision-log/048` (D170/D171, 2026-08-07) ratified the opposite instinct four weeks +into exactly this problem: *docs should describe things that exist*, and a name held in reserve is +indistinguishable, to a reader six months later, from something they cannot find. That ruling +retired two phantom repositories and deleted the disambiguation rule they had forced. + +The same reasoning applies to a permission held in reserve, with an extra argument on top: +**removal fails closed.** If a `.gitleaksignore` is ever genuinely wanted, the additive-only gate +will refuse the diff until `FORK.md` and `ALLOW` are updated together — which is the contract doing +its job, and precisely the review step that `007` found had been missing. + +## 4. What changed + +- `scripts/fork-gates/check-additive-only.sh` — `.gitleaksignore` removed from `ALLOW` (13 → 12). +- `.harness-hash` re-pinned, because `scripts/fork-gates/*.sh` is inside the hash-pinned policy + surface (`.harness-hash-extra-patterns:7`). An unpinned edit to a gate script is the thing that + pin exists to catch. + +`FORK.md` is unchanged — it was already correct; the array had drifted away from it. + +**Incidental finding, surfaced by the re-pin and worth naming rather than letting it ride in +silently:** `.harness-hash` was missing an entry for `000-docs/007-AA-AUDR-fork-contract-breach-2026-08-03.md`. +That file is inside the pinned surface, so it should have been pinned when it was added on 2026-08-03 +and `scripts/audit-harness init` was evidently not re-run then. Re-pinning here picked it up, so the +manifest now covers 14 files rather than 12. Nothing was tampered with — an unpinned file is simply +one the verify step was silently not watching, which makes this the second instance in this same +audit of *enforcement whose scope quietly stopped matching its subject*. + +## 5. Verified + +`check-additive-only.sh upstream/main` and `check-must-survive.sh` both pass against the reduced +array, and `scripts/audit-harness verify` passes on the re-pinned manifest. The divergence set is +byte-for-byte what it was before this change. + +## 5b. A correction to this record, and it proves the point + +The first draft of this audit stated "14 `ALLOW` entries" and "11 rows", and listed `REVIEW.md` +among the matched entries. **Those numbers were read off the wrong branch** — the unmerged +`chore/retire-phantom-lab-repos`, which adds `REVIEW.md` to `ALLOW` *and* to `FORK.md` (correctly, in +lockstep). On `main`, the base this change targets, `REVIEW.md` exists in neither list and the file is +not in the divergence set at all. The correct counts are **13 → 12** against **10** `FORK.md` rows. + +Caught in review by CodeRabbit, verified against `git show origin/main:…` before accepting. Recorded +rather than silently amended, because an audit about two lists disagreeing that itself miscounted the +lists is the strongest available argument for the follow-up in § 6: **counts asserted by a human are +exactly the thing a gate should be computing.** + +## 6. Method note + +This was found by diffing the two lists rather than by reading either one. `007`'s causal chain was +*"the gates existed but were never in CI"* — enforcement that is present but not wired. This is the +adjacent failure: enforcement that is wired, but whose scope no longer matches the contract it +claims to enforce. A comment saying *"keep these in lockstep"* is an unenforced assertion, and this +repository's own history is the argument for not trusting those. + +**Worth considering as a follow-up, deliberately not done here:** a check that parses the `FORK.md` +table and asserts set-equality with `ALLOW`, so the lockstep comment becomes a gate. It is a small +script; it is not this change, because this change should be reviewable as a one-line removal. diff --git a/scripts/fork-gates/check-additive-only.sh b/scripts/fork-gates/check-additive-only.sh index 8f4f22fe7c..ea33390297 100755 --- a/scripts/fork-gates/check-additive-only.sh +++ b/scripts/fork-gates/check-additive-only.sh @@ -25,7 +25,6 @@ ALLOW=( "TEST_AUDIT.md" "000-docs/" ".beads/" - ".gitleaksignore" "lefthook-local.yml" "scripts/fork-gates/" "scripts/audit-harness"