diff --git a/bin/gstack-pregate b/bin/gstack-pregate index 3fdf66be3..b16e6d4d2 100755 --- a/bin/gstack-pregate +++ b/bin/gstack-pregate @@ -33,7 +33,7 @@ import { PREGATE_CONFIG_PATH, explainConfig, loadConfigFromHead } from '../lib/p import { describeDraft, draftConfig } from '../lib/pregate/init-draft'; import { buildRunCheck } from '../lib/pregate/run-check'; import { buildContext, defaultUserConfigPath, describeRefusal, loadedDotenvFiles } from '../lib/pregate/context'; -import { CHECKS, CHECK_IDS, PREGATE_GUARDS_OUT_REL, PREGATE_OUT_REL, PREGATE_TIER2, PREPUSH_CHECK_IDS, clearDecision, clearObligation, readPregateFile, renderTable, runPregate, verifyPregate, writePregateFile } from '../lib/pregate/index'; +import { CHECKS, CHECK_IDS, PREGATE_GUARDS_OUT_REL, PREGATE_OUT_REL, PREGATE_TIER2, PREPUSH_CHECK_IDS, clearDecision, clearObligation, keepSameTreeClears, readPregateFile, renderTable, runPregate, verifyPregate, writePregateFile } from '../lib/pregate/index'; import { describeLane, discoverLanes } from '../lib/pregate/workflows'; import { REMOTE_GATE_LANE } from '../lib/pregate/checks/lanes'; import { describeSubstitution } from '../lib/pregate/remote-receipt'; @@ -200,9 +200,11 @@ async function cmdRun(root: string, rest: string[], json: boolean): Promise c.status === 'fail' || c.status === 'incomplete' || c.status === 'not_installed'); const status = file.checks.some(c => c.status === 'incomplete' || c.status === 'not_installed') && !file.checks.some(c => c.status === 'fail') ? 'incomplete' : 'complete'; if (json) { diff --git a/changelog.d/capy-gst-1627-fix-check-chain.md b/changelog.d/capy-gst-1627-fix-check-chain.md new file mode 100644 index 000000000..ad86e9c42 --- /dev/null +++ b/changelog.d/capy-gst-1627-fix-check-chain.md @@ -0,0 +1 @@ +- **finish counts every granted fix-check in a chain, and accept keeps clears made at the same tree.** A second granted fix-check (a merge resolution, say) logs its range from the first fix-check's commit. `gstack-ship-release finish` read only the newest `review-fix-check` row and refused any range that didn't start at the reviewed tree, so the later fix-check unbound the earlier one and lanes logged a synthetic combined row (#4063). finish now chains each row to the earlier row whose commit is its `range_base`, back to the reviewed tree, and counts the chain when every link is clean and has its own owner grant (one grant counts for one link); a gap or an ungranted link still refuses. Separately, accept's final `gstack-pregate` rewrote pregate.json and dropped the `macos-named-regressions` and `windows-smoke` clears the lane had made at the same tree, so accept never exited 0. A rerun at the same head, tree, policy and base branch now keeps each earlier receipt for the same obligation and prints `PREGATE_CLEAR_KEPT:`; another head or tree, or a rerun with a failed or unfinished check, keeps nothing. (GST-1627) diff --git a/docs/pregate.md b/docs/pregate.md index 76a99c2a9..c43568fe8 100644 --- a/docs/pregate.md +++ b/docs/pregate.md @@ -1233,6 +1233,25 @@ tests in s`. The run is correct, only slower. Adding `"os": next accept carry the tests stage too, when the run's `tree.json` covers the selection. +**A rerun at the same tree keeps its clears (GST-1627).** accept's final +pregate reran `gstack-pregate` on the tree the lane had already cleared +`macos-named-regressions` and `windows-smoke` on from CI runs, and the fresh +record dropped both receipts, so accept stopped on `requires-remote (2 +uncleared)` and never exited 0 (#4063, GST-1595). Now, when `gstack-pregate` +writes over a record for the same head, tree, policy and base branch, each uncleared +obligation takes the earlier receipt for the same lane, platform, workflow and +job, with its `cleared_by`, stamp-only substitution and flaky exception, as long +as the earlier obligation listed every test the new one needs. Each kept +receipt prints `PREGATE_CLEAR_KEPT: receipt= (recorded at this +tree ; …)` (on stderr under `--json`), and accept relays the lines +before its `PREGATE:` line. A record for another head or tree keeps nothing, +so any commit after the clear, even an amend that keeps the tree, needs a new +clear at the new head: a receipt and its flaky exception were vetted against +the head they name. A rerun with a +failed, incomplete or not-installed check also keeps nothing, so a remote gate +that ran again and timed out stays uncleared. `gstack-pregate verify` checks a +kept receipt as it checks any other one. + **An inventory file CI's JUnit tree never lists (GST-1595).** bun registers the tests of a test file another test file imports under the importer, so the imported file's own JUnit suite never appears in `tree.json` and the carry diff --git a/docs/review-policy.md b/docs/review-policy.md index 9639ef136..7dce9b55b 100644 --- a/docs/review-policy.md +++ b/docs/review-policy.md @@ -686,11 +686,13 @@ route as behavior, with `--reviewed-base` (as /ship passes it) so does a file too large for the scoped review, and without the record nothing changes. A completed fix-check is a review, not an owner acceptance (GST-1130). Finish -reads the newest `review-fix-check` row from `gstack-review-read`. When it is a -completed clean read on committed content (freshness `CURRENT` against its own -tree) whose commit is on the branch, whose `range_base` is a branch commit -holding the reviewed tree, and for which an approved `review_loop_grant` in -`gstack-approvals` names a stop head inside `range_base..commit`, each code or test path inside `range_base..commit` +reads the newest `review-fix-check` row from `gstack-review-read`, chained back +through earlier rows whose commit is the next row's `range_base` +([chained fix-checks](ship-policy.md#fix-check-chain), GST-1627). When every link +is a completed clean read on committed content (freshness `CURRENT` against its own +tree) whose commit is on the branch, the oldest link's `range_base` is a branch commit +holding the reviewed tree, and for each link an approved `review_loop_grant` in +`gstack-approvals` names a stop head inside its `range_base..commit`, each code or test path inside a link's `range_base..commit` that is unchanged since, or whose change against the base is still the one the fix-check read after a base merge also edited it (GST-1195), routes as `fix_checked=` in `ROUTE:` and is listed on a diff --git a/docs/ship-policy.md b/docs/ship-policy.md index 211f2ec20..4bb4bec28 100644 --- a/docs/ship-policy.md +++ b/docs/ship-policy.md @@ -1635,7 +1635,8 @@ ruling: `ruled`, `action: "ruled"` or any other claim the lane writes on its own row is ignored. Step 16's `finish` reads the branch's rulings (`lib/ruled-notes.ts`) and prints each as `RULED_NOTE: at ruled by at