Skip to content

v1.91.263.0 feat(ship-queue): screens read from the run, train watch/forget/prune --stale, verify --post-merge, ready --dispatch-ci, --stack-tests - #3484

Merged
capy-ai[bot] merged 20 commits into
mainfrom
train-ops-screen-verdict
Oct 27, 2026
Merged

capy-ai[bot] merged 20 commits into
mainfrom
train-ops-screen-verdict

Conversation

@garrytan

@garrytan garrytan commented Oct 26, 2026 •

Copy link
Copy Markdown
Owner
{
  "schema_version": 1,
  "pr": 3484,
  "head": "fe019b3bed01fa4239003897a84edb0d6dab6682",
  "version": "1.91.255.0",
  "base": "main",
  "gate": {
    "train-ops": {
      "pass": 78,
      "fail": 0,
      "skip": 0
    },
    "adjacent": {
      "pass": 405,
      "fail": 0,
      "skip": 0
    },
    "windows-curation": {
      "pass": 112,
      "fail": 0,
      "skip": 0
    },
    "typecheck": {
      "pass": 1,
      "fail": 0,
      "skip": 0
    }
  },
  "session_kind": "unattended",
  "pregate": "requires-remote cleared @0afd9728f320 (1 checks, current for fe019b3bed01)",
  "requires_remote": [
    "free-tests.yml/cso-macos-launcher: https://github.com/garrytan/gstack/actions/runs/40400373328",
    "free-tests.yml/macos-named-regressions: https://github.com/garrytan/gstack/actions/runs/40400373328",
    "windows-free-tests.yml/windows-free-shard: https://github.com/garrytan/gstack/actions/runs/40400379884",
    "pregate.json/remote_gate: remote-gate tree=0afd9728f320 tests=21570"
  ],
  "issues": {
    "fixes": [],
    "refs": [
      3465
    ],
    "flakes": []
  }
}

What changed

gstack-ship-queue train --help at main (before) and on this branch (after): train watch, train forget, prune --stale, ready --dispatch-ci, verify --screen / --post-merge and build --dry-run --stack-tests are new, each read from the run or the record instead of lane prose or hand steps

gstack-ship-queue train --help at main (before) and on this branch (after): train watch, train forget, prune --stale, ready --dispatch-ci, verify --screen / --post-merge and build --dry-run --stack-tests are new, each read from the run or the record instead of lane prose or hand steps.

Before/after as text: gstack-ship-queue train --help at main (before) and on this branch (after): train watch, train forget, prune --stale, ready --dispatch-ci, verify --screen / --post-merge and build --dry-run --stack-tests are new, each read from the run or the record instead of lane prose or hand steps
--- Before · before.txt · captured output
+++ After · after.txt · captured output
+  train build --prs <n>@<sha>[,...] [--order <n>,...] [--urgent | --repair] [--dry-run [--stack-tests [--stack-tests-command "<cmd>"]]] [--free-timeout <s>]
-  train build --prs <n>@<sha>[,...] [--order <n>,...] [--urgent | --repair] [--dry-run] [--free-timeout <s>]
                                            --order: explicit slot order, every PR in --prs once (default: screened
                                            first, then READY order)
   train build --train <nonce>              resume a train (push, free tests, dispatch) from its record
@@ ⋯ 5 unchanged ⋯ @@
   train bisect --train <nonce> --spend-cap <usd> [--dry-run]
                                            red cases on every prefix T0..Tk, resumable and capped
   train rebuild --train <nonce> [--infra]  the one rebuild an all-green bisect earns (or the one INFRA re-dispatch)
+  train watch --train <nonce> [--timeout <s>]
+                                           resumable follow: runs the step the record asks for (build, status), waits for the
+                                           pending run, reads the verdict, prints NEXT; rerun it after a restart (no daemon)
+  train forget --train <nonce> | --receipt <pr>@<sha> [--dry-run]
+                                           remove a settled train record (attempts, bisect) or a READY receipt from
+                                           refs/notes/gstack-trains under an exact lease, then delete the local files
+  train prune [--train <nonce>] [--dry-run] [--stale]
+                                           delete train/<nonce> branches of merged, superseded or dropped trains; --stale also
+                                           settles merging or green trains whose every PR is merged or closed on GitHub, and
+                                           deletes screen/<pr>-* branches of merged or closed PRs
+  ready --pr <n> --screen [--broad] | --no-screen [--dry-run] [--dispatch-ci <wf.yml[,…]> [--timeout <s>]]
+                                           (train policy) READY plus the screen choice, recorded as a receipt; a head whose
+                                           screen run is RED is refused (QUEUE_SCREEN_RED). --dispatch-ci runs the named
+                                           workflows on the branch first (a conflicting PR has no pull_request CI), waits for
+                                           them and clears the matching requires-remote pregate lanes with the run URLs
-  train prune [--train <nonce>] [--dry-run]
-                                           delete train/<nonce> branches of merged, superseded or dropped trains
-  ready --pr <n> --screen [--broad] | --no-screen [--dry-run]
-                                           (train policy) READY plus the screen choice, recorded as a receipt
   verify --pr <n> --train <nonce> [--no-fetch]
                                            (train policy) the merge check against a green train record
+  verify --pr <n> --screen                 (train policy) the PR head's screen verdict read from its run: SCREEN_VERDICT and
+                                           FLAKY lines, recorded in the READY receipt
+  verify --post-merge <sha> [--timeout <s>] after a merge: wait for every check run at the merged commit to settle;
+                                           POST_MERGE: green|red|pending plus one CHECK: line per workflow (resumable)
   Merge trains need a "train" block in the base revision's ship policy (docs/ship-policy.md#run-a-merge-train).
 

The merge-train coordinator's operational gaps from 2026-10-26, each red before green, all in gstack-ship-queue (train policy surface) and its docs. Every surface is generic: workflow, check and branch names come from the ship policy or flags.

Screens are read from the run, not the lane. lib/ship-queue-screen.ts reads a dispatched screen's verdict from the run's own artifacts (gate-binding-a<attempt>: verdict, reconcile exit, flaky cases; report-verdict-a<attempt>/paid-report/collector-outcomes.json: failing panels and rule-16 flaky lines; a confirmed reuse in paid-plan/gate-reuse.json). ready --screen, verify --pr <n> --screen and train build print SCREEN_VERDICT: #<n> run <id> GREEN|RED|NOT-RUN|INCOMPLETE [red=…] [flaky=…] plus one FLAKY: line per flaky case, and record it in the READY receipt (screen.verdict, local state and refs/notes/gstack-trains). A RED screen refuses ready under --screen and --no-screen alike, is never re-dispatched at the same merge SHA, and train build refuses to seat the pin (QUEUE_SCREEN_RED). Runs 40269992077 (#3434) and 40275443393 (#3453) were VERDICT RED while their lanes reported green.

A screen that ran no slice is NOT-RUN at verdict. 18 of 41 PR screens on 2026-10-26 concluded success with every slice skipped (the route job found the head superseded by a push, so it planned nothing). Such a run is NOT-RUN: verify --screen refuses with QUEUE_SCREEN_NOT_RUN, the receipt records NOT_RUN, ready --screen dispatches afresh instead of following it, and train build seats the pin unscreened with a SCREEN: … counted as not-run line.

Scratch-merge screens (#3465). When refs/pull/<n>/merge lags the PR head, is missing or cannot be fetched, ready --screen plans the screen on a scratch merge of the head onto the base, pushed as screen/<pr>-<head12> (SCREEN_MERGE:), the way train build builds prefixes. Only a real conflict with the base is QUEUE_SCREEN_STALE_REF (its text now says so); an unreachable remote is POLICY_SOURCE_UNAVAILABLE.

Following, settling and forgetting trains.

  • train watch --train <nonce> [--timeout <s>] (lib/ship-queue-train-watch.ts): the one resumable follow command. It reads the record, runs the step its state asks for, waits for the pending run by polling gh, reads the verdict and prints the last step's NEXT:. No daemon, no process state: rerun after an interruption and it continues from the record; it never dispatches anything the record would not dispatch on its own.
  • train prune --stale: a merging or green train whose every PR is MERGED or CLOSED on GitHub (gate.train-23af94b3c5e9 and -6755ab829acf) is marked stale (new terminal state), each PR logged on a STALE: line, its branch and the PRs' screen/<pr>-* branches deleted; an OPEN PR keeps it.
  • train forget --train <nonce> | --receipt <pr>@<sha> [--dry-run] (lib/ship-queue-train-forget.ts): removes one settled train (attempts included) or one READY receipt from local state and the notes ref with an exact --force-with-lease; a merging, gate-pending or free-pending train is refused.

After the merge. verify --post-merge <sha> [--timeout <s>] (lib/ship-queue-post-merge.ts) waits for every check run at the merged commit to settle, prints one CHECK: <name> <conclusion> per check and POST_MERGE: <sha12> green|red|pending|none (…); neutral/skipped count as skipped, a failure is QUEUE_POST_MERGE_RED, a timeout is QUEUE_TRAIN_PENDING with the same command as NEXT:.

A conflicting PR's CI in one command. ready … --dispatch-ci <wf.yml[,…]> [--timeout <s>] (lib/ship-queue-dispatch-ci.ts) dispatches each named workflow on the branch (skipped when a run at this head already concluded), waits (CI_DISPATCH:), clears every requires-remote pregate lane whose workflow is one of them with the run URL (PREGATE_CLEARED:), then reads the head as usual. A red run clears no lane and refuses; a fork head is QUEUE_TRAIN_UNTRUSTED. This replaces the four-step hand procedure in docs/ship-policy.md.

Stacked tests before the gate. train build --dry-run --stack-tests [--stack-tests-command "<cmd>"] (lib/ship-queue-stack-tests.ts) runs each PR's new test files on the integrated prefix that includes it (T) in a scratch worktree: STACK_TESTS: #<pr> T<k> <n> new test file(s) pass|FAIL (<files>); a failure is QUEUE_TRAIN_STACK_RED with nothing written, pushed or dispatched (the #3460-on-#3451 case).

Also: downloadJson finds a named file anywhere in a multi-path artifact; ciAtHead is exported with its per-check list; test/ship-queue-train-ops.test.ts is excluded from the Windows subset like the other gh-shim drivers; docs/ship-policy.md documents every command above; docs/troubleshooting.md gains QUEUE_SCREEN_RED, QUEUE_SCREEN_NOT_RUN, QUEUE_TRAIN_STACK_RED, QUEUE_POST_MERGE_RED.

Why

Every item is a step the coordinator did by hand or got wrong in operation this week: trusting a lane's screen prose, following a hollow screen, hand-editing refs/notes/gstack-trains, a gh run watch chain lost to a machine restart, a gate spent on a stack that a few test files would have caught.

Approvals

Ask Words By Scope
Harness phase 2 (ship-queue gaps seen in operation) "Do it and also improve it: fix the issues all the captains have seen in this Capy project" Garry, 2026-10-26, via GStack Minder this PR and its siblings
New command surfaces and result codes (verify --screen, verify --post-merge, train watch, train forget, prune --stale, ready --dispatch-ci, train build --dry-run --stack-tests; QUEUE_SCREEN_RED / QUEUE_SCREEN_NOT_RUN / QUEUE_POST_MERGE_RED / QUEUE_TRAIN_STACK_RED; screen/- branches; a lagging merge ref is no longer QUEUE_SCREEN_STALE_REF) "Accepted as designed" GStack Minder (Captain), 2026-10-26 #3478, #3483, #3484

Summary

The feature commits (ab9a854..c75ec3a) add the train-ops surfaces described above: run-read screen verdicts, NOT-RUN detection, scratch-merge screens, train watch, train prune --stale, train forget, verify --post-merge, ready --dispatch-ci and train build --dry-run --stack-tests, with their docs and result codes. The /ship commits on top (c75ec3a..fe019b3, 17 commits, the last being the one-time rule-19 merge of main b004c06 granted by GStack Minder) are the review-loop fixes: the regenerated doctor-components render (its freshness test failed at c75ec3a), the RH-15 exact assertion restored, --dry-run no longer persisting or pushing the read verdict, forgetNotes restoring the local notes ref on a rejected lease and forget refusing every in-flight state, verify --post-merge counting commit statuses, --dispatch-ci failing closed on fork or unreadable PRs with gh's error text and the screen: line after READY, train watch rejecting a malformed --free-timeout, stack-tests counting only bun test files (.test/_test/.spec/_spec) passed as exact paths, artifact-list paging in newestArtifact, the documentation-audit corrections to docs/ship-policy.md, docs/troubleshooting.md and the CHANGELOG entry (still under ## [Unreleased]; VERSION, package.json and the agents digest stay at main's values, stamp-at-merge), and one test repair the remote gate required: test/host-conformance.test.ts C3 deletes the named scope.md instead of the first .md readdir lists (deterministic red on remote-gate VMs, #3479; the identical hunk ships in #3471, so the two merge cleanly).

Follow-ups (not in this PR)

Gate-ahead for trains; a ready-report validator and tree-equivalence check as generic policy (the READY receipt and verify --train already do this for gstack's check and stamp names; making the stamp file list and check names policy fields is the small change that lets another repo use them).

Two items GStack Minder raised after this head was pushed, left out so the pin stays frozen (filed on #3485): a KNOWN_WINDOWS_INCOMPATIBLE entry in scripts/lib/windows-curation.ts for test/pregate-remote-stamp-only.test.ts (#3486, which describe.skipIfs itself on win32 and left the curation entry to this file's owner; reason: it expects the Linux-host lanes verdict like test/pregate-remote.test.ts, on Windows that lane is a requires-remote obligation), and a dry-run merge check before train build's fill-rule wait, since a QUEUE_TRAIN_WAITING result today says nothing about conflicts.

Gate integrity

No threshold, rubric, trial count, case kind or judge prompt changed. A screen's verdict is read as evals.yml bound it; nothing here changes what a case must pass.

Test Coverage

Coverage: 63% value-weighted (19/30 paths, 11 gaps) at c75ec3a per the Step 7 audit; the /ship fixes added 1 test and extended 5 (dry-run writes nothing; forget on a rejected lease and in every in-flight state; post-merge commit statuses; dispatch-ci READY/screen ordering; watch --free-timeout; stack-tests helper-only PR and the _test suffix). Test value: 1 test written, 0 rejected by the authoring gate, 5 existing tests extended. Regression proof for the added and extended cases: fail at c75ec3a with the fix stashed · base control on origin/main: feature absent (base_unavailable) · pass after fix.

Remaining gaps (named, not filled): the artifact paging loop is exercised only on the single-page path; --dispatch-ci's fork, unreadable-PR and failed gh workflow run paths have no test; state-matrix cells without a test: ScreenOutcome 5/18, prune --stale 4/6, forget 2/4, watch 2/5, post-merge 2/6.

Tests ran: train-ops 78 · adjacent 405 (incl. doctor-components and host-conformance) · Windows-curation check 112 · typecheck count unavailable (tsc, 0 errors).

Pre-Landing Review

Three passes (the cap; crew rule 23), reviewer records bound at the reviewed tree c50ead11 (pass 3). Pass 1 reviewed the whole diff: core checklist, testing, maintainability, simplification and state-machines specialists, Red Team, QA smoke, and the native adversarial pass. 21 findings, 14 fixed in this PR (2 CRITICAL: the stale doctor-components render, which fails test/doctor-components.test.ts at c75ec3a, and the relaxed RH-15 assertion; plus stack-tests false red for helper-only PRs, dry-run persistence, notes-ref restore on a rejected lease, forget's in-flight states, post-merge commit statuses, dispatch-ci fail-closed and error text, screen-line ordering, watch --free-timeout, artifact paging, the vacuous worktree assertion, a dead clause, three stale doc passages). Pass 2 (fix range only): no blocking findings; one informational note on the TEST_FILE regex, fixed in 94f06fb. Pass 3 (that commit only): no findings. Pass 4 (delta only, after the GStack Minder-granted rule-19 merge of main b004c06 as fe019b3): the two conflict resolutions (CHANGELOG.md through mergeChangelogs, this entry still under ## [Unreleased], main's released sections intact; scripts/lib/windows-curation.ts keeping both appended entries, #3478's test/ship-queue-train-cost.test.ts first and this PR's test/ship-queue-train-ops.test.ts second, reason strings unchanged), the auto-merged shared files (doctor-components render, ship-policy.md, troubleshooting.md, result-codes-release.ts: all six new codes anchored once) and main↔PR module drift (#3478 verdict cost, #3480 pregate scratch field): no findings. Total: 4 passes. Blocking floor applied: a finding blocks only if it would fail a test, break production, or lose data or secrets.

Deferred and advisory (below the floor or outside this diff), filed as #3485: readiness admits only pull_request runs so a scratch-merge screen on a conflicting PR cannot route and ready --screen re-dispatches on each call; the screen verdict is not bound to the receipt's pr/head/merge SHA; --stack-tests runs PR test files with the coordinator's full environment and a symlinked node_modules; verify --post-merge can settle before every push workflow attached a check run; one RED screen pins a head red after main moves; re-dispatch bounds for incomplete or moved-main screens; train forget leaves the remote train/<nonce> branch; a fork's scratch merge is pushed before the fork refusal; a pending screen is seated as screened; artifact-derived strings printed verbatim; serial --dispatch-ci waits, clearObligation bypassing clearDecision, lane clears without a head check, a cancelled dispatch run blocking until a new push; reconcile_exit != 0 classified RED; ScreenChoice.branch unused; duplicated sleep helpers; TEST_FILE lacks bun's case-insensitivity (Foo.Test.ts skips the stack check, never a false red); a train that died in built/pushed/free-green/dispatch-* with its PRs merged elsewhere can be neither forgotten nor pruned; lib/result-codes-release.ts's QUEUE_SCREEN_STALE_REF summary and bin/gstack-ship-queue's top-level HELP (no forget; post-merge "check runs only") still carry the old wording; the CHANGELOG Changed bullet says "a real conflict only" where the Added bullet also names an unlistable remote.

Gate edits: 13 listed, 10 read, 1 finding — 0 kept, 1 restored, 0 open (at fe019b3 after the merge: 12 listed, 9 read, 0 findings; the host-conformance hunk is on main as #3471)

  • RH-15 test/ship-queue-train.test.ts:233 restored (exact stderr line count toBe(1) back from toBeGreaterThan(0), commit f07c2ea); tagged hunks RH-16 lib/ship-queue-screen.ts, RH-12 lib/ship-queue-stack-tests.ts, RH-16 lib/ship-queue-train-ready.ts read and judged not findings (the verdict reader and test runner are the feature, not relaxations).

Outside review: unavailable (Codex not installed on this machine; Greptile off for this repository) — listed as missing coverage, not as passed.

Exploratory QA

Step 9.2.1 smoke at c75ec3a, report-only, owned state GSTACK_STATE_ROOT=/tmp/qa-state, real repository read through gh only: 5 of 12 planned probes run, 5 pass (train --help names every new surface; verify --post-merge not-a-sha is a usage error; verify --post-merge 5755601… --timeout 90 ends QUEUE_TRAIN_PENDING with the same command as NEXT and 70 CHECK lines; train forget --receipt <unknown> --dry-run refuses QUEUE_PROOF_MISSING and writes nothing; train watch --train deadbeefdead refuses QUEUE_PROOF_MISSING). Not probed live, by isolation rule (each dispatches CI, pushes or deletes a branch, or writes the shared notes ref): ready --dispatch-ci, train build --dry-run --stack-tests, train prune --stale, ready --screen, train forget without --dry-run; the green path of verify --post-merge was not observed live. These are covered by the gh-shim tests. No defect reproduced. Probes were not rerun after the fixes; the fixed paths are covered by the extended tests above.

Design Review

No frontend files changed — design review skipped.

Eval Results

No prompt-related files changed — evals skipped. No paid eval was dispatched (thread cap); the Ubicloud free-tier lane is the only spend.

Greptile Review

Greptile triage: UNAVAILABLE (Greptile is not enabled for this repository; Steps 6.5 and 10 off).

Scope Drift

Scope Check: CLEAN

Plan Completion

Plan completion audit: not run — no plan is bound to this branch (no Plan: reference in the PR body, no matching docs/designs plan file).

Issues

Refs #3465

Verification Results

No Step 8.1 obligations (no bound plan). Step 16 at the frozen tree 0d696a55 (HEAD 63c4530): train-ops lane 78 pass / 0 fail; adjacent lane 403 pass / 0 fail (an earlier parallel run at 8f72d82 failed test/test-free-shards.test.ts because the concurrently running train-ops lane wrote an evidence log under the real HOME it watches — an environment interaction, rerun alone and green); bun run typecheck 0 errors; gate scan GATE_SUMMARY listed=13 eligible=10 inspected=10 unread=0; docs-candidate compare at the audit's post snapshot (8f72d82): no content changed, and the only commit since is the host-conformance test repair. CI at 63c4530 (the PR conflicts with main on CHANGELOG.md only, so GitHub runs no pull_request workflow; both workflows were dispatched by hand per docs/ship-policy.md): Windows Free Tests run 40367330518 success; Free Tests run 40367324107 attempt 1 red on free-suite (13)/(14) (Chromium launch crashes on the runner), attempt 2 shards green but the aggregate job red on artifact digest mismatch after a partial rerun; fresh Free Tests run 40369510393 success (all shards and the aggregate job). Remote free-tier gate (Ubicloud, us-east-a2): run 1 no VM (capacity), run 2 at 8f72d82 failed=2 (host-conformance C3 #3479, cookie-auth-verification flaky on the serial retry), run 3 at 63c4530 failed=5 on disjoint timing/PTY assertions (slow VM), run 4 at 63c4530 PREGATE_REMOTE: tree=0d696a55552c6d249180d7df5db151353d454387 tests=21487 failed=0 spent=0.07; four runs spent $0.37 total. At the merged head fe019b3 (tree 0afd9728): train-ops lane 78 pass / 0 fail; adjacent lane 405 pass / 0 fail; Windows-curation check (test/test-free-shards.test.ts test/setup-hook-syntax-gate.test.ts test/ubicloud-pregate-remote.test.ts under a private HOME and GSTACK_STATE_ROOT) 112 pass / 0 fail; bun run typecheck 0 errors; gate scan listed=12 eligible=9 inspected=9 unread=0. CI at fe019b3 (main stamped v1.91.256.0 minutes after the merge, so the PR conflicts on CHANGELOG.md only again and both workflows were dispatched by hand): Free Tests run 40400373328 success (all shards and the aggregate job); Windows Free Tests run 40400379884 success. Ubicloud run 5 at fe019b3: run 5 PREGATE_REMOTE_INFRA (VM setup could not resolve nodejs.org, $0.05, no tests ran), run 6 PREGATE_REMOTE: tree=0afd9728f32069070a0c15586f19dafc44332600 tests=21570 failed=0 spent=0.09; six runs spent $0.51 in total. Lanes cleared with runs 40400373328 and 40400379884 and run 6 (PREGATE_VERIFY: ok … current for tree 0afd9728f320). Pregate at 63c4530: preflight regen/strays/literals/timing/guards pass, secrets warn (5 MEDIUM PII patterns in test lines: run ids 40269992077/40275443393 and version strings 1.2.4.0 read as a phone number and IPv4 addresses; not PII), tests requires-remote, cleared by run 4 and by the three dispatched CI runs (PREGATE_VERIFY: ok … current for tree 0d696a55552c).

TODOS

No TODO items completed in this PR.

Documentation

Status: updated. Three factual doc fixes, no blockers; two source wording items from the first audit stay deferred and four more source/metadata observations are recorded as decisions.

Scope: base ab9a854, head 1062c0c (branch train-ops-screen-verdict), mode edit, audit docs-3484-re-163517-18ae19f0. Audited the 22 committed files and the 125-file doc inventory from the candidate (no staged, unstaged or untracked content). Read docs/ship-policy.md in full, the queue and train sections of docs/troubleshooting.md in full (its other sections were not read), the CHANGELOG [Unreleased] entry, and checked every changed contract against source: lib/ship-queue-screen.ts, ship-queue-post-merge.ts, ship-queue-train-forget.ts, ship-queue-train-watch.ts, ship-queue-dispatch-ci.ts, ship-queue-stack-tests.ts, the ready, train, record, github and cli diffs, bin/gstack-ship-queue and lib/result-codes-release.ts. A cross-doc search found no other doc that describes these commands (README, CLAUDE.md, CONTRIBUTING.md, PROJECT_STRUCTURE.md, TESTING_INTERNALS.md, unattended.md and the /ship pr-body template only mention the unchanged receipt checks).

Edits

  • docs/ship-policy.md: the "Screens are read from the run" paragraph now says a RED screen is not seated by train build (its NEXT: names the build without that PR), matching QUEUE_SCREEN_RED in admitSlots and the CHANGELOG.
  • docs/troubleshooting.md: QUEUE_PROOF_MISSING now lists the new train-command causes (train forget on a missing or live record, train watch on an unknown record, verify --pr <n> --screen on a run with no verdict, ready --screen when the scratch branch cannot be pushed).
  • docs/troubleshooting.md: POLICY_SOURCE_UNAVAILABLE now says ready under a train policy fetches origin/ first and refuses with this code when that fetch fails (the 1062c0c decision, previously undocumented there).

Documentation health

File Status
docs/ship-policy.md Updated (RED screen vs train build). Every other command claim verified against source: prune --stale scope, forget live-state list, watch timeouts, post-merge statuses and full SHA, dispatch-ci, stack-tests rule and default command, INCOMPLETE/PENDING/UNKNOWN verdicts, scratch merge.
docs/troubleshooting.md Updated (two entries). QUEUE_SCREEN_RED, QUEUE_SCREEN_NOT_RUN, QUEUE_TRAIN_STACK_RED, QUEUE_POST_MERGE_RED and QUEUE_SCREEN_STALE_REF match source; anchors match bin/gstack-doctor-components.sh (test/doctor-components.test.ts: 6 pass).
CHANGELOG.md Reviewed, not edited (protected). Matches the shipped behavior; see decisions.
bin/gstack-doctor-components.sh Generated output, not edited; freshness test passes.
README.md, CLAUDE.md, CONTRIBUTING.md, other docs No contradiction found.

Coverage debt (reported, not filled): every new command and code has reference coverage (ship-policy.md and troubleshooting.md), and ship-policy.md carries the how-to procedure for each. There is no tutorial or explanation page for screen verdicts, train watch, forget, post-merge or stack tests; run /document-generate only if wanted. Diagram drift: none; the changed docs hold no ASCII or Mermaid diagrams naming renamed entities.

Test plan

  • bun test test/ship-queue-train-ops.test.ts test/ship-queue-train.test.ts test/gstack-ship-queue.test.ts test/bun-entry-isolation.test.ts test/spawnsync-timeout-tripwire.test.ts: 78 pass, 0 fail (at 63c4530)
  • bun test test/ship-queue-train-logic.test.ts test/harness-version.test.ts test/parity-suite.test.ts test/changelog-merge-damage.test.ts test/troubleshooting-anchors.test.ts test/module-size-ratchet.test.ts test/test-free-shards.test.ts test/windows-free-selection-autoplan-guard.test.ts test/windows-native-workflows.test.ts test/doctor-components.test.ts test/host-conformance.test.ts: 403 pass, 0 fail (at 63c4530)
  • bun run typecheck: 0 errors (at 63c4530)
  • gstack-pregate run --allow-repo-commands --base main at 63c4530, then the remote free tier (Ubicloud) and the dispatched free-tests.yml / windows-free-tests.yml runs clearing the requires-remote lanes (see the receipt block)

🤖 Generated with Claude Code

Open in Capy

… --stale, verify --post-merge, ready --dispatch-ci, --stack-tests

Operating merge trains on 2026-10-26 showed the gaps this closes. A dispatched
screen's verdict is read from the run's gate-binding and report-verdict artifacts
(lib/ship-queue-screen.ts) and recorded in the READY receipt: a RED screen refuses
ready under either choice and is never re-dispatched at the same merge SHA
(QUEUE_SCREEN_RED); a run that concluded success with no slice is NOT-RUN
(QUEUE_SCREEN_NOT_RUN), never followed, and counted as unscreened by train build.
When refs/pull/<n>/merge lags or is missing the screen is planned on a scratch merge
pushed as screen/<pr>-<head12> (#3465); QUEUE_SCREEN_STALE_REF means a real
conflict only. train watch --train is the resumable follow command; train prune
--stale settles a merging/green train whose PRs all merged or closed elsewhere;
train forget removes one record with an exact lease on refs/notes/gstack-trains;
verify --post-merge <sha> watches main's push workflows until they settle;
ready --dispatch-ci <wf,…> dispatches the free workflows on a conflicting PR,
waits, and clears the matching requires-remote pregate lanes with the run URLs;
train build --dry-run --stack-tests runs each PR's new test files on its integrated
prefix before anything is dispatched (QUEUE_TRAIN_STACK_RED).

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

trunk-io Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

😎 This pull request was merged.

garrytan and others added 11 commits October 26, 2026 16:12
…t codes

The committed Bash render was four case lines behind its generator, so
test/doctor-components.test.ts failed at c75ec3a. Output of
bun run gen:skill-docs; no hand edits.

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

RH-15: toBeGreaterThan(0) after a toMatch is vacuous; the refusal is one
deterministic line, so toBe(1) holds and is restored.

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

Three passages still described the pre-scratch-merge refusal; they now
match screenMerge: a missing or lagging refs/pull/<n>/merge gets a
screen/<pr>-<head12> scratch merge, and QUEUE_SCREEN_STALE_REF is a real
conflict with the base only.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
r.detail === 'pass' can never hold when r.ok is false; the dry-run test
now checks git worktree list instead of a state-dir name that was never
written.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…h errors, keep screen: after READY

dispatchCi now uses prInfo (a fork head or an unreadable PR is refused
instead of dispatched), reads gh's error text when the workflow run call
fails, and calls runsAt once. The screen: line is inserted after the
READY line instead of at index 1, which with --dispatch-ci put it before
READY and after the first CI_DISPATCH line.

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

settled and red were computed from check runs only while ci.green also
counted commit statuses, so a pending status was called settled and a
failed status was reported as 'red: ' with no name. Pending statuses now
keep the verdict pending; a red status with no failed check run is named
as such. The fixture gains a statuses knob to drive both.

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

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…use every in-flight state

forgetNotes removed the note locally before the leased push, so a
rejected lease left a local notes ref without the note that the next
plain persist pushed without a lease. It now snapshots the ref and
restores it on rejection, reporting failed removals separately. forget
refused only merging/gate-pending/free-pending; built, pushed,
free-green, dispatch-unknown and dispatch-absent are in flight too and
are refused the same way. CHANGELOG and ship-policy say so.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
admitSlots recorded a verdict that differed from the receipt and pushed
refs/notes/gstack-trains before the dryRun branch printed 'nothing
written, pushed or dispatched'. It now takes dryRun and skips the
persist, matching trainReady's guard.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
TEST_FILE matched every .ts under test/, so a PR whose only added file
was a helper or fixture ran 'bun test test/helpers/x.ts', which exits 1
(the filter matches no test file) and was reported QUEUE_TRAIN_STACK_RED.
A bare positional is also a substring filter that picks up unrelated
files. The rule is now bun's own (.test, _test_, .spec, _spec_ in the
name) and each file is passed as ./<path>, which bun treats as the exact
file. The fixture PR 3 now adds a helper and is still 'no new test
files'.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
One page of 100 artifacts can miss gate-binding/report-verdict on a
broad or rerun screen (three artifacts per slice plus reruns), which
read as 'bound no verdict' and bought a fresh screen. newestArtifact now
follows page= until a short page.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
garrytan and others added 4 commits October 26, 2026 16:25
Bun discovers a file whose name ends in .test, _test, .spec or _spec
before the extension. The previous rule missed the underscore forms
(b_test.ts, e_spec.ts), so a PR adding only such files got no stack
check, and it matched names bun ignores. PR 1 in the fixture now adds
test/pr-1_test.ts to prove the underscore form is run.

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
Step 14.5 documentation audit: the stack-tests naming rule is bun's own
(.test, _test, .spec, _spec); prune --stale deletes every merged or
closed PR's screen/<pr>-* branch; verify --post-merge takes the full SHA
and counts commit statuses; train watch --free-timeout and
ready --dispatch-ci --timeout defaults; PENDING/UNKNOWN/INCOMPLETE screen
verdicts; QUEUE_SCREEN_STALE_REF's Meaning no longer contradicts its Fix;
one sentence each for the new QUEUE_NOT_READY, QUEUE_TRAIN_UNTRUSTED and
QUEUE_TRAIN_PENDING triggers.

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

Three details the documentation audit found wrong against the code; the
entry stays under [Unreleased] (stamp-at-merge).

Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
…CE_UNAVAILABLE name the train-command causes

Step 14.5 re-audit: ship-policy.md says train build does not seat a RED
screen and its NEXT names the build without that PR; troubleshooting.md
lists train forget, train watch, verify --screen and the scratch-branch
push under QUEUE_PROOF_MISSING, and the origin/<base> fetch under
POLICY_SOURCE_UNAVAILABLE.

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

A test repair the remote gate requires, not a review finding. The case
deleted the first .md readdirSync listed under gstack-qa/sections, and
on the remote-gate VM's ext4 that was a file setup --status does not
count, so the case was deterministically red there (#3479) while green
locally and on Actions. The same one-line change ships in #3471
(fd468eb); this copy carries no CHANGELOG line so the two merge cleanly.

Refs #3479

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>

# Conflicts:
#	CHANGELOG.md
#	scripts/lib/windows-curation.ts
garrytan and others added 2 commits October 27, 2026 02:36
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>

# Conflicts:
#	CHANGELOG.md
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
@github-actions github-actions Bot changed the title feat(ship-queue): screens read from the run, train watch/forget/prune --stale, verify --post-merge, ready --dispatch-ci, --stack-tests v1.91.263.0 feat(ship-queue): screens read from the run, train watch/forget/prune --stale, verify --post-merge, ready --dispatch-ci, --stack-tests Oct 27, 2026
@capy-ai
capy-ai Bot merged commit f375b87 into main Oct 27, 2026
63 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant