Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions scripts/pm/check-dispatch-gates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,31 @@
*
* node scripts/pm/check-dispatch-gates.mjs # runs the tool's --self-test
*
* ## On an agent container, run this DETACHED (#14281)
*
* `package.json`'s `check:pm-dispatch-gates` script is exactly this file —
* `node scripts/pm/check-dispatch-gates.mjs` — and JSON holds no comments, so
* the instruction a script comment would carry lands here instead, in the
* header of the file that script runs. The battery this file spawns re-runs
* `dispatch-gates.mjs`'s own CLI as a child process many times (see the "Why
* the self-test ONLY" section below), and on an agent container that makes a
* full run longer than the container's foreground command cap, which SIGTERMs
* a run past it — this file's `result.signal` branch further down reports
* exactly that kill, but only once the process has already been cut off. Do
* not run `pnpm check:pm-dispatch-gates` (or `dispatch-gates.mjs --self-test`
* directly) in the foreground there. Detach it and poll the log instead:
*
* nohup pnpm check:pm-dispatch-gates > /tmp/pm-dispatch-gates.log 2>&1 &
*
* then tail the log file until it stops growing. `dispatch-gates.mjs`'s
* `selfTest()` streams each case's `✓`/`✗` line as that case is decided, so a
* run killed mid-battery — by this cap, or by anything else — leaves every
* case decided before the kill in the log, readable as a partial result. The
* measured runtime and case count are not repeated here — a reading belongs
* to a named commit, not to a header (the convention the next section states
* for this same file) — see #14281 for the reading that motivated this
* section.
*
* ## Why the gate exists
*
* scripts/pm/dispatch-gates.mjs derives the "local gates for this card" line of
Expand Down
40 changes: 37 additions & 3 deletions scripts/pm/dispatch-gates.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,26 @@
* node scripts/pm/dispatch-gates.mjs --repo <owner>/<name> ... # refuse unless this checkout IS that repo
* node scripts/pm/dispatch-gates.mjs --self-test
*
* ## Run --self-test DETACHED on an agent container (#14281)
*
* The battery re-spawns this tool's own CLI as a child process many times —
* deliberate (see `check-dispatch-gates.mjs`'s header for why a self-test this
* size is not fixture-only) — and on an agent container that makes the full
* run longer than the container's foreground command cap, which SIGTERMs a
* run past it. Do not run `--self-test` (or `pnpm check:pm-dispatch-gates`,
* which is exactly that flag) in the foreground there. Detach it and poll the
* log instead:
*
* nohup pnpm check:pm-dispatch-gates > /tmp/pm-dispatch-gates.log 2>&1 &
*
* then tail the log file until it stops growing. Each case's `✓`/`✗` line
* prints the moment that case is decided, so a run killed mid-battery — by
* this cap, or by anything else — still leaves every case decided before the
* kill in the log, readable as a partial result rather than a silent zero. The
* measured runtime and case count are not repeated here — they move with the
* tree and belong to a named commit, not to this header (see #14281 for the
* reading that motivated this section).
*
* ## Harvest the machine-readable modes, never this prose (#13462)
*
* The matched block renders in TWO spellings — `pnpm check:NAME` and
Expand Down Expand Up @@ -10032,7 +10052,19 @@ export function bannerLines({ identity, paths = [], drift = null }) {

function selfTest() {
const cases = [];
const t = (name, cond) => cases.push([name, cond]);
// Stream the verdict the moment it is decided (#14281) rather than only at
// the tail: every `t()` call evaluates `cond` eagerly at the call site, so
// the line below is not a preview of the tail loop's output — it prints the
// SAME verdict, just however many calls earlier than a buffered run did. A
// run that dies mid-battery (the container's foreground cap SIGTERMs a run
// past ~10 minutes; see check-dispatch-gates.mjs's header for the detached
// workaround) used to leave zero case lines; now the log already carries
// every case decided before the kill. `cases` still collects every entry —
// the tail's `failed`/`length` summary reads it unchanged.
const t = (name, cond) => {
cases.push([name, cond]);
console.log(` ${cond ? '✓' : '✗'} ${name}`);
};

const wf = [
'jobs:',
Expand Down Expand Up @@ -16829,10 +16861,12 @@ function selfTest() {
}
}

// The per-case line already printed inside `t()`, streamed as each verdict
// was decided (#14281) — this tail is the summary only, unchanged in shape
// and wording from the pre-streaming version.
let failed = 0;
for (const [name, cond] of cases) {
for (const [, cond] of cases) {
if (!cond) failed++;
console.log(` ${cond ? '✓' : '✗'} ${name}`);
}
if (failed) {
console.error(`✗ dispatch-gates self-test: ${failed} of ${cases.length} case(s) failed.`);
Expand Down
Loading