Repository navigation
Commit cdb949a
fix(adr-0087): predicate 2 reads a
<!-- claude-projects-attribution: {"github_login":"os-support-ai"} -->
_Requested by **Yibo Wang** · [project
thread](https://claude.ai/code/project/chan_01BVUyyPie8gHwoPM18iABwB?thread=cmsg_01BVUyyPie8gHwoPM18iABwBDFDmSVzwiQ3bKV9WbePMBf)_
Fixes #26324
Fixes #27022
Clause-②: no
Metadata-protocol: none
Skills-docs: none — no file under `skills/` names
`runtime-export-retired`, `no-metadata-surface` or the ADR-0087 gate
(`git grep` over `skills/`: 0 hits), so neither predicate is taught
there
## 维护者速读
- 改了什么:ADR-0087 登记门禁的谓词 2 修两处。导出名为 `default` 的退役只看"有没有元数据面 import
了这个默认导出,或以命名空间导入、命名空间再导出、动态 `import()` / `require()` 加载了整个模块",不再按单词扫
`default`;整包退役(`PACKAGE#*`)把路径或 URL 字符串里出现的包名也算作引用,但 `@scope/plugin-x`
仍不算无作用域的 `plugin-x`。
- 为什么改:`default` 是元数据里的普通键(`{ value: 'technology', default: true }`、Zod
`.default()`),单词扫描在每棵树上都命中,所以任何 `default` 导出的退役都无法如实申报,卡住了 #26206 的后半(移除
driver-memory 的旧默认导出)。路径/URL 那一处是 D9
原文"包名的任何其他出现,含字符串值"与门禁实际放行之间唯一已知的缺口。
- 风险与回滚:只动 `scripts/` 下一个不发布的门禁脚本。`default` 一侧放宽的范围只限导出名恰为 `default`
的操作数,其他导出名读法不变;路径一侧是收紧(多拒)。回滚即还原本 PR。
- 先看:`scripts/check-adr-0087-registration.mjs` 的
`defaultImportReference`(四条线性 import 正则,及 `metadataSurfaceReference`
开头的分流)、`packageReference` 的 `mention` 正则(新增一个排除 `@scope/` 段的负向后顾)、自测里的
DX 电池与 WP-U6–U9。
- 两分钟验证:`node scripts/check-adr-0087-registration.mjs --self-test`,预期打印
`705 assertions`、退出码 0。
- 需要你做的:无,席位落地
## What changes
- **#26324, predicate 2 for an export named `default`.**
`metadataSurfaceReference` hands a `default` symbol to a new
`defaultImportReference`, which reads the import arm only. A metadata
surface reaches a default export through an import that binds it: a
default binding (`import x from 'M'`, with named bindings or a namespace
beside it, `type` or not) or `default` inside the braces of an `import`
/ `export … from` clause (`{ default as x }`, `export { default } from
'M'`). The specifier is attributed through the existing
`specifierNamesModule`, and comment spans are blanked through the shared
`maskComments`, as before. The bare-word arm is not read for `default`,
because `default` is an ordinary key in exactly the files predicate 2
reads. Every other export name keeps today's reading, both arms. The
shared primitive serves `runtime-interface-only` too, so a
`PATH#default` there gets the same reading.
- The import shapes are linear regexes anchored at a statement start.
They deliberately do **not** reuse `importSpecifiersFor`'s `[\s\S]*?`
clause scan. That scan runs today only on files that already contain the
symbol's word, and over every metadata surface it is super-linear in the
whitespace runs `maskComments` leaves: the first version of this fix
reused it and the real-tree run had not finished after 12 minutes of CPU
(one file alone, `packages/spec/src/api/discovery.zod.ts`, took 41 s).
The linear version runs the whole real-tree gate in 7 s.
- **Round 2 (contract review 6466959531, two should-fixes).** (1) A
`default` operand is also refused by a metadata surface that binds the
whole declaring module: a namespace import (`import * as ns from 'M'`,
`ns.default` one read away), a namespace re-export (`export * as ns from
'M'`), or a dynamic `import('M')` / `require('M')`. The refusal rests on
the binding alone, never on a `.default` read after it, so no member
tracking is needed; every other export name already refuses these shapes
through its bare-word arm, so this closes the admit gap round 1 opened.
Both new readers are linear (statement-anchored, no `[\s\S]*?`). (2)
`SELF_TEST_BATTERY_FLOOR` moves from 58 to 59 for the new DX battery.
- **#27022, the `PACKAGE#*` mention regex.** Its negative lookbehind
drops `/` from the excluded set, and a second negative lookbehind
refuses an `@SCOPE/` segment just before the name (`@[\w.~-]+/`). A `/`
may now precede the name, so a path or URL inside a string counts as a
`mention`, but not a `/` that closes an `@scope` segment, so an unscoped
`plugin-x` still does not match inside `@scope/plugin-x`. The
name-boundary rules on both sides are unchanged (`plugin-xy` and
`my-plugin-x` are other packages).
- Header comments of `metadataSurfaceReference` and `packageReference`
say the same.
## Tests
- New battery `DX (#26324)`, floor 19, and the roster floor
`SELF_TEST_BATTERY_FLOOR` 58 to 59: DX-G1 (the #26206 shape: a retired
`default` export beside a `default: true` field option and a Zod
`.default('')`) green, with DX-G1b naming the operand and its declaring
entry; DX-G2 (the import quoted only in a comment) green; DX-G3 (another
module's default imported) green; DX-R1 (a metadata surface that imports
the package's default) red; DX-R2 (`{ default as x }`) red; DX-R3
(`import * as ns`, then `ns.default`) red; DX-R4 (a dynamic `import()`)
red; DX-R5 (a `require()`) red; DX-R6 (`export * as ns from`) red; DX-U1
to U3 units (default beside named bindings, a type-only subpath default,
a multi-line `export { default } from` after a `;`; named bindings, a
`default:` key and a `.default()` call alone are not imports; a
non-`default` export name keeps the bare-word arm).
- WP battery floor 55 to 59: WP-U6 (the package name inside a path
string is a `mention`, with its line), WP-U7 (inside a URL), WP-U8
(`@scope/plugin-x` is not `plugin-x`, bare, in a path and in a URL),
WP-U9 (an unscoped `plugin-x` in a path and a URL is still a mention).
WP-G3 (comment only) and WP-U4 (`plugin-xy` is not `plugin-x`) stay
green unchanged.
- Self-test: 682 to 705 assertions.
<details><summary>Self-test under the verification lock, at
`f402e245`</summary>
```
$ OS_VERIFY_LOCK_SLOT=issue-26324-selftest bash scripts/pm/os-verify-lock.sh -c 'node scripts/check-adr-0087-registration.mjs --self-test'
✓ check-adr-0087-registration --self-test: 705 assertions over real temp git repos (real scan()/assertInputs() path)
os-verify-lock: VERDICT command-exit 0 · held the lock 62s (1m02s) · waited 0s
```
</details>
## Acceptance notes
- **The driver-memory measurement (the real shape #26206 blocked on).**
A local probe commit on `origin/main` `72629f38` deletes the `export
default { … }` block from `packages/drivers/driver-memory/src/index.ts`
and adds a changeset carrying `runtime-export-retired
@objectstack/driver-memory#default` with the line `` - FROM `default` TO
`InMemoryDriver`: … ``. The probe was never pushed.
| Gate | Base | Command | Exit | Verdict |
|---|---|---|---|---|
| `origin/main` copy | `72629f38` | `node
scripts/check-adr-0087-registration.mjs --base origin/main` | **1** |
predicate 2 false: `examples/app-crm/src/objects/account.object.ts`
mentions `default` (`{ label: 'Technology', value: 'technology',
default: true }`), the card's reading exactly |
| this PR (`2e1e09d5`) | `72629f38` | same | **0** | `verified:
@objectstack/driver-memory#default (export,
packages/drivers/driver-memory/src/index.ts)` |
| this PR (`2e1e09d5`) | `72629f38` plus one object file `import
memoryPlugin from '@objectstack/driver-memory'` | `--base PROBE_BASE` |
**1** | predicate 2 false: `probe-host.object.ts` (an object definition)
IMPORTS `default` from the module that declares it |
| this PR, round 2 (`f402e245`) | `9dacccf9` (the same probe on the
then-current `origin/main`) | `node
scripts/check-adr-0087-registration.mjs --base origin/main` | **0** |
`verified: @objectstack/driver-memory#default (export,
packages/drivers/driver-memory/src/index.ts)`: the namespace and dynamic
readers find nothing on main's metadata surfaces |
- **Read for `default` on the binding, not on `.default`:** a namespace
import, a namespace re-export and a dynamic `import('M')` /
`require('M')` of the declaring module refuse on the module alone (round
2). The member spelling `.default` is never read, since it cannot be
told from object keys and `.default()` calls; refusing on the binding is
the conservative direction.
- `importSpecifiersFor`'s super-linear clause scan is left as it is: its
callers gate it on the word being present, so no current run is slow.
Noted, not filed.
- The order expected `Clause-②: n/a`; both claims carry `Clause-②: no`,
and the body copies the claim. No published accept-set moves
(`scripts/**` is not shipped), so `no` is accurate either way.
- No changeset: the root package is private and `scripts/**` is not
published. Labelled `skip-changeset`.
- The ADR text needs no change: D9's second 2026-10-27 note already says
"any other occurrence of the package name, a string value included", and
the `default` reading is the D7 import primitive the note points to.
## Verification
<details><summary>Derived gates (dispatch-gates --commands, 33 families)
at `f402e245` (merge base `b322b5da`)</summary>
```
node scripts/check-adr-0087-registration.mjs --base origin/main :: exit 0
node scripts/check-adr-0087-registration.mjs --self-test :: exit 0
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:changeset-gate-self-tests :: 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:watch-hint-literal :: exit 0
$ node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran ran.txt
✓ dispatch-gates --ran: 33 derived famil(ies) accounted for — 33 run, 0 NOT-MEASURED (a DERIVED zero — all 33 recorded an exit code and none of them is 3).
```
</details>
---
_Generated by [Claude
Code](https://claude.ai/code/session_01WGufziGaNnGcwiYSC9Qzck)_
---------
Co-authored-by: Claude <noreply@anthropic.com>default export through its import, and a package name inside a path or URL (#27207)1 parent c5ee99d commit cdb949a
1 file changed
Lines changed: 152 additions & 5 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
463 | 463 | | |
464 | 464 | | |
465 | 465 | | |
466 | | - | |
| 466 | + | |
| 467 | + | |
467 | 468 | | |
468 | 469 | | |
469 | 470 | | |
| |||
496 | 497 | | |
497 | 498 | | |
498 | 499 | | |
499 | | - | |
| 500 | + | |
500 | 501 | | |
501 | 502 | | |
502 | 503 | | |
| |||
3161 | 3162 | | |
3162 | 3163 | | |
3163 | 3164 | | |
| 3165 | + | |
| 3166 | + | |
| 3167 | + | |
3164 | 3168 | | |
3165 | 3169 | | |
3166 | 3170 | | |
| 3171 | + | |
3167 | 3172 | | |
3168 | 3173 | | |
3169 | 3174 | | |
| |||
3199 | 3204 | | |
3200 | 3205 | | |
3201 | 3206 | | |
| 3207 | + | |
| 3208 | + | |
| 3209 | + | |
| 3210 | + | |
| 3211 | + | |
| 3212 | + | |
| 3213 | + | |
| 3214 | + | |
| 3215 | + | |
| 3216 | + | |
| 3217 | + | |
| 3218 | + | |
| 3219 | + | |
| 3220 | + | |
| 3221 | + | |
| 3222 | + | |
| 3223 | + | |
| 3224 | + | |
| 3225 | + | |
| 3226 | + | |
| 3227 | + | |
| 3228 | + | |
| 3229 | + | |
| 3230 | + | |
| 3231 | + | |
| 3232 | + | |
| 3233 | + | |
| 3234 | + | |
| 3235 | + | |
| 3236 | + | |
| 3237 | + | |
| 3238 | + | |
| 3239 | + | |
| 3240 | + | |
| 3241 | + | |
| 3242 | + | |
| 3243 | + | |
| 3244 | + | |
| 3245 | + | |
| 3246 | + | |
| 3247 | + | |
| 3248 | + | |
| 3249 | + | |
| 3250 | + | |
| 3251 | + | |
| 3252 | + | |
| 3253 | + | |
| 3254 | + | |
| 3255 | + | |
| 3256 | + | |
| 3257 | + | |
| 3258 | + | |
| 3259 | + | |
3202 | 3260 | | |
3203 | 3261 | | |
3204 | 3262 | | |
| |||
4802 | 4860 | | |
4803 | 4861 | | |
4804 | 4862 | | |
4805 | | - | |
4806 | | - | |
| 4863 | + | |
| 4864 | + | |
| 4865 | + | |
| 4866 | + | |
| 4867 | + | |
| 4868 | + | |
4807 | 4869 | | |
4808 | 4870 | | |
4809 | 4871 | | |
| |||
4813 | 4875 | | |
4814 | 4876 | | |
4815 | 4877 | | |
4816 | | - | |
| 4878 | + | |
4817 | 4879 | | |
4818 | 4880 | | |
4819 | 4881 | | |
| |||
8262 | 8324 | | |
8263 | 8325 | | |
8264 | 8326 | | |
| 8327 | + | |
| 8328 | + | |
| 8329 | + | |
| 8330 | + | |
| 8331 | + | |
| 8332 | + | |
| 8333 | + | |
| 8334 | + | |
| 8335 | + | |
| 8336 | + | |
| 8337 | + | |
| 8338 | + | |
| 8339 | + | |
| 8340 | + | |
| 8341 | + | |
| 8342 | + | |
| 8343 | + | |
| 8344 | + | |
| 8345 | + | |
| 8346 | + | |
| 8347 | + | |
| 8348 | + | |
| 8349 | + | |
| 8350 | + | |
| 8351 | + | |
| 8352 | + | |
| 8353 | + | |
| 8354 | + | |
| 8355 | + | |
| 8356 | + | |
| 8357 | + | |
| 8358 | + | |
| 8359 | + | |
| 8360 | + | |
| 8361 | + | |
| 8362 | + | |
| 8363 | + | |
| 8364 | + | |
| 8365 | + | |
| 8366 | + | |
| 8367 | + | |
| 8368 | + | |
| 8369 | + | |
| 8370 | + | |
| 8371 | + | |
| 8372 | + | |
| 8373 | + | |
| 8374 | + | |
| 8375 | + | |
| 8376 | + | |
| 8377 | + | |
| 8378 | + | |
| 8379 | + | |
| 8380 | + | |
| 8381 | + | |
| 8382 | + | |
| 8383 | + | |
| 8384 | + | |
| 8385 | + | |
| 8386 | + | |
| 8387 | + | |
| 8388 | + | |
| 8389 | + | |
| 8390 | + | |
| 8391 | + | |
| 8392 | + | |
| 8393 | + | |
| 8394 | + | |
| 8395 | + | |
| 8396 | + | |
| 8397 | + | |
| 8398 | + | |
| 8399 | + | |
| 8400 | + | |
| 8401 | + | |
| 8402 | + | |
| 8403 | + | |
| 8404 | + | |
| 8405 | + | |
| 8406 | + | |
| 8407 | + | |
| 8408 | + | |
| 8409 | + | |
| 8410 | + | |
| 8411 | + | |
8265 | 8412 | | |
8266 | 8413 | | |
8267 | 8414 | | |
| |||
0 commit comments