docs: regen inventory blocks - #1623
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
|
This pull request has been ignored for the connected project Preview Branches by Supabase. |
e69d35f to
b71dbca
Compare
Auto-generated by .github/workflows/docs-regen.yml. Sources: src/lib/types/database.ts, src/app/**/page.tsx, src/app/**/actions/**/*.ts, src/hooks/**/*.ts.
b71dbca to
df16b1f
Compare
) Two days of repairs left the pieces better and unable to check each other. This makes drift observable, so the next forensic pass is a command instead of a week. THE PATTERN, STATED ONCE control written -> documented -> assumed -> stops running -> docs remain -> agent trusts docs -> failure Observed, all of it: guard-bash.sh existed, unwired, deleted guard-sql.sh existed, unwired, deleted retire-worktrees.sh existed, never invoked four rule files claimed hooks that were gone worktree GC keyed on a ref GitHub deletes on merge Docs Regen opened a PR that sat open while main went stale a fixture test operated on the real repository Not one was a missing control. Every one was a control that stopped running while its documentation stayed put. WHAT THIS ADDS npm run control-plane:verify static + runtime npm run control-plane:verify:static CI-safe, wired as its own required job READ-ONLY by construction. It regenerates nothing, deletes nothing, mutates no config. The previous docs gate re-ran the generator and diffed, so the only way to learn the docs were stale was to have already fixed them — a verifier that repairs what it inspects cannot tell you what was wrong. 0 VERIFIED passed, or a named acknowledged gap 1 CONTROL FAILURE a control that should hold does not 2 UNKNOWN a required state could not be established UNKNOWN outranks FAIL and never becomes PASS. If something could not be established, "these specific things are broken" would imply everything else was checked. ACKNOWLEDGED GAP != UNKNOWN. Four gaps carry an id, an owner, a date, a reason and a closing condition in config/control-plane-gaps.json, and every run prints them so they cannot fade. MUTATION BUDGET, ENFORCED BEFORE ALLOCATION HELM_MAX_MUTATION_WORKTREES defaults to 1. Refused before `git worktree add` and before any install, so a refusal costs nothing. Classification FAILS TOWARD MUTATION: an unreadable or undeclared workspace counts. A declared release workspace escapes the budget only if it is ALSO detached — on a branch it can still be committed to. The disk reserve stopped a catastrophe; it never stopped waste. Six worktrees in one day was a concurrency problem that only became visible as a disk problem. BRANCH-GC AUTHORIZATION, RECORDED IN THE TOOL ITSELF Verdict renamed DELETE_SAFE -> DELETE_MERGED_EXACT so it states its own evidence, and the grant lives in the authority, not in a paragraph elsewhere: PR MERGED + local tip === PR head OID + not protected + not checked out Nine verdicts are explicitly excluded. The sharpest is new: NO_UPSTREAM_UNIQUE_WORK. Measured — ten branches hold up to 19 commits with no upstream, existing nowhere else. Folding those into UNKNOWN_PR conflated "the lookup failed" with "this is the only copy", and only one of those is permanent. THE GATE-LIE FROM #1672, ACTUALLY CLOSED #1672 raised the timeout and its own PR said that makes the unknown RARER, not DISTINGUISHABLE. The eleven repo sweeps now run in a dedicated `guards` project under scripts/repo-guards.mjs: PASS ran, found nothing POLICY_FAILURE ran, found violations exit 1 INFRASTRUCTURE_FAILURE did not finish — UNKNOWN exit 2 Proven end to end by injecting a real 200s hang into a real guard: exit 2, never reported as a violation. The guards are UNTOUCHED. They are 116-357 lines of bespoke matching logic each; rewriting them to fix a REPORTING defect would risk weakening the guards themselves. The lie was at the reporting boundary and is fixed there. Worth recording: vitest's JSON reporter does not carry the timeout text — a real timeout arrives as `Error: STACK_TRACE_ERROR`. A first draft scraped the human-readable stream to recover it. That did not match, and it was the wrong idea: parsing a tool's console output to make a safety decision is the brittle-regex pattern this repo has already deleted guards for. The guarantee is the DEFAULT — an unrecognised failure is INFRASTRUCTURE_FAILURE — not a pattern. TOOL AUTHORITY, AND EVIDENCE THAT EXPIRES docs/TOOL_AUTHORITY_MATRIX.md, generated. Five words that are not synonyms: CONFIGURED, CONNECTED, EXPOSED, ALLOWED, EXERCISED. ET-4 lost two days reading the first as the last. Probed live, not inferred: Sentry BOTH namespaces connected, find_organizations byte-identical. Redundant -> mcp__claude_ai_Sentry__* is authority, plugin denied. Reversible: one deny line restores it. Vercel plugin exposes ONLY authenticate -> CONFIGURED, not CONNECTED. Account connector is authority; dead namespace denied. GitHub the gh CLI is the lifecycle path, exercised three ways: MERGED #1676, OPEN #1659, and a branch with no PR. A failed lookup stays UNKNOWN_PR (#1668). Supabase sanctioned mcp__supabase__* is installed but NOT connected. Every observation carries a fingerprint of the configuration that produced it. Change a deny rule and the matching EXERCISED claims become STALE on the next regeneration. Nobody has to remember to invalidate them. Two bugs found by running it: Sentry and GitHub produced an IDENTICAL fingerprint (both slices empty), which would have made drift undetectable for both; and a service governed by nothing now says `ungoverned` rather than implying coverage it does not have. SUPABASE — A STRUCTURAL FINDING Starting the sanctioned server's OAuth flow shows its requested scopes: organizations:read projects:read database:read analytics:read secrets:read edge_functions:read environment:read storage:read Every scope is :read. That is connector-enforced capability restriction — real evidence, not a URL string, and obtainable without any write probe. It also means mcp__supabase__apply_migration almost certainly CANNOT function under this grant, while an explicit owner authorization says it may. Surfaced as gap SUPABASE_MIGRATION_GRANT_VS_READ_SCOPES rather than resolved, because resolving it means attempting a production migration to answer a documentation question. USER-GLOBAL, UNDER EXPLICIT AUTHORIZATION AND WITH A BACKUP removed mcp__plugin_supabase_supabase__{execute_sql,apply_migration} — no such plugin is installed; a grant waiting to activate on install is a trap, not a capability removed mcp__claude_ai_Supabase__apply_migration — account-WIDE mutation nobody authorized kept mcp__supabase__apply_migration — the owner's explicit grant kept mcp__claude_ai_Supabase__execute_sql as TEMPORARY_FALLBACK, named UNENFORCED, because it is the only working query path until the sanctioned one connects fixed the autoMode prose claiming a PreToolUse hook blocks destructive SQL. It never did; it had been copied from this repo's own docs. SANDBOX — MEASURED, NOT ASSUMED, AND NOT ENABLED Ten disposable probes: writes inside the project, outside it, into .claude/settings.json and .claude/hooks, reads of .env.local, and ../ traversal ALL SUCCEEDED — including paths the config lists under denyRead and denyWithinAllow. sandbox.filesystem.disabled is true and authoritative. Network sandboxing IS enforced (observed: deny network-outbound analytics.brew.sh:443). NOT enabled. The configured allowWrite covers /private/tmp/helmv3-*, ~/.npm and ~/Library/Caches/deno — not the repository — so flipping it as configured would block every worktree write, user-globally, for every project and any concurrent session. Recorded as gap SANDBOX_FILESYSTEM_DISABLED with the closing condition. No fake Bash parser was added as compensation. DOCS REGEN — created != integrated #1623 existed because main carried a stale route count (234 vs 235, after /admin/self-heal shipped) and the fix lived in a bot PR that nothing merged. That workflow's own header recorded that GITHUB_TOKEN PRs may receive no required CI, so it could not be merged confidently either. regen-docs.mjs gains a genuinely NON-MUTATING --check that computes expected blocks, diffs them, names the first differing line, and leaves the tree byte-identical. It is now a required PR-time gate. The auto-PR workflow is verification-only and creates nothing. #1623's diff is byte-for-byte what regeneration produces here, so it closes as superseded. FAILURE INJECTION — 15 cases, every one in a disposable COPY delete a configured hook -> FAIL point a hook at a nonexistent script -> FAIL break the blocking hook's matcher -> FAIL reintroduce a false safety claim -> FAIL the same claim, QUOTED -> PASS (corrections stay writable) declare a namespace never observed -> FAIL move the budget check after allocation -> FAIL remove the budget check -> FAIL change a service's config -> its observations STALE change one service -> others NOT staled a service governed by nothing -> ungoverned, not fresh inject a real 200s guard hang -> INFRASTRUCTURE_FAILURE, exit 2 inject a real banned import -> POLICY_FAILURE, exit 1 Plus a SENTINEL proving the injections cannot reach the live checkout. That is the direct regression for #1676, where a fixture test resolved its target back to the real repository and parked a live worktree. THREE THINGS THE VERIFIER CAUGHT IN ITS OWN AUTHORS' WORK 1. It reported mutation-budget-enforced FAIL against a correctly-ordered script, because indexOf matched `git worktree add` in the script's own HELP TEXT at line 15. Substring is not mechanism — the same error the enforcement generator made on its first run. Now line-based and comment-aware. 2. The matrix rendered the whole Supabase namespace as DENIED when only its ten mutators are, and folded DENIED_BY_POLICY and NOT_EXERCISED into "FAILED" — which reads as "we tried and it broke", untrue of both. 3. #1672's own test asserted `unit` must be no stricter than its siblings, because `unit` held the sweeps. They moved. The failure was the premise announcing itself, and the test now pins the invariant that survives: whichever project runs the sweeps must be the most generous. DELIBERATELY NOT DONE No UNKNOWN or no-upstream branch deleted. No production SQL write as a probe. No regex Bash/SQL pseudo-guard. #1638 not merged. sandbox.filesystem not enabled. The Repair LaunchAgent not re-armed — a green control plane is not evidence about a different unresolved runtime problem. Verified: npm run preflight 0; npm test 1265 files / 12049 passed; control-plane:verify 0 (20 pass, 0 fail, 0 unknown, 1 acknowledged gap); control-plane:verify:static 0; enforcement:check 0; docs:inventory-check 0; tool-authority:check 0; guards 32/32; check:cycles 0; shellcheck 0; repo:doctor 0. Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Superseded by #1677. Your diff was The architecture that created you is gone: generated-inventory drift is now a REQUIRED PR-time check ( |
…lsof's silence (#1683) * fix(lifecycle): an OPEN PR's checkout needs its owner's consent, not lsof's silence Reproduced 2026-08-30: `npm run worktrees:retire` removed a concurrent session's checkout (agent/round-type-reclassify, PR #1681, OPEN). Every mechanical signal said disposable — clean, tip identical to its pushed remote, and no process whose cwd `lsof` could see. Nothing was lost, because parking is defined to keep the branch and PARKABLE already required the tip to match its remote. But the checkout had an owner and the tool could not tell, so this is a classifier defect, not a slip. The unsound step is reading silence as absence. `lsof +D` samples one instant: hasLiveProcess === true proof of activity — a sound veto hasLiveProcess === false NOT proof of inactivity — an agent session between two tool calls has no visible cwd classifyWorktree's own header stated the defect as design — "parking does NOT consult the PR at all" — so the comment is rewritten in the same commit. A file whose prose contradicts its code is the failure this program exists to remove. WHAT CHANGED New worktree verdict KEEP_PR_OWNER_INTENT_REQUIRED, deliberately neither ACTIVE (nothing proved anyone is using it) nor UNKNOWN (the PR read fine; what is missing is a decision). It is in REQUIRES_HUMAN_VERDICTS, so the standing authorization already excludes it. config/open-pr-dispositions.json gains `worktree_policy`, because the disposition LABEL was being asked to imply an ACTION readers had to infer: KEEP never parked automatically PARK_IF_REPRODUCIBLE park once clean and pushed; the branch stays A missing row, an unrecognised policy, or a disposition of ACTIVE/UNKNOWN all KEEP. #1659 — an open PR waiting on a physical-device test — is released explicitly by its owner and stays parkable, which is the case the park/retire split exists for. The registry is now current state in BOTH directions. It carried ACTIVE rows for #1623, #1638, #1679 and #1680 after they closed or merged; control-plane -verify now fails on a stale row as well as a missing one, and on a worktree_policy outside the vocabulary. That vocabulary check lives in the verifier because the lifecycle tool must fail SAFE on a malformed entry (unrecognised policy => KEEP) and would therefore never report one. #1681's row is recorded ACTIVE/KEEP, transcribed from observable state — PR OPEN, worktree checked out — by this session and not by its owner, who should confirm it. Recorded rather than left blank because leaving it blank is exactly what let --retire park it. WHAT THIS DOES NOT COVER A worktree whose branch has NO PR is still parked on reproducibility alone — the same defect class, with no PR to key a disposition on. Requiring recorded intent for every branch would make --park unable to act at all, which defeats the reason parking exists. Registered as WORKTREE_PARK_NO_PR_OWNERSHIP rather than quietly accepted. VERIFIED preflight 0 · 1269 files / 12,101 tests 0 · docs:check 0 · knowledge:check 0 · markdown ratchet 30515, unchanged · control-plane:verify VERIFIED exit 0 (was CONTROL FAILURE on open-pr-residue) · lifecycle suite 60 passed. Failure injection: disabling the ownership gate turns 8 of them red, including the end-to-end CLI case where --park refuses a fixture worktree whose PR is OPEN with no disposition. The lib was restored from a hashed backup and re-verified byte-identical. Assumption stated once: this ran in the canonical checkout rather than a worktree. HELM_MAX_MUTATION_WORKTREES=1 and the other session holds the only mutation workspace, so new-worktree.sh refuses by design; AGENTS.md permits a single session in canonical, and the concurrency hazard the worktree rule addresses does not apply because the other session is isolated in its own. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH * chore(dispositions): record this PR's own row — the new rule's first cost Opening #1683 made control-plane:verify red on open-pr-residue immediately, because the key set must now equal the live open-PR set exactly. That is the chosen tradeoff, not a surprise: a PR number does not exist until the PR does, so the row can only ever land in a follow-up commit. KEEP rather than PARK_IF_REPRODUCIBLE: this work runs in the canonical checkout, which classifyWorktree holds ACTIVE before consulting anything else. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
The registry is CURRENT STATE, so a merge makes its own row stale — this is the two-ended cost ADR-2026-08-30 records, paid on schedule. control-plane:verify reported it as a CONTROL FAILURE the moment #1687 merged (open-pr-residue: "disposition rows for PRs no longer open: #1687"), which is the check working: a current-state registry that only failed on MISSING rows would have carried an ACTIVE row for a merged PR indefinitely, exactly as this file did for #1623, #1638, #1679 and #1680 before this run. After: 3 open PRs (#1659, #1678, #1681), all owned elsewhere, all classified. control-plane:verify VERIFIED, exit 0 — 21 pass, 0 fail, 0 unknown. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH
…e merge Found by running the acceptance test for the first half. After merging, a row whose PR has landed is stale until someone pushes — fixed by exact merge identity. BEFORE merging, the mirror image: a row that lives in its own PR is absent from main for the PR's entire flight, so `open PRs with no recorded disposition` fails main from the moment such a PR opens. Observed directly: with #1688 open, control-plane:verify from canonical reported CONTROL FAILURE — "open PRs with no recorded disposition: 1688". Adding the row in an EARLIER PR only moves the problem one PR back; pushing it straight to main is the bypass this whole change exists to remove. Both exits were closed on one side and open on the other. Second exception, proved the same way — by identity, not assumption: the row is absent from the verified checkout AND it IS present in config/open-pr-dispositions.json at that PR's OWN head -> IN FLIGHT, not unclassified Absent at the head, or unreadable there, still FAILS. That is the line between "arriving" and "missing", and it is the same line as everywhere else in this check: #1623 sat open for weeks with no row anywhere and must stay caught. Verified against the live PR rather than only in fixtures: deleting #1688's row from the working tree while the PR head still carried it produced PASS 4 open PR(s) ... | in flight (row present at the PR's own head): #1688 and restoring it returned the file byte-identical. Injection: treating an unproven row as in-flight turns two tests red, and the script restored byte-identical (sha256). preflight 0, 45 tests in this file, verifier VERIFIED. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH
…hes (#1688) * fix(control-plane): close the two routes that produced the direct pushes Two unreviewed commits reached main on 2026-08-30. Neither was a lapse of judgement in isolation — each was the only exit from a control that had no other one. Both exits are now closed. 1. THE DISPOSITION CLOSING TRAP A PR that carries its own open-pr-dispositions row makes main fail `open-pr-residue` the instant it merges: the row is now stale by the file's own current-state rule. The only ways out were a second PR — which needs its own row, so the same thing happens again — or a direct push. A control whose only escape is bypassing another control is a defect in the first one. The exception is the narrowest thing that closes it: row's PR is no longer OPEN AND GitHub says MERGED AND merge_commit_sha === the verified checkout's HEAD -> TRANSITIONALLY CLOSED Exact merge IDENTITY, never "merged recently"/"today"/"within N commits" — those widen silently as history grows. This one narrows on its own: one more commit on main and HEAD moves, so the row fails again. It survives its own merge and nothing more; the next ordinary PR clears it while adding its own row. A transitional row is named in the check's output, so nobody has to remember it. Every other stale shape still fails, including the ones where the evidence for the exception is missing: closed-but-unmerged, unreadable merge state, MERGED with no merge commit, unreadable local HEAD, and any second stale row. Refusing a RELAXATION on unproven evidence is the safe direction — distinct from the open-PR LISTING failing, which stays UNKNOWN, because there we cannot establish what is open at all. 2. THE STANDING ADMIN BYPASS New runtime check `github/main-branch-protection`. main is protected and requires six contexts, but enforce_admins is off, so ordinary agent credentials push straight past both the PR requirement and the checks. It reads BOTH mechanisms. Classic protection reports enforce_admins; repository RULESETS are a separate system with their own bypass_actors and report on /rulesets. This repo has classic protection and zero rulesets today — but the bypass message GitHub printed is ruleset wording, and a check reading only the first endpoint would report PASS against a bypass reinstated in the second. That is the difference between a real check and a decorative one. It cannot fix itself, by design: branch protection is repository SETTINGS, and an agent credential able to relax its own gate is not a gate. So the condition is registered as MAIN_ADMIN_BYPASS_AVAILABLE and reported as ACKNOWLEDGED_GAP — and a known condition is a gap only while it is REGISTERED. Bypass present with no gap entry is a FAIL, never a quiet excuse. 3. THE GAP COUNT WAS COUNTING THE WRONG THING The final line printed the number of CHECKS returning ACKNOWLEDGED_GAP (1) labelled as the acknowledged-gap count, against five registered gaps. Four owned, dated, closing-condition-bearing gaps were invisible on the one line anybody reads. summarise() now exposes registered_gap_count and gap_state_check_count separately, in text and in --json. Exit precedence is untouched: gaps never move it, UNKNOWN still outranks FAIL. VERIFIED — 21 pass, 0 fail, 0 unknown REGISTERED OPEN GAPS — 6 (checks reporting GAP state this run: 2) Verified: three failure injections, each red for its own reason — unwiring the new check, replacing exact merge identity with "always true", and ignoring rulesets — and the script restored byte-identical (sha256 checked). preflight 0, 202 tests across src/test/scripts, docs:check 0, knowledge:check 0, ratchet unchanged. `gh` is stubbed in the wiring tests, so no test reaches GitHub. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH * chore(control-plane): record #1688's own disposition row The row this PR's exception exists to let survive its own merge. After it merges, main HEAD === #1688's merge commit, so open-pr-residue reports it TRANSITIONALLY CLOSED instead of failing — which is the acceptance test for the defect, run from canonical without touching this file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH * fix(control-plane): the disposition trap has a second half, before the merge Found by running the acceptance test for the first half. After merging, a row whose PR has landed is stale until someone pushes — fixed by exact merge identity. BEFORE merging, the mirror image: a row that lives in its own PR is absent from main for the PR's entire flight, so `open PRs with no recorded disposition` fails main from the moment such a PR opens. Observed directly: with #1688 open, control-plane:verify from canonical reported CONTROL FAILURE — "open PRs with no recorded disposition: 1688". Adding the row in an EARLIER PR only moves the problem one PR back; pushing it straight to main is the bypass this whole change exists to remove. Both exits were closed on one side and open on the other. Second exception, proved the same way — by identity, not assumption: the row is absent from the verified checkout AND it IS present in config/open-pr-dispositions.json at that PR's OWN head -> IN FLIGHT, not unclassified Absent at the head, or unreadable there, still FAILS. That is the line between "arriving" and "missing", and it is the same line as everywhere else in this check: #1623 sat open for weeks with no row anywhere and must stay caught. Verified against the live PR rather than only in fixtures: deleting #1688's row from the working tree while the PR head still carried it produced PASS 4 open PR(s) ... | in flight (row present at the PR's own head): #1688 and restoring it returned the file byte-identical. Injection: treating an unproven row as in-flight turns two tests red, and the script restored byte-identical (sha256). preflight 0, 45 tests in this file, verifier VERIFIED. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Auto-generated inventory update
Triggered by a push to
mainthat touched a source of truthfor the inventory blocks in
memory/glossary.mdandmemory/projects/golfhelm.md.What changed: the auto-regenerated sections between
<!-- AUTOGEN:* -->markers. Hand-curated narrative outsidethose markers is preserved.
What to do: review the diff. If it looks sane, squash-merge.
If something looks wrong, the script lives at
scripts/regen-docs.mjs.See
.github/workflows/docs-regen.ymland the"Auto-regen inventory docs" section of
CLAUDE.md.🤖 Generated by GitHub Actions