Repository navigation
fix(scripts): check:i18n-coverage declares the example configs and their src trees to the dispatch derivation - #21271
Merged
objectstack-fleet[bot] merged 2 commits intoOct 2, 2026
Conversation
…e source trees they import to the dispatch derivation dispatch-gates names a gate for a card from the path literals in the gate's own source, and refuses the bare 'examples' constant as too generic, so an edit under examples/ never derived check:i18n-coverage. The gate runs os lint on each example config, which bundles the config's whole relative import graph; measured at 30c530e that graph is the config plus files under its own src/ tree (153 tracked files). Declare exactly those two shapes and hold the declaration in --self-test through the derivation's own extractor and covering rule. Claude-Session: https://claude.ai/code/session_01FNKm1SmPpuJASnbjxWGtsJ Co-authored-by: Claude <noreply@anthropic.com>
…mples row as DECLARED-NARROWER The row was SPELLABLE-UNDECLARED for want of a consumer; #21011 is that consumer, measured. Its recorded spelling now names what the gate reads (each example config and the src/ tree its bundled import graph stays inside), re-measured on one tree at 30c530e, and is held set-equal to the gate's declared array. Claude-Session: https://claude.ai/code/session_01FNKm1SmPpuJASnbjxWGtsJ Co-authored-by: Claude <noreply@anthropic.com>
This was referenced Oct 2, 2026
objectstack-fleet
Bot
deleted the
claude/issue-21011-i18n-coverage-examples-roots
branch
October 2, 2026 01:16
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #21011
Clause-②: no
What
check:i18n-coveragenow declares what it reads to the dispatch derivation, so an edit under an example app derives the gate locally. CI already ran it on the same diff.scripts/check-i18n-coverage.mjs:const ROOT_DIR_WATCH_HINTS = ['examples/*/objectstack.config.ts', 'examples/*/src/**'];besideEXAMPLES_DIR, plus a new--self-testbattery that holds the declaration against the live tree (details below). What the gate judges is unchanged.scripts/pm/bare-root-worklist.mjs: thecheck-i18n-coverage.mjs EXAMPLES_DIR examplesrow is re-decided fromSPELLABLE-UNDECLAREDtoDECLARED-NARROWER. Its recorded spelling is re-measured as the two hints above, and its old single-hint spelling entry is replaced.scripts/pm/dispatch-gates.mjsis not touched. It is frozen under ruling 208 R6, and its self-test stayed green with the declaration in place (see Gates).Why this spelling and not
examples/**The gate runs
os linton each example config.os lintloads the config through bundle-require: esbuild bundles every relative import, and@objectstack/*plus the driver modules stay external (BUNDLE_REQUIRE_EXTERNALSinpackages/cli/src/utils/config.ts). So the count moves with anything in the config's relative import graph. Measured with esbuild and those externals at30c530e5:examples/*/objectstack.config.ts+examples/*/src/**examples/**(bare-root spelling)Every closure file is either a config or a file under that same example's
src/. Here are the 17 declared files that no config imports:src/docs/*.mdpages.os lintreads them, but only throughdocs/*rules, and the gate countsi18n/rules alone.*.test.tsfiles underapp-todo/src.app-showcase/src.src/ofembed-objectql, which has no config.examples/**would add the test suites, e2e specs, READMEs, changelogs and manifests. That is 86 more files, none of which a config imports.Pins (in the gate's own
--self-test, new battery, 10 cases)The battery imports the derivation's own
extractWatchHintsandhintCovers. The import is dynamic and sits insideselfTest, which the extractor masks. So the gate's own extracted hints gain exactly the two declared literals, and its import follow is unchanged: before[cli-build-prerequisite.mjs, import-prerequisite.mjs], after the same.discoverExamples()finds (4).src/resolves outside that example'ssrc/. On this tree that is 177 edges and 0 escapes. A negative control proves the scan still sees an escape.examples/app-showcase/test/gap-fill.test.ts,examples/README.md, and the twopackages/paths of PR feat(spec)!: an analytics cube member's sql is a column reference, and the showcase done rate moves to its dataset (#20943) #20998. Controls show that the extractor drops a computed spelling, and thatexamples/**would have named the test file.Measured end to end with
dispatch-gates --commandsBefore is base
30c530e5, after is head61bd05aa.check:i18n-coveragepnpm check:i18n-coverageexamples/app-showcase/**paths alonepackages/paths alone (packages/spec/src/data/analytics.zod.ts,packages/services/service-analytics/README.md)examples/app-showcase/test/gap-fill.test.tsaloneAblations
All four were run through
scripts/ablation-replace.mjsagainst the committed head. Each mutation was proven on disk by its anchor count and blob hash, and each restore was proven byblob == HEADand an emptygit diff HEAD:['examples/**']: the self-test goes red, 1 failure. The precision case names the test file andexamples/README.md.EXAMPLES_DIR: red, 4 failures. The extracted hints fall back to["scripts/i18n-coverage-baseline.json","i18n","node_modules"].src/**hint dropped: red, 2 failures (the showcase edit and the import targets are no longer derived).bare-root-worklist.mjs --self-test: red, 1 failure, "NOT DECLARED: examples/*/src/**". The map and the gate cannot drift apart silently.Gates (all at head
61bd05aa)The family list came from
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands(no paths, change set from the merge base). It names the same 30 the dispatch listed, and all 30 exited 0.--ranreconciliation: "30 derived famil(ies) accounted for — 30 run, 0 NOT-MEASURED".node scripts/check-i18n-coverage.mjs --self-testpassed, then the gate itself:check-i18n-coverage: OK (13 config(s), 621 baselined untranslated string(s), none new). It ran after the gate's own closure build under the verify lock (VERDICT command-exit 0).node scripts/pm/bare-root-worklist.mjs --self-test: OK. There are now 12 DECLARED-NARROWER records held set-equal to their gates' arrays; there were 11.pnpm check:pm-dispatch-gates:dispatch-gates self-test: 1976 cases pass, run detached for 825.6s. No pin moved, and the frozen file is not in the diff.node scripts/check-declared-population-live.mjspassed with 266 of 326 families live.eslint --no-inline-config --format jsonover the 2 changed files returned 2 files, 0 errors and 0 warnings.eslint.config.mjsenables no type-aware linting (noparserOptions.project), so this diff cannot move the verdict on any untouched file. The fullpnpm lintis left to CI.Acceptance notes
PACKAGES_DIRstays undeclared, and its worklist row keepsSPELLABLE-UNDECLARED(9 extract configs share one spelling withcheck:i18n-bundlesandcheck:i18n-stale-fill, deferred together). The gate's closure also reaches every workspace package a config imports by name, so apackages/specedit can move this count too. Declaring that would be thepackages/root wholesale, the REFUSE-WIDE shape. The CLI half already reaches this gate throughcli-build-prerequisite.mjs.mainthe row wasSPELLABLE-UNDECLAREDwith "Deferred: no consumer has asked". This card is that consumer, and moving the row to DECLARED-NARROWER follows the split criterion of the 2026-08-26 ruling recorded in the worklist header. A paragraph there records the re-decision. The stale header comment in the gate is replaced.selfTestincheck-i18n-coverage.mjsbecameasync, because it needs the dynamic import. The dispatch reads(await selfTest()) !== SELF_TEST_VERDICT, a spelling other gates already use. Self-test runtime went from about 0.11s to about 0.2s.skip-changeset:scripts/**publishes nothing from any package.Generated by Claude Code