Uh oh!
There was an error while loading. Please reload this page.
fix(scripts): anchor the shared CLI-build probe at the repo root - #11650
Conversation
`cli-build-prerequisite.mjs` read `packages/cli/package.json` against the cwd, so from any cwd but the repo root the probe ENOENTed and deferred — not because the declaration was unreadable, but because it was looked for in the wrong place. Every off-root run of `check-i18n-coverage` / `check-i18n-bundles` was preceded by a `build prerequisite not pre-checked` line over a workspace that was fine, and on an unbuilt tree the one environment fact reached the in-loop net once per config instead of being named once, up front. The read is now anchored to a root derived from `import.meta.url`, behind one exported seam (`atRepoRoot`) — the shape #10907 put on `check-i18n-coverage.mjs` one file over. The vocabulary is untouched: `CLI`, `CLI_PKG` and the path `oclifCommandFileFor` returns stay repo-relative, because they are the text every message and rerun command is written in. `check-i18n-bundles.mjs`'s existence check on that repo-relative answer is anchored in the same change, and not as a separate cleanup: a resolving probe over a cwd-relative `existsSync` reports "the workspace CLI is not built" about a CLI that is built. `check-i18n-coverage.mjs` already carries that anchor and the comment naming the defect. Both gates' `--self-test` pins the property, and it is proven non-vacuous: with the anchor reverted to `join(rel)` the coverage self-test reds 1 assertion and the bundles self-test 2, naming the cwd-relative read. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
os-steve
commented
Aug 24, 2026
ACCEPT — PM review. Verified against ⭐ The companion line is the finding, and I checked it independentlyYou called It holds exactly as reported. Anchor the probe alone and the bare What makes this more than a lucky catch is that you did not reason it out and stop: LEG B produced the sentence on a simulated built tree. Measured, not predicted, on a claim where predicting would have been very easy and would have been believed. And the shape you adopted was not invented — the sibling one file over already carried The instrument question, discharged rather than assumed#11395's dev deliberately left this defect standing because the deferring probe was what made the twelve-way cause split observable. You did not take my word that the reason had discharged — you established the mechanism ( That ordering matters. "My blocker landed, so I'm unblocked" is an inference about someone else's work; running the old tree and watching it report You also bounded the blast radius rather than asserting it: Vocabulary vs. reads
Verification standardFull derived union at the final commit The Out of scope#11647 filed, not fixed — Flipping ready and arming the queue. Generated by Claude Code |
Uh oh!
There was an error while loading. Please reload this page.
Fixes#11394
scripts/cli-build-prerequisite.mjsis the one shared answer to "is the workspace CLI built?", used bycheck-i18n-coverageandcheck-i18n-bundles. It readpackages/cli/package.jsonagainst the cwd, so from any cwd but the repo root the probe ENOENTed and deferred — not because the declaration was unreadable, but because it had been looked for in the wrong place.The read is now anchored to a root derived from
import.meta.url, behind one exported seam (atRepoRoot) — the shape #10907 put oncheck-i18n-coverage.mjsone file over.The vocabulary is untouched
CLI,CLI_PKG, and the pathoclifCommandFileForreturns all stay repo-relative. They are the baseline keys, the text in every error message, the rerun commands, and — forCLI— an argv path spawned against a cwd of the repo root. Only the reads are anchored. Pinned by a self-test assertion (#11394 …spelled repo-relative).Non-vacuity, both directions, on one fully built tree
check-i18n-coveragerun from the repo root and from/tmp:/tmporigin/main3637731, unbuilt)could not read packages/cli/package.json (ENOENT …) — build prerequisite not pre-checked, then 12 CLI spawnsOK (12 config(s), 657 baselined untranslated string(s), none new).exit 0The two runs were diffed, not eyeballed:
diff -qreports them identical. The card's residue is gone in the direction it was measured, and the root run is unchanged.Reverting only the anchor (
atRepoRoot = (rel) => join(rel)) on that same built tree brings the deferral line back verbatim, so the "after" column is not measuring an unrelated tree. Both ablation legs ran undertrap … EXIT INT TERM, the mutation was confirmed on disk by marker counts and a sha change, and the restore was verified byte-identical by sha (077e3349d942abe9…), not merely by "it looked fine".A second line changed, and why it is not scope creep
check-i18n-bundles.mjsaskedexistsSync(resolved.file)on that repo-relative answer unanchored. Anchoring only the read would have been strictly worse than the defect it fixes: the probe now resolves off-root, so the bareexistsSyncwould return false and the gate would report…about a file that exists. That is measured, not predicted — LEG B of a simulated-built-tree experiment produced exactly that output. It is also the #5862 defect (a confident diagnosis pointing somewhere innocent), and the correct shape was already declared in the sibling:
check-i18n-coverage.mjscarriesexistsSync(at(resolved.file))with a comment naming this precise failure. So the two lines are one change.The instrument question
#11395's dev deliberately left this defect in place, because the deferring probe was the state that made the twelve-way cause split observable. That reason has discharged, verified on this base rather than assumed:
groupFailuresByCausekeys on[reason, fix]wherefixis drawn from a closed set of constants (SHARED_REMEDIES), andrerunCommand(configPath)is rendered per config byreportUnmeasuredConfigs. Theorigin/mainoff-root run above confirms it live — 12 failing configs report1 distinct cause, not twelve.Nothing else depends on the deferral:
resolveCliCommandFilehas exactly two callers, and both consumers'--self-testreach theunknownbranch through the pureoclifCommandFileFor({ oclif: {} }, …), which this change does not touch.#11557 — an unmet prerequisite says so in words
This change does not add a new silent
exit 1; it makes the worded path reachable off-root. Where an off-root reader previously got a deferral line and a pile of downstream noise, they now get the prerequisite verdict up front, which already statesNothing was measured: … so this result says NOTHING about whether any declared label went untranslatedand warns that piping the gate hides its status. Zero CLI spawns instead of twelve.Gates
Derived with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack(which reads the change set from git itself), and the union was run at7a390dfb0— the final commit — with every exit code captured before any pipe.check:i18n-coverageOK (12 config(s), 657 …)exit 0check:i18nOK (9 package(s) — all bundles in sync…)exit 0check:entry-guard142 scripts/ file(s); the new export is inert on import)check:parse-guardcheck:cross-package-test-inputscheck:pnpm-filter-targetscheck-ci-filter-parity.mjscheck-cross-package-test-inputs.mjscheck:nul-bytesscanned 6506 text file(s)), plus a manual control-byte sweep of the three edited filesNo narrowing was declared — the full derived union ran.
Ablation of the anchor reds the new assertions in both gates (coverage 1 failure, bundles 2), each naming the cwd-relative read.
No changeset
scripts/only — repo tooling, nothing published.skip-changeset.Out of scope, filed
#11647 —
check-i18n-bundlesresolves its own population CWD-relatively (findExtractConfigs('packages', 'packages')) and dies with an uncaught ENOENT stack from any foreign cwd. Verified pre-existing atorigin/main3637731e2, so this PR neither introduces nor fixes it; it is the last unanchored half of the pair. Filed unassigned, nopm:queue.Generated by Claude Code