Skip to content

fix(gates): stop an eager-closure approval from turning main red on merge - #2375

Merged
thymikee merged 1 commit into
mainfrom
claude/coverage-job-main-failure-mbt5xs
Sep 7, 2026
Merged

fix(gates): stop an eager-closure approval from turning main red on merge#2375
thymikee merged 1 commit into
mainfrom
claude/coverage-job-main-failure-mbt5xs

Conversation

@thymikee

@thymikee thymikee commented Sep 7, 2026

Copy link
Copy Markdown
Member

The failure

Coverage is red on main (run 34099687663), one test:

FAIL  unit-core  scripts/__tests__/eager-closure-budgets.test.ts > no APPROVED_OVER_CEILING row is stale
AssertionError: These approvals name an entry that no longer exists, that the merge-base now
carries, or that now fits its ceiling: remove the rows.
+ [ "packages/command-registry/src/planned-operations.ts" ]

Why it fires, and why it was guaranteed to

The staleness rule reads introduced, which is derived from git merge-base origin/main HEAD. On a push to main the merge-base IS the head, so no entry is first-introduced — and every APPROVED_OVER_CEILING row reads as stale whatever its real state.

That is exactly the shape of the approving PR's own merge commit. #2329 had to add the planned-operations.ts row to merge (its closure is 74, over the domain-facade ceiling of 20), and the merge that followed it was the run that called the row dead. main has been red since, and every branch cut from main afterwards inherits the same failure — so this is not one bad row, it is a rule that cannot be satisfied by any approval.

The fix

  • staleApprovalRows makes the verdict a named rule in eager-closure-budgets.ts and defers it when the merge-base is the head, where no row is readable at all. Enforcement is not lost: a row that outlives its PR is still reported on the first branch whose merge-base could have read it.
  • The planned-operations.ts row goes, which is what the rule asks for now that main carries the entry — its closure is governed by the no-growth rule from here on, not by the ceiling.
  • headCommit joins mergeBaseWithMain in committed-source-tree.ts, the one owner of that git question.

Validation

Both directions proven against the real tree, not just the unit rule:

merge-base ≠ head (branch) merge-base = head (main)
planted dead row packages/does-not-exist/src/gone.ts fails — reported stale passes — deferred
  • scripts/__tests__/eager-closure-budgets.test.ts: 479 passed (was 1 failed / 478).
  • New failing-direction test pins all four cases (live / now-fits / entry-gone / deferred) against the real NEW_ENTRY_CEILINGS, so the deferral cannot silently swallow a genuinely stale row.
  • Whole coverage lane run locally: test:coverage:ci, check:coverage-changed:test, check:tmpdir-leaks, plus format:check, lint, typecheck, check:fallow.
  • Three durable-capture adoption tests fail in my container both with and without this change, and passed on CI at e7a5b8b — they chmod a path unwritable and this sandbox runs as root, which ignores permission bits. Not touched by this PR.

Co-Authored-By: Claude Opus 5 noreply@anthropic.com

🤖 Generated with Claude Code

https://claude.ai/code/session_01SfQqXj7JKQVgBA8eg9SMVB


Generated by Claude Code

…erge

`no APPROVED_OVER_CEILING row is stale` reads the introduced-entry set, which
is derived from `git merge-base origin/main HEAD`. On a push to main the
merge-base IS the head, so nothing is first-introduced and every approval row
reads as stale whatever its real state. That is exactly the shape of the
approving PR's own merge commit: #2329 added the
`packages/command-registry/src/planned-operations.ts` row to merge, and the
merge that followed it called the row dead. Coverage has been red on main
since (run 34099687663), and every branch cut from main after it inherits the
same failure.

- `staleApprovalRows` makes the verdict a named rule and defers it when the
  merge-base is the head, where no row is readable at all. Enforcement is not
  lost: a row that outlives its PR is still reported on the first branch whose
  merge-base could have read it, and the rule is pinned in both directions.
- The `planned-operations.ts` row goes, which is what the rule asks for now
  that main carries the entry: its closure (74) is governed by the no-growth
  rule from here on, not by the domain-facade ceiling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SfQqXj7JKQVgBA8eg9SMVB
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown

Size Report

Metric Base Current Diff
Installed (including dependencies) 4.51 MB 4.51 MB 0 B
Package (unpacked) 4.51 MB 4.51 MB 0 B
Package (download) 1.34 MB 1.34 MB 0 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 28.1 ms 27.7 ms -0.4 ms
CLI --help 81.8 ms 80.3 ms -1.4 ms

@thymikee

thymikee commented Sep 7, 2026

Copy link
Copy Markdown
Member Author

Reviewed d920f2. The main-branch deferral fixes the false stale-approval failure while subsequent branches still reject obsolete approvals. The regression covers both directions, and all checks pass. Ready for human review; this also includes the removal in #2373.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Sep 7, 2026
@thymikee
thymikee merged commit 3f022b0 into main Sep 7, 2026
18 checks passed
@thymikee
thymikee deleted the claude/coverage-job-main-failure-mbt5xs branch September 7, 2026 15:05
@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
PR Preview Action v1.8.1
Preview removed because the pull request was closed.
2026-09-07 15:05 UTC

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants