release-train: staging -> main - #401
Open
LukasWodka wants to merge 3 commits into
Open
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>
release-train: develop -> staging
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 885df27. 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-mainbranch (a mirror ofstaging), 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-attribution tooling used before destructive git operations; failures are mostly fail-closed, but incorrect pagination or baseline logic could block workflows or mis-attribute branches until fixed.
Overview
Fixes two operational bugs that made automation look healthy while misbehaving, plus test harness updates to lock the behavior in.
Kanban archive baseline recall (backend#2802) sets
GH_REPOon the recall step sogh run downloadcan resolve the repository without a checkout (listing worked via URL; download failed on “not a git repository”). Download failures now capture stderr inprev.stderrand surface it inprev.errorinstead of swallowing it with2>&1, without writing stderr intoprev.erroron success (which would falsely mark the baseline unreadable).branch_owner.py(backend#2972) replaces cappedgh pr list --limit 1000with a fully paginated GraphQL pull-request read validated againsttotalCount(duplicate-page and mid-read count checks). Incomplete reads exit non-zero with a marked refusal instead of printing hundreds ofunattributablerows.gh repo viewfor default branch and repo identity now passes the repo positionally because--repois invalid on that subcommand. Selftests and mutation suites were extended forGH_REPO, stderr handling, pagination,$endCursor, and the incomplete-list refusal path.Reviewed by Cursor Bugbot for commit 885df27. Bugbot is set up for automated code reviews on this repo. Configure here.