Repository navigation
Description
Symptom
The check-i18n-bundles gate reports a stale-dist prerequisite failure as a content verdict — check-i18n-bundles: 1 bundle problem(s) / extract failed … — instead of naming the unmet prerequisite the way its sibling check-i18n-coverage does. In the QA run, packages/spec/dist predated commit 06be54ec (#7285, which added authorisesIrreversibleAction), so platform-objects' extract threw "The requested module '@objectstack/spec/system' does not provide an export named 'authorisesIrreversibleAction'". The coverage gate handled the same cause well — it refused to judge the ratchet ("Nothing was compared… the baseline was left exactly as committed", the designed #6033/#5862 honesty) — but the bundles gate graded it as content.
Root cause
Located, and verified still present on origin/main as of this filing. In scripts/check-i18n-bundles.mjs, the only prerequisite classifier is looksLikeMissingCliCommand() (scripts/cli-build-prerequisite.mjs), which matches oclif's Error: command … not found — an unbuilt/half-built CLI — only. A stale dependency dist that makes extraction throw a module-export mismatch does not match that signature, so the prerequisite branch (reportPrerequisiteNotMet) never fires. Execution falls to the in-loop failure path: collectDriftedBundles(stdout) finds no drift lines (the extract blew up before producing any), so it lands in the else branch that does broken.push(${pkg}: extract failed — …), and the final verdict prints check-i18n-bundles: ${broken.length + drifted.length} bundle problem(s). That is a content verdict for a prerequisite failure — the same "bundle/extract" wording (#5217 comment header) that misdirects the reader to the i18n configs.
Fix shape. The bundles gate should recognize the stale-dist / module-export-mismatch prerequisite and name it the way its sibling coverage gate does — a hard failure that states it checked nothing — rather than counting it as a bundle problem.
Stale-premise note. The packages/spec/dist staleness in the run was a checkout artifact, not the bug. The bug is the mislabel, and the mislabel path (else → broken.push('extract failed') → "N bundle problem(s)") is present on origin/main. #5217 (closed) added the prerequisite classifier for the unbuilt-CLI case; it does not cover this stale-dependency-dist / missing-export case.
Reproduction
With packages/spec/dist older than a commit that adds a new @objectstack/spec/system export, run node scripts/check-i18n-bundles.mjs. It prints 1 bundle problem(s) / extract failed …, while node scripts/check-i18n-coverage.mjs on the same tree refuses to judge ("Nothing was compared…").
Source
Extracted from the QA run #7640 (framework 92f26f7, console 09987b6).
Activity
huangyiirene commentedon Aug 11, 2026
Claim: PM loop round 3 (devx seat, 2026-08-11 term) — wave 3 unit A
Session:
session_01GZKbx4xyF7U5WXj6ch49BMBranch:
claude/issue-7681-i18n-bundles-prereqWorktree: cloud session, own clone
Domain:
domain:devxFile surface:
scripts/check-i18n-bundles.mjs+ (if the classifier is shared there)scripts/cli-build-prerequisite.mjs; stop on breachContainer & model: M (gate-classifier design judgment),
mode:cloud,model: opusSerial constraints cleared: no other in-flight claim or open PR touches these scripts (checked at claim time; wave-3 units B–E are all
docs/qa/**area files, disjoint).Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
{ "issue": 7681, "status": "done", "branch": "claude/issue-7681-i18n-bundles-prereq", "pr": "https://github.com/objectstack-ai/objectstack/pull/7718", "premise_still_valid": true, "summary": "Verified at origin/main 21888ab: `looksLikeMissingCliCommand()` is still the only prerequisite classifier in `check-i18n-bundles.mjs`, so a module-export mismatch from a stale dependency dist falls to `broken.push('extract failed …')` and prints as 'N bundle problem(s)'. Added `looksLikeStaleWorkspaceDist()` to the shared `scripts/cli-build-prerequisite.mjs` (so the sibling gates can adopt it) covering two shapes of one prerequisite - an export mismatch on a workspace specifier, and a `Cannot find module` reaching into a workspace package's `dist/` - and the bundles gate now raises a hard PREREQUISITE NOT MET naming the package whose build output is at fault, exonerating the i18n config in words, and prescribing a rebuild of that package rather than of the CLI. `reportPrerequisiteNotMet` gained a `scanned` count because the in-loop nets can fire after other packages printed 'in sync', where the old fixed 'Nothing was checked' sentence would have been false; it now states what was and was not judged, mirroring the coverage gate's partial-round wording. Deliberately narrow: a third party's export mismatch, CommonJS interop's `Named export 'x' not found`, a non-dist specifier, a real drift and an undeclared authoring key all keep the verdict they had. No changeset: internal gate tooling under `scripts/`, nothing published or user-visible - `skip-changeset` applied by this session (labels read back: size/m, skip-changeset).", "tests": "node scripts/check-i18n-bundles.mjs --self-test -> green, assertions 29 -> 53: '✓ check:i18n --self-test — bundle-drift, undeclared-authoring-key, missing-CLI-build and stale-workspace-dist classifiers all go red, and stay distinct.' | node scripts/check-i18n-coverage.mjs --self-test -> green (shared module behaviour unchanged). | pnpm check:nul-bytes -> 'OK (scanned 7104 text file(s) … no raw ASCII control bytes)' - it caught a raw NUL my own edit had materialised into a string literal, which was removed before commit. | eslint scripts/check-i18n-bundles.mjs scripts/cli-build-prerequisite.mjs --no-inline-config -> 0 errors, 0 warnings on both files (verified via --format json that both were actually linted, not ignored). | END-TO-END, fixture workspace with a scripted CLI, before = the origin/main copies of both scripts, after = this branch, same tree: healthy 'OK (2 package(s) …)' unchanged; genuine drift '1 bundle problem(s)' unchanged; genuinely broken config '1 bundle problem(s)' unchanged; stale spec dist BEFORE '1 bundle problem(s) / beta: extract failed' -> AFTER 'PREREQUISITE NOT MET — a workspace package this gate loads is built from older source — `@objectstack/spec`' + 'Fix: pnpm exec turbo run build --filter=@objectstack/spec'; dependency never built -> 'PREREQUISITE NOT MET — … is not built'; unbuilt CLI -> the #5217 verdict verbatim, unchanged. Both `scanned` branches exercised (first package -> 'Nothing was checked'; second package -> 'Nothing was judged … the 1 attempted before it read the same unbuilt output — an \"in sync\" line above is not a clean bill'). | REVERSE VERIFICATION, direction predicted RED before running: neutering `looksLikeStaleWorkspaceDist` to return null turned exactly the 9 positive pins red, by name and with reasons, and left every negative pin green; restored -> green. | NOT RUN, stated plainly: no full workspace build (this container has no node_modules; only the root workspace project was installed, for eslint), so the healthy-tree evidence is the fixture matrix above plus the real gate on this worktree still raising the unbuilt-CLI prerequisite. The self-test corpus is node's exact message shape produced locally against a fixture standing in for the stale packages/spec/dist, carrying the QA run's own specifier and export name - not a transcript of the QA run itself, and the code comment says so.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
huangyiirene commentedon Aug 11, 2026
ACCEPT — PR #7718. Review record: files exactly the claimed two scripts; the new
looksLikeStaleWorkspaceDistclassifier is deliberately narrow (workspace-scope-gated, third-party/interop/non-dist shapes all negative-pinned), the two prerequisite classifiers are mutually exclusive by test, the partial-scan wording keeps the "nothing judged" sentence true when the net fires mid-loop, and the reverse verification ran with the direction predicted before execution. The honest NOT-RUN declaration (no full workspace build in-container; fixture matrix + real gate as substitute) is acceptable for a gate whose CI runs on a built tree. Landing: flip + arm once gate jobs conclude.Generated by Claude Code
fix(scripts): report a stale workspace dist as a prerequisite, not a …
fix(scripts): anchor check-i18n-bundles' population at the repo root