Stop the pre-merge check from accepting a half-finished run (GST-2194) (#4258)

* Make pregate verify refuse a record from a partial run (GST-2194)

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

* Update pregate and queue test fixtures to complete records

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

* Document that verify needs every check and that a staged rerun keeps the rest

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

* Skip the partial-record pregate tests on Windows, where the fixture lane is a remote obligation

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

* Give the crew queue tests complete pregate records

The train, train-ops and wave tests wrote one-check pregate records, which verify now refuses as a partial run. They now write every registered check, as test/gstack-ship-queue.test.ts already does (CI free-suite run 42718782737).

Review-Finding: lib/pregate/index.ts:251:functional-contract reader=core
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

* Explain the missing-checks pregate refusal in troubleshooting

Documents that verify refuses a record missing registered checks, and that a fix commit needs a full gstack-pregate run (Step 14.5 docs audit).

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 01:33:31 +00:00
1 parent 00cb80cce8
commit 56c4e873b2
18 files changed
+250 -50

No files matched your search

+25 -7
View File
@@ -445,12 +445,27 @@ The record is `.gstack/tmp/pregate.json` (`gstack-artifact validate --as pregate
(Step 18) refuses unless the record is current for the tree being published
(`PREGATE_STALE`: rerun after the final stamp), green (`PREGATE_LANE_FAILED`,
`PREGATE_INCOMPLETE`, or `PREGATE_ENVIRONMENT` when every incomplete check is
the machine's) and every `requires-remote` obligation carries a receipt
the machine's), every `requires-remote` obligation carries a receipt
(`PREGATE_REMOTE_UNCLEARED`: dispatch the job, wait for it to finish green, then
`gstack-pregate clear --remote <workflow.yml/job> --run-url <url>`). The ship
`gstack-pregate clear --remote <workflow.yml/job> --run-url <url>`), and it holds
every registered check. The `PREGATE:` line prints `checks=N of M`. A record
from a `--only` or `--stage preflight|tests` run that is missing checks is
`PREGATE_INCOMPLETE` ("pregate.json holds checks=1 of 8 (missing: …)"): run
`gstack-pregate --allow-repo-commands` with neither flag at that tree. The ship
receipt then carries `pregate` and `requires_remote`. `gstack-pregate verify`
runs the same check standalone.
<a id="same-tree-checks"></a>
**A staged rerun keeps the rest.** A `--only` or `--stage preflight|tests` run
keeps the checks it skipped from the record it replaces, when that record has
the same head, tree, base commit, policy and registry. It prints
`PREGATE_MERGED: kept <check>=<status>,… from the record at this tree …`. So
rerunning `--stage tests` after a full run at an unchanged tree keeps an earlier
`secrets` failure and an earlier pass, and the full run's obligations come along
when `lanes` is one of the kept checks. A record for another head or tree, or
an earlier `--stage guards` run, keeps nothing. After a fix commit moves the
tree, a staged run alone is not a full pass.
**By tree.** Every record `gstack-pregate` writes is also mirrored, byte for
byte, to `<state root>/pregate/by-tree/<tree>.json` (the state root from
docs/state-root.md). `gstack-ship-queue ready` reads the checkout's
@@ -461,11 +476,14 @@ printing `PREGATE: … (from the state root's pregate/by-tree/<tree12>.json,
recorded by another checkout)`. This is for the lane whose `gstack-pregate
--remote` had to run from a separate clone (a worktree cannot host it): the
clone's record clears the lane's own checkout as long as both hold the same
tree. Only a run that holds the tests stage stands in (what `--stage tests
--remote` writes, `checks=[lanes]`; a `--only timing` or preflight-only run
is "a run without the tests stage"), and it must be recorded against
`origin/<base>` and not under `--policy-from head`;
otherwise the `PREGATE:` line says why the mirror cannot stand in. A record
tree. Only a complete run stands in: the clone runs the full
`gstack-pregate --remote` (not `--stage tests --remote`, whose `checks=[lanes]`
record verify refuses `PREGATE_INCOMPLETE`), or the lane clears its own record
with `gstack-pregate clear --remote pregate.json/remote_gate --receipt <file>`.
A `--only timing` or preflight-only run is "a run without the tests stage",
and the record must be recorded against `origin/<base>` and not under
`--policy-from head`; otherwise the `PREGATE:` line says why the mirror cannot
stand in. A record
whose own checks failed or stayed incomplete is final and no mirror overrides
it. An explicit `--pregate <file>` that verifies is used as before; a mirror
for a different tree changes nothing. Writing the mirror is best effort (a
+12 -3
View File
@@ -4406,7 +4406,10 @@ first, then merge the base into this branch and rerun.
`set -o pipefail`, or reported zero tests (ZERO-RUN).
**Fix.** Read the printed lane log, fix the failure, rerun
`gstack-pregate --stage tests`. A `| tail`-hidden exit is still an exit.
`gstack-pregate --stage tests`. A `| tail`-hidden exit is still an exit. A fix
that changes the tree leaves the staged rerun nothing to keep, so finish with a
full `gstack-pregate --allow-repo-commands` before `verify`
([docs/pregate.md](pregate.md#same-tree-checks)).
<a id="pregate-incomplete"></a>
### `PREGATE_INCOMPLETE`
@@ -4414,7 +4417,11 @@ first, then merge the base into this branch and rerun.
**Meaning.** A check timed out, a runner process was killed by a signal (out of
memory, an outside kill) and ended without an exit code, repo commands were not
allowed, no runner is declared or detected, or the working tree changed while
the check ran. Incomplete is never pass and blocks publication. A tool missing from PATH, a
the check ran. `gstack-pregate verify` also refuses a record that is missing
registered checks ("pregate.json holds checks=1 of 8 (missing: …)"): a
`--only` or `--stage preflight|tests` run with no record at the same head, tree,
base and policy to keep the rest from
([docs/pregate.md](pregate.md#same-tree-checks)). Incomplete is never pass and blocks publication. A tool missing from PATH, a
network or quota error before any test ran, or a full disk is
[`PREGATE_ENVIRONMENT`](#pregate-environment) instead, so the machine's failure
reads apart from the diff's.
@@ -4423,7 +4430,9 @@ reads apart from the diff's.
package the message says has none (or declare `runner`), raise `--timeout`, or
keep the tree still, then rerun. A runner killed by a signal never passes: read
the lane log, then rerun or split the selection. A tool missing from PATH is
[`PREGATE_ENVIRONMENT`](#pregate-environment), with its own fix.
[`PREGATE_ENVIRONMENT`](#pregate-environment), with its own fix. A record
missing checks needs a full `gstack-pregate --allow-repo-commands` (neither
`--only` nor `--stage`) at that tree.
<a id="pregate-stalled"></a>
### `PREGATE_STALLED`