Repository navigation
refactor(spec): codemod split of conversions/registry.ts into per-entry modules (#29987) - #29993
Conversation
…ry modules (#29987) WIP: the codemod and its generated split, before the reader census. Claude-Session: https://claude.ai/code/session_01WGufzg1QFj9ukYzafVoAqg Co-authored-by: Claude <noreply@anthropic.com>
…ntry modules (#29987) The ADR-0087 registration gate, the affected-docs self-test, the ADR anchor and the major-18 merge test read the split registry with its entries. Claude-Session: https://claude.ai/code/session_01WGufzg1QFj9ukYzafVoAqg Co-authored-by: Claude <noreply@anthropic.com>
#29987) Under the spec package's CommonJS default the tsx loader rewrites every imported call to (0, import_x.name)(...), so a moved entry's function source differed only by the loader's spelling of its import (93 of 112 digests). Both trees now load from a scratch copy marked type: module, and the probe refuses a CommonJS-loaded function instead of comparing it. Result: 112 of 112 digests equal. Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzg1QFj9ukYzafVoAqg
📓 Docs Drift CheckThis PR changes 1 package(s): 149 hand-written doc(s) name something this change touched — list omitted above 15 rows. Re-derive on the tree named below: ⛔ 19 release-owned page(s) also affected — read-only, see AGENTS.md Documentation Guardrails. What this run could not see
Coarse fallback — 169 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin e0820a5df6d06eecbaeee21a2ee3c3cee0a262b6 && git checkout e0820a5df6d06eecbaeee21a2ee3c3cee0a262b6
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin c2d353d2ac538ccddfad083a1c9f6f168b9a231d dca57060c584739094493510918ce8067e672d7f && git checkout -B drift-repro c2d353d2ac538ccddfad083a1c9f6f168b9a231d && git merge --no-ff dca57060c584739094493510918ce8067e672d7f
node scripts/docs-audit/affected-docs.mjs --json c2d353d2ac538ccddfad083a1c9f6f168b9a231d
|
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K Contract-review-claim: session_01WGufzfgvGexKn9vLHsy89K · head a8c5d94 · 2026-11-04T00:42Z Schema face ( |
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K Contract reviewServed-tier: ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Findings:
Implemented-by: VERDICT: PASS |
… remedies (#29987) After the split, a new D2 conversion is a module under src/conversions/entries/<toMajor>/ plus its import and array line in src/conversions/registry.ts. The three remedy texts in build-schemas.ts said to add it in registry.ts. They now name both, and the deletion-proofs and retired-keys check-mode tests pin the entries/ path (both fail on the old text). Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WGufzg1QFj9ukYzafVoAqg
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K Contract-review-claim: session_01WGufzfgvGexKn9vLHsy89K · head dca5706 · 2026-11-04T10:46Z Phase 1 delta review (the split regenerated on the latest |
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K Contract review — Phase 1 deltaServed-tier: ① Derived judgments
② Semver level
③ Boundary flags
④ Design judgment
Findings:
Implemented-by: VERDICT: PASS |
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K 维护者速读
席位意见:fable 契约复审两轮都是 PASS(Phase 0 和 Phase 1)。 席位核对 — ACCEPT · domain:spec#3 · head
|
⛔ merge queue 构建失败 — 先分诊,再决定要不要重排队列构建 41819688971 红了。队列跑的是全量套件(PR 侧 CI 只跑 affected 子集), 分类: 失败的 job(日志抽取,best effort):
跨 PR 相同签名(24h,按失败测试文件聚合):
历史信号:
分诊清单:
Generated by Claude Code · merge-queue-triage workflow (#4859) |
|
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K Dequeued, not this PR's: the merge-group CI run 41819688971 (merge commit Posted 2026-11-04T11:44Z. |
domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K
Requested by Yibo Wang · project thread
Fixes #29987
Ruling-ref: 6583399215
Clause-②: no (move-only)
Metadata-protocol: none
Skills-docs: follow-up filed as #29994 — .claude/skills/spec-property-retirement/SKILL.md (it still says a new conversion is written in
conversions/registry.ts; after the split it is a module underconversions/entries/plus one import line inregistry.ts)ADR-0087 / D3: no migration entry moves.
migrations/is untouched, andcheck-adr-0087-registration --base origin/mainexits 0.维护者速读
scripts/codemod-split-conversions-registry.mjs把packages/spec/src/conversions/registry.ts(16,019 行)拆成 112 个条目模块(entries/<toMajor>/<id>.ts)加一个entries/shared.ts;registry.ts剩 354 行,只留导入和四张表。另有 4 个按路径读这个文件的读者同步放宽,build-schemas 的三处 D2 补救提示也改成了拆分后的写法。main(c2d353d2)上重新生成。这张表是冲突最多的文件之一,按条目拆开后,每条 conversion 单独成文件,评审和合并都更容易。ALL_CONVERSIONS和每个CONVERSIONS_BY_MAJOR[n]的 id、顺序和函数源码在 base 与 head 完全一致;每次 head 构建的 134 个声明文件都与一次同状态的 base 构建逐字节相同(main自己的 d.ts 构建在两种状态间交替,见 Tests)。回滚就是 revert 这个 PR。packages/spec/src/conversions/registry.ts(新的宿主文件)、entries/shared.ts,以及下面的读者普查表。pnpm install --frozen-lockfile,然后node scripts/codemod-split-conversions-registry.mjs --verify --base origin/main(字节一致)和--arrays --base origin/main(表相等)。dca57060上全绿,由 spec 席位送入合并队列。What changes
scripts/codemod-split-conversions-registry.mjs. It sits beside the pilot'scodemod-split-sql-driver.mjsand follows its conventions (ts-morph in memory, a plan mode,--write,--verify,--self-test).packages/spec/src/conversions/entries/11/(3),15/(2),17/(12) and18/(95) hold one module per conversion entry, named by itsid.entries/shared.tsholds the 11 helpers that two or more entries read. The 31 helpers that only one entry reads move into that entry's module, following pilot ruling 6591753301. Every module is a leaf: it imports../../types.js,../../walk.js,../shared.jsand the spec modulesregistry.tsalready imported (for exampleui/assembled-views.zod.js), and never another entry.registry.tskeeps its module docblock,import type { MetadataConversion }, one import line per entry in base definition order, andOrderedConversion,inApplicationOrder,MAJOR_18_CONVERSIONS,CONVERSIONS_BY_MAJORandALL_CONVERSIONSbyte for byte, including the@__PURE__markers. The public import pathconversions/registryand its two exports are unchanged.packages/spec/scripts/conversions-major18-merge.test.tsnow reads the import lines inregistry.tsand eachentries/18/module.scripts/check-adr-0087-registration.mjsreads the conversions ledger asregistry.tsplusentries/**, and gains a CR1-CR3 battery.scripts/docs-audit/affected-docs.mjstreatsregistry.tsplusentries/**as the conversion table.scripts/adr-anchors/: the ADR-0120 anchor followsdeclared-index-unique-scopeinto its module, and the host keeps ADR-0087.scripts/regen-artifacts.mjsrow note was updated.Reader census (all 111 files on base
c2d353d2that nameconversions/registry)registry.ts(3 testsvi.mockit, same exports)packages/spec/scripts/conversions-major18-merge.test.tsscripts/check-adr-0087-registration.mjs--base origin/mainexit 0scripts/docs-audit/affected-docs.mjsscripts/adr-anchors/packages__spec__src__conversions__registry.ts.jsonentries/18/declared-index-unique-scope.ts.check:adr-anchorsexit 0scripts/regen-artifacts.mjspackages/spec/scripts/build-schemas.tsc5fc1136): its three D2 remedies now name a module undersrc/conversions/entries/plus its import and array line insrc/conversions/registry.tspackages/spec/scripts/build-schemas-check-mode.deletion-proofs.test.tsc5fc1136): the remedy namessrc/conversions/entries/with the toMajor directory. It fails on the old remedy textpackages/spec/scripts/build-schemas-check-mode.retired-keys.test.tsc5fc1136): the remedy namessrc/conversions/entries/. It fails on the old remedy text. The two check-mode tests pass 29/29packages/spec/src/root-entry-migrations-split.pin.test.tsregistry.tsis still in the root graph; passespackages/spec/export-origins/root.jsonregistry.ts;check:export-originsexit 0packages/spec/liveness/action.jsonregistry.ts:5578, which was already stale onmainbefore this PRscripts/check-spec-docblock-symbol-anchors.mjsscripts/check-future-spec-major.mjsTo reproduce the census:
git grep -l 'conversions/registry' c2d353d2 -- scripts packages/spec. The one file new since the Phase 0 base5cdaddbcispackages/spec/src/system/auth-revoke-sessions-on-password-reset-retirement.test.ts, and it is an import.Tests
Phase 1 readings: head
dca57060(a plain merge ofmainc2d353d2intoc5fc1136, no rebase), basec2d353d2.maindid not touchpackages/spec/src/conversions/between5cdaddbcandc2d353d2. Regenerating frommain'sregistry.tswith--writeleavesgit diff HEADempty, so the merge is the regenerate.--verify --base origin/main(c2d353d2) exits 0. It compares 159 statements (727,159 bytes). All 112 of 112 entries and all 42 helpers moved (11 intoentries/shared.ts), and 5 statements stayed. It writes 113 modules and checks 584 import bindings. Undoing the split rebuilds the baseregistry.tsbyte for byte.--arrays --base origin/mainexits 0. Exports match (ALL_CONVERSIONS,CONVERSIONS_BY_MAJOR).ALL_CONVERSIONSholds 112 ids, sha2566dfde60307ccd336d6265e84bb095632acbbdbcd08483d73f5e83070c9728ae7, in the same order.CONVERSIONS_BY_MAJORis{11: 3, 15: 2, 17: 12, 18: 95}with the same membership and order. 112 of 112 entry digests are equal, where a digest is JSON with the function source included.--writeruns frommain's unsplitregistry.ts(input sha2563f5386899b7024a1e429d6a7b93cd41ce567f1171bfb5ee27974d1ffb2ec6c01) both give output tree sha256960cdabf7a6532e0f0ffaa035cbe200a85b0eff2a1ddea58b0df515b4147d74b, the same as Phase 0, and leavegit diff HEADempty.pnpm --filter @objectstack/spec buildproduced base-1, head-1, base-2 and head-2. Each build's 134 declaration files fall into one of two states, with set sha256cb955a20e1de3c63…orcdac5d7b0c33761e…. base-1 and head-2 are in the first state; head-1 and base-2 are in the second.dtsnorm.mjspasses on both pairs, and its control (a renamed declaration inaction.zod-CQhac7BH.d.mts) is caught, with the normalised hash and the surface digest both DIFFER. The codemod's--dts base-1 head-2reads PASS, with its control (a droppedreadonly) caught.--dts base-2 head-2reads FAIL (9). The 9 are the 8 filesapi,contracts,marketplaceandsystemindex.d.ts/index.d.mts, plus the renamedautomation-api.zodchunk pair. base-1 against base-2 differs in exactly the same way: 10 files and 34 statements, with string-literal members in another order insidez.ZodEnumrecord types and object shapes, and the declared-surface digest EQUAL on every file. This ismain's own.d.tsbuild being nondeterministic from run to run, not the split. Every quiet head build equals a quiet base build byte for byte, so no reorder belongs to head.issue-29987/phase1/.check:api-surfaceandcheck:dual-source-exportsexit 0.--self-testruns 40 cases in 6 batteries, and all pass.c2d353d2and headdca57060both givetest811/811 files and 24,376 tests plus 1 todo, andtest:repo90/90 files and 1,539 tests.pure-schema-construction.test.ts, including the./sharedconsumer bundle, is in the local suite above and passes.pnpm --filter @objectstack/spec typecheckexits 0 at head withNODE_OPTIONS=--max-old-space-size=6144. Without the flag, thecheck:test-typecheckstep runs out of heap at about 2 GB on this box, at base and at head alike.Acceptance notes
c2d353d2) is over the 3,000-line threshold. The maintainer approved landing it in today's window.skip-changeset: the.d.tsmeets ruling 6348891160 item 1 in its strongest form, raw identity against a base build of the same state. Following 6441032442 item 4 and the pilot PR refactor(driver-sql): codemod pilot — generated, byte-identity-proved section split of sql-driver.ts (#29520) #29598, the PR takes no changeset.main's spec.d.tsbuild alternating between two states on a quiet tree (see Tests). A.d.tsreading for any spec split therefore has to pair builds of the same state, and a single base-against-head pair can read FAIL with no change at all.MAJOR_18_CONVERSIONSdocblock in the host still says to define a conversion directly above the entry that follows it. It has to stay byte-identical in a move-only PR, so the merge test now gives the post-split spelling: import it directly above that entry's import.Verification
main, never a rebase):git checkout origin/main -- packages/spec/src/conversions/registry.ts, thennode scripts/codemod-split-conversions-registry.mjs --write.--writedeletes stale codemod-marked modules and refuses any file underentries/that it did not write. If the regeneration moves different code, re-check the reader table above.node scripts/codemod-split-conversions-registry.mjs --verify --base origin/main, then--arrays --base origin/main..d.ts: build@objectstack/specat least twice at base and twice at head on a quiet tree, pair builds of the same state, then runnode scripts/codemod-split-conversions-registry.mjs --dts BASE_DIST HEAD_DIST. The report reading under 6441032442 B isdtsnorm.mjs, kept in the project files atissue-29987/dtsnorm.mjs, sha256e0b4b0c3d6a29e99dea99b2a65b683b0649f3e7c6d4fa671b994d590d48219b4. Run it asnode dtsnorm.mjs --typescript node_modules/typescript --dirs BASE_DIST HEAD_DIST --control, and expect exit 0 and"pass": true.dca57060:node scripts/pm/dispatch-gates.mjs --commandsderives 96, and all 96 exit 0, includingcheck:dts-closure,check:dual-build-cjs-loads,check:lean-entry-closureandcheck:doc-formula-expressions, which are measurable now.--ranexits 0: 96 run, 0 NOT-MEASURED, 0 unrun.dca57060: 54 check runs succeeded and 10 were skipped; none failed.🤖 Generated with Claude Code
https://claude.ai/code/session_01WGufzg1QFj9ukYzafVoAqg
Body refreshed by spec seat 3 (Phase 1 on c2d353d / dca5706; contract review PASS 6628915927): 2026-11-04T11:09Z