Skip to content

ci(safe-paths): honor risk-tier paths instead of merging past the decline - #150

Merged
topcoder1 merged 1 commit into
mainfrom
claude/safe-paths-honors-risk-tier
Aug 10, 2026
Merged

ci(safe-paths): honor risk-tier paths instead of merging past the decline#150
topcoder1 merged 1 commit into
mainfrom
claude/safe-paths-honors-risk-tier

Conversation

@topcoder1

Copy link
Copy Markdown
Owner

What happened

topcoder1/inbox_superpilot#215 merged a tests-only PR touching web/tests/e2e/auth/signup.spec.ts 12 minutes after claude-author-automerge posted "Auto-merge blocked — risk-tier paths touched. Manual click-merge required." That comment is still on the merged PR.

The two gates never disagreed in any resolvable sense. claude-author-automerge cannot block a merge — it can only decline to arm one. safe-paths-automerge is the only workflow that arms a docs/tests diff, and the only one that can revoke a standing arm. The decline was an abstention; the permissive gate won by default.

The defect is not that the wrong gate won. It is that a gate announced an enforcement it never had, leaving a merged PR whose audit trail asserts a human approval that never happened.

The fix

A tier-2 risk-tier hold in safe-paths-automerge.yml, generalizing the docs/legal override already there (wxa_vpn#1268): safe-by-glob is not safe-by-content. The *.spec.ts premise "passing tests can't break runtime" is true about runtime and false about detection — deleting the assertion that catches a lockout is how the lockout ships in a later PR, laundered through a green suite.

Scoped in both directions:

  • Only where this workflow would arm. The hold runs in the branch where every changed file is safe-by-glob. Hoisting it beside the tier-1 override looks equivalent and is not: it would emit a revoke-triggering reason on PRs safe-paths never arms — a dependabot bump of .github/workflows/** matches the risk patterns — and the revoke step would disarm dependabot-auto-merge's legitimate arm. Pinned structurally in test_workflow_guards.py.
  • Released by risk_bypass_label, the same one-click label the sibling's blocked-PR comment advertises. Ignoring it would kill the advertised escape hatch. docs/legal stays absolute and is not releasable by the label — a label click is not evidence anyone read the clause.

The pattern list is copied verbatim from claude-author-automerge.yml, with a drift guard that re-derives both and fails if they diverge.

What this deliberately does NOT do

It does not narrow the auth pattern away from test roots. That looked like the fix — but the coverage it would remove is arbitrary. Matching is anchored on directory segments:

path verdict
web/tests/e2e/auth/signup.spec.ts BLOCKED
web/tests/e2e/auth.spec.ts escapes
web/tests/e2e/auth-flows.spec.ts escapes
web/tests/e2e/login-flow.spec.ts escapes
web/tests/e2e/session/expiry.spec.ts BLOCKED
web/tests/e2e/stripe/stripe-integration.spec.ts escapes

On #215 itself the Stripe payment spec sailed through while the auth spec tripped. Narrowing would trade a real hold for a gap that is already the majority case. The gap is real, but closing it is a separate decision about who reviews auth-test edits; a corpus entry is added so a future "narrow the false positive" change has to confront it.

Evidence

  • #215's exact four files against origin/main's classify block → all_safe=1 (it auto-merged). Against this branch → all_safe=0, reason=risk-tier-hold.
  • Drift guard verified to fail on an injected pattern change (not a no-op test).
  • 17 new behavioral cases + drift guard; existing 17 override cases unchanged; 66 pytest selftests pass; BB corpus selftest 179 cases pass; shellcheck clean; both selftests pass under macOS bash 3.2.57.

Notes for the reviewer

  • Auto-merge rationale: none — manual merge required. PRs to ci-workflows are always manual per policy, and this touches .github/workflows/** (high-risk tier). Both gates correctly decline this PR.
  • Codex rounds: 0 (local). Not run locally; this repo's own Codex Review + Claude Review lanes run on the PR. Flagging since .github/workflows/** is on the pre-review list.
  • Behavior change for consumers: a diff that is 100% docs/tests and touches a risk-tier path now holds for a human instead of auto-merging. Bypass is one auto-merge-approved click. All authors, matching the existing docs/legal override's scope.

🤖 Generated with Claude Code

…line

topcoder1/inbox_superpilot#215 merged a tests-only PR touching
web/tests/e2e/auth/signup.spec.ts twelve minutes after
claude-author-automerge posted "Auto-merge blocked — risk-tier paths
touched. Manual click-merge required." That comment is still on the
merged PR.

The two gates never disagreed in any resolvable sense.
claude-author-automerge cannot block a merge — it can only decline to
ARM one — and safe-paths-automerge is the only workflow that arms a
docs/tests diff, and the only one that can revoke a standing arm. So the
decline was an abstention, and the permissive gate won by default. The
failure is not that the wrong gate won; it is that a gate announced an
enforcement it never had, leaving a merged PR carrying an audit trail
that asserts a human approval that never happened.

Adds a TIER 2 risk-tier hold to safe-paths-automerge.yml, generalizing
the docs/legal override already there (wxa_vpn#1268): safe-by-glob is not
safe-by-content. The `*.spec.ts` premise "passing tests can't break
runtime" is true about RUNTIME and false about DETECTION — deleting the
assertion that catches a lockout is how the lockout ships in a LATER PR,
laundered through a green suite.

Scoping, both directions:

- The hold runs ONLY in the branch where every changed file is
  safe-by-glob, i.e. where this workflow would otherwise arm. Hoisting it
  beside the tier-1 override looks equivalent and is not: it would emit a
  revoke-triggering reason on PRs this workflow never arms — a dependabot
  bump of .github/workflows/** matches the risk patterns — and the revoke
  step would then disarm dependabot-auto-merge's legitimate arm. Pinned
  structurally in test_workflow_guards.py.
- The hold is released by the caller's risk_bypass_label, the same
  one-click label claude-author-automerge's blocked-PR comment
  advertises. Ignoring it would kill the advertised escape hatch.
  docs/legal stays absolute and is NOT releasable by the label: a label
  click is not evidence anyone read the clause.

The pattern list is copied VERBATIM from claude-author-automerge.yml and
a drift guard re-derives both and fails if they diverge — two gates that
disagree about what is risky is how this reopens.

Deliberately NOT narrowing the auth pattern away from test roots. That
looked like the fix, but the coverage it would remove is arbitrary:
matching is anchored on directory SEGMENTS, so auth/signup.spec.ts trips
while auth.spec.ts, auth-flows.spec.ts and login-flow.spec.ts do not, and
on #215 itself the Stripe payment spec sailed through while the auth spec
tripped. Narrowing would trade a real hold for a coverage gap that is
already the majority case. The gap is real but is a separate decision
about who reviews auth-test edits; corpus entry added so a future
"narrow the false positive" change has to confront it.

Evidence:
- #215's exact four files against origin/main's classify block => all_safe=1
  (it auto-merged); against this branch => all_safe=0, reason=risk-tier-hold.
- 17 new behavioral cases + drift guard; existing 17 override cases
  unchanged; 66 pytest selftests pass; BB corpus selftest 179 cases pass;
  shellcheck clean; both selftests pass under macOS bash 3.2.57.

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

cursor Bot commented Aug 10, 2026

Copy link
Copy Markdown

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.

@github-actions github-actions Bot added the risk:blocked Risk class: blocked label Aug 10, 2026
@github-actions

Copy link
Copy Markdown

Risk class: blocked — manual merge required.

This PR touches one of the blocked path categories from .github/risk-paths.yml (Dockerfiles, docker-compose, .github/workflows/**, **/.env*, **/secrets*, infra/, terraform/, k8s/, or the classifier config itself).

Auto-merge is refused by claude-author-automerge.yml. A maintainer should review the diff and click "Squash and merge" themselves.

(This is a policy notice, not a code-quality failure. The classify job itself does not fail — required CI checks remain authoritative for "is the code green.")

@github-actions

Copy link
Copy Markdown

Coverage Floor — mode: enforce

metric value
measured 100.0%
floor (current) 99.0%
target 100.0%
last bumped 2026-05-12

@claude

claude Bot commented Aug 10, 2026

Copy link
Copy Markdown

No issues found. Tier-2 hold logic is correctly scoped to the would-arm branch, bypass-label path is wired through end-to-end, rename coverage and drift guard both check out, and the new test cases cover the key behavioral properties.

@topcoder1
topcoder1 merged commit 861fca6 into main Aug 10, 2026
16 checks passed
@topcoder1
topcoder1 deleted the claude/safe-paths-honors-risk-tier branch August 10, 2026 08:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk:blocked Risk class: blocked

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant