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] os lint --json --eval --generator UNRESOLVABLE_PATH leaks esbuild's diagnostic to stderr — the sibling pin one file over asserts the opposite property holds #16358
os lint --json --eval --generator UNRESOLVABLE_PATH writes 54 bytes to stderr — esbuild's own diagnostic, [ERROR] Could not resolve ... — while the run's --json face is otherwise well-formed on stdout.
A --json invocation is a machine face. Anything on stderr is a human-channel emission the caller did not ask for, and here it is an internal bundler's diagnostic, not an ObjectStack refusal.
⭐ Why this is a contradiction and not just a leak
One file over, packages/cli/test/lint-eval-generator-load-envelope.e2e.test.tspins the opposite property:
expect(run.stderr).toBe('')
with the comment "A --json run leaks nothing to the human channel".
That pin is green, and it is honest about what it measures: it drives a module that exists and throws at import. The unresolvable-path branch is a different door into the same failure, it is uncovered, and it leaks.
⇒ Same command, same face, two answers — with a pin asserting the one that holds. The pin's comment states a property of the --json face as a whole; the code only delivers it on one of the two branches that reach the same catch.
Where it comes from
The leak is esbuild's logger writing directly, inside the bundleRequire call that loads the generator. The [ERROR] Could not resolve text is emitted during bundling, before any ObjectStack code sees a throw — so the surrounding try/catch, which does produce a correct one-key {error} JSON document on stdout, never gets the chance to suppress it.
Scope note — why it was not repaired where it was found
Measured during #16161's round, and deliberately not fixed in PR #16341. The repair is silencing esbuild's logger inside the bundleRequire call, and the correct form of that (a logLevel, a custom logger, or a captured stderr) is not settled by existing evidence in this repo — so it fails the bounded-in-place exemption and would have been an unargued rider on an unrelated diff.
Provenance and what a taker must re-run
⚠️ Measured by the implementer at branch point 4a1a3b0c254 / head 26bc91fc8e7. Not independently re-driven by the filing seat — recorded as the implementer's reading. Whoever takes this should re-run rather than inherit:
the 54-byte stderr on the unresolvable-path branch, under --json;
that lint-eval-generator-load-envelope.e2e.test.ts is green at the same head while (1) holds — the two together are the finding.
Dedupe
Run with a known-hit control in the same session, because a bare zero from this channel is not evidence of absence.
⭐ A channel property worth recording: the control "Failed to load generator message text quality wording" returned total_count: 0 even though that exact phrase appears in the body of cards this same search returns under other phrasings. A zero from one phrasing of this semantic search is not a zero from the area — only a control sharing the failing query's vocabulary can settle that.
Grading
⛔ Filed unlabelled. domain:* and type grading are triage's, not this seat's. The implementer's suggestion, relayed as a suggestion only: domain:cli, bug.
Held on #16161 (comment 5559999365) while the dedupe channel was down; filed now that a positive control fires in the same session.
The defect
os lint --json --eval --generator UNRESOLVABLE_PATHwrites 54 bytes to stderr — esbuild's own diagnostic,[ERROR] Could not resolve ...— while the run's--jsonface is otherwise well-formed on stdout.A
--jsoninvocation is a machine face. Anything on stderr is a human-channel emission the caller did not ask for, and here it is an internal bundler's diagnostic, not an ObjectStack refusal.⭐ Why this is a contradiction and not just a leak
One file over,
packages/cli/test/lint-eval-generator-load-envelope.e2e.test.tspins the opposite property:with the comment "A --json run leaks nothing to the human channel".
That pin is green, and it is honest about what it measures: it drives a module that exists and throws at import. The unresolvable-path branch is a different door into the same failure, it is uncovered, and it leaks.
⇒ Same command, same face, two answers — with a pin asserting the one that holds. The pin's comment states a property of the
--jsonface as a whole; the code only delivers it on one of the two branches that reach the same catch.Where it comes from
The leak is esbuild's logger writing directly, inside the
bundleRequirecall that loads the generator. The[ERROR] Could not resolvetext is emitted during bundling, before any ObjectStack code sees a throw — so the surrounding try/catch, which does produce a correct one-key{error}JSON document on stdout, never gets the chance to suppress it.Scope note — why it was not repaired where it was found
Measured during #16161's round, and deliberately not fixed in PR #16341. The repair is silencing esbuild's logger inside the
bundleRequirecall, and the correct form of that (alogLevel, a custom logger, or a captured stderr) is not settled by existing evidence in this repo — so it fails the bounded-in-place exemption and would have been an unargued rider on an unrelated diff.Provenance and what a taker must re-run
4a1a3b0c254/ head26bc91fc8e7. Not independently re-driven by the filing seat — recorded as the implementer's reading. Whoever takes this should re-run rather than inherit:--json;lint-eval-generator-load-envelope.e2e.test.tsis green at the same head while (1) holds — the two together are the finding.Dedupe
Run with a known-hit control in the same session, because a bare zero from this channel is not evidence of absence.
os lint --eval --json's generator-load failure emits a bare{error}— nocode, nohttpStatus— while the same command's project-lint catch-all emits the full ADR-0112 envelope #15549 (closed): same command, same face, but about the payload's shape (a bare{error}with nocode/httpStatus), not about a stderr emission. Distinct populations —os lint --eval --json's generator-load failure emits a bare{error}— nocode, nohttpStatus— while the same command's project-lint catch-all emits the full ADR-0112 envelope #15549 is about what stdout carries, this is about stderr carrying anything at all.os lint --eval --generator ""runs the offline eval silently — indistinguishable from not passing the flag at all #16161,os lint --eval --json's generator-load failure emits a bare{error}— nocode, nohttpStatus— while the same command's project-lint catch-all emits the full ADR-0112 envelope #15549, [finding, STATIC ONLY]os lint --generator's description says "Requires --eval." and nothing enforces it — the flag is referenced only insiderunEval, whichrun()reaches only when--evalis set #15550, [finding]os lint --eval --jsonhas no JSON face for an uncaught throw —runEvalis dispatched above thetry, so the error escapes as oclif's human output #14974, packages/lint's three validators score an unparseable source CLEAN — the defect is the unread parseDiagnostics, not the try/catch #10653), proving the query shape reaches this area.⇒ No duplicate.
⭐ A channel property worth recording: the control "Failed to load generator message text quality wording" returned
total_count: 0even though that exact phrase appears in the body of cards this same search returns under other phrasings. A zero from one phrasing of this semantic search is not a zero from the area — only a control sharing the failing query's vocabulary can settle that.Grading
⛔ Filed unlabelled.
domain:*and type grading are triage's, not this seat's. The implementer's suggestion, relayed as a suggestion only:domain:cli,bug.Held on #16161 (comment 5559999365) while the dedupe channel was down; filed now that a positive control fires in the same session.