Skip to content

docs(cli-test): repair the dead VITEST counterfactual in three serve spawner comments - #12504

Merged
os-litant merged 1 commit into
mainfrom
claude/issue-12498-dead-vitest-counterfactual
Aug 26, 2026
Merged

docs(cli-test): repair the dead VITEST counterfactual in three serve spawner comments#12504
os-litant merged 1 commit into
mainfrom
claude/issue-12498-dead-vitest-counterfactual

Conversation

@os-litant

Copy link
Copy Markdown
Collaborator

Fixes#12498

Comment prose only. Verified mechanically: transpiling each file before and after with removeComments emits byte-identical JS (7970/7970, 9080/9080, 8786/8786 bytes), and no added line carries a @ts-*, eslint-*, /// or *-ignore directive — so nothing executable moved.

What was false

The three serve spawners that supply OS_SECRET_KEY each carried the same six-line comment — byte-identical across all three, proven rather than eyeballed (md5sum of the block is d8cd78d887531891f0f2f9a1e4b84d98 in every file):

Explicit, not minted: with VITEST no longer inherited (#11267), local-crypto-provider.ts's detectMode answers development for this child instead of test

detectMode has read NODE_ENV and nothing else since #11448 (a58eac3e2, "select crypto posture from the deployment signal, never the test runner", committed 2026-08-23 — sha and date re-derived here with git log -1 a58eac3e2, not copied from the card). The live function sits at packages/services/service-settings/src/local-crypto-provider.ts:185 on origin/maine966c5926 — a line number read off this tree.

So the attribution is dead in both directions: stripping VITEST no longer selects development, and the testdevelopment flip the wording predicted is unreachable, because a leaked VITEST would no longer produce test posture either.

What survives, untouched

The conclusion. OS_SECRET_KEY: E2E_SECRET_KEY stays in all three, and the sentence explaining it is kept and strengthened rather than weakened: development posture persists a minted key to $HOME/.objectstack/dev-crypto-key, so an explicit key is what keeps these boots out of the runner's home directory and out of a cross-test ordering coupling.

Measured on this tree, not argued

A runtime probe drove LocalCryptoProvider on this worktree's source (each case with its own fresh OS_HOME):

caseenvkey file writtenkeySource
ANODE_ENV=developmentyesgenerated-file
BVITEST=true, NODE_ENV absentyesgenerated-file
CVITEST=true, NODE_ENV=developmentyesgenerated-file
DNODE_ENV=development + OS_SECRET_KEYnoenv:OS_SECRET_KEY
ENODE_ENV=testnoephemeral

B is the dead counterfactual measured directly: a leaked VITEST with NODE_ENV absent still answers development, not test. E is the anti-vacuity control — the probe can produce the test/ephemeral outcome the deleted arm used to force, so B's answer is a measurement rather than a blind instrument. D is the conclusion this comment exists for.

Each file's spawn shape measured separately

Per the ruling on PR #12495 — which repaired this class in two sibling files and needed different repairs for each — the three were measured, not assumed identical:

fileentrypointargvNODE_ENV on the child
serve-mcp-stdio-answers.e2e.test.tsbin/run.js (line 84)serve -p PORT --devundefined, no call site overrides
serve-mcp-capability-collision.e2e.test.tsbin/run.js (line 85)serve -p PORT --devundefined, no call site overrides
serve-stdio-stdout-purity.e2e.test.tsbin/run.js (line 81)serve -p PORT --devundefined, no call site overrides

They are identical — and that is the measurement, not an inspection. Every boot(...) call site in the three files was enumerated; none passes NODE_ENV through the ...env spread.

This is also where they differ from the sibling repaired in PR #12495: that file's children run bin/run-dev.js, which pins process.env.NODE_ENV = 'development' before argv is parsed. These three run bin/run.js, which pins no NODE_ENV at all (the whole 46-line file was read; the only NODE_ENV assignment anywhere under packages/cli/bin is run-dev.js:28). With the variable unset, serve.ts assigns process.env.NODE_ENV = 'development' in-process on the flags.dev branch, well before runtime.start(), and resolveDataKey reads a live process.env when it resolves the key — so the posture is development by the route the NODE_ENV entry twelve lines below already documents.

Census, re-run unnarrowed

Swept all 6,912 tracked files, not just packages/cli/test. Exactly three sites carry the dead counterfactual and they are the three in this PR — no fourth site, fenced or otherwise. Every other place that quotes the deleted arm already does so correctly in the past tense and was left alone: local-crypto-provider.ts (read-only here), crypto-posture-deployment-signal.test.ts, helpers/serve-process.ts, scripts/check-runner-env-posture.mjs, .github/workflows/lint.yml, and the .changeset for the deletion. artifact-pinned-boot.e2e.test.ts cites #11267 next to its own OS_SECRET_KEY, but for the TEST/better-auth reason only and under NODE_ENV: 'production' — not this class.

Instrument controls, because a zero is only worth what the instrument's "no" is worth: a control term present in all three target files and not a substring of anything searched (OS_DISABLE_CONSOLE) returns 14 hits across 13 files; an absent token returns zero and exit 1. The instrument says both yes and no over the same population.

Gates

Run on 541d9b77b (git rev-parse --short HEAD at the final commit), derived with node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack rather than from a hand-written list. Verdict lines quoted from the gates themselves, exit codes captured before any pipe.

Green: check:cli-test-child-env ("35 spawner source(s) among 95 … no new bulk process.env copy reaches a spawned child"), check:cross-package-test-inputs, check:objectql-double-limit, check:page-declaration-shape, check:published-files, check:slot-lookup, check:test-source-alias, check:type-check-coverage, check:type-source-resolution, check:query-options-erasure, check:engine-double-contract, check:where-matcher, check:comment-mask-adoption, check:nul-bytes ("scanned 6905 text file(s) … no raw ASCII control bytes"), check-ci-filter-parity, check-plugin-teardown-shape, docs-audit/check-affected-docs, docs-audit/check-drift-comment. Repo-wide pnpm lint (eslint . --no-inline-config) also runs clean in 58s — no narrowing claimed, the whole tree was linted.

NOT MEASURED, declared rather than implied:check:i18n, check:i18n-coverage and check:type-check-debt all stop at PREREQUISITE NOT MET on an unbuilt worktree (the first two need the workspace CLI built; the third refuses --re-measure without 56 dependencies' dist/*.d.ts). Those refusals are not failures and say nothing about this tree. CI builds the closure and runs all three. Note also that packages/cli/tsconfig.json includes only src, so the package's own typecheck reads none of these three files — a green there would have been a true sentence about nothing, and is not claimed.

Deliberately not touched

packages/services/service-settings/src/local-crypto-provider.ts (read-only; its header quotes the deleted arm correctly, in the past tense), packages/cli/test/serve-node-env-production-default.e2e.test.ts and serve-process-child-env.e2e.test.ts (held by open PR #12495), and packages/cli/vitest.config.ts (held by open PR #12494).

skip-changeset: tests only, nothing published changes.


Generated by Claude Code

…spawners
The three `packages/cli/test` serve spawners that supply `OS_SECRET_KEY`
explicitly credited the `VITEST` strip (#11267) for putting the child's crypto
layer in `development` posture "instead of `test`". That attribution is dead:
`detectMode` has read `NODE_ENV` and nothing else since #11448 (`a58eac3e2`,
merged 2026-08-23), so stripping `VITEST` cannot move crypto posture in either
direction any more.
The conclusion the comment supports is untouched and still correct — supply the
key, because development posture PERSISTS a minted key to
`$HOME/.objectstack/dev-crypto-key`. Only the reason is repaired: these three
spawn `bin/run.js` (which pins no `NODE_ENV`) with the variable UNSET, so
`serve.ts` assigns `process.env.NODE_ENV = 'development'` in-process for
`--dev` before `runtime.start()`.
Comment prose only; no executable line changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UjujZN219uFzBhSYfMykCd
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing 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.

What this run could not see
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 76c18be8ad56400c85cde381e63c7755bbd6153apackageMentionDocs.

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/sskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants

@os-litant@claude