Uh oh!
There was an error while loading. Please reload this page.
test(cli): route 14 e2e spawners through childEnv(), 18 -> 3 on the child-env ratchet - #11653
Conversation
…hild-env ratchet The `check:cli-test-child-env` gate (#11341) baselined 18 bulk `process.env` copies reaching spawned children under `packages/cli/test/**`. This is the cheap-batch slice of that burn-down: 15 references across 14 files, each `{ ...process.env, X }` replaced with `childEnv({ X })`, the choke point from #11267 that strips the vitest worker family (`TEST`, `VITEST`, `VITEST_*`) before the overrides are applied. `scripts/cli-test-child-env.baseline.json` drops the 14 repaired keys in the same commit -- the ratchet fails on a stale ceiling too, so leaving 18 there would silently license 15 new leaks. Left in the ledger deliberately: the three `serve-*` files the card flags for the crypto/auth re-check (`$HOME/.objectstack/dev-crypto-key`, the `OS_SECRET_KEY` precedent), which need a second slice. The two `DELIBERATE` sites are untouched. Every one of the 14 files was run individually after the edit -- 147 tests, all green -- so no child in this slice turned out to depend on an inherited runner variable. Part of #11596 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019siH5jDmk5hrayvfyojUqR
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. |
os-zhuang
commented
Aug 24, 2026
ACCEPT — PM seat review ( |
Uh oh!
There was an error while loading. Please reload this page.
Part of #11596 — the cheap-batch slice of the
check:cli-test-child-envburn-down.Deliberately not a closing reference: the card stays open for the three
serve-*filesthis slice leaves alone.
What changed
15 bulk references across 14 files under
packages/cli/test/**stop building their spawnedchild's environment out of the whole of
process.env:childEnv()(from #11267, inpackages/cli/test/helpers/serve-process.ts) copies theenvironment minus the vitest worker family —
TEST,VITEST,VITEST_*— and then appliesthe overrides, so nothing about being a test worker arrives in the child by accident.
scripts/cli-test-child-env.baseline.jsondrops the 14 repaired keys in this same commit:the ratchet fails on a stale ceiling too, so leaving 18 there would silently license 15 new
leaks.
The only behaviour change in this diff is what the child process inherits. No assertion,
helper or fixture was touched, and the import added to each file is the one line
import { childEnv } from './helpers/serve-process.js';.The ledger, before and after
node scripts/check-cli-test-child-env.mjs --list, which is the source of truth rather thanany hand-maintained worklist, agreed exactly with the slice boundary before the edit
(18 bulk copies in 17 files) and reports 3 in 3 files after it.
The gate's own verdict line at
b475dab3:Anti-vacuity: the leaks are gone, not moved
git grep -n '\.\.\.process\.env' packages/cli/test/after the edit, with comment and proselines dropped, leaves exactly four code sites:
serve-app-anchored-optional-import.e2e.test.ts:160serve-app-runtime-hooks.e2e.test.ts:84serve-host-fallback-base.e2e.test.ts:187serve-process-child-env.e2e.test.ts:114(leakedEnv)DELIBERATE— the pin leg that keeps the pre-repair recipe executableThe second
DELIBERATEsite, thechildEnvchoke point itself, spells its bulk readObject.entries(process.env)(helpers/serve-process.ts:154), which this literal-spreadgrep does not match — the gate's
--listreports it, and it is untouched.A zero-hit grep certifies nothing on its own, so the same search machinery was run for a term
known to be present:
git grep -c 'childEnv(' packages/cli/test/returns 21 files, includingall 14 touched here.
Why no changeset
Test-only, under
packages/cli/test/**, plus a repo-root ratchet artifact underscripts/.Neither ships. Measured rather than assumed:
@objectstack/clideclaresfiles: ["dist","README.md","CHANGELOG.md"], andnpm pack --dry-runon the package yields433 files of which 0 are under
test/and 0 match*.e2e.test.*. Nothinguser-visible changes, so the PR carries
skip-changeset.Verification
Gate union derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackand re-derived on the final committed diff — both derivations name an identical family
set. Everything below ran under
scripts/pm/os-verify-lock.shagainst the final commitb475dab3, on a tree built first withpnpm exec turbo run build --filter="./packages/*" --filter="./packages/*/*"(70/70 taskssuccessful) — several of these refuse outright on an unbuilt closure, and a refusal is not a
pass.
All 20 families green, none printing
PREREQUISITE NOT METor "Nothing was checked":check:cli-test-child-env·check:cross-package-test-inputs·check:entry-guard·check:i18n·check:i18n-coverage·check:parse-guard·check:pnpm-filter-targets·check:published-files·check:slot-lookup·check:test-source-alias·check:type-check-coverage·check:type-check-debt·check:type-source-resolution·check:query-options-erasure·check:engine-double-contract·check:where-matcher·check:nul-bytes·check-ci-filter-parity.mjs·check-plugin-teardown-shape.mjs·docs-audit/check-affected-docs.mjscheck:type-check-debtgenuinely re-measured rather than refusing:Each touched file, run individually after the edit
This is the step the card asks for rather than a sed pass: a file that stops claiming to be a
vitest worker may change what its child does, and
serve-node-env-production-defaultis therecorded precedent for exactly that. Every one of the 14 was therefore run on its own. All 14
passed, 147 tests, so no file had to be dropped from the slice — none of these children
turned out to depend on an inherited runner variable.
cloud-login-json-ndjsongenerate-agent-retiredgenerate-skillhook-body-build-reachinit-created-files-summaryinvocation-loudnessjson-stdout-puritylogin-json-ndjsonlogin-json-noninteractivemigrate-exit-codemigrate-metaqa-empty-glob-exit-codevalidate-json-warning-parityvalidate-top-level-strictEach ran as its own
vitest rununder the same header, e.g.The full
packages/clisuiteSharded, because the package's own config header measures it around 495s and the foreground
budget here is tighter than that. Both shards green — 168 files, 1908 tests:
pnpm --filter @objectstack/cli typecheck→tsc --noEmit, exit 0.Lint, narrowed and shown to lose nothing
The repo-wide
pnpm lintscan belongs to CI. The local run was narrowed to the changed paths,with the three things that make a narrowing a measurement rather than a skip:
ESLint's
isPathIgnoredputs 14 in population and excludes exactly one —scripts/cli-test-child-env.baseline.json, which is JSON.errorCount: 0,warningCount: 0.eslint.config.mjsstates in its own header that thisrepo "never enables type-aware linting (no
parserOptions.project, no typed@typescript-eslintrules) for ANY file", so nothing in this diff can move the verdict ona file it does not touch.
Fences observed
Slice boundary held. The three
serve-*files keep their baseline entries and were notopened. burn down the
cli-test-child-envbaseline: 18 spawned children in 17packages/cli/testfiles still built from the whole ofprocess.env#11596 stays open for them.The gate was not widened.finding: 8
packages/cli/testspawners pass noenvat all, so the child inherits the vitest worker environment verbatim — the purer form of #11341's leak, and the new gate is silent on it #11595 — spawners that pass noenvoption at all — is adifferent defect form with a different repair, and this PR does not address it. Two of the
14 files do carry such a call site beside the spread that was repaired, and both were
left exactly as they were:
cloud-login-json-ndjson.e2e.test.ts:311execFileSync('script', ['--version'], { stdio: 'ignore' })— abeforeAllavailability probe forscript(1)login-json-ndjson.e2e.test.ts:299Both inherit
process.envverbatim, which is finding: 8packages/cli/testspawners pass noenvat all, so the child inherits the vitest worker environment verbatim — the purer form of #11341's leak, and the new gate is silent on it #11595's form in its purest shape. Neither isin this ledger, the gate is silent on both, and touching them would mean widening the gate
inside a shrink-only burn-down.
Shrink only. No count was raised, no key added, and the two
DELIBERATEsites areuntouched.
Serial check re-confirmed on today's board.test(cli): three e2e spawners name the entrypoint they actually reach #11462 touches three
serve-mcp-*/serve-stdio-*files that already callchildEnv, and feat(cli): i18n coverage + extract gain the flow/screen bucket #11615 adds one new non-spawningtest file. Neither intersects these 14.
Generated by Claude Code
Generated by Claude Code