Skip to content

feat(control-plane): the control plane verifies the control plane - #1677

Merged
njrini99-code merged 1 commit into
mainfrom
agent/control-plane-final-convergence
Aug 29, 2026
Merged

feat(control-plane): the control plane verifies the control plane#1677
njrini99-code merged 1 commit into
mainfrom
agent/control-plane-final-convergence

Conversation

@njrini99-code

Copy link
Copy Markdown
Owner

The control plane verifies the control plane

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.

npm run control-plane:verify

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.

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, owner, date, reason and
closing condition, and every run prints them so they cannot fade.

control-plane:verify:static runs as its own required CI job — not a step
inside "Feature knowledge", where a control-plane failure would have surfaced
under someone else's name.

Mutation budget, enforced before allocation

HELM_MAX_MUTATION_WORKTREES defaults to 1, refused before git worktree add
and before any install. Classification fails toward mutation: an unreadable
or undeclared workspace counts. A declared release workspace escapes 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.

Branch-GC authorization, recorded in the tool itself

DELETE_SAFEDELETE_MERGED_EXACT, so the verdict states its own
evidence: 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. 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 said so itself: that makes the unknown rarer, not
distinguishable
. The eleven 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 by injecting a real 200 s hang into a real guard: exit 2, never
reported as a violation.

The guards are untouched — 116–357 lines of bespoke logic each; rewriting
them to fix a reporting defect would risk weakening the guards themselves.

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 console
stream to recover it. It didn't match, and it was the wrong idea: parsing a
tool's human-readable output to make a safety decision is the brittle-regex
pattern this repo has already deleted guards for. The guarantee is the
default
, 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:

Service Finding
Sentry both namespaces connected, find_organizations byte-identical → redundant. Account connector is authority; plugin denied, reversibly
Vercel plugin exposes only authenticate → CONFIGURED, not CONNECTED. Dead namespace denied
GitHub the gh CLI is the lifecycle path, exercised on a MERGED PR, an OPEN PR, and a branch with no PR
Supabase sanctioned mcp__supabase__* installed but not connected

Every observation carries a fingerprint of the configuration that produced
it
. Change a deny rule and the matching EXERCISED claims go STALE on the next
regeneration.

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.

Supabase — a structural finding

Starting the sanctioned server's OAuth flow reveals its scopes:

organizations:read  projects:read  database:read  analytics:read
secrets:read  edge_functions:read  environment:read  storage:read

Every scope is :read — connector-enforced capability restriction, real
evidence rather than a URL string, obtained 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 a gap, not resolved — 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 installed; a grant waiting to activate on install is a trap
removed mcp__claude_ai_Supabase__apply_migration — account-wide mutation nobody authorized
kept mcp__supabase__apply_migration — your explicit grant
kept mcp__claude_ai_Supabase__execute_sql as TEMPORARY_FALLBACK, named UNENFORCED
fixed autoMode prose claiming a PreToolUse hook blocks destructive SQL

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.

Not enabled. The configured allowWrite covers /private/tmp/helmv3-*,
~/.npm and Deno's cache — not the repository — so flipping it as configured
would block every worktree write, user-globally, for every project and any
concurrent session. Recorded as a gap with its closing condition. No fake Bash
parser 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 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 names the
first differing line and leaves the tree byte-identical. Now a required PR gate.
The auto-PR workflow is verification-only and creates nothing.

Failure injection — 15 cases, every one in a disposable copy

Injection Result
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 200 s guard hang INFRASTRUCTURE_FAILURE, exit 2
inject a real banned import POLICY_FAILURE, exit 1

Plus a sentinel proving injections cannot reach the live checkout — the
direct regression for #1676.

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.
  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. fix(vitest): a red check that asserted an import which does not exist #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.

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

preflight 0 · npm test 1265 files / 12049 passed ·
control-plane:verify 0 (20 pass, 0 fail, 0 unknown, 1 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

🤖 Generated with Claude Code

https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH

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.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH
@vercel

vercel Bot commented Aug 29, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
helmv3 Ignored Ignored Aug 29, 2026 11:42pm

Request Review

@supabase

supabase Bot commented Aug 29, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project qmnssrrolpinvwjjnufo because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@qodo-code-review

Copy link
Copy Markdown

ⓘ Qodo reviews are paused because your trial has ended. Ask your workspace admin to add credits to resume reviews. Manage billing

@coderabbitai

coderabbitai Bot commented Aug 29, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 204f1438-5a2a-405f-bf8e-a4baf92acc20

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@njrini99-code
njrini99-code merged commit ee02519 into main Aug 29, 2026
48 checks passed
@njrini99-code
njrini99-code deleted the agent/control-plane-final-convergence branch August 29, 2026 23:55
njrini99-code added a commit that referenced this pull request Aug 30, 2026
…ven, one registered (#1679)

* fix(incidents): an unreadable resolution ledger is not an unresolved incident

MC-PRODUCER. The hypothesis was that `fetchResolutions` loses information at its
I/O boundary. A red test proved it, and the test that proved it also proved the
obvious fix would have been worse.

THE DEFECT

`fetchResolutions` returned a bare `Map<fingerprint, row>`. On a Supabase error
it logged a warning and returned an EMPTY map — byte-identical to the map it
returns when the ledger is healthy and genuinely holds no rows. Its own comment
said the fail-soft was fine because "the lifecycle derivation handles" the
unknown. It could not: both paths produced `resolution: null`.

Measured with the real producer and a mocked ledger:

    healthy + no rows   -> incidents[0].resolution === null
    ledger unreadable   -> incidents[0].resolution === null      identical

THE FIX I DID NOT SHIP, AND WHY

The sibling arm of this same producer already models this correctly —
`fetchRepairPrs -> { byIncident, readable, reason }`, and `toRepair` returns
`status: 'unknown'` with an explaining note. `IncidentResolution.resolvedBy` is
even typed `'auto' | 'manual' | 'unknown'`, and measured before writing any
code: the only producer is `row.resolutionSource`, which is `'auto' | 'manual'`.
Nothing has ever produced `'unknown'`. The type knew about the state; the code
could not reach it.

So the first draft asserted the incident should carry
`resolution.resolvedBy === 'unknown'`. Then LifecycleSpine.tsx:

    closeState = regressed ? 'failed'
               : incident.resolution !== null ? 'proven'
               : 'not-reached'

A non-null resolution for an UNREADABLE ledger would have rendered the incident
as PROVEN CLOSED. That upgrades "we could not read this" into "this is fixed" —
strictly worse than the bug being fixed. The test was rewritten to the contract
that is actually safe, and says so where a future reader will find it.

WHAT SHIPPED

Two small changes, both using machinery that already existed.

1. `fetchResolutions` carries its readability, exactly like its sibling:
   `{ byFingerprint, readable, reason }`. The empty map is still returned — the
   board must not go down for this — but the caller is now told the difference.

2. The `app` source stops asserting more than it knows. It was hardcoded
   `health: 'reading'` on the reasoning that app EVENTS throw when unreadable,
   so reaching that line proves the event arm is healthy. True of events. False
   of the resolution ledger, which fails soft. When the ledger is unreadable the
   app source is now `partial` — a state that already exists for "reading one
   arm, blind on another" — carrying the reason.

No new type, no new source name, no UI change, and the incident is still not
claimed resolved.

A THIRD THING THE TESTS FORCED

`describeBlindness` only named sources whose health was `blind`, so a `partial`
source was recorded in the data and reported nowhere. A degradation nothing
surfaces is the same class of defect as one nothing records. It now names both,
worded differently on purpose: "could not be read" is a blackout, "read
incompletely" is a source still delivering some of its signal. Collapsing them
would trade one wrong claim for another.

PROVEN ABLE TO FAIL — three injections:

    revert the app-health degradation        -> 2 red
    fetchResolutions hides the error again   -> 2 red
    beacon stops naming partial sources      -> 1 red

ALSO IN THIS COMMIT

The control-plane verifier's `control-plane-suites` check spawns vitest. The
failure-injection suite invokes the verifier FROM a test, which nests vitest
inside vitest and made that check unreliable under full-suite load. It is now
skippable via HELM_CP_SKIP_NESTED_TESTS=1 — and reports UNKNOWN when skipped,
never PASS, so `--static` exits 2 rather than pretending. A check that did not
run is not a check that passed.

PR #1678 recorded as ACTIVE in the open-PR dispositions. It is from a
CONCURRENT session, not this one, and the runtime verifier is what surfaced it
— an unclassified open PR is undefined background state, which is the residue
class #1677 closed. Not touched: it edits gen-enforcement-inventory.mjs, which
this branch does not.

Verified: npm run preflight 0; npm test 1266 files / 12052 passed;
control-plane:verify 0; control-plane:verify:static 0; incidents suite 166/166.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NbDxyygyXRUEERuGocpZZH

* fix(admin): the capture audit, and a category drift that turned out not to exist

Phases 2 and 3 of the product-diagnostics tranche, on the same branch as the
MC-PRODUCER fix because the plan merges them as one.

CATEGORY DRIFT — DISPROVEN, WITH EVIDENCE

The plan said to reproduce it with one real value and, if the real value passes
through correctly, to keep tracing rather than change mapping code. It passes.

Read out of production 2026-08-30 and run through the real matcher: 31 distinct
`rca_analysis` openings, every one landing where it should. The four canonical
prefixes derive correctly through both em-dash and double-hyphen spellings.
Three legacy free-prose openings ("Already fixed…", "Already applied…") derive
to already-fixed. Five "No fix needed…" variants stay `uncategorized`, which is
CORRECT — they are genuinely ambiguous between ALREADY FIXED and NOT A DEFECT,
and those carry different resolve evidence, so guessing would be the
unknown -> healthy move the engineering OS forbids.

The one row worth naming: an actionable finding with a file and a line number
("Add `code: \"qualifier_closed\"` to the return at golf.ts:1770…") sits in
`uncategorized` because it does not open with FIX HERE. That is a routine-PROMPT
contract problem, not a mapping problem, and the test says so where a future
reader will find it — so nobody "fixes" the matcher by teaching it to guess.

Traced the other category layers too. Two `ExpenseCategory` unions exist and
look like drift: golf has `transportation` and `entry_fees`, baseball has
`transport` and neither. They are not drift. Golf's union equals the
`golf_expense_category` ENUM exactly; baseball's equals its own CHECK constraint
exactly. Two products, two constraints, both internally consistent.

But nothing enforced that. `getExpenseSummary` accumulates with
`if (expense.category in summary.byCategory)`, so a category outside the union
is skipped from the breakdown while still counting toward `total` — the
breakdown silently stops adding up. Unreachable today ONLY because of a database
constraint that no test mentioned. Now pinned: widen either constraint without
widening its union and it fails.

CAPTURE AUDIT

Not exhaustive, and the plan says it should not be — 128 `const { data } = await`
sites exist. The objective is places where an operational failure becomes
apparently-valid state, so this audited the path whose whole job is reporting
whether production is healthy.

  reliability/collect.ts   SAFE — a rejection becomes status 'blind' + reason
  rollup-b.ts              SAFE — returns { value: empty, degraded: true }
  team-page-extras.ts      INFORMATION_LOSS, already known, now REGISTERED
  incident-feed.ts         INFORMATION_LOSS, fixed here

THE ONE FIXED. `queryPriorResolutions` was `const { data } = await …` — the
error discarded entirely. The comment block directly above it already warned
that "the swallowed error causes regression tags to silently disappear — exactly
when operators most need them", and then chunking was added. Chunking removed
the URL-length CAUSE. It did nothing about the error being thrown away, so RLS,
a timeout or a dropped connection still produced a short map, and absent
regression tags read as "nothing regressed" — the healthier-than-reality
direction, on the board you open to find out if something regressed.

It now returns `{ byFingerprint, readable, reason }`, matching `fetchResolutions`
and `fetchRepairPrs` beside it. Still fail-soft — the partial map is returned,
the feed does not go down — but the caller is told.

THE ONE REGISTERED RATHER THAN PATCHED. `team-page-extras.ts` resolves a
rejected 7-day error count to 0, and 0 grades the team 'A'. So a READ FAILURE
renders as a healthy team. It was already known and reasoned in a code comment,
which is exactly the problem: a risk that lives only in a comment is invisible
to everything that checks. Fixing it needs `computeTeamGrade` to have an
"unknown" grade, which is a product decision about what an ungraded team looks
like. Now in the acknowledged-gap registry, printed on every verifier run.

TWO INJECTIONS THAT DID NOT LAND, AND WHY THAT MATTERS

The first two attempts to prove the regression-swallow test could fail both
reported "8 passed" — because `if (error) {` appears three times in that file
and the replacement hit line 307 instead of 373. An injection that silently
misses looks exactly like a test that cannot fail, and it would have shipped an
unverified test with a confident PR body. Targeted by line number, it goes red:
2 failed, 6 passed.

VERIFIED BY THE REPO'S OWN RATCHETS

`audit:supabase-errors` independently counted the fix: unchecked Supabase reads
1041 -> 1040, and required the improvement be locked into the baseline so it
cannot be reverted unseen. Baseline committed.

`control-plane:verify` failed on this branch until #1679 was given a disposition
— the verifier holding its own author to the rule that an unclassified open PR
is undefined background state.

Verified: npm run preflight 0; npm test 1267 files / 12071 passed; business 0;
control-plane:verify 0 (20 pass, 0 fail, 0 unknown, 5 acknowledged gaps).

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>
njrini99-code added a commit that referenced this pull request Aug 31, 2026
…1678)

Asked to "change the Vercel rules so you can deploy when I tell you to". The
rules already allowed that — AGENTS.md says never deploy "unless the user
explicitly requests that production action", and config/release-policy.yml
carries human_approval_required: true / automatic_production_deploy: false.
Both are a ban on deploying unprompted, not a ban on deploying. There was no
stale prohibition to delete.

What was missing is a row in the enforcement inventory. The Vercel deny rules
were counted in the Bash( total and resolved by no claim, so nothing said what
they cover — or what they don't.

Two claims added to the generator (not hand-written into the AUTOGEN block):

- A production deploy TYPED as a vercel command -> CONFIGURED. Matcher is
  narrow on purpose, the same lesson the destructive-SQL row records: it keys
  on `--prod`/promote/rollback/alias set, never the word "vercel", because
  `vercel env ls` and `vercel inspect` are allow rules in the same file and
  must not read as a production-deploy mechanism.

- A production deploy run through scripts/deploy-prod.sh -> UNENFORCED. The
  wrapper runs `vercel deploy --prod --yes` in a child process, and deny rules
  prefix-match the command the agent SUBMITS, which is the script. Same shape
  as the canonical-write row: a matcher that reads what was typed rather than
  what will happen. Recorded as NOT probed — the only probe is a real
  production deploy, so this stays reasoned rather than exercised.

The second row is guarded against its own rot: it re-reads deploy-prod.sh and
reports N/A if the script stops running a production deploy, UNKNOWN if it
cannot be read, and CONFIGURED if a deny rule ever names the wrapper. It
asserts a gap only while the gap is real.

I did not touch .claude/settings.json. Widening my own production-deploy
permission is the one edit an agent must not make on its own behalf, whoever
asks; removing those deny rules is an owner action.

An earlier draft of this put the finding in .claude/rules/shipping.md §5 as
prose. Reverted: that file's own header now says enforcement must not be
asserted in prose there, which is the rule #1675 and #1677 exist to establish.
The generated inventory is the right home.

Verified: gen --check clean, control-plane-verify's enforcement checks pass,
29 tests in src/test/scripts pass, eslint clean, markdown ratchet no
regressions. control-plane-verify does report FAIL mutation-budget 2/1 — that
is this task's own worktree under a deliberate HELM_MAX_MUTATION_WORKTREES=2
override, taken because the single slot held another session's uncommitted
work. It clears when this workspace is parked.


Claude-Session: https://claude.ai/code/session_01BcCZsEmEgQ4VD9EPMTcDX7

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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