Surfaced while implementing #11317. Filed unassigned rather than folded in: that
card's declared surface is three test files, and the guard below is a new
mechanism, not a truthfulness repair.
The self-cancelling pair
A packages/cli test that spawns bin/run.js is asking for the built CLI. A
test that puts development or test in the child's NODE_ENV is asking
oclif to resolve commands from src/. Doing both is a no-op with a false
comment attached, and nothing in the repo says a word.
@oclif/core@4.13.3 skips its TypeScript path lookup only when isProd(),
which lib/util/util.js:66 defines as a negated membership test — a
leading logical-NOT applied to
['development', 'test'].includes(process.env.NODE_ENV ?? '').
Measured directly against @oclif/core's own Config.load() on
packages/cli, with packages/cli/dist present, reading back the root
plugin's resolved commandsDir:
child NODE_ENV | resolved commandsDir |
|---|
| unset | packages/cli/dist/commands |
development | packages/cli/src/commands |
test | packages/cli/src/commands |
production | packages/cli/dist/commands |
Note that vitest exports NODE_ENV=test on its worker, and childEnv()
deliberately does not strip it (its header says why), so a spawner that names
bin/run.js and simply says nothing about NODE_ENV lands in the rerouted leg
by inheritance — the failure does not require anyone to set the variable on
purpose.
Why a guard rather than a sweep
#11317 removed the three files that had the pair. The tree is clean today: the
only remaining bin/run.js spawners are invocation-loudness.e2e.test.ts and
serve-node-env-production-default.e2e.test.ts, and the latter reaches dist/
precisely because it leaves NODE_ENV unset. Nothing keeps the next author
from reintroducing the pair, and the reintroduced version is silent in both
directions: the suite stays green, and the comment claiming the built entry
stays plausible.
This is the same shape as #11341 one property over — a spawned child's env
quietly changing what is under test, where the sweep is easy and the mechanism
is the part that lasts. If both land, they likely want to be one walk over the
same population of spawner files rather than two.
Not obvious which way it should read
The guard's polarity depends on a ruling that is open on #11317: whether these
suites should reach src/ (spawn bin/run-dev.js) or dist/ (spawn
bin/run.js with NODE_ENV unset). Either way the guard is the same
assertion — the two properties must not contradict each other — but which
combination is the recommended one differs, and so does the failure text.
Blocked-by: #11317
Related
Generated by Claude Code
Surfaced while implementing #11317. Filed unassigned rather than folded in: that
card's declared surface is three test files, and the guard below is a new
mechanism, not a truthfulness repair.
The self-cancelling pair
A
packages/clitest that spawnsbin/run.jsis asking for the built CLI. Atest that puts
developmentortestin the child'sNODE_ENVis askingoclif to resolve commands from
src/. Doing both is a no-op with a falsecomment attached, and nothing in the repo says a word.
@oclif/core@4.13.3skips its TypeScript path lookup only whenisProd(),which
lib/util/util.js:66defines as a negated membership test — aleading logical-NOT applied to
['development', 'test'].includes(process.env.NODE_ENV ?? '').Measured directly against
@oclif/core's ownConfig.load()onpackages/cli, withpackages/cli/distpresent, reading back the rootplugin's resolved
commandsDir:NODE_ENVcommandsDirpackages/cli/dist/commandsdevelopmentpackages/cli/src/commandstestpackages/cli/src/commandsproductionpackages/cli/dist/commandsNote that vitest exports
NODE_ENV=teston its worker, andchildEnv()deliberately does not strip it (its header says why), so a spawner that names
bin/run.jsand simply says nothing aboutNODE_ENVlands in the rerouted legby inheritance — the failure does not require anyone to set the variable on
purpose.
Why a guard rather than a sweep
#11317 removed the three files that had the pair. The tree is clean today: the
only remaining
bin/run.jsspawners areinvocation-loudness.e2e.test.tsandserve-node-env-production-default.e2e.test.ts, and the latter reachesdist/precisely because it leaves
NODE_ENVunset. Nothing keeps the next authorfrom reintroducing the pair, and the reintroduced version is silent in both
directions: the suite stays green, and the comment claiming the built entry
stays plausible.
This is the same shape as #11341 one property over — a spawned child's env
quietly changing what is under test, where the sweep is easy and the mechanism
is the part that lasts. If both land, they likely want to be one walk over the
same population of spawner files rather than two.
Not obvious which way it should read
The guard's polarity depends on a ruling that is open on #11317: whether these
suites should reach
src/(spawnbin/run-dev.js) ordist/(spawnbin/run.jswithNODE_ENVunset). Either way the guard is the sameassertion — the two properties must not contradict each other — but which
combination is the recommended one differs, and so does the failure text.
Blocked-by: #11317
Related
bin/run.jsas "the SHIPPED entrypoint" never reachdist/— oclif's ts-path reroutes them tosrc/under NODE_ENV=test|development #11317 — where the pair was found and removed from three files.packages/cli/testspawner from re-introducing the bare...process.envchild env #11341 / finding: #11341's bare-...process.envworklist is two files short, and one of them spawns a realos serve#11441 — the sibling gate over the same spawner population.NODE_ENV !== 'production'still open in a real production deployment that never sets NODE_ENV (os servedoes not force it,os startdoes) #11113 — added the only file that genuinely consumesdist/, andchanged
turbo.jsonso@objectstack/cli#testnow depends on@objectstack/cli#build.Generated by Claude Code