Repository navigation
Commit 65767d2
fix(pm): measure the runtime stderr noise floor in the dispatch-gates self-test (#17977)
Fixes #17765
## What was wrong
The self-test battery in `scripts/pm/dispatch-gates.mjs` described a
spawned child's stderr **stream** in two places while meaning what
**this module** prints. Every such child inherits the run's
`NODE_OPTIONS`, and under `--use-env-proxy` node writes two lines before
any user code runs:
```
(node:NNN) [UNDICI-EHPA] Warning: EnvHttpProxyAgent is experimental, expect them to change at any time.
(Use `node --trace-warnings ...` to show where the warning was created)
```
That flag is not exotic: it is what `check-required-contexts.mjs
--verify-required-set` prints as its own remedy, citing #9642. So a seat
that follows one gate's advice is punished by another — and the
punishing gate is one nobody runs casually, because this self-test runs
past the container's ten-minute foreground cap.
Both assertions were true statements about a real property, and both
reds were entirely spurious:
| case | assertion before |
|:--|:--|
| entry guard (the card's, at `:22373` on the merge base) |
`(imported.stderr ?? '').trim() === ''` |
| end-to-end CLI banner (found by running the full self-test under the
flag) | `(plainRun.stderr ?? '').split('\n')[0].includes('gate list
derived from the tree of')` |
The second one is a **deviation from the dispatched file face**,
declared here: it is the same defect class, in the same file, in the
same gate family, and the card's own acceptance ("the self-test reaches
its verdict with exit 0 under `--use-env-proxy`") is unreachable while
it stands. No other file is touched.
## The fix — one measured floor, not a pattern
For each probe an identical child that does **nothing** runs with the
same argv shape, cwd and inherited env. Whatever **it** prints is what
this runtime prints unprompted; anything the probe prints beyond that
came from the module. The single normalisation is node's pid, which
differs between any two children by construction.
- `stderrBeyondRuntime(probe, baseline)` — what the probe wrote
**beyond** the floor (the entry-guard case).
- `moduleStderrLines(probe, baseline)` — the probe's lines with an exact
leading match of the floor removed, so a case can still speak about
**which** line the module wrote first (the banner case).
Both live once, above the end-to-end CLI block, and both instances call
them — one explanation and one subtraction in the file rather than two
copies.
⛔ **Not a shape filter.** The `(Use ...)` hint line carries no `[CODE]
Warning:` at all, so a filter written to node's warning shape leaves it
behind — the case stays red — while swallowing a line the module wrote
in that same shape. Triage measured this on the card: `grep -c
"Warning:"` over that stderr answers 1, not 2.
⛔ **No shared helper across files, and
`scripts/check-cross-package-test-inputs.mjs` is untouched** — that half
is another domain's.
## Controls
Without controls, "prints nothing of its own" and "prints nothing that
is ever looked at" are the same green. Four were added:
- NEGATIVE: importing a module that writes nothing is clean under THIS
runtime.
- POSITIVE: one line the imported module writes to stderr still reds.
- POSITIVE: a line **disguised** as a node warning still reds — this is
what separates a measured baseline from a shape filter, which would
swallow it.
- CONTROL: the floor child writes no line of its own, so the banner
subtraction cannot be answering an empty list.
## Acceptance readings
Direct-drive probe of each case's own consumer shape, flag as the only
variable. `OLD` is the assertion on the merge base `400167ab`, `NEW` is
the assertion on this head.
**Entry-guard case** — a child importing this module, argv `--self-test
--tier packages/spec/src/index.ts`:
```
NODE_OPTIONS=--max-old-space-size=4096
status 0, stdout CONSUMER-REACHED, probe stderr "" OLD true NEW true
NODE_OPTIONS=--use-env-proxy --max-old-space-size=4096
status 0, stdout CONSUMER-REACHED
probe stderr: (node:30022) [UNDICI-EHPA] Warning: ... + hint line
baseline stderr: (node:30030) [UNDICI-EHPA] Warning: ... + hint line
beyond-runtime text: "" OLD false NEW true
```
**Banner case** — the real CLI child, argv `--tier
packages/spec/src/index.ts`:
```
NODE_OPTIONS=--max-old-space-size=4096
baseline stderr lines: [] OLD true NEW true
NODE_OPTIONS=--use-env-proxy --max-old-space-size=4096
baseline stderr lines: 2 (the UNDICI-EHPA warning + the hint line)
module first line: "dispatch-gates: gate list derived from the tree of ..."
control: floor-vs-floor 0 lines, probe 7 lines OLD false NEW true
```
**Full self-test, detached** — `pnpm check:pm-dispatch-gates` runs past
the ten-minute foreground cap, so it is run detached and polled to its
verdict line. No full run was taken on the merge base (the merge-base
readings above are the direct-drive probes). The run taken with the
entry-guard repair alone, at `e53c83c3` under `--use-env-proxy`, ended:
```
✗ and it opens with the banner, on the FIRST line of stderr
✗ dispatch-gates self-test: 1 of 1681 case(s) failed.
```
which is how the second instance was found. On this head under the same
flag:
```
✓ and it opens with the banner, on the FIRST stderr line THIS module writes
✓ CONTROL: the floor child writes no stderr line of its own — the subtraction above cannot be vacuous
✓ imported, this module prints nothing of its own on either stream
✓ NEGATIVE CONTROL: importing a module that writes nothing is clean under THIS runtime
✓ POSITIVE CONTROL: one line the imported module writes to stderr still reds
✓ POSITIVE CONTROL: an imported line DISGUISED as a node warning still reds
✓ dispatch-gates self-test: 1682 cases pass.
```
`pnpm check:pm-dispatch-gates` exit **0** at `12a89168` (merged with
`origin/main` `45b90b6a`), under `NODE_OPTIONS=--use-env-proxy
--max-old-space-size=4096`. Case count 1682 = the 1678 the card
measured, plus the four controls this PR adds.
## Gates
Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` (no paths; change set taken from git, 1
path, against merge base `45b90b6a9`). The first derivation was taken on
a stale tree and warned so; `origin/main` was merged in and the list
re-derived on `12a89168` — identical, 31 commands. All 31 run, every
exit code recorded, reconciled:
```
✓ dispatch-gates --ran: 31 derived famil(ies) accounted for — 31 run,
0 NOT-MEASURED (a DERIVED zero — all 31 recorded an exit code and none of them is 3).
```
Outside that link, and not claimed here: the 52 artifact-roster
families, the 11 wide-population families, the 14 pending-changeset
families (none apply — this PR carries no changeset by design), the
path-scheduled CI job and the always-runs tail. Repo-wide `pnpm lint` is
CI's run, not this one.
## Acceptance notes
- **Should the two files share one helper?** The card asks this and
triage adopted it as a must-answer. Measured answer: **not yet.** The
population of "literally empty child stderr" assertions in the repo is
exactly two — this file and the sibling — and a `git grep` over
`scripts/**` finds no third: every other child-stderr assertion there is
a targeted `.includes()` on content the child itself wrote, which
runtime noise cannot falsify. The part that could be shared is four
lines of pure text subtraction; the part that must **not** be shared is
the spawn, whose argv shape has to match each file's real probe by
construction. A cross-file import would also add an edge into this
tool's own derivation, whose module-body literals are inherited as watch
hints by anything importing it. The trigger that changes the answer is a
third copy; filing that is for whoever meets one.
- Noted, not filed: nothing else. Successor for the shared-helper
question if a third instance appears: the `domain:devx` seat that owns
`scripts/check-cross-package-test-inputs.mjs`.
- `skip-changeset`: `scripts/pm/**` ships in no package's `files[]`, so
this diff publishes nothing.
- Hold #14290 declares `Restart-touch: scripts/pm/dispatch-gates.mjs`;
its re-measurement after this lands is the devx seat's, not this PR's.
#17797 names this file on the docblock-prose face and is untouched here.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01DAcomhvR9kKizeYgg89Vo8)_
---
_Generated by [Claude Code](https://claude.ai/code)_
---------
Co-authored-by: claude <noreply@anthropic.com>1 parent 4dab2bc commit 65767d2
1 file changed
Lines changed: 132 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
22190 | 22190 | | |
22191 | 22191 | | |
22192 | 22192 | | |
| 22193 | + | |
| 22194 | + | |
| 22195 | + | |
| 22196 | + | |
| 22197 | + | |
| 22198 | + | |
| 22199 | + | |
| 22200 | + | |
| 22201 | + | |
| 22202 | + | |
| 22203 | + | |
| 22204 | + | |
| 22205 | + | |
| 22206 | + | |
| 22207 | + | |
| 22208 | + | |
| 22209 | + | |
| 22210 | + | |
| 22211 | + | |
| 22212 | + | |
| 22213 | + | |
| 22214 | + | |
| 22215 | + | |
| 22216 | + | |
| 22217 | + | |
| 22218 | + | |
| 22219 | + | |
| 22220 | + | |
| 22221 | + | |
| 22222 | + | |
| 22223 | + | |
| 22224 | + | |
| 22225 | + | |
| 22226 | + | |
| 22227 | + | |
| 22228 | + | |
| 22229 | + | |
| 22230 | + | |
| 22231 | + | |
| 22232 | + | |
| 22233 | + | |
| 22234 | + | |
| 22235 | + | |
| 22236 | + | |
| 22237 | + | |
| 22238 | + | |
| 22239 | + | |
| 22240 | + | |
| 22241 | + | |
| 22242 | + | |
| 22243 | + | |
| 22244 | + | |
| 22245 | + | |
| 22246 | + | |
| 22247 | + | |
| 22248 | + | |
| 22249 | + | |
| 22250 | + | |
| 22251 | + | |
| 22252 | + | |
| 22253 | + | |
| 22254 | + | |
| 22255 | + | |
| 22256 | + | |
| 22257 | + | |
22193 | 22258 | | |
22194 | 22259 | | |
22195 | | - | |
| 22260 | + | |
| 22261 | + | |
| 22262 | + | |
| 22263 | + | |
| 22264 | + | |
| 22265 | + | |
| 22266 | + | |
| 22267 | + | |
| 22268 | + | |
| 22269 | + | |
| 22270 | + | |
22196 | 22271 | | |
22197 | 22272 | | |
22198 | 22273 | | |
| |||
22362 | 22437 | | |
22363 | 22438 | | |
22364 | 22439 | | |
22365 | | - | |
22366 | | - | |
22367 | | - | |
22368 | | - | |
| 22440 | + | |
| 22441 | + | |
| 22442 | + | |
| 22443 | + | |
| 22444 | + | |
| 22445 | + | |
| 22446 | + | |
| 22447 | + | |
| 22448 | + | |
22369 | 22449 | | |
22370 | 22450 | | |
22371 | 22451 | | |
22372 | 22452 | | |
22373 | | - | |
| 22453 | + | |
| 22454 | + | |
| 22455 | + | |
| 22456 | + | |
| 22457 | + | |
| 22458 | + | |
| 22459 | + | |
| 22460 | + | |
| 22461 | + | |
| 22462 | + | |
| 22463 | + | |
| 22464 | + | |
| 22465 | + | |
| 22466 | + | |
| 22467 | + | |
| 22468 | + | |
| 22469 | + | |
| 22470 | + | |
| 22471 | + | |
| 22472 | + | |
| 22473 | + | |
| 22474 | + | |
| 22475 | + | |
| 22476 | + | |
| 22477 | + | |
| 22478 | + | |
| 22479 | + | |
| 22480 | + | |
| 22481 | + | |
| 22482 | + | |
| 22483 | + | |
| 22484 | + | |
| 22485 | + | |
| 22486 | + | |
| 22487 | + | |
| 22488 | + | |
| 22489 | + | |
| 22490 | + | |
| 22491 | + | |
| 22492 | + | |
| 22493 | + | |
| 22494 | + | |
| 22495 | + | |
| 22496 | + | |
| 22497 | + | |
| 22498 | + | |
| 22499 | + | |
22374 | 22500 | | |
22375 | 22501 | | |
22376 | 22502 | | |
| |||
0 commit comments