Repository navigation
Commit acd190b
ci(test-source-alias): follow a changed test into the source it loads, and red a cold literal import() paid there (#30969)
<!-- claude-projects-attribution: {"github_login":"os-elon-musk"} -->
_Requested by **Elon** · [project
thread](https://claude.ai/code/project/chan_01WedDzV26nniwxv7jC88B9D?thread=cmsg_01WedDzV26nniwxv7jC88B9DWeevjnj6yeVVrex8nUuQRA)_
domain:devx#1 · os-elon-musk · session_016WV4d1Nibc5bxtbQZv6ssS
Fixes #30909
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:`check:test-source-alias`
的时钟窗口规则新增第三个读取器:顺着测试收集期的导入链走进同包被测源码,找出藏在函数体里的字面量 `import()`(该包经 `dist/`
解析的那批 specifier),要求测试在模块顶部预热或 mock;只判本次改动新增或修改的测试文件。
- **为什么改**:#30873 的测试经 `rest-server.ts` 走到回填路由里的 `await
import('@objectstack/objectql')`,冷加载 3.2 秒落在 5000 毫秒窗口里,把无关 PR 的 Test
Core 打红;门禁当时 exit 0。
- **风险与回滚**:只改一个门禁脚本,不动产品代码与测试;误报方向是让作者多写一行模块顶部 import。回滚即 revert。全量扫描耗时
32 秒 → 24 秒(加了解析缓存)。
- **先看**:① `sourceReachFindings` 与 `reachEdgesOf`(可达与预热的判定);② 入口处
`changedFilesSinceMergeBase`(只判改动测试、找不到 merge base 判红);③ 头部新节 "The
source reach" 里为什么不对全部测试判红的实测。
- **两分钟验证**:`git show
98f640d:packages/rest/src/meta-write-door-capability-enumeration.test.ts
> packages/rest/src/meta-write-door-capability-enumeration.test.ts &&
node scripts/check-test-source-alias.mjs`,预期 exit 1 并点名
`meta-record-currency-backfill-route.ts:177`;之后 `git checkout HEAD --
packages/rest/src/meta-write-door-capability-enumeration.test.ts`。
- **需要你做的**:无,席位落地。
## What changes
One file, `scripts/check-test-source-alias.mjs`.
- **A third reader for the clocked-window rule, "the source reach".**
From each test file it follows every same-package file the test loads
during COLLECTION (a static import or a module-scope dynamic one),
transitively, never across a bare specifier. A literal dynamic load of a
specifier the package resolves through `dist/` (the rule's existing
population, unchanged) inside a function body of a reached file is a
finding against the test, unless a file in the same reach loads that
specifier at module scope or the test `vi.mock`s / `vi.doMock`s it. The
remedy is the line the rule already prints: a module-top `import 'SPEC'`
in the test file. The failure names the specifier, every site of it in
the reach, and the import chain to the first one.
- **Scope: the test files a change adds or edits.** Measured from the
merge base with `origin/main` (committed, staged, unstaged and untracked
alike); `--changed-from REF` names another base and `--reach-all` runs
the census over every test file. No merge base is a failure, never a
pass. On a `main` push the base is HEAD and the half judges nothing; on
a PR or a queue build it judges that change's test files. The `Lint ·
CI, release & engine gates` job already checks out with `fetch-depth:
0`, so no workflow edit.
- **Why not every test file.** Static reach is not execution:
`rest-server.ts` registers every route, so every rest test that builds a
`RestServer` reaches every handler's guarded import while only the cases
that call that handler pay it. Over every test file at `main`
0e88208, the reach flags 2307 test files / 5491 (test, specifier)
pairs, from only 89 source sites in 53 files. The header's new section
"The source reach" records this and the boundaries.
- **Speed.** Each file's edges are read once per scan, a file with no
dynamic form skips masking, and relative resolution is cached; the full
scan measured 32.0 s before and 24.3 s after on this container (4 vCPU),
the census over every file 34.8 s.
- **Self-test:** a new battery, "the source reach: a load the source
under test pays (#30909)", 12 cases over six fixtures: the 98f640d
shape (test → hub → route, two collection-time hops) reported with its
site and chain; the remedy, a load warm elsewhere in the reach, a
`vi.mock`, and a lazy relative hop all silent; one finding per specifier
when the direct reader already reports it; the scope judged in and out;
the direct reader left unscoped. `SELF_TEST_BATTERY_FLOOR` 11 → 12.
## Tests
- `node scripts/check-test-source-alias.mjs --self-test` →
`check-test-source-alias --self-test OK`.
- Three mutations, each committed-then-restored with `git checkout HEAD
--` and `git diff HEAD` empty: dropping the warm-set check reds two
cases (remedy, warm-in-reach); dropping the scope filter reds both scope
cases; dropping the mock read reds the mock case.
- **Negative control (the card's ask):** with
`packages/rest/src/meta-write-door-capability-enumeration.test.ts` at
its `98f640d5` blob, `node scripts/check-test-source-alias.mjs` exits 1:
```text
packages/rest/src/meta-write-door-capability-enumeration.test.ts:60: reaches `import('@objectstack/objectql')` in the source under test, at packages/rest/src/meta-object-state-routes.ts:235, packages/rest/src/meta-record-currency-backfill-route.ts:177 —
inside a function body, a CLOCKED window for whichever case first calls it.
Reached during collection through (the first site): packages/rest/src/meta-write-door-capability-enumeration.test.ts → packages/rest/src/rest-server.ts → packages/rest/src/meta-object-state-routes.ts
```
Restored with `git checkout HEAD --`, `git status --porcelain` clean of
it; the same command then exits 0.
## Acceptance notes
- **How many existing test files the extended rule flags:** 0 under the
CI scope (no test file changes here). Over every test file
(`--reach-all`, `main` 0e88208): 2307. By package:
`ui/packages/app-shell` 932, `packages/runtime` 387,
`ui/packages/components` 287, `packages/metadata-protocol` 200,
`packages/rest` 187, `packages/cli` 179,
`packages/services/service-datasource` 64, `packages/verify` 37,
`packages/metadata` 18, `packages/cloud-connection` 6,
`ui/scripts/__tests__` 6, `packages/plugins/plugin-dev` 4. Reproduce the
full list with `node scripts/check-test-source-alias.mjs --reach-all`.
They are not fixed here (over the card's "fix if small" bound): each is
fixed with one module-top line when a change next touches it.
- In `packages/rest` only two specifiers stay cold,
`@objectstack/objectql` and `@objectstack/spec/ui`. The card's other
latent sites (`@objectstack/spec/api` in `batch-routes.ts` /
`crud-routes.ts`, `@objectstack/spec/system` in `form-routes.ts` /
`meta-item-read-gate.ts`) are not flagged: another file in the same
reach already imports those subpaths statically, so they are paid during
collection today.
- Boundaries (header): a lazy relative hop is not followed; a module-top
import of another workspace package whose `dist/` loads the specifier is
not credited (the loud direction); a mock counts whether or not it calls
`importOriginal`; a source edit that adds a cold site reds no unchanged
test.
- No timeout raised; no test file touched, so #30901's lane (PR #30919,
`packages/formula` only) does not overlap.
## Verification
All on head `efd622a9` (this branch merged with `origin/main` 6ddf827),
this container, 4 vCPU.
- `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 31 families for the one changed
path; all 31 ran sequentially, each exit code captured before any pipe;
31 exit 0. `--ran`: "31 derived famil(ies) accounted for — 31 run, 0
NOT-MEASURED".
- `pnpm exec eslint scripts/check-test-source-alias.mjs` exit 0.
- `node scripts/check-test-source-alias.mjs`: exit 0, "the source reach
judged 0 test file(s) changed since 6ddf827", 24.3 s. `--reach-all`:
exit 1, 5491 findings over 2307 test files (the same counts as at
0e88208), 34.8 s.
- Negative control repeated on this head: the `98f640d5` blob (hash
76ae2b8) exits 1 with the finding quoted under Tests; restored blob
hash equals the HEAD blob.
<details><summary>gates-ran-efd622a9</summary>
```text
node scripts/check-closing-keyword-parity.mjs :: exit 0
node scripts/check-closing-keyword-parity.mjs --self-test :: exit 0
node scripts/check-comment-mask-corpus.mjs :: exit 0
node scripts/check-declaration-mirrors.mjs :: exit 0
node scripts/check-declaration-mirrors.mjs --self-test :: exit 0
node scripts/check-self-test-wired.mjs :: exit 0
node scripts/check-self-test-wired.mjs --self-test :: exit 0
node scripts/check-self-test-workflow-commands.mjs :: exit 0
node scripts/check-self-test-workflow-commands.mjs --self-test :: exit 0
node scripts/check-whole-set-label-write.mjs :: exit 0
node scripts/check-whole-set-label-write.mjs --self-test :: exit 0
node scripts/ci/plan-test-core-shards.mjs --self-test :: exit 0
node scripts/pm/bare-root-worklist.mjs --self-test :: exit 0
pnpm check:agent-test-spelling :: exit 0
pnpm check:bash32-floor :: exit 0
pnpm check:ci-filter-parity :: exit 0
pnpm check:cli-command-ids :: exit 0
pnpm check:cross-package-test-inputs :: exit 0
pnpm check:driver-memory-census :: exit 0
pnpm check:entry-guard :: exit 0
pnpm check:gitlink-declared :: exit 0
pnpm check:nul-bytes :: exit 0
pnpm check:parse-guard :: exit 0
pnpm check:pm-dispatch-gates :: exit 0
pnpm check:pnpm-filter-targets :: exit 0
pnpm check:pnpm-flag-spellings :: exit 0
pnpm check:ratchet-remedy-authority :: exit 0
pnpm check:refd-timer-probe :: exit 0
pnpm check:scripts-symbol-anchors :: exit 0
pnpm check:test-source-alias :: exit 0
pnpm check:watch-hint-literal :: exit 0
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_016WV4d1Nibc5bxtbQZv6ssS)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 40ecdf9 commit acd190b
1 file changed
Lines changed: 472 additions & 9 deletions
0 commit comments