fix(claude-lane-incident): state the real coverage condition and re-pin the stale label comment - #350
Conversation
…abel now exists Both halves of the write job's `labels` comment were stale. `claude-lane-incident` is declared in github-iac (`GovernedRepositories.cs`, this repository's `ExtraLabels`) and exists live on this repository with that description, so the next taxonomy apply keeps it rather than pruning it. The comment sits inside the byte-pinned write job, so the workflow, its pin, and every fixture carrying the block are re-pinned in this one commit: 49 files, one identical five-line substitution each, applied by script so the pin stays the workflow's byte-exact tail. Each fixture's deliberate single-property deviation is untouched — the block is substituted in place rather than the pinned tail being re-synced over it. Closes #348 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…y, and test it Both coverage sentences pointed the operator at the rendered table. The gate is `coverageGap`, which reads the TRACKED index (`MAX_TRACKED_REPOSITORIES` = 60) plus `repositoriesSeen`; the table is capped separately at `MAX_RENDERED_REPOSITORIES` = 40 and a character budget. The copy was therefore correct only for small incidents and wrong in the fleet-wide case it was written for — a 120-repository incident tracks 60 and renders 40 rows at short names, 24 at the longest name that can exist. Step 4 also attributed a permanent hold to a gone repository alone. `coverageGap` documents three standing causes; the other two — an incident wider than the tracked cap, and a state-schema bump — are now in the durable artifact rather than only in the run warning. Adds a rendered-body substring assertion over the fleet-wide state, following the suite's existing convention. Reverting the copy alone turns that test red and leaves the other 43 green, which is the regression the issue asked for. Closes #344 Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…st the tracked index Naming the tracked index still overpromised. `coverageGap` holds on `unlisted > 0` as well — `repositoriesSeen` above what the index names — so an incident wider than `MAX_TRACKED_REPOSITORIES` never gets a counting clean cycle however much was polled. Both sentences now carry the whole condition: every tracked repository polled, AND the index accounting for everything seen. The header bullet defers to step 4 rather than restating a partial rule, since one parenthetical cannot hold the condition without misstating it. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Bugbot is not enabled for your account, so this pull request was not reviewed. Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs. |
|
Claude finished @kyle-sexton's task in 1m 13s —— View job Security reviewScope: all 51 files changed in this PR (diffed against Findings: none. This PR is a pure documentation/copy change with one accompanying test — there is no security-relevant surface here:
No |
|
Claude finished @kyle-sexton's task in 3m 46s —— View job Code review
Findings: none. This PR is copy-accuracy work plus one regression test, and I traced every claim it makes back to the code rather than trusting the description.
Third standing-hold cause checked: New test ( Label-comment re-pin: diffed Not independently verified (author-claimed only): the No architecture, error-handling, or maintainability concerns. Security scope for this PR was already covered by the security lane above (no security-relevant surface — pure comment/copy changes). |
|
Claude has reviewed this PR 1 time. The lane skips further automatic reviews after 5; deleting this comment resets the count. |
Independent review: outstanding items before mergeA fresh-context reviewer cold-read this branch at Still outstanding (a cold agent can pick these up):
Cross-repo note: the contradiction between this repo's "a pruned label degrades a sanity query and nothing else" and github-iac |
Addendum from a second independent reviewer (narrow copy-focused pass at HEAD
|
…not just a schema bump `namesNothing` is the gate condition, and `coverageGap` reaches it whenever the index names nothing this watchdog can read — a hand-edited state block and one written by an older schema degrade identically. A `STATE_SCHEMA_VERSION` bump is how that happens to every open incident at once, not the only way it happens, so the copy named the cause by one of its triggers and left the operator of a corrupted block with no matching entry. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Claude finished @kyle-sexton's task in 58s —— View job Security reviewScope: all 51 files changed in this PR, diffed against
Findings: none. This PR is a pure documentation/copy change plus one additive regression test — there is no security-relevant surface here.
No |
… its own wording (#358) ## Summary #350 closed #344 by fixing the copy and adding a test. The test greps the rendered body, so it pins the copy against its own wording — which is the #344 defect one level up. This makes the assertion check the copy against the **gate** it describes. Two failure modes survived the merge, both found by the pre-merge reviewers and confirmed here at #350's merged head `9681fee`: - **The fleet-wide fixture was inert.** All five assertions passed unchanged against a one-repository state, so `fleetWideTally(120, 40)` exercised nothing. The asserted strings were static literals, insensitive to all three of the numbers the fixture exists to make disagree. - **The negative guard was pinned to two literal sentences.** `/every repository (?:listed above|below)/u` caught only the phrasings #331 happened to ship. An equivalent rewording would have reintroduced #344 with a green suite. ## What changed Only `.github/scripts/claude-lane-incident.test.cjs`. No production copy or logic is touched. **The gate is now the assertion.** From the same fleet-wide state the test renders, it derives the tracked index and calls `coverageGap` over every tracked repository — which is still non-null, with `unobserved: []` and `unlisted === 60`. That is the condition the copy claims: complete coverage needs the polled scope **and** the index's own accounting, so an incident wider than the tracked cap never gets a counting clean cycle however much was polled. Copy and gate are held to one predicate instead of two independent restatements of it. **The fixture is no longer inert.** `repositoriesSeen === 120`, `tracked.length === 60`, and `tracked.length > 40` are asserted against the state rather than assumed, and `unlisted` is derived (`repositoriesSeen - tracked.length`) rather than hardcoded. **The guard is widened to the defect's shape** — a counting rule tied to a position in the document rather than to the tracked index — and a second test holds it to the paraphrases a future editor would plausibly reach for. It is bounded to a single sentence so the copy's own contrastive "not the table above", a separate sentence, stays legal. **The false comment is corrected.** The old annotation claimed "The three sets differ exactly when the copy matters", which was true of the fixture and false of the assertions it annotated. ## Verification - `node --test .github/scripts/*.test.cjs` — 513 pass, 0 fail on the branch; 512 pass, 0 fail on `origin/main`, both measured directly rather than carried over. - `npx @biomejs/biome@2.5.4 ci --config-path=fixtures/typescript/good/biome.json --error-on-warnings .github/scripts` — clean, matching CI's biome job at the version its action pins. - `comment-hygiene` scan — 12 violations with and without this change: an unchanged pre-existing baseline, zero delta from this PR. **Mutation-tested, because a green suite is exactly what the old test proved and it was not evidence:** - Collapsing the fixture to `fleetWideTally(1, 1)` now **fails** (`1 !== 120`). Against the merged head's test, the identical collapse passed all five assertions. - Rewording the copy to "it polled every repository in the table above" now **fails**. Checked directly against that mutated body, the old guard returns `false` and the widened guard returns `true` — the exact phrasing the reviewer named as the hole. ## Body budget No copy changed, so the 65536 budget is untouched. Recording the re-measure #350 owed but never wrote down, since the question will come up again: `fixedLength` (`claude-lane-incident.cjs:737-742`) deducts the actual prologue and epilogue length from the table allowance, so copy growth costs rendered rows rather than headroom — the bound is structural, not a margin to be spent. Re-measured across 8,568 incident shapes at #350's two heads: zero over-limit bodies, and the worst case moved 65486 → 65487 of 65536 across the step-4 copy growth that prompted the concern. Two notes for whoever edits this copy next. The reviewer's "65433 at 120×10, 103 characters of headroom" did not reproduce in the shapes swept here (120×10 measures 64364, or 64786 at nine-digit pull numbers); hostile `statusCounts` crossed with that shape was not swept, so the figure is not contradicted, just unconfirmed. Separately, the body-budget test drives three shapes — 40×10, 120×40, 200×300 — and none is near the true worst case, which sits at 65487 of 65536 (49 characters of headroom) at 54×14 with nine-digit pull numbers. Tightening that test is out of scope here and is tracked in #360, together with the two copy gaps whose fixes would grow this region. Closes #357 ## Related - #350 — merged the copy fix and the assertion this PR replaces. - [Independent review: outstanding items before merge](#350 (comment)), item 1. - [Addendum from a second independent reviewer](#350 (comment)), item 2. - #344 — the original defect, whose class this test now actually detects. --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ope instead of widening its pattern (#368) ## Summary A post-merge review of #358 found its prose guard defective in both directions (#366). The `coverageGap` correspondence assertion #358 added is sound and untouched — it remains the pin. This replaces the broken backstop beside it. **Decision: the vocabulary-membership regex backstop is removed, not repaired.** Two rounds of independent verification demonstrated that its enumeration cannot be closed — every synonym for the rendered report is a fresh escape, and widening far enough to close them fires on copy that correctly names the durable index. Patching the blacklist went 0 for 3. What remains is what is load-bearing and proven: the `coverageGap` gate-correspondence assertion, and an **exact-string pin** on the step-4 counting-rule copy, whose forced test edit is the human review seam. No completeness is claimed anywhere. Getting there took three refuted attempts, and those refutations are the argument for the final shape. ## What was wrong at `194c61a` **False positive.** The assertion ran against the whole flattened body while the claim it pinned belongs to one sentence of step 4. Editing the prologue's "PRs in the repositories below" to "all repositories below" — unrelated to the counting rule — turned the suite red. **False negatives.** Keyed on a quantifier immediately followed by the singular-or-plural noun, then `above|below`, with no `i` flag. Deictic-first order, `repo` shorthand, capitals, loose adjacency, and positional words outside that pair all escaped. **Inert fixtures.** All eleven breadth fixtures were written to the regex's own model, so they could confirm the pattern was not narrower than itself but never that the model was too narrow. **Two false comments**, including one claiming `[^.]` bounded a sentence when it bounds a period-free run. ## Why the fix is a pin and not a better pattern Narrowing the scope to step 4's first sentence and broadening the vocabulary was the first attempt. Review refuted it three times: 1. A dotted abbreviation truncated the scope, so `..., i.e. every row above.` cut off at `i.` and left the assertion inspecting a string the defect was no longer in. 2. The broadened vocabulary fired on correct copy — "every repository listed in the tracked index" is not a defect, and `following`/`earlier`/`later` read temporally. 3. Narrowing the vocabulary to fix that reopened the escapes: six defective clarifications shipped green ("shown in the report", "named in the body", "each visible repository", "you can see", …), and the `list` added along the way false-fired on "every repository the tracked index lists". The comment asserting the trade was lossless was false — the third false comment in this PR. The pattern is the wrong instrument. A blacklist here enumerates an **open set**: every synonym for the rendered report is a fresh escape, and widening far enough to close them starts firing on copy that correctly names the durable index. Vocabulary cannot satisfy both directions. Exact equality has neither failure mode. No synonym to chase, no completeness to overclaim, and no way to be vacuous — a clarification appended to the counting rule changes the string and fails, and an extraction that runs long or stops short fails too rather than silently checking the wrong span. Byte-exact comparison is already this repo's discipline for text that cannot afford to drift. ## What changed Only `.github/scripts/claude-lane-incident.test.cjs`. No production copy or logic, so the body budget is untouched. The pinned sentence is a constant; `countingRuleOf` extracts step 4's first sentence and the test asserts equality. The replacement test drives the extractor rather than trusting it: exact match against the real body, all six verified escapes rejected, the `i.e.` case kept inside the fence, step 4 asserted to continue past the pin so the disclaimer prose is demonstrably *not* frozen, and a renumbered step failing as a loud null. **The cost is deliberate and documented in the code.** Any edit to that sentence fails here, including a good one — which leaves the editor standing beside the `coverageGap` assertions, having to confirm the new wording still states what the gate requires. That review is what this copy never got. Only the one sentence carrying the gate condition is pinned; the disclaimer sentences after it stay free. **Residual, stated rather than papered over:** a contradiction planted in a *later* sentence of step 4 is out of reach of text comparison, because that is where naming the rendered table is correct. Catching it needs meaning. `coverageGap` and the gate assertions are what hold the copy to the gate; this fences the sentence that states the rule. ## Verification - `node --test .github/scripts/*.test.cjs` — 514 pass, 0 fail on the branch; 514 on `origin/main` (this replaces assertions rather than adding tests). - `npx @biomejs/biome@2.5.4 ci --config-path=fixtures/typescript/good/biome.json --error-on-warnings .github/scripts` — clean, at the version the action pins. - `claude-lane-incident.cjs` byte-identical to `origin/main`. **Mutation battery** — each defect applied to the real production copy, then the suite run against both this branch's test file and `origin/main`'s: | mutation to the counting rule | `origin/main` | this PR | |---|---|---| | deictic-first: "the table above lists every repository a cycle polls" | red | **red** | | `repo` shorthand: "every repo listed above" | red | **red** | | "every repository listed here — that is, …" | **green (escaped)** | **red** | | "every repository shown in the report — that is, …" | **green (escaped)** | **red** | | "every repository named in the body — that is, …" | **green (escaped)** | **red** | | "each visible repository — that is, …" | **green (escaped)** | **red** | | "every repository you can see — that is, …" | **green (escaped)** | **red** | | "the output shows every repository polled" | red | **red** | | CONTROL — unrelated prologue edit | **red (false positive)** | green (inert) | Five defective clarifications that ship green on `main` today are caught here, and the false positive is gone. Closes #366 ## Related - #358 — introduced the guard this replaces; its `coverageGap` assertion is retained unchanged. - #357 — the issue #358 closed. - #360 — the remaining #350 rework items (counting-rule vacuity, recovery-instruction copy, untested body-budget worst case). No overlap: those are product copy, this is the test.
…e false recovery promise, and gate the body budget at the shape that binds (#369) ## Summary Drains all three residuals from #360 — the last of the #350 rework list. Two are production copy in `renderIssueBody`; one is the body-budget test that never drove the shape that binds. ## 1. The counting rule was vacuously satisfiable `coverageGap` gates on three things. The copy named two: every tracked repository polled, and the index accounting for everything seen. When the tracked index names nothing, both read as satisfied — polling the empty set, an empty index accounting for zero seen — so the copy told the operator cycles were counting exactly while the gate withheld every one. Reachable, not theoretical. A hand-edited `"repositories":{}` block parses, and the gate returns `namesNothing: true`: ``` gate holds (coverageGap non-null): true | namesNothing: true ``` The rule now leads with the condition that was missing, and the sentence after it says why that clause exists rather than leaving it looking redundant beside the other two. ## 2. "once you have confirmed recovery" promised recovery that does not exist None of the three permanent-hold causes has anything to recover. A repository that is gone (archived, or removed from the installation) is not coming back; an index this watchdog cannot read is a corrupted record rather than an outage; and this file's own `coverageGap` docstring describes the third as an incident "wider than `MAX_TRACKED_REPOSITORIES`, whose `unlisted` remainder never resolves". #350's own rework widened the unreadable-index cause, so the promise covered strictly more causes it could not keep. It now says none of the three recovers on its own, and closes on the operator having addressed the lane failures behind the incident — true of all three, and consistent with the docstring. **My first attempt at this got the count wrong**, claiming "two of them leave nothing to recover" without saying which two. Review flagged the ambiguity; checking it against the docstring showed there was no exception to name. `f0fbead` drops the count instead of spelling out a subset that does not exist. #360's body carries the same wrong count and is corrected in a comment there rather than quietly edited. ## 3. The body-budget test never drove the shape that binds The test drove 40×10, 120×40, and 200×300 at the longest legal name — all roughly 700–1400 characters clear of the limit. A sweep finds the real bound at ~49 characters of headroom. **A fixed tight shape would not have fixed this**, and this PR is the proof. The two shapes measured as tightest on `origin/main` — 40×20 at 65418 (118 spare) and 54×14 at 65487 (49 spare) — now sit at 63760 and 63672, or **1776 and 1864 characters of headroom**, because the budget converts epilogue growth into dropped rows and the binding shape moves. Hardcoding them would have looked like a budget gate while measuring slack — the same inert-fixture failure this lane has been unwinding since #357. So the new test **sweeps** a 144-shape grid bracketing the tight region (146 ms) and asserts the maximum fits. It also asserts at least one shape lands in the row-dropping regime, because a grid where everything sat comfortable would be proving nothing about the bound. The existing three-shape test keeps its remainder-semantics role and gains two assertions: that the body fits by **dropping rows** rather than by happening to be short (fewer rows render than the 40-row cap allows, so the character budget bit), and that rows plus remainder account for every repository the incident holds. ### What the budget gate does and does not catch — measured, not assumed | mutation | result | |---|---| | drop the `fixedLength` deduction | **RED** | | budget by rows instead of characters | **RED** | | drop `REMAINDER_LINE_RESERVE` | green (80 is slack; the remainder line is ~35 chars) | | add 12 lines of epilogue copy | green | The last row is the important one: **copy growth alone cannot breach this bound**, because rows drop to pay for it. That is the bound being structural, not the test being weak, and the comments now say so instead of crediting the test with protection it does not provide. ## The pin seam worked as designed The pinned counting-rule string moves with the copy in the same commit. That is what the pin is for — copy cannot change without someone re-reading it against the `coverageGap` assertions beside it. Updated deliberately, both sides together. ## Verification - CI is the authority for the full suite and is green on this head. - `node --test .github/scripts/claude-lane-incident.test.cjs` — **46 pass, 0 fail**, the file this PR changes. - The full local suite measured 515 pass / 0 fail earlier in this branch's life. It cannot be reproduced on this workstation right now: 8 tests in `claude-security-review-fail-closed.test.cjs` and 2 in the retry-resolution suite fail locally, and they fail **identically at `origin/main` content**, so the cause is this machine (subprocess spawning degraded partway through the session), not this change. Reported rather than papered over; CI on GitHub runners is unaffected and green. - Worst-case rendered body, measured on both sides rather than carried over. `origin/main`: 65485 of 65536 at 54×9, 51 spare. This branch: **65487 of 65536 at 48×17, 49 spare.** Zero over-limit across the swept space on either side. - The binding **shape** moved (54×9 → 48×17) while the binding **value** did not (65485 → 65487). That is the row-drop mechanism absorbing ~260 characters of copy growth: the loose shapes each lost roughly that much headroom — 120×40 went 1010 → 748 spare — while the tight bound stayed pinned against the ceiling because rows drop to pay for the copy. - Both copy fixes asserted against the rendered body at the reachable empty-index state. Closes #360 ## Related - #350 — the PR whose rework list these three items are the remainder of. - #357 / #358, #366 / #368 — the earlier items from the same list. - [Outstanding-items comment](#350 (comment)) and [addendum](#350 (comment)), where all three originate.
Summary
Two findings against the claude-lane incident watchdog, both left over from #331,
fixed in one PR because neither is worth a branch of its own.
#348 — the write job's label comment was stale in both halves
The pinned comment claimed
claude-lane-incident"does not exist in thisrepository's label taxonomy yet, and that taxonomy is managed by github-iac
(Labels.cs)". It exists: github-iac declares it in
GovernedRepositories.csunder this repository's
ExtraLabels, and it is live on this repository withthat description.
Labels.csowns the shared core taxonomy and is not where aper-repository extra label is declared, so the new comment cites
GovernedRepositories.csinstead. The consequence half is rewritten too: thenext apply keeps the label rather than pruning it.
#344 — the coverage copy named the rendered table, and was untested
renderIssueBodytold the operator that a clean cycle counts only if it polled"every repository listed above" (and "below" in the header bullet). The gate is
coverageGap, which reads the TRACKED index —MAX_TRACKED_REPOSITORIES= 60 —and
repositoriesSeen, while the table is capped separately atMAX_RENDERED_REPOSITORIES= 40 and a character budget. So the copy was rightfor a small incident and wrong in exactly the fleet-wide case it was written for.
Measured on this branch: a 120-repository incident tracks 60 and renders 40 rows
at short names, 23 at the longest repository name that can exist.
Naming the tracked index alone would have replaced one overpromise with another:
coverageGapalso holds onunlisted > 0, so an incident wider than the trackedcap never gets a counting clean cycle however much was polled. Both sentences now
state the whole condition — every tracked repository polled, AND the index
accounting for everything seen — and the header bullet defers to step 4 rather
than compressing the rule into a parenthetical that would misstate it.
Step 4 also attributed a permanent hold to a gone repository alone.
coverageGapgates on three, so the other two now appear in the durable artifact rather than
only in the run warning: an incident wider than the tracked cap, and an index
this watchdog can no longer read. The second is stated as the gate condition
(
namesNothing) rather than as one of its triggers — a hand-edited state blockand one written by an older schema degrade identically, and a
STATE_SCHEMA_VERSIONbump is how that reaches every open incident at once, notthe only way an operator meets it.
The copy was also untested: the issue's second finding is that reverting it left
the suite green. A rendered-body substring assertion over the fleet-wide state now
covers it, following the convention the suite already uses.
How the re-pin was done
The repo's pin discipline is byte-exact text comparison, not a digest.
claude-lane-incident-write-gate.cjscompares the workflow from the marker# THE ONLY WRITE-SCOPED JOB.to end of file againstclaude-lane-incident-write-job.pinned.yml, and the aggregator test additionallyasserts
workflow.endsWith(pinned). Every fixture that carries the write jobcarries the same bytes, so the comment could not be fixed in one file.
Rather than re-syncing the pinned tail over each fixture — which would have made
the deliberately-broken write-job fixtures conformant and turned their CORPUS
assertions green-on-nothing — a script substituted the same five comment lines in
place, once per file, failing loudly on any file where the block did not appear
exactly once. 49 files changed in one commit;
workflow-not-a-mapping.ymlis theone fixture carrying no write job and was correctly skipped.
claude-lane-incident-mint-step.pinned.ymlis a separate pinned region and isuntouched.
Verification
node --test .github/scripts/*.test.cjs— 505 pass, 0 fail (504 on origin/mainplus the one assertion this PR adds).
claude-lane-incident.cjsalone, with thenew test retained, turns exactly that test red (43 pass, 1 fail). A green suite
would not have been evidence — that is the finding.
npx @biomejs/biome@2.5.4 ci --config-path=fixtures/typescript/good/biome.json --error-on-warnings .github/scripts— clean, matching what CI's biome job runs.(
workflow.slice(marker) === pinned) as well as by the test.rather than taken from the issue text, and the "keeps rather than prunes" claim
was traced through
Labels.Apply, which unions_corewith the repository'sExtraLabelsfor every spec withManagedLabels(defaulttrue, whichci-workflowstakes).All 38 CI checks on the head commit are green.
Closes #344
Closes #348
Related
verifier as non-blocking (verdict PASS-WITH-CONCERNS).
claude-lane-incidentin thetaxonomy, which is what made the pinned comment stale.
claude-lane-incident-aggregator.yml, but only in theworkflow's header comment block and the aggregator test's poll assertions. No
overlap with the write-job region or the fixtures this PR re-pins; the two
merge in either order.