Uh oh!
There was an error while loading. Please reload this page.
fix(standards-sync): a create failure disarms the writes, it does not truncate the audit (backend#2735) - #366
fix(standards-sync): a create failure disarms the writes, it does not truncate the audit (backend#2735)#366LukasWodka wants to merge 2 commits into
Conversation
… truncate the audit (backend#2735) Bugbot (High) on the staging->main promotion, .github#363. Two paths reach one condition -- "this credential cannot open PRs". The pre-flight identity refusal disarms remediation and lets the read-only audit finish (#348). The mid-loop `pr create` failure used to `break` the fleet loop, so the table covered only the repos before the failure. Which path fires depends only on WHEN the fact becomes knowable, and check_author_identity cannot know it: a token with the wrong fine-grained scopes, or one never SSO-authorized, passes every read-only check and fails at `pr create`. So the truncating path was the reachable one. The writes still stop dead -- remediate() cuts the branch ref before it calls `pr create`, so continuing to remediate really would leave a branch on every drifted repo and a PR on none. Only the classification continues. Six selftest checks, incl. a non-vacuous twin, plus a mutation entry that restores the `break`. Verified: 66 checks 0 failed; under the restored `break` exactly the two audit-completeness checks redden. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Uh oh!
There was an error while loading. Please reload this page.
…d#2735) Bugbot on .github#366. The check searched the whole report for "cannot open PRs", a phrase the failed row and the DISARMED footer both already carry -- so every later row could still say the pre-flight "refused" and the check would pass. It could not fail for its own reason. Now asserted on the bravo/charlie rows themselves, and that they do NOT say "refused". Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
LukasWodka
commented
Aug 27, 2026
bugbot run |
LukasWodka
commented
Aug 27, 2026
|
| PR | closes | ticket framing |
|---|---|---|
| #366 | backend#2735 | Bugbot High, blocking the prod hop (.github#363, staging → main) |
| #368 | backend#2690 | Bugbot Medium/Low, shipped at the staging hop |
backend#2690 and backend#2735 are the same Bugbot finding recorded at two hops of the same promotion chain, so the two tickets are duplicates of each other as well.
Both PRs touch the identical three files and make the identical change:
break→remediating = False+continuein theAuthorUnusablehandler- rename the tracking variable (
writes_stopped_athere,halted_atin fix(standards-sync): a PR refusal stops the writes, not the audit (backend#2690) #368) - rewrite the
**ABORTED at …**footer - add selftest coverage and a mutation entry
They will conflict. Whichever merges second gets a conflict in standards-sync.py and in both test files.
Recommendation
Merge one, close the other, and close the losing ticket as a duplicate. I have no strong preference on which — they are equivalent in behaviour. Marginal differences:
- fix(standards-sync): a PR refusal stops the writes, not the audit (backend#2690) #368 carries a slightly larger mutation addition.
- fix(standards-sync): a create failure disarms the writes, it does not truncate the audit (backend#2735) #366 carries a row-scoped cause assertion that Bugbot forced here (a whole-report search was passing vacuously), plus the report wording fix for the
NOT REMEDIATEDrows, which otherwise still name the pre-flight cause after a create failure.
I am not closing either — the org rule is that an AI session does not close PRs without an explicit instruction, and this one is LukasWodka's on both sides. @LukasWodka / @saadqbal, one call closes it out.
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit a95d357. Configure here.
LukasWodka
commented
Aug 27, 2026
Closing as the duplicate — .github#368 carries this fix and is the one to merge. Both PRs were written in parallel against the same defect from two tickets (
Chose this direction rather than the reverse because an AI session may only close a PR it opened itself in the same session, and #368 came from a parallel one. On merit the two are equivalent.
One thing that must not be lost with this PR: the Bugbot thread on the promotion .github#363 is deliberately left unresolved and is still blocking the staging → main hop. Merging #368 puts the fix on |
What
standards-sync.py's fleet loopbreaks whenpr createfails, so the report covers only the repos before the failure. This makes it disarm remediation and keep classifying instead — matching what the pre-flight identity refusal already does.Closes tracebloc/backend#2735
Why it is real, not a style point
Two paths reach one condition — this credential cannot open PRs:
check_author_identitypr createWhich one fires depends only on when the fact becomes knowable, and
check_author_identitycannot know it: a token with the wrong fine-grained scopes, or one never SSO-authorized for the org, passes every read-only check and fails atpr create. The selftest says so itself at the_ensure_prcase. So the truncating path is the reachable one, and the fleet report silently depended on timing.standards-sync.ymlargues against exactly this twenty lines above the secret: aborting before the audit turns "PRs could not be opened" into "fleet state unknown", which is strictly less information.What is deliberately preserved
The writes still stop dead at the first failure.
remediate()cuts the branch ref (POST git/refs) before it callspr create, so continuing to remediate really would leave a branch on every drifted repo and a PR on none — the half-rollout themain()gate exists to prevent. The bound the selftest pins, at most one repo with a branch and no PR, still holds; a new check assertsremediateis called exactly once.The row text also had to stop assuming the pre-flight cause —
NOT REMEDIATED: … refusedis wrong wording for a create failure, so both causes now name themselves.Evidence
standards-sync-selftest.py: 66 checks, 0 failed (60 before, 6 added).breakreddens exactly the two audit-completeness checks, and nothing else.standards-sync-mutations.py; full run 12 mutations, 0 stale, 0 malformed, 0 uncaught.The new checks were inserted above the summary computation — that file documents its own past defect where checks appended below it printed FAIL and did not count.
Note
Medium Risk
Changes remediation control flow and CI exit/report semantics for org-wide sync runs when the author PAT fails at PR creation—high operational impact but bounded writes and stronger audit completeness.
Overview
When
pr createfails withAuthorUnusableduring--create-prs,standards-sync.pyno longerbreaks the fleet loop. It now matches pre-flight PAT refusal (#348): turn off further remediation,continueclassifying every target, and exit 2 with a full table.Behavior preserved: only the first repo still gets a
remediate()attempt (avoids branches on every repo with no PRs). Row text and report footer distinguish pre-flight “refused” vs mid-loop “cannot open PRs” viaremediation_off; the footer says REMEDIATION DISARMED instead of ABORTED, clarifying the audit covered the whole fleet.Tests:
standards-sync-selftest.pyadds a 3-repo scenario (audit all targets, one remediate call, correct later-row wording).standards-sync-mutations.pypins restoringbreakas a regression.Reviewed by Cursor Bugbot for commit a95d357. Bugbot is set up for automated code reviews on this repo. Configure here.