release-train: develop -> staging - #450
Conversation
…ket (backend#3357) (#445) The `closing-ref` gate read the conventional-commit scope `chore(0071)` as GitHub ticket #71 and demanded the PR reference it. But a GitHub issue number is never zero-padded -- `0071` is the rfcs repo's RFC-document convention (measured 2026-09-08: `chore(0071)`, `docs(0077)`, `chore(0081)`, `docs(0075)`, `docs(0067)`, each naming an RFC, none a ticket). rfcs#78 (`chore(0071): Adopted -- epic tracebloc/backend#3289`) was the measured casualty: `0071` read as #71, so the gate rejected the PR's truthful `Part of tracebloc/backend#3289` -- which names the epic, not #71 -- and offered only a FALSE `Closes #71` (the wrong issue) or deleting `(0071)` from the title (the RFC traceability). That is rule 4's failure mode: a gate whose only remedy is a lie or a deletion. Narrow `SCOPE_BARE_RE` to require a non-zero leading digit (`[1-9]\d*`). An unpadded `fix(71)`/`fix(#71)` still parses, so the narrowing costs no real ticket any recall; a repo that means issue #71 never writes `fix(0071)`. The `rfc-0068`/`rfc-664` scopes the same repo also writes never reached the parser (a dash is no `#?\d+`), so this closes the one shape that did. Selftest: adds the rfcs#78 end-to-end case (must PASS), the padded-scope parse cases, and pins that an unpadded `fix(71)` with no reference still FAILS. Mutation harness: updates the `#N`-scope anchor and adds one reverting the narrowing, which the rfcs#78 case catches. Part of tracebloc/backend#3357 Co-authored-by: Syed Saqlain <syedsaqlain@MacBook-Pro.local> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
|
bugbot run |
…te can actually mint its token (backend#3242) (#446) * fix(conflict-gate): write a check run, not a commit status (backend#3242) The Conflict gate has never once run. Its token mint asks the tracebloc-release-train App for `permission-statuses: write`, but the App's installation does not grant `statuses` at all, so the mint is refused ("The permissions requested are not granted to this installation") before the sweep starts -- no successful run since it landed. The signal has to be written from OUTSIDE the PR onto its head sha (a conflicted PR has no merge ref, so no `pull_request` job can run); both a commit status and a check run satisfy that. The choice is a permission one, and `statuses` is the scope the App cannot give. So switch the two network seams from the Statuses API to the Checks API: `checks: write` is a scope the App already holds. Same red-row-on-the-PR signal, a scope the mint can actually get -- the same class fix as backend#3360 (bugbot-gate reads off checkSuites) and backend#3222 (release-train reads the verdict off check-runs): never depend on the `statuses` scope. `classify`/`plan`/`STATE_FOR`/`CONTEXT` and the seam signatures are unchanged; only `existing_state` (now reads `commits/{sha}/check-runs`, newest run by id) and `post_status` (now POSTs `check-runs` with a status/conclusion mapping) change API. The check-run NAME is the same `conflict-gate / mergeable` context, so nothing that might later require it needs renaming. Nothing else reads the old commit-status context (only this gate's own tests did). Selftest and mutation harness updated to the check-runs read/write and the `checks: write` mint; a mutation pins that the read never returns to a commit-status source and that the mint never re-adds `statuses`. Closes tracebloc/backend#3242 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(conflict-gate): update the one check run in place, not append a new one (backend#3242) Bugbot (High): post_status always POSTed a fresh check run. Check runs APPEND (unlike a commit status, one slot per context that success overwrote), and statusCheckRollup -- what branch protection reads -- is worst-of across every same-name run on the sha. So a later success could never clear an earlier failure, and an in_progress (pending) POST left uncompleted kept the rollup pending forever after mergeability was known. post_status now PATCHes the greatest-id run we already own (via the shared _latest_own_run helper, factored out of existing_state) and POSTs only when none exists, so the single run transitions success<->failure<->in_progress in one slot. New selftest case 13c exercises the real post_status: PATCH when a run exists, POST when absent -- reddens if either reverts to always-POST. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(conflict-gate): retarget the two mutations my refactor moved (backend#3242) Bugbot round 2 (two Medium): moving the name filter and the read-fail handler from existing_state into _latest_own_run left two mutations stale/broken. - The name-filter mutation looked for a standalone `if run.get(\"name\") == CONTEXT:`; it now lives inside a list comprehension, so the anchor matched 0 times and the property went untested. Retargeted to the comprehension filter. - The read-fail mutation returned \"success\" from a function that must return a run dict or None; a bare string AttributeErrors in check_run_state and scores UNCAUGHT (harness broke). It now returns a completed-success run dict, so existing_state reads \"success\" instead of None and the mandatory-write property reddens as intended. Harness: 29 mutations, 0 stale, 0 uncaught. Selftest: 124 assertions pass. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(conflict-gate): force the check-runs read to GET, read it once, pin the method (backend#3242) Address @saadqbal review on #446: - _latest_own_run passed -f without --method GET, so gh api POSTed the read; there is no POST route on /commits/{sha}/check-runs, so it 404d on every call -- _latest_own_run returned None always, killing the dedup and forcing post_status down the CREATE branch forever (check-runs accumulate). Force --method GET and add filter=latest so the endpoint returns the current run per name (no reliance on paging a 30-per-page history). - Read our run ONCE in sweep_repo and thread it into post_status, dropping the redundant second GET for changed verdicts. - Document the pending-PATCH reliance (status->in_progress un-completes the run, so its old conclusion no longer contributes to the rollup) as a stated, re-confirm-before-arming assumption rather than a silent guess. - Selftest now asserts any api read carrying -f also carries --method GET, and a new mutation strips --method GET; retarget the two mutations the refactor moved. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Syed Saqlain <syedsaqlain@MacBook-Pro.local> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…n, not the restricted workflow token (backend#3447) (#449) * fix(advance-deploy-env): read /commits/{sha}/pulls under the App token, not the restricted workflow token (backend#3447) Since .github#438 reached main (2026-09-08 19:10 UTC) the extract step read each commit's PR with github.token. The org default workflow permission is the restricted read (contents + packages only), and that endpoint needs pull-requests:read on a private repo -- so every private-repo board advance 403'd and failed closed, while every public-repo one passed. Mint the installation token (which already carries pull-requests:read) before the extract step and run the read under it; keep the read's stderr in the ::error line so the next failure names its status. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(extract-advanced-prs): build the stderr excerpt without a pipe, so pipefail cannot read head's early close as a failure Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> * fix(advance-deploy-env): grant the mint contents:read — the extract step's call site moved onto this token (backend#3447) Bugbot High on #449. The extract step now reads `GET /repos/{r}/commits/{sha}/pulls` under the App token, which this mint scoped to `pull-requests: read` only. `fr-gate.yml` records that endpoint as needing `contents: read + pull-requests: read`, derived from its own calls under backend#2157 and green as a required check ever since; no workflow here reads it under `pull-requests: read` alone. Short by that one scope, this PR reproduces backend#3447 in the same silent shape — the read 403s, the fail-closed branch refuses the subject fallback, no card moves on any private repo. saadqbal's .github#324 finding is untouched and still correct on its own test (check the call site, not the prose): the mapper call at `:94` runs BEFORE this mint under `github.token`, so the router's need genuinely does not generalise to it. What changed is that .github#438 added a SECOND consumer and this PR moves it AFTER the mint — a call site that did not exist when #324 was written. The comment block now says that, so the next reader does not re-derive the dropped-by-analogy argument against a call it never covered. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
|
bugbot run |
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 20f7325. Configure here.
| listing = CD.gh_json(["api", "--method", "GET", | ||
| f"repos/{org}/{name}/commits/{sha}/check-runs", | ||
| "-f", f"check_name={CONTEXT}", | ||
| "-f", "filter=latest"]) |
There was a problem hiding this comment.
Latest filter hides pending check runs
High Severity
_latest_own_run lists check runs with filter=latest, which GitHub filters by completed_at and therefore omits in_progress runs. An undetermined sweep POSTs a pending run; the next sweep cannot see it, treats the head as empty, and POSTs a sibling success or failure. statusCheckRollup is worst-of across every same-name run, so the leftover in_progress check stays pending and can never be cleared — the stuck shape this rewrite’s PATCH path exists to prevent.
Additional Locations (1)
Triggered by project rule: Bugbot guide — tracebloc/.github
Reviewed by Cursor Bugbot for commit 20f7325. Configure here.
|
REFUSED. This promotion was blocked by 1 HIGH severity finding(s): Latest filter hides pending check runs, per the severity policy in release-train's README (High stops the line; an unreadable severity blocks too, because unknown is not low; Medium/Low are recorded and ship, at both hops). Blocking threads stay UNRESOLVED by design, so this promotion remains blocked until they are fixed on What the train did with each:
|


Automated promotion by the release train (RFC-0008 D14). Head is the train-managed
release-train/to-stagingbranch (a mirror ofdevelop), so it never collides with a human PR. Merged only when the fr-gate is green.Note
Medium Risk
Changes org-wide CI auth, kanban card moves on deploy pushes, and how conflict/PR-title gates signal on PRs—high impact if token scopes or check-run PATCH behavior regress, but behavior is heavily self-tested.
Overview
Fixes private-repo kanban advancement by minting the release-train App token before PR extraction and calling
GET /repos/.../commits/{sha}/pullswith that token (contents: read+pull-requests: read), instead ofgithub.token, which 403’d on private repos and left cards behind shipped code.extract-advanced-prs.shnow surfaces realghstderr on API failures so 403s are not misread as rate limits.Conflict gate switches from commit statuses (scope the App cannot mint) to check runs (
checks: write): reads latest state via REST check-runs, PATCHes the existing run when the verdict changes (avoid duplicate runs on the rollup), and keeps write-only-when-changed dedup.Closing-ref gate treats zero-padded conventional-commit scopes like
chore(0071)as RFC document numbers, not GitHub issue #71 (SCOPE_BARE_RErequires a non-zero leading digit), fixing false failures on rfcs adoption PRs that truthfullyPart ofan epic.Reviewed by Cursor Bugbot for commit 20f7325. Bugbot is set up for automated code reviews on this repo. Configure here.