release-train: develop -> staging - #400
Merged
Merged
Conversation
…ame itself (backend#2802) (#397) * fix(kanban): give the baseline download a repo, and let its failure name itself (backend#2802) kanban-archive.yml has been red on every scheduled run while ARCHIVING PERFECTLY -- today: 72 archived, 0 failed, then a non-zero exit. The failure is one missing env var, and the reason it took a reproduction to find is a second defect in the same step. THE CAUSE. `gh run download` takes no `--repo`, and this job has NO checkout (its steps are all API calls; it needs no source). So gh resolved the repository from the git remote, found no `.git`, and died BEFORE making any API call. That is exactly why the artifacts LISTING in the same step succeeded -- it puts the repo in the URL path -- while the fetch failed. Reproduced outside Actions, gh 2.98.0: $ cd /tmp/empty && gh run download 33393320354 -n board-baseline failed to run git: fatal: not a git repository (or any of the parent directories) $ GH_REPO=tracebloc/.github gh run download 33393320354 -n board-baseline -D prev $ cat prev/board.total 574 574 is the baseline the job could not read. `gh` does NOT read `GITHUB_REPOSITORY` -- tested -- so being on a runner does not supply it. `GH_REPO` is the variable it does read, and it is narrower than adding a checkout to a job that needs no source. RULED OUT RATHER THAN GUESSED PAST: not retention (`retention-days: 30`; the artifact is 142 bytes, created 2026-08-31, `expired: false`); not permissions (`actions: read` is set and the same token succeeded on the listing in the same step); not the download-artifact v4 cross-run restriction (there is no `actions/download-artifact` in this file at all). AND THE SECOND DEFECT, which is why five red runs were undiagnosable from their own logs: `>/dev/null 2>&1` on the download threw away the only line that said why, and the refusal below then CLOBBERED `prev.error` with a generic summary. Now stderr is captured to `prev.error` and the summary APPENDS the tool's own words rather than overwriting them. A refusal that cannot say what it saw sends the next reader to reproduce it by hand, which is what happened here. NOT A DUPLICATE: backend#2802 and backend#2903 are both closed, and #2903 is a different defect (a `per_page=100` listing treated as complete -- the class tracked by the open #2944). Neither describes this cause. The download path itself landed 2026-08-30 in .github#383. GUARDED. `archive-baseline-selftest.py` now asserts the recall step sets `GH_REPO` from `github.repository` and captures the download's stderr. Both mutation-proved against the live file: removing `GH_REPO` -> "does not set \`GH_REPO\`"; restoring `2>&1` -> "not capture stderr". Full selftest green either side -- 10 cross-run + 10 identity + 6 completeness cases + the detector anchors. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(kanban): re-anchor the stale download-failure mutation (backend#2802) The fix in the previous commit rewrote the download-failed branch to capture gh stderr and append to prev.error, so archive-baseline-mutations.py own anchor for that branch matched 0 times. THE HARNESS CAUGHT IT ITSELF and refused, rather than reporting 0 uncaught about a premise nobody typed -- which is why this is a re-anchor and not a discovery. An inert mutation is indistinguishable from good coverage in a log, and that guard is the reason this commit exists. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(kanban): anchor the whole printf, not its first line (backend#2802) The re-anchor in the previous commit applied but changed nothing: it replaced only the printf FIRST line, leaving the continuation ("$rid" ... > prev.error) standing as its own command -- so prev.error was still written and the mutation went UNCAUGHT rather than inert. Two different failures with the same symptom in a log, and the harness distinguished them: "anchor matched 0 times" first, then "the suite passed with this broken". Anchoring both lines makes the mutation actually remove the write. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(kanban): capture the download stderr WITHOUT dirtying the unreadable sentinel (backend#2802) Bugbot High on my own fix, and it is right about the coupling. The previous commit sent `gh run download` stderr straight into `prev.error` -- but the assert step treats ANY non-empty `prev.error` as an unreadable baseline (`if [ -s prev.error ]` at :724). So a SUCCESSFUL download that printed anything at all would mark the baseline unreadable and keep the job red after a good archive: the exact failure this PR exists to fix, arriving from the other side. MEASURED, AND THE FINDING AS DESCRIBED DOES NOT REPRODUCE: `gh run download` writes 0 bytes to stderr on success on a non-TTY (tested, gh 2.98.0; a runner is also non-TTY). So no run would have gone red today. FIXED ANYWAY, because the coupling is the defect rather than the current byte count. One deprecation notice on stderr in a future gh is all it takes, and this file is full of exactly that shape -- a sentinel that means "could not read" quietly acquiring a second meaning. stderr now goes to `prev.stderr` and only the FAILURE branch promotes it into `prev.error`, so the sentinel has one writer and one meaning. The stale comment claiming stderr "lands in prev.error" is corrected in the same commit -- it would otherwise describe the shape this change just removed. Selftest extended both ways: the download must capture into `prev.stderr`, and it must NOT write into `prev.error`. Two mutations, both reddening -- restore the straight-into-sentinel write; drop the capture entirely. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…e out loud (backend#2972) (#398) `branch_owner.py` asked `gh pr list --limit 1000`. `tracebloc/backend` has 1418 pull requests, so the seam failed closed on the org's LARGEST repo -- the one carrying 62 of the org's 99 stale branches -- and `main` printed `108 branch(es): 0 attributed, 108 unattributable` and exited 0. That line is character-for-character what a genuine "nobody can be named here" answer looks like, so a reader who trusted the tool concluded every branch in the repo was unowned. A bigger number would only move the date this happens again, so the read now PAGES TO THE END (`gh api graphql --paginate --slurp`, cursor variable named `$endCursor` because gh injects into that name and no other) and asks the repository for its own `totalCount` on the same connection. "Did the read finish?" is then two measured numbers compared, not a threshold anybody picked: rows == totalCount, or a refusal naming both counts and the shortfall. The fail-closed backstop survives and gets sharper. A short read, a page that came back twice (what a broken cursor looks like), a count that disagrees with itself between pages, and a GraphQL `errors[]` at HTTP 200 are all refusals -- carrying a marker `main` matches on, so it prints no rows and exits 2 rather than tallying a refusal into the shape of data. The other PR-list problems still print their rows, with the one reason carried into the summary line. Also, found while verifying: `gh repo view` has NO `--repo` flag -- it takes the repository positionally, and the flag form exits 1 with `unknown flag: --repo`. `default_branch()` built the flag form, so the authoritative lookup was unreachable on every `--repo` run, the answer silently came from `origin/HEAD` (a clone-time cache), and the first-commit signal was withheld for every branch while the message blamed a remote that was never asked. Measured on `tracebloc/backend`: 88 of 108 attributed with the paging fix alone, 102 of 108 with both. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Contributor
Author
|
bugbot run |
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 a8c0546. Configure here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 affect daily kanban CI gates and branch-ownership tooling used for stale-branch workflows; misbehavior could cause false reds or wrong attribution, but there is no auth or data-path change.
Overview
Kanban archive no longer fails baseline recall on checkout-less jobs: the recall step sets
GH_REPOsogh run downloadcan resolve the repo, captures download stderr intoprev.stderr(notprev.error, which would false-fail asserts), and surfacesgh’s error text when a liveboard-baselineartifact cannot be fetched.branch_owner.pyreplaces the cappedgh pr list --limit 1000path with paginated GraphQL (gh api graphql --paginate --slurp), validates completeness viarows == totalCount(plus duplicate-page / inconsistent-count checks), and exits non-zero without branch rows when the list is incomplete so output is not mistaken for “everyone unattributable.” It also fixesgh repo viewfor--reporuns by passing the repository positionally (the--repoflag was never valid). Selftests and mutation harnesses are updated for these behaviors.Reviewed by Cursor Bugbot for commit a8c0546. Bugbot is set up for automated code reviews on this repo. Configure here.