Repository navigation
refactor(spec): codemod split of conversions/registry.ts into per-entry modules (#29987) - #29993
objectstack-fleet[bot] wants to merge 4 commits into
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 45089076a39d962c144b862b39268d19d8c9e382 && git checkout 45089076a39d962c144b862b39268d19d8c9e382
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 0b99c2b1645b101459b1dd9fd4fecdf996194a76 c5fc11367642c409ba5d65656145d0624cf50ff4 && git checkout -B drift-repro 0b99c2b1645b101459b1dd9fd4fecdf996194a76 && git merge --no-ff c5fc11367642c409ba5d65656145d0624cf50ff4
node scripts/docs-audit/affected-docs.mjs --json 0b99c2b1645b101459b1dd9fd4fecdf996194a76
|
|
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
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 个按路径读这个文件的读者同步放宽。ALL_CONVERSIONS和每个CONVERSIONS_BY_MAJOR[n]的 id、顺序和函数源码在 base 与 head 完全一致;134 个声明文件逐字节相同。回滚就是 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(表相等)。main上重新生成、跑一次 CI、你批准(超过 3,000 行,Tier H),然后进合并队列。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 110 base files that name
conversions/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.tssrc/conversions/registry.ts, and that is still where an entry is registeredpackages/spec/scripts/build-schemas-check-mode.deletion-proofs.test.tspackages/spec/scripts/build-schemas-check-mode.retired-keys.test.tspackages/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' 5cdaddbc -- scripts packages/spec.Tests
--verify --base 5cdaddbccompares 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 5cdaddbcloads both registries. 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.960cdabf7a6532e0f0ffaa035cbe200a85b0eff2a1ddea58b0df515b4147d74b(input sha2563f5386899b7024a1e429d6a7b93cd41ce567f1171bfb5ee27974d1ffb2ec6c01). A--writefrom base'sregistry.tson this branch leavesgit diff HEADempty.dist/*.d.tsand*.d.mtsfiles are raw byte-identical between base and head. The set sha256 is757dc13d98549d73dc2c199941bd2f75b49dd071e1ccfa139472b5e72ea9dcbcon both sides.action.zod-CQhac7BH.d.mts, is caught: the normalised hash and the declared-surface digest both differ. The codemod's own--dtsreads PASS, with its control (a droppedreadonly) caught.check:api-surfaceandcheck:dual-source-exportsexit 0.--self-testruns 40 cases in 6 batteries, and all pass.test:repohas 89 files and 1,524 tests. Head has 807 files plus 1 named skip, 24,275 tests plus 1 skipped. The skip isroot-entry-type-nameability.pin.test.ts, which skips by design whiledistis stale. Run after the head build withOS_EXPECT_ROOT_NAMEABILITY=1, it passes 2/2, which brings head to base's counts.test:repoat head: 89 files and 1,524 tests.pure-schema-construction.test.tspasses 7/7 at head. That includes the./sharedconsumer bundle, which drops every conversion for the console's names and keeps all of them fornormalizeStackInput.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. The first run, at the codemod commit beforedistexisted, exited 0 without the flag.Acceptance notes
skip-changeset: the.d.tsmeets ruling 6348891160 item 1 in its strongest form (raw identity). 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.z.ZodEnumargument (low/high,paused/pendingand others). The declared-surface digest stayed EQUAL. The two pairs disagreed with each other as well as with base. Two quiet head builds and four base builds are all byte-identical. The cause is not established. The reading above comes from the quiet builds, and the readings from all builds are kept in the project files.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 base and at head on a quiet tree, 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.node scripts/pm/dispatch-gates.mjs --commandsderives 96. Of those, 92 exit 0 and 4 are NOT MEASURED with exit 3:check:doc-formula-expressions,check:dts-closure,check:dual-build-cjs-loadsandcheck:lean-entry-closure. Each one needs sibling packages built that this card does not touch, and CI runs them.--ranaccounts for all 96 (92 run, 4 NOT-MEASURED, 0 unrun).🤖 Generated with Claude Code
https://claude.ai/code/session_01WGufzg1QFj9ukYzafVoAqg
Body refreshed by spec seat 3 (Skills-docs follow-up filed as #29994; head c5fc113 rewords the three D2 remedies in
packages/spec/scripts/build-schemas.tsto namesrc/conversions/entries/plus theregistry.tsimport and array line, pinned in deletion-proofs and retired-keys tests): 2026-11-04T01:37Z