Repository navigation
test(cli): load the os doctor suites' oclif Config without the command scan (#23181 slice 8) - #25633
Conversation
Eight in-process `os doctor` suites called `Doctor.run(argv, { root })`,
which makes oclif build the command manifest by importing every compiled
command (no oclif.manifest.json ships): 6.6 s of each file's first test.
Doctor never reads `this.config`, so a shared helper loads the package's
own Config with only `oclif.commands` dropped; hooks still load.
Claude-Session: https://claude.ai/code/session_013fXj9gbwakFbBp5U9x4EjF
Co-authored-by: Claude <noreply@anthropic.com>
`tsconfig.json`'s rootDir is `src`, so a `src/` test cannot import from `test/helpers/`. `src/**/__tests__/**` is the place the build already excludes (as `src/utils/__tests__/server-body.ts`). Claude-Session: https://claude.ai/code/session_013fXj9gbwakFbBp5U9x4EjF Co-authored-by: Claude <noreply@anthropic.com>
`environments.test.ts` walks every `.ts` under `src/commands` as a command source, so a helper there registered a phantom `__tests__ doctor-config` id in its model. `src/utils/__tests__/` already holds the package's other non-test helper and is excluded from the build the same way. Claude-Session: https://claude.ai/code/session_013fXj9gbwakFbBp5U9x4EjF Co-authored-by: Claude <noreply@anthropic.com>
📓 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. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
席位核对ACCEPT · Checklist conclusions (read on GitHub, not from the report):
Deviations accepted: as reported. The one local unit failure ( Carried to slice 9: the remaining doctor time is the three real tool probes ( Landing: Generated by Claude Code |
Part of #23181 (slice 8). The card is a series and stays open.
Clause-②: no
Metadata-protocol: none
Rows this PR addresses
Eight
@objectstack/cliunit-tier rows from the card's table, theos doctorin-process suites. They share one cause, which this PR removes:src/commands/doctor-ledger-read-failure.test.tssrc/commands/doctor-ledger-posture-independence.test.tssrc/commands/doctor-unexamined-spec-tree.test.tssrc/commands/doctor-node-env-default.test.tssrc/commands/doctor-deprecation-hint-commands.test.tssrc/commands/doctor-config-load-cause.test.tssrc/commands/doctor-ledger-dir-authority.test.tssrc/commands/doctor-config-env-overlay.test.tsThe pin is the card's: the next landed refresh's per-file list no longer names a "done" row. The "projected" rows rest on a ratio applied to the card's old CI reading, so CI decides them, not this table.
The cause and the fix
Each suite drives the real command with
Doctor.run(argv, { root: CLI_ROOT }). Given a root, oclif loads a freshConfig.@objectstack/cliships nooclif.manifest.json, so that load builds the command manifest by importing every compiled command underdist/commands(73 commands). Measured in-process: 6.6 s for thatConfig.load, paid by each file's first test.doctor.tsnever readsthis.config, so the command list is pure overhead for these suites.packages/cli/src/utils/__tests__/doctor-config.ts(new, 36 lines) loads oneConfigper file from the package's ownpackage.jsonwith onlyoclif.commandsdropped. Hooks still load (thepreparseseparator strip is present:hooks=["preparse"]), and the load takes 36 ms. The eight files passawait doctorConfig()instead of{ root: CLI_ROOT }(12 call sites) and drop the now-unusedCLI_ROOT/HERE/fileURLToPathlines.src/**/__tests__/, the pathtsconfig.build.jsonalready excludes, next tosrc/utils/__tests__/server-body.ts. It is not undertest/helpers/, becausetsconfig.json'srootDir: srcrefuses asrc/test importing fromtest/(TS6059, measured). It is not undersrc/commands/, becauseenvironments.test.tswalks every.tsthere as a command source and would have modelled a phantom__tests__ doctor-configcommand id (measured: the unit tier went from 4812 to 4813 tests).Why these rows (A2: win per changed line)
One 36-line helper plus 12 one-line call-site swaps (+57 / −48) removes 6.6 s from each of eight rows and brings four under the line. Rows looked at and not taken:
@objectstack/cliintegration files at 90 to 301 s (data-commands.absent-database,stack-conversion-record-door,package-install-local-*, ...). Each spawns the real CLI per fixture. Their fix is either a per-file restructuring or thetest-budget:header method (slice 6), and that method needs a CI reading this container could not obtain (see A1).test/scaffold-emission-typechecks.test.ts(unit, 33.3 s): a type-graph compile, atest-budgetclass candidate, so the same CI-reading constraint applies.migrate-meta-*andexplain-rule-idunit rows (10.2 to 18.1 s): not measured in this slice.runtime,client,verify,restandcreate-objectstack.A1: the work list
PR #25409 (
97be89bb3b), the newest landed refresh, carries no per-file list: its--diffrefused (exit 1) onpackages/cli/src/commands/migrate/audit-mail-bodies.archive.integration.test.ts:2(test-budget: 85, off the 10 s grid).origin/mainate649c2d9already reads90there, so the next refresh can list files. Reproducing the diff locally was not possible: thetest-core-timings-N-of-6captures are retained one day, so only 2 of the window's 8 runs still had them, and this container's proxy refuses the artifact blob host (HTTP 403). So the rows above come from the card's table, each re-measured one649c2d9(every one still read over 10 s locally before the change).What the remaining time is (for the next slice)
Measured per warm
Doctor.run(about 0.6 to 0.9 s): the three real tool probespnpm -v(0.4 to 0.9 s under vitest's PATH),tsc -v(0.1 to 0.4 s) andgit --version(about 15 ms). On top of that, each file's first run pays the lazy@objectstack/cloud-connectionimport (4.3 s). The files still near or over the line are the ones with 13 to 18 runs. Stubbing the probes is a separate decision, because the suites then stop seeing the real probe rows. It is not taken here.Proof
bash scripts/pm/os-verify-lock.sh -c 'cd packages/cli && pnpm exec vitest run --project unit --maxWorkers=2 --reporter=json --outputFile=FILE' + the 8 files. Per-file = the json reporter'sendTime − startTime(the per-file module line CI reports; it sums to vitest'steststotal). "Before" restored the 8 files frome649c2d9(tree only), then restored fromHEAD(git diff HEADempty afterwards). Shared box: absolute seconds are box readings, so ratios are the comparable figure.doctor.tsand every otherDoctor.runsuite (doctor-env-provenance,doctor-tenancy-posture-report) are untouched.pnpm --filter @objectstack/cli typecheck(tsc +check:test-typecheckOK): exit 0 atf0e74dd1d. The--noEmitprogram includes the helper; the build program (tsconfig.build.json --listFilesOnly, 1318 files,doctor.tsamong them) includes nothing under__tests__.f0e74dd1d: 326/327 files, 4811/4812 tests. The one failure issrc/utils/boot-preparation-parity.test.ts, a 5 s vitest timeout under load (9.15 s) in a file this diff does not touch. Re-run alone: 37/37, exit 0. The two earlier full runs passed it (327/327). The integration tier is declared to CI: the diff touches no integration file and no spawn entry.node scripts/pm/dispatch-gates.mjs --commandsatf0e74dd1d: 58 commands, all exit 0.--ran: "58 derived, 58 run, 0 NOT-MEASURED, 0 UNRUN".eslint --no-inline-config packages/cli: exit 0.pnpm lint(eslint . --no-inline-config, the whole repo): exit 0 atf0e74dd1d.Changeset
skip-changeset: nothing published changes. Every changed file is a*.test.tsor sits undersrc/**/__tests__/, whichtsconfig.build.jsonexcludes, so no changed file reachesdist/(files: ["dist", ...]).Acceptance notes
@objectstack/cliships nooclif.manifest.json, so anyConfig.loadfrom the package root imports every command. Whether the publishedosbinary pays the same cost per invocation was NOT MEASURED here. This is an observation only.src/utils/boot-preparation-parity.test.ts"every SERVE_ONLY entry is still used by serve.ts" ran 9.15 s against vitest's 5 s default in one contended full-tier run. Observed once.🤖 Generated with Claude Code
https://claude.ai/code/session_013fXj9gbwakFbBp5U9x4EjF
Generated by Claude Code