Warn when a branch-only run hides a red PR check, and make ready refuse when its note or base is missing (GST-2205) (#4270)

* Warn when a red check is replaced by a run from another suite, and refuse a plain ready whose note never reached origin (GST-2205)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Fetch the base before ready picks the train or plain path (GST-2205)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Let the train path report its own fetch failure when ready cannot refresh the base (GST-2205)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Give the no-origin/main routing test a complete pregate record (GST-2205)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Give the unpushed ready-note test a complete pregate record (GST-2205)

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

---------

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
This commit is contained in:
Garry Tanandcapy-ai[bot] authored and GitHub committed 2026-11-10 06:36:56 +00:00
1 parent 90fded4dd0
commit 4685fa9233
12 files changed
+226 -32

No files matched your search

+17 -3
View File
@@ -223,7 +223,10 @@ READY_RECEIPT: <state root>/ship-queue/ready/<repo key>/42-<head>.json (notes pu
```
Under `changelog_fragments`, a `READY_RECEIPT:` line follows, written only when
every check above passed; `land` refuses a pin without one.
every check above passed; `land` refuses a pin without one. It says `notes
pushed` only once origin holds the note; otherwise `ready` refuses with
[`QUEUE_READY_NOTE_UNPUSHED`](troubleshooting.md#queue-ready-note-unpushed),
as it does under a train, because `land` reads the note on origin.
CI's Version Gate (`scripts/compare-pr-version.ts`) accepts that head as
unstamped when `VERSION` and `package.json`'s version match its merge base, the
@@ -276,6 +279,14 @@ counts as a failed check `<workflow> (run <id>, no jobs)` unless a later run of
the same workflow replaced it; a run cancelled before any job is not counted.
An unreadable list is unknown, never green.
When a check counts as passing only because a newer run from another check
suite replaced a red one (a branch-only `free-tests.yml` dispatch beside the red
`pull_request` run, which tested the merge with the base), `ready` prints
`CI_SUPERSEDED: <check> red run <id> replaced by <id> (suite <a> → <b>)` under
the `ci:` line, one per replaced run, and `land` prints the same under its `CI:`
line. It is a warning and changes no verdict; a rerun in the same suite prints
nothing ([what to do](troubleshooting.md#ci-superseded)).
It refuses (`QUEUE_NOT_READY`) when the working tree has tracked edits, HEAD
is not the PR's pushed head, CI at that exact head is not green, or the pregate
result is not a current pass, and (`QUEUE_RECEIPT_MISSING`,
@@ -732,9 +743,12 @@ slot. The queue enforces this at every step from the PR body alone:
`REVIEW_TARGETED:` line) when a targeted class the head needs has no done
targeted pass in the receipt, and `QUEUE_RECEIPT_EXCEPTION_INVALID` when an
owner exception it records does not stand ([the ship receipt](#ship-receipt)).
There is no flag around it. Before any of these checks, `ready` fetches
There is no flag around it. Before any of these checks, and before it
chooses the train or plain path from the policy, `ready` fetches
`origin/<base>` and reads the policy and every receipt field against that
fresh ref, so a lane clone whose base is behind the remote never turns a good
fresh ref (a clone with a missing or stale base ref would otherwise run plain
`ready` under a train policy and skip the screen, conflict and READY-receipt
steps), so a lane clone whose base is behind the remote never turns a good
receipt into `RECEIPT_INVALID` (GST-2232); a failed fetch refuses with
`QUEUE_BASE_UNFETCHED` before anything is compared. The stamp path of `land`
refuses the same way; `land --pin` (`merge: direct`) refuses a failed fetch
+26 -4
View File
@@ -5503,8 +5503,8 @@ resumes its own lock.
### `QUEUE_BASE_UNFETCHED`
**Meaning.** `gstack-ship-queue ready` (or the stamp path of `land`) could not
fetch `origin/<base>`, so it stopped before reading the policy or comparing
any receipt field. Both compare the receipt's recorded selection, depth and
fetch `origin/<base>`, so it stopped before reading the policy (which also
picks `ready`'s train or plain path) or comparing any receipt field. Both compare the receipt's recorded selection, depth and
targeted classes with what the current base gives the head; a local
`origin/<base>` a few landings old measures the PR from an older merge base,
pulls in files of PRs that already landed, and reports a false
@@ -6525,10 +6525,30 @@ CHANGELOG drops or renames a released heading (the message then names the
CHANGELOG). `train prune --stale` deletes the scratch branches of merged or
closed PRs.
<a id="ci-superseded"></a>
### `CI_SUPERSEDED: <check> red run <id> replaced by <id> (suite <a> → <b>)`
**Meaning.** `gstack-ship-queue ready` or `land` judges each check by its
newest run, and here the newest run passed in a different check suite from an
older red run of the same check. The usual cause is a lane dispatching
`free-tests.yml` on its branch after the `pull_request` run went red. The
`pull_request` run tested GitHub's merge of the branch with the base, and the
dispatched run tested the branch alone, so a failure that exists only on the
merge with main can be hidden. The line is a warning: CI still counts as
green, and nothing is refused. A rerun of the red run in its own suite prints
nothing (reports/GSTA-461.md item 7).
**Fix.** Nothing is required. Before sending READY or landing, open the red
run (`gh run view <id>` names the job) and check whether it failed for a reason
the branch-only run could not see. If it was a flaky test, log it as flaky the
usual way. To clear the line, rerun the failed `pull_request` run itself
(`gh run rerun <run> --failed`), which replaces it in the same suite.
<a id="queue-ready-note-unpushed"></a>
### `QUEUE_READY_NOTE_UNPUSHED`
**Meaning.** `gstack-ship-queue ready` wrote the READY receipt in the local
**Meaning.** `gstack-ship-queue ready` (under a train policy, or under
`changelog_fragments` without one) wrote the READY receipt in the local
state root, but origin does not hold its note on `refs/notes/gstack-trains`.
`ready` pushes the notes ref, then fetches it back and requires origin's tip
to be the local tip or to contain it. It tries three times, fetching and
@@ -6543,7 +6563,9 @@ the land failed instead (#4245). Don't send the READY block.
refused it, then run the `NEXT:` line, which is the same `ready` command
without `--pregate`, `--gate-exit` or `--gate-log`: add back any of those you
passed the first time. It keeps the first `ready_at`, follows a screen run already dispatched at the
same merge SHA, and pushes the kept receipt. To see the raw error, run
same merge SHA, and pushes the kept receipt. Without a train policy there is
no `NEXT:` line: rerun the same `ready` command with the same flags, and it
writes the receipt again and pushes it. To see the raw error, run
`git push origin refs/notes/gstack-trains:refs/notes/gstack-trains`.
<a id="queue-screen-red"></a>