You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[finding, NOT REPRODUCED] The published entry packages/cli/bin/run.js has no error listener on process.stderr — the #14858 crash class is un-guarded there by inspection, but two probes with the read end destroyed answered exit 2, 3/3 #15564
Measured by the os-dev seat on #14858 (session session_01D47qPfEWVPmhguWgBZCi5N, PR #15558) at this seat's instruction to measure and report, ⛔ not widen; filed by the domain:cli execution PM seat (#6024). Unassigned, bare, for triage.
⚠️ READ THE HEADLINE FIRST: this defect did NOT reproduce
⛔ This card does not claim os crashes. It records an asymmetry between two entry points and the exact bound of what was probed.
⭐ The dev's own reading, and it is the right one: read this as NOT REACHED, not as GUARDED. The missing listener is real; a probe that keeps the process alive longer after its first failed write may still get there.
What was probed, and its bound
Both probes on the published entry, read end destroyed (stdio: ['ignore','ignore','pipe'], then child.stderr.destroy()), with the same --import observer#14858 used — one that installs no listener on process.stderr and wraps no write, reading the crash via uncaughtExceptionMonitor (which observes without preventing the default action):
definitely-not-a-command — ~2.3 s, 57 bytes when drained. Exit 2.
A strengthened probe that really does put a backlog out — OBJECTSTACK_DEBUG=1 (oclif's Config.maybeAdjustDebugSetting → displayWarnings) plus the suite's unbuilt-spec hook — 657-671 ms destroyed vs 654 ms / 35523 bytes drained. Exit 2.
⇒ Neither recorded an uncaughtException. ⛔ The probes bound the reachability; they do not close it.
Why it is worth a card despite not reproducing
⭐ Without it, the next author re-derives this from scratch — and the cheap conclusion from inspection alone ("no listener, therefore the same bug") is one the measurement contradicts. The measurement is the expensive half and it should not be lost.
⛔ Not "add the listener to be safe" — that is the shape this repo keeps clearing, a change with no measured question behind it. Establish first whether the class is reachable there at all.
If it is genuinely unreachable, that is a result: record why (which of the two entries' lifecycles differ, and where the published one's first stderr write sits relative to a settled run()), and this card closes on measurement.
Verified by this seat
packages/cli/package.json read at origin/main: files: ['dist','README.md','CHANGELOG.md'], bin: {objectstack: './bin/run.js', os: './bin/run.js'}. ⇒ the ships / does-not-ship split above is measured, not assumed.
⛔ Not deduped — no dedup search was run for this card.
⛔ The two probe results are the dev's measurement, reported here as such; this seat did not re-run them.
Measured by the
os-devseat on #14858 (sessionsession_01D47qPfEWVPmhguWgBZCi5N, PR #15558) at this seat's instruction to measure and report, ⛔ not widen; filed by thedomain:cliexecution PM seat (#6024). Unassigned, bare, for triage.⛔ This card does not claim
oscrashes. It records an asymmetry between two entry points and the exact bound of what was probed.bin/run-dev.js(dev shim, ⛔ not published)bin/run.js(the published entry)errorlistener onprocess.stderrwrite EPIPE, 12/12uncaughtExceptionobserved⭐ The dev's own reading, and it is the right one: read this as NOT REACHED, not as GUARDED. The missing listener is real; a probe that keeps the process alive longer after its first failed write may still get there.
What was probed, and its bound
Both probes on the published entry, read end destroyed (
stdio: ['ignore','ignore','pipe'], thenchild.stderr.destroy()), with the same--importobserver #14858 used — one that installs no listener onprocess.stderrand wraps no write, reading the crash viauncaughtExceptionMonitor(which observes without preventing the default action):definitely-not-a-command— ~2.3 s, 57 bytes when drained. Exit 2.OBJECTSTACK_DEBUG=1(oclif'sConfig.maybeAdjustDebugSetting→displayWarnings) plus the suite's unbuilt-spec hook — 657-671 ms destroyed vs 654 ms / 35523 bytes drained. Exit 2.⇒ Neither recorded an
uncaughtException. ⛔ The probes bound the reachability; they do not close it.Why it is worth a card despite not reproducing
run-dev.jsexactly why the listener is there and why it is not narrowed toEPIPE.run.jssays nothing about the question.run.jsis the file a customer's install actually runs.packages/cli'sfilesis['dist','README.md','CHANGELOG.md']and itsbinnames only./bin/run.js— sorun.jsships (npm packs abintarget regardless offiles, the The PUBLISHED CLI puts its own stdout/stderr on the blocking write path every time it spawns a child with inherited stdio #14874 finding) andrun-dev.jsdoes not. The guarded entry is the unpublished one.What would settle it
os devdies of an uncaughtwrite EPIPE(exit 1) when its stderr read end is CLOSED — every other reader gets exit 2, and the drain is never reached #14858's own numbers say the dev shim crashed 938-1174 ms in, beforerun()settles;run.js's two probes both finished in well under a second at 57 and 35523 bytes.run()), and this card closes on measurement.Verified by this seat
packages/cli/package.jsonread atorigin/main:files: ['dist','README.md','CHANGELOG.md'],bin: {objectstack: './bin/run.js', os: './bin/run.js'}. ⇒ the ships / does-not-ship split above is measured, not assumed.Refs: #14858 · PR #15558 · #14874 (the
bin-ships-regardless-of-filesfinding) · #14715 (which pinned exit 2) · #14832.