@@ -392,6 +392,17 @@ const POPULATION_PROPERTY = /^(?:[a-z][A-Za-z0-9]*Roots?|[a-z][A-Za-z0-9]*Dirs?|
392392 * drift this docblock permits; pairing any one of those numerators with another
393393 * reading's denominator is the defect it forbids, and the spread is why.
394394 *
395+ * ⭐ A TWENTY-FIRST row was re-decided on 2026-10-01 (#21011), and from the
396+ * OTHER side of the 2026-08-26 split: `check:i18n-coverage EXAMPLES_DIR
397+ * examples` was one of the fifteen that became SPELLABLE-UNDECLARED for want of
398+ * a recorded consumer, and #21011 is that consumer, measured on a real diff the
399+ * derivation was silent for and CI failed. Moving it to DECLARED-NARROWER is the
400+ * criterion that ruling drew, not a new licence. What did change is the
401+ * SPELLING, and that is why the row is re-measured whole rather than re-labelled:
402+ * the old one named the config FILENAME the constant filters for, but the gate
403+ * reads the import graph `os lint` bundles from each config, so the recorded set
404+ * is now that graph's two shapes, measured with the bundler itself on one tree.
405+ *
395406 * ⭐ ATTRIBUTION was added on 2026-09-19 (#15926), and it is a widening of a
396407 * PIN rather than a re-decision on any row: no verdict is added, changed or
397408 * withdrawn, and the 46/13/14 census is the one it was measured at. The
@@ -508,11 +519,6 @@ const SPELLINGS = new Map([
508519 holds : ( s ) => s [ 0 ] === 'packages' && s . length >= 3
509520 && s [ s . length - 1 ] === 'i18n-extract.config.ts' && s [ s . length - 2 ] === 'scripts' ,
510521 } ] ,
511- [ 'example app configs' , {
512- segments : [ 'examples' , '*' , 'objectstack.config.ts' ] ,
513- claim : 'the named app config in each immediate child of the examples root' ,
514- holds : ( s ) => s . length === 3 && s [ 0 ] === 'examples' && s [ 2 ] === 'objectstack.config.ts' ,
515- } ] ,
516522 [ 'published skill files' , {
517523 segments : [ 'skills' , '*' , '**' ] ,
518524 claim : 'every file inside a published skill directory, at any depth' ,
@@ -557,6 +563,21 @@ const SPELLINGS = new Map([
557563 holds : ( s ) => s [ 0 ] === 'packages' && s . length >= 2
558564 && [ '.ts' , '.tsx' , '.mts' ] . some ( ( ext ) => s [ s . length - 1 ] . endsWith ( ext ) ) ,
559565 } ] ,
566+ [ 'example app configs and their source trees' , {
567+ // What `os lint` loads when check:i18n-coverage hands it a config: the
568+ // config, and the relative import graph its bundler follows from it, which
569+ // on this tree never leaves that example's own `src/` (the gate's
570+ // --self-test holds that). The config hint alone was this entry until
571+ // #21011 and named the FILTER, not the read.
572+ segments : [
573+ [ 'examples' , '*' , 'objectstack.config.ts' ] ,
574+ [ 'examples' , '*' , 'src' , '**' ] ,
575+ ] ,
576+ claim : 'the app config in each immediate child of the examples root, or any file at any depth '
577+ + "under that child's src directory" ,
578+ holds : ( s ) => s [ 0 ] === 'examples'
579+ && ( ( s . length === 3 && s [ 2 ] === 'objectstack.config.ts' ) || ( s . length >= 4 && s [ 2 ] === 'src' ) ) ,
580+ } ] ,
560581 [ 'examples TypeScript source' , {
561582 segments : [ 'examples' , '**' , '*.ts' ] ,
562583 claim : 'every `.ts` file at any depth under the examples root' ,
@@ -860,6 +881,31 @@ const TRIAGE = new Map([
860881 + 'any other extension satisfies neither hint, so no arbitrary file at the top of the root '
861882 + 'is reached — which is what this verdict says and is correct, not outstanding debt' ,
862883 } ] ,
884+ [ 'scripts/check-i18n-coverage.mjs EXAMPLES_DIR examples' , {
885+ verdict : 'DECLARED-NARROWER' ,
886+ spelling : 'example app configs and their source trees' ,
887+ why : 'RE-DECIDED 2026-10-01 (#21011) from SPELLABLE-UNDECLARED, which deferred the declaration '
888+ + 'because no consumer had asked for this gate to be nameable. #21011 is that consumer, and '
889+ + 'it is MEASURED: PR #20998 edited showcase source files, the derivation for its diff '
890+ + 'named 116 families and not this one, and CI then failed it here (app-showcase 414 -> '
891+ + '416 untranslated). So the row takes the DECLARED-NARROWER half of the 2026-08-26 split, '
892+ + 'the criterion that ruling drew, and no wider authorisation is claimed. ⛔ The recorded '
893+ + 'spelling is NOT the old one: it named the FILTER the constant applies, one config per '
894+ + 'child directory, while the gate READS what os lint bundles from each config. '
895+ + 'RE-MEASURED at commit 30c530e5, every term on one tree: esbuild with the CLI '
896+ + 'bundle-require externals reaches 153 tracked files from the 4 configs, each the config or '
897+ + 'a file under its own example src/. The gate declares that as two hints beside '
898+ + 'EXAMPLES_DIR under the ROOT_DIR_WATCH_HINTS idiom; they cover 170 of the 256 tracked '
899+ + 'files under the bare root — all 153 (complete) plus 17 no config imports (11 src/docs '
900+ + 'pages os lint reads but never counts as i18n, 2 tests and 3 strays under src/, one '
901+ + 'config-less example src/), 90% — where the bare-root spelling would be 153 of 256, 60%, '
902+ + 'naming the gate for every test suite and README. The recorded set is SET-EQUAL to the '
903+ + 'gate array at this root, and the gate own --self-test holds the other side: the '
904+ + 'derivation reads both hints off its source, and no relative import in a config or '
905+ + 'under its src/ leaves that src/. The row STAYS in the sweep because the bare root is '
906+ + 'still not covered — no arbitrary file at the top of examples/ is reached — which is what '
907+ + 'this verdict says and is correct, not outstanding debt' ,
908+ } ] ,
863909 // ── Refused: the population is the whole root, and the root is saturated ──
864910 [ 'scripts/check-skill-identifier-liveness.mjs IMPL_ROOTS packages' , {
865911 verdict : 'REFUSE-WIDE' ,
@@ -1049,14 +1095,6 @@ const TRIAGE = new Map([
10491095 // rested on. What is recorded now is the measured spelling and the reason the
10501096 // declaration is deferred, which is a different claim from "no honest
10511097 // declaration exists" and the only one these rows can still make.
1052- [ 'scripts/check-i18n-coverage.mjs EXAMPLES_DIR examples' , {
1053- verdict : 'SPELLABLE-UNDECLARED' ,
1054- spelling : 'example app configs' ,
1055- why : 'one named config file per child directory — 3 of 241 tracked files under the root '
1056- + '(1.2%), re-measured 2026-08-26. The recorded spelling is live and reaches 3 of 3, 100% '
1057- + 'precise and complete. Deferred: no consumer has asked for this gate to be nameable, and '
1058- + 'the i18n family it belongs to would want one declaration per gate rather than one here' ,
1059- } ] ,
10601098 [ 'scripts/check-i18n-coverage.mjs PACKAGES_DIR packages' , {
10611099 verdict : 'SPELLABLE-UNDECLARED' ,
10621100 spelling : 'i18n extract configs' ,
0 commit comments