Repository navigation
Commit b17dbcf
fix(scripts): the ObjectQL double-limit lift reads identifiers from code, never from string or template text (#30521)
<!-- claude-projects-attribution: {"github_login":"os-bill"} -->
_Requested by **Bill** · [project
thread](https://claude.ai/code/project/chan_016iMXWSZDzqWRWvWzdNo8wg?thread=cmsg_016iMXWSZDzqWRWvWzdNo8wgMPwCdpvbf2imf5vac9Zoo4)_
domain:server#4 · os-bill · session_01Utp6CZMkHvuDeVYgTD73qF
Fixes #30473
Clause-②: no — an internal instrument; no product surface moves
Metadata-protocol: none
## 维护者速读
- **改了什么:** ObjectQL 测试替身 `limit` 检查在"把替身的 `find`
抽出来单独运行"时,改为只顺着代码里出现的名字去找同文件依赖;字符串、模板文字正文和注释里的单词不再算数,`${…}`
里的表达式照收。与刚合入的 #30472(where-matcher 检查)同一处修法。
- **为什么改:**
原来是对源码正文跑单词正则。替身报错文案里只要提到一个同文件的导出函数名,检查就会把它拉进来,抽取直接语法报错,一个合规替身被判"无法判定",门禁结论取决于文案用词。
- **风险与回滚:** 只动一个仓库内部检查脚本,不发布任何包。全树 985 个候选改前改后判定逐条一致(含原因列),耗时持平(约 27
秒)。回滚即撤 PR。
- **先看:** `scripts/check-objectql-double-limit.mjs` 的
`identifiersIn`(改为遍历语法树)、`discoverInSource` 里的
`sourceIdentifiers`(方法只取参数和函数体)、`buildCallable` 读集合的两行。
- **两分钟验证:** `pnpm check:objectql-double-limit`,预期 self-test 打印 OK,全树一行
`41 unjudged`,与 main 相同(合 main 后共 987 个候选)。
- **需要你做的:** 无,席位落地。
## What changes
`identifiersIn` was a word regex over source TEXT, the same function PR
#30472 replaced in `check-where-matcher-conformance.mjs`. It now walks
the parsed tree and collects `Identifier` nodes only: string literals, a
template literal's text, regular expressions and comments contribute
nothing, and an identifier inside a `${…}` hole is collected. Discovery
computes the sets off the nodes it already holds, so nothing is
re-parsed: each visible declaration carries `identifiers` beside its
`text`, and the candidate carries `sourceIdentifiers` for exactly the
text its `source` lifts (a method lifts as `function (params) body`, so
its parameters and body are walked and its own name is not; an
expression is walked whole). `buildCallable` follows those sets.
**Not imported from the where-matcher gate.** The seat asked for one
implementation, shared if it fits. It does not fit here: this file's
header records why its scope walk is hand-copied rather than imported
("a gate that imports its own substrate from another gate's file couples
two tripwires that must be able to fail independently"). The walker is
the same tree walk in both files (this one takes several nodes, for the
method case), and the doc comment names its twin.
**Where the defect bites in this gate.** Measured, not assumed: this
lift already survives a text-pulled sibling that throws `X is not
defined` (it stubs the name and retries) and stubs non-function
initializers at stub class 2, so the where-matcher reproducer ("sparse
driver" beside `const driver = { name }`) seats here either way. What it
cannot survive is a text-pulled FUNCTION-like sibling whose source
cannot sit in the lift (function-like declarations are never stubbed).
The self-test case uses an `export function`: `export` inside the lift
body is a syntax error at every stub class, so the old lift answers
`UNJUDGED could not lift: SyntaxError: Unexpected token 'export'` for a
double that never calls it.
## Tests
Two fixtures and seven assertions in the existing battery (floor 56 →
63):
- `FIXTURE_TEXT_NAMES_SIBLING`: a bounding, refusing double whose
messages say "openDriver" (one template literal with a `${k}` hole, one
plain string), beside `export function openDriver`. Pinned: discovered;
`openDriver` and `implemented` not collected; judged CONFORMING.
- `FIXTURE_HOLE_NAMES_HELPER`: a same-file helper `key` named only
inside a `${…}` hole on the answering path. Pinned: discovered; `key`
collected; judged CONFORMING.
<details><summary>Mutation replay (one-off, restored by blob hash ==
HEAD)</summary>
- A, old semantics (word regex over each node's text): self-test exit 1
— `template-literal TEXT names no identifier: "openDriver" in the
message is not collected`, `nor does a plain string literal: its
"implemented" is not collected either`, `a double beside text naming a
sibling binding lifts and is CONFORMING, not UNJUDGED`.
- B, holes skipped (`if (ts.isTemplateExpression(n)) return;`):
self-test exit 1 — `the helper named only inside the hole is collected`,
`so the hole-reading double lifts with its helper and is CONFORMING`.
- The text fixture through `main`'s module directly: `UNJUDGED could not
lift: SyntaxError: Unexpected token 'export'`; through this branch:
`CONFORMING`.
</details>
## Acceptance notes
- Whole-tree verdicts, before (48231b0) and after (c6af339): 985
structural candidates, 488 CONFORMING, 158 BLIND, 32 WRONG, 41 UNJUDGED,
266 OUT_OF_SCOPE, both runs; a per-candidate diff (file, line, verdict,
wrap order, reason) is empty. No verdict changed, so nothing newly lifts
and no count moves. The 41 UNJUDGED are not this defect. After merging
`origin/main` (head 07592b3): `987 structural candidate(s): 680 graded,
41 unjudged`, gate exit 0.
- No real producer in the tree today (the card said read, not measured);
the reach is the self-test case.
- Observation, not touched: a function-like same-file declaration
spelled `export function` cannot be lifted even when the double's CODE
calls it. That limit is unchanged by this PR and no corpus double hits
it today.
## Verification
Gate list derived by `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` (31 commands), each run with its exit
code recorded before any pipe and reconciled with `--ran`; `pnpm lint`
run. Readings are in the os-dev-report on #30473.
No changeset: the diff is one repo-root script that no released package
ships (`skip-changeset`).
---
_Generated by [Claude
Code](https://claude.ai/code/session_01Utp6CYZ6tmbWZDWzLW4Yzg)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent ae5bd5b commit b17dbcf
1 file changed
Lines changed: 96 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
384 | 384 | | |
385 | 385 | | |
386 | 386 | | |
| 387 | + | |
387 | 388 | | |
388 | 389 | | |
389 | 390 | | |
390 | 391 | | |
391 | 392 | | |
392 | 393 | | |
393 | | - | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
394 | 397 | | |
395 | 398 | | |
396 | 399 | | |
397 | 400 | | |
398 | 401 | | |
399 | 402 | | |
400 | | - | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
401 | 419 | | |
402 | | - | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
403 | 425 | | |
404 | | - | |
| 426 | + | |
405 | 427 | | |
406 | 428 | | |
407 | 429 | | |
| |||
468 | 490 | | |
469 | 491 | | |
470 | 492 | | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
471 | 499 | | |
472 | 500 | | |
473 | 501 | | |
| |||
506 | 534 | | |
507 | 535 | | |
508 | 536 | | |
509 | | - | |
| 537 | + | |
510 | 538 | | |
511 | 539 | | |
512 | 540 | | |
| |||
516 | 544 | | |
517 | 545 | | |
518 | 546 | | |
519 | | - | |
| 547 | + | |
520 | 548 | | |
521 | 549 | | |
522 | 550 | | |
| |||
1113 | 1141 | | |
1114 | 1142 | | |
1115 | 1143 | | |
| 1144 | + | |
| 1145 | + | |
| 1146 | + | |
| 1147 | + | |
| 1148 | + | |
| 1149 | + | |
| 1150 | + | |
| 1151 | + | |
| 1152 | + | |
| 1153 | + | |
| 1154 | + | |
| 1155 | + | |
| 1156 | + | |
| 1157 | + | |
| 1158 | + | |
| 1159 | + | |
| 1160 | + | |
| 1161 | + | |
| 1162 | + | |
| 1163 | + | |
| 1164 | + | |
| 1165 | + | |
| 1166 | + | |
| 1167 | + | |
| 1168 | + | |
| 1169 | + | |
| 1170 | + | |
| 1171 | + | |
| 1172 | + | |
| 1173 | + | |
| 1174 | + | |
| 1175 | + | |
| 1176 | + | |
| 1177 | + | |
| 1178 | + | |
| 1179 | + | |
| 1180 | + | |
| 1181 | + | |
| 1182 | + | |
| 1183 | + | |
| 1184 | + | |
| 1185 | + | |
| 1186 | + | |
1116 | 1187 | | |
1117 | 1188 | | |
1118 | 1189 | | |
| |||
1147 | 1218 | | |
1148 | 1219 | | |
1149 | 1220 | | |
1150 | | - | |
| 1221 | + | |
1151 | 1222 | | |
1152 | 1223 | | |
1153 | 1224 | | |
| |||
1267 | 1338 | | |
1268 | 1339 | | |
1269 | 1340 | | |
| 1341 | + | |
| 1342 | + | |
| 1343 | + | |
| 1344 | + | |
| 1345 | + | |
| 1346 | + | |
| 1347 | + | |
| 1348 | + | |
| 1349 | + | |
| 1350 | + | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
| 1354 | + | |
| 1355 | + | |
| 1356 | + | |
1270 | 1357 | | |
1271 | 1358 | | |
1272 | 1359 | | |
| |||
1394 | 1481 | | |
1395 | 1482 | | |
1396 | 1483 | | |
1397 | | - | |
| 1484 | + | |
| 1485 | + | |
1398 | 1486 | | |
1399 | 1487 | | |
1400 | 1488 | | |
| |||
0 commit comments