Repository navigation
Commit 5612dd9
tooling(test-source-alias): a type reference or literal text is not a clocked load (#25781)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoGqmNfHDtRjRpMLtsG8NzYZ)_
Fixes #25766
Part of #25677 (cutover prep G, the gate half of decision F; the
test-file half is #25763).
Clause-②: no
Metadata-protocol: none
## What this changes
One file, `scripts/check-test-source-alias.mjs`, the clocked-window rule
only (`moduleLoadSites`). The ledger half of the gate
(`extractRuntimeImports`, `KNOWN_UNALIASED_TEST_IMPORTS`, the vitest
alias reading) is untouched.
Before this PR the rule counted every `import('x')` the import regex
could see in the comment-masked text, and its only type-position guard
was `typeof` in front of the keyword. Two kinds of sites were therefore
read as clocked loads although they load nothing:
1. **Type references.** `type T = import('p').T` and `const s:
import('p').Schema = ...` are erased by `tsc`. The new
`isImportTypeReference` decides this from what FOLLOWS the call: a type
reference is always qualified (a bare `import('p')` in a type position
is a compile error) and its member chain is never called. A runtime
`import()` is awaited, assigned, passed, or chained into a call
(`.then(...)`, a generic `.then` call with a type argument,
`?.then(...)`). The head cannot decide it: `{ key: import('p') }` is an
object-literal load behind the same colon an annotation uses. Type
arguments after the member are balanced (braces, semicolons and
function-type arrows inside them included), so the token after the
closing angle bracket tells a type argument list from a generic call.
Only the `import(` form is read this way; `require('p').member` is the
ordinary CJS spelling of a runtime load and stays a load. Anything the
reader cannot parse reads as a load (the loud direction).
2. **Text.** A dynamic form written inside a string or a template body
(a scanner's own test feeding it input, a child-process script) is not
code. A match now counts only when its keyword is executed code: plain
code in the `codeOnly` projection, or a template interpolation interior,
which `codeOnly` blanks too, read from `scanSource`'s `interpolation`
array. That scan runs only when a keyword is not plain code.
Both rules skip the site for the module-scope set as well, matching what
the header already said for `typeof`: an erased site is neither a
finding nor a compliance token. A module-top `type T = import('p').T`
therefore no longer pays, on paper, for a real clocked `await
import('p')` in the same file.
## Measurements
**Merged layout** (verify branch
`claude/project-thread-dwhq6r-25697-verify` at 9e37acd, this diff
applied at the root with `git apply`, `node
scripts/check-test-source-alias.mjs`):
| | before | after |
|---|---|---|
| unique clocked findings (file:line) | 37 | 30 |
| the card's 7 false positives | 7 | 0 |
| new clocked findings | | 0 |
| non-clocked findings (ledger, alias) | 42 | 42, byte-identical lines |
The 7 that are gone are exactly the card's table:
`spec-symbol-4650.test.ts` in plugin-calendar :58, plugin-form :50,
plugin-grid :73, plugin-kanban :50,
`dashboard-global-filters-spec-binding.test.ts:102`,
`data-table.test.ts:66`,
`ui/scripts/__tests__/check-spec-range-floors.test.ts:286`. The 30 left
are #25763's real ones. No `ui/` file is edited and nothing is added to
`KNOWN_UNALIASED_TEST_IMPORTS` or any allowlist.
**objectstack main** (merge base ab510f4):
- `pnpm check:test-source-alias`: self-test OK, run OK, same green line
as before (76 packages scanned, 60 registered, 55 published subpaths).
- Ledger recompute: `node scripts/check-test-source-alias.mjs --list`
before and after are identical (60 of 76 packages, 295
package-dependency pairs).
- Corpus-wide reading, with no population filter: every tracked test
file's sites, before vs after. main: 48 site entries reclassified, all
of them removals, 0 additions. merged: 145 removals, 0 additions. Every
main removal was read by hand. They are child-process scripts in
template literals (`SEED_CHILD`, `WORKER_SOURCE`, `PROBE`, `DRIVER_CJS`,
an `os start` stub), RuleTester-style code strings, and erased type
positions (`s is import('typescript').X` predicates, `as
import('node:crypto').BinaryLike` casts, `{ knex: import('knex').Knex }`
annotations). None of the files is a finding before or after, because
none of these specifiers is in its package's measured set.
- Gate wall time on this box: 19.5 s before, 18.2 s after.
## Self-test
New battery `a type reference or literal text is not a load (#25766)`,
21 cases. The roster floor goes from 10 to 11 batteries.
- End to end: fixture (29) `packages/clocked-type-reference` holds an
alias and an annotation (type arguments carrying a semicolon) inside a
test body, plus a dynamic import as template text, each putting its
specifier in the measured set. A module-top alias of `@fx/core` sits
beside a real `await import('@fx/core')`. Only the real load may be
reported, and it must be reported.
- Shape table read straight off `moduleLoadSites`. 8 erased rows (alias,
annotation, generic annotation, qualified chain with array and indexed
access, parameter annotation, string, template body, `require` in a
template body) and a module-top `export type` row. 9 load rows:
unawaited assignment, object-literal value, awaited, `.then(...)`,
generic `.then` call, `?.then(...)`, a load inside a template
interpolation, a load right after an erased alias on the same line (the
#12555 lesson: erasing one site must not swallow its neighbour), and
`require('p').member`.
On scratch copies of the gate (repo root pinned, imports pointed at this
tree; the unmutated copy shows 12 relocation-only failures, subtracted
below), each mutation reds rows of the new battery:
| mutation | new-battery rows red |
|---|---|
| drop the executed-keyword test | the 3 text rows, the end-to-end text
and real-load legs |
| drop the type-reference test | the 5 type rows, module-top alias,
end-to-end legs, the same-line neighbour row |
| executed-keyword test without the interpolation array | the
interpolation load row |
| type reference ignores a following call | the `.then(...)` and generic
`.then` rows |
| a generic argument list reads as a load | the generic annotation row,
module-top generic alias, end-to-end legs |
| a head-based rule (colon or equals in front means type) | the
unawaited-assignment and object-literal rows |
| the type rule also applied to `require` | the `require('p').member`
row |
Every erased row is reached by at least one mutation. The awaited and
`?.then(...)` load rows are not reached by these seven; they stand guard
against a wider erasure rule.
## Gates
Derived with `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at 85fe6b0 (1 path, +173/-4). Exit codes
were captured before any pipe. Every derived command exits 0:
`node scripts/check-ci-filter-parity.mjs`,
`check-closing-keyword-parity.mjs` (+ `--self-test`),
`check-comment-mask-corpus.mjs`, `check-declaration-mirrors.mjs` (+
`--self-test`), `check-position-name-fold-loaders.mjs` (+
`--self-test`), `check-scripts-symbol-anchors.mjs` (+ `--self-test`),
`check-self-test-wired.mjs` (+ `--self-test`),
`check-self-test-workflow-commands.mjs` (+ `--self-test`),
`check-whole-set-label-write.mjs` (+ `--self-test`),
`scripts/pm/bare-root-worklist.mjs --self-test`; `pnpm
check:agent-test-spelling`, `check:bash32-floor`,
`check:cli-command-ids`, `check:cross-package-test-inputs`,
`check:driver-memory-census`, `check:entry-guard`,
`check:gitlink-declared`, `check:nul-bytes`, `check:parse-guard`,
`check:pm-dispatch-gates`, `check:pnpm-filter-targets`,
`check:pnpm-flag-spellings`, `check:ratchet-remedy-authority`,
`check:refd-timer-probe`, `check:test-source-alias`,
`check:watch-hint-literal`.
Reconciled at 85fe6b0 with `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --ran ran.list`: 33 derived, 33 run, 0
NOT-MEASURED, 0 UNRUN.
The first run of six of them exited 3 (PREREQUISITE NOT MET: `yaml`,
`typescript`, `@typescript-eslint/parser` missing in a fresh worktree).
After `pnpm install --frozen-lockfile` all six exit 0. NOT MEASURED
locally, left to CI: the two families that take a value from the
workflow (`check-shard-attestation.mjs --emit`,
`check-test-completeness.mjs`) and the Test Core job steps.
No changeset: the root package is private and `scripts/**` ships in no
package's `files[]`. The PR carries `skip-changeset`.
## Acceptance notes
1. **Out of scope by the card, noted:** the ledger half
(`extractRuntimeImports`) still reads type references and string or
template text as runtime imports. That is why such specifiers keep
entering a package's measured set (all 7 merged-layout sites were in
it). It belongs to the vitest-alias half that the cutover adaptation
commit owns. No finding is wrong because of it after this PR, since the
clocked rule no longer reports those sites.
2. **Observed, not fixed (outside the card's step 1):** a STATIC import
spelled as text inside a string or template at module top still counts
as a module-scope compliance token. That is the fail-open direction.
Measured with a scratch copy that applies the same executed-keyword test
to static matches: 67 such tokens on main and 141 on the merged layout,
and none of them pairs with a clocked load of the same specifier in its
file. Today it hides nothing. Carrier: none.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Mj3sUeTnVuFsWPY37TxDmS)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent f0cf338 commit 5612dd9
1 file changed
Lines changed: 173 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
259 | 259 | | |
260 | 260 | | |
261 | 261 | | |
262 | | - | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
263 | 267 | | |
264 | 268 | | |
265 | 269 | | |
| |||
346 | 350 | | |
347 | 351 | | |
348 | 352 | | |
349 | | - | |
| 353 | + | |
350 | 354 | | |
351 | 355 | | |
352 | 356 | | |
| |||
850 | 854 | | |
851 | 855 | | |
852 | 856 | | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
| 860 | + | |
| 861 | + | |
| 862 | + | |
| 863 | + | |
| 864 | + | |
| 865 | + | |
| 866 | + | |
| 867 | + | |
| 868 | + | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
| 872 | + | |
| 873 | + | |
| 874 | + | |
| 875 | + | |
| 876 | + | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
| 880 | + | |
| 881 | + | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
| 887 | + | |
| 888 | + | |
| 889 | + | |
| 890 | + | |
| 891 | + | |
| 892 | + | |
| 893 | + | |
| 894 | + | |
| 895 | + | |
| 896 | + | |
| 897 | + | |
| 898 | + | |
| 899 | + | |
| 900 | + | |
| 901 | + | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
853 | 922 | | |
854 | 923 | | |
855 | 924 | | |
| |||
1017 | 1086 | | |
1018 | 1087 | | |
1019 | 1088 | | |
1020 | | - | |
| 1089 | + | |
| 1090 | + | |
| 1091 | + | |
1021 | 1092 | | |
1022 | 1093 | | |
1023 | 1094 | | |
1024 | 1095 | | |
| 1096 | + | |
| 1097 | + | |
| 1098 | + | |
| 1099 | + | |
| 1100 | + | |
| 1101 | + | |
| 1102 | + | |
| 1103 | + | |
1025 | 1104 | | |
1026 | 1105 | | |
1027 | 1106 | | |
| |||
1039 | 1118 | | |
1040 | 1119 | | |
1041 | 1120 | | |
| 1121 | + | |
1042 | 1122 | | |
| 1123 | + | |
1043 | 1124 | | |
1044 | 1125 | | |
1045 | 1126 | | |
| |||
2745 | 2826 | | |
2746 | 2827 | | |
2747 | 2828 | | |
| 2829 | + | |
| 2830 | + | |
| 2831 | + | |
| 2832 | + | |
| 2833 | + | |
| 2834 | + | |
| 2835 | + | |
| 2836 | + | |
| 2837 | + | |
| 2838 | + | |
| 2839 | + | |
| 2840 | + | |
| 2841 | + | |
| 2842 | + | |
| 2843 | + | |
| 2844 | + | |
| 2845 | + | |
| 2846 | + | |
| 2847 | + | |
| 2848 | + | |
| 2849 | + | |
2748 | 2850 | | |
2749 | 2851 | | |
2750 | 2852 | | |
| |||
2777 | 2879 | | |
2778 | 2880 | | |
2779 | 2881 | | |
| 2882 | + | |
2780 | 2883 | | |
2781 | 2884 | | |
2782 | 2885 | | |
| |||
2785 | 2888 | | |
2786 | 2889 | | |
2787 | 2890 | | |
2788 | | - | |
| 2891 | + | |
2789 | 2892 | | |
2790 | 2893 | | |
2791 | 2894 | | |
| |||
3239 | 3342 | | |
3240 | 3343 | | |
3241 | 3344 | | |
| 3345 | + | |
| 3346 | + | |
| 3347 | + | |
| 3348 | + | |
| 3349 | + | |
| 3350 | + | |
| 3351 | + | |
| 3352 | + | |
| 3353 | + | |
| 3354 | + | |
| 3355 | + | |
| 3356 | + | |
| 3357 | + | |
| 3358 | + | |
| 3359 | + | |
| 3360 | + | |
| 3361 | + | |
| 3362 | + | |
| 3363 | + | |
| 3364 | + | |
| 3365 | + | |
| 3366 | + | |
| 3367 | + | |
| 3368 | + | |
| 3369 | + | |
| 3370 | + | |
| 3371 | + | |
| 3372 | + | |
| 3373 | + | |
| 3374 | + | |
| 3375 | + | |
| 3376 | + | |
| 3377 | + | |
| 3378 | + | |
| 3379 | + | |
| 3380 | + | |
| 3381 | + | |
| 3382 | + | |
| 3383 | + | |
| 3384 | + | |
| 3385 | + | |
| 3386 | + | |
| 3387 | + | |
| 3388 | + | |
| 3389 | + | |
| 3390 | + | |
| 3391 | + | |
| 3392 | + | |
| 3393 | + | |
| 3394 | + | |
| 3395 | + | |
| 3396 | + | |
| 3397 | + | |
| 3398 | + | |
| 3399 | + | |
| 3400 | + | |
| 3401 | + | |
| 3402 | + | |
| 3403 | + | |
| 3404 | + | |
| 3405 | + | |
| 3406 | + | |
| 3407 | + | |
| 3408 | + | |
| 3409 | + | |
| 3410 | + | |
3242 | 3411 | | |
3243 | 3412 | | |
3244 | 3413 | | |
| |||
0 commit comments