Repository navigation
feat(adr-0087): the seventh disposition category, runtime-export-retired — retired exports and members, proven by the compiler at both revs - #22940
Merged
Conversation
…an becomes metadataSurfaceReference The same reading, extracted unchanged so a second category can ask it of a retired export at the merge base without a second spelling of the question. Self-test: 463 assertions, unchanged. Claude-Session: https://claude.ai/code/session_012yK1ddAdAqfzwigRHZq3r2 Co-authored-by: Claude <noreply@anthropic.com>
…rammar, the compiler export reader, the three predicates (WIP: ADR half and self-tests follow) Claude-Session: https://claude.ai/code/session_012yK1ddAdAqfzwigRHZq3r2 Co-authored-by: Claude <noreply@anthropic.com>
…red -- the ADR addendum (D9) and the self-test batteries Claude-Session: https://claude.ai/code/session_012yK1ddAdAqfzwigRHZq3r2 Co-authored-by: Claude <noreply@anthropic.com>
…ntime-export-retired
Contributor
Author
维护者速读改了什么
为什么改
风险与代价(含回滚)
席位意见
你要做的
Generated by Claude Code |
os-zhuang
approved these changes
Oct 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #22918
Clause-②: no
What this does
ADR-0087's closed disposition vocabulary gains a seventh category,
runtime-export-retired, for a declared-breaking changeset that retires published runtime exports (and members of an exported type) and carries the FROM → TO line each retired name owes. Built on the maintainer's ruling6116982351on #22918 (Q1 → B narrowed · Q2 → A) and the unrevised clauses of ruling A6116351873on #22915.The marker, written here without its comment delimiters (this body cannot carry them):
adr-0087: not-required (runtime-export-retired PACKAGE#EXPORT, PACKAGE#TYPE.MEMBER) WHY. The two operand kinds mix in one marker; the package is named, never a file.Three predicates, re-verified on every run and pinned by name (
RUNTIME_EXPORT_PREDICATES):retired-from-entry— an export is reachable from the package's published entry at the merge base and absent at HEAD; for a member, its type is reachable at the base, the member is present on it there (getPropertiesOfType) and absent at HEAD while the type is still exported. Read by the TypeScript compiler: a Program over the package's source entry at each rev, served from that rev's blobs, andgetExportsOfModuleon the entry's symbol (soexport *resolves). The entry is mapped through theexportsmap (resolveTypesEntry, imported read-only from the readme-exports gate) and tsup'sdist/index.d.ts→src/index.ts; anything else is refused loudly, never guessed. Anexport *the reader cannot follow refuses an absence claim at HEAD.no-metadata-surface— at the merge base, no operand is declared in a*.zod.ts, underpackages/spec/src/contracts/or in an object definition, none is a Zod projection, and no metadata surface references it in code (theruntime-interface-onlyprimitives; its step-4 reference scan is extracted unchanged asmetadataSurfaceReferenceand now shared).from-operands-named— every FROM operand is a named operand spelled as in the marker (TYPE.MEMBERfor a member), and every named operand has a FROM side. A callname(...)/new Name(...)reads as that name; no constructor argument or object literal is parsed, sonew EmailServicePlugin({ seedTemplates: false })namesEmailServicePluginand is refused as out of range (the ruling's own example). The category is not exempt from theno-migration-prescriptionrefusal: it sets aside exactly the FROM lines it read and runs the same detector over what is left.typescriptis loaded lazily (loadExportReader, throughimport-prerequisite.mjs), only when a changeset names the category: the entry point scans, and if a scan reportsneedsExportReaderit loads the compiler and scans again. The header line "Zero third-party IMPORTS" is retracted, as ruled.Files:
scripts/check-adr-0087-registration.mjsanddocs/adr/0087-metadata-protocol-upgrade-contract.md(the vocabulary block, and a new addendum beside the sixth category: D9, both operand kinds, the predicates, the mapping refusal, the accepted deviation, the worked example, what was not taken).Two readings taken where the ruling's words leave a choice (please confirm on review)
REX-R7). This also mechanises the house rule that a removed export's changeset carries its FROM → TO line. If only the first direction was meant, the second check is oneforloop to delete..d.mts/.d.ctstwin maps likedist/index.d.ts. Re-measured at018b077fb:resolveTypesEntrylands@objectstack/spec's.ondist/index.d.mts(itsimportcondition). Mapping only the literal.d.tsmakes 5 of 70 published packages unmappable; with the twin it is the 4 the ruling cites (@objectstack/client-react: nosrc/index.ts;@objectstack/console,@objectstack/skills,create-objectstack: no types entry).Evidence (all at HEAD
f06cee413, which includesorigin/maine4ad6776d)7de0265fc, its changeset re-marked under the new category, judged with--base 9e9e6f97f:verified: @objectstack/plugin-email#createSysEmailTemplateLoader (export, packages/plugins/plugin-email/src/template-loader.ts), …(the entry point took the load-and-rescan path);the FROM operand new EmailServicePlugin({ seedTemplates: false }) names EmailServicePlugin, which the marker does not name -- out of range.node scripts/check-adr-0087-registration.mjs --self-test→548 assertions(463 before; +3 from the vocabulary growing, +82 new in four batteries: the category,REX-Npredicates by name,REX-Uunits,REX-Llazy load). The ruled cases: accept the export half (REX-G1); refuse a still-present export (REX-R1), a*.zod.tssymbol (REX-R2), a FROM operand outside the named set (REX-R3a,REX-R3b= lines 29–30 verbatim), a non-canonical member spelling (REX-R4a,REX-R4b), an unmappable package (REX-R5a,REX-R5b); the six existing categories' batteries all green, andREX-Cpins that the worked example's ownno-migration-prescriptionverdict is unchanged.scripts/ablation-replace.mjs, trap-guarded): predicate 1's still-present check off →REX-R1red; predicate 3's out-of-range check off →REX-R3a,REX-R3b,REX-R4ared; the inherited-detector residual off →REX-R8ared. Each restore proven: blob322b6f872= HEAD and an emptygit diff HEAD.--listbefore (at018b077fb) and after is byte-identical (md5862b7498…): 131 declared-breaking, 131 with a disposition, 83 onno-migration-prescription.--base origin/mainexit 0 before and after.typescript(REX-L1, positive controlREX-L2). Interleaved wall time on an empty diff, 6 runs each on a shared box: median 3848 ms (base gate) vs 3795 ms (this gate).node scripts/pm/dispatch-gates.mjs --ran→43 derived famil(ies) accounted for — 43 run, 0 NOT-MEASURED (a DERIVED zero — all 43 recorded an exit code and none of them is 3).check:doc-formula-expressionsfirst answered exit 3 (PREREQUISITE NOT MET:@objectstack/formula/@objectstack/lintunbuilt) and was re-run green after building them.check:pm-dispatch-gates:1828 cases pass(fast tier)..md, matched by no config object'sfiles);eslint --no-inline-config --format jsonreports 1 file, 0 errors, 0 warnings. The config resolved for it has noparserOptions.project/projectService, so type-aware linting is off and this diff cannot move any untouched file's verdict.Acceptance notes
not-requiredhonest" section still says "four of the five dispositions" — stale since the sixth category, not touched here (prose drift, nothing reads it).FROM … TOline (6 of 417 stock changesets, 4 declared-breaking, none read by the detector), stating it stays out of the detector's reach and is read by this category..changeset/15205-email-templates-resolve-registry.md) is not re-graded, as ruled.维护者速读(草稿)
改了什么:ADR-0087 的「破坏性变更怎么处置迁移账本」词表新增第七类
runtime-export-retired。一个 changeset 删掉了已发布包的公开函数、常量、类型,或某个导出类型上的配置项时,作者在标记里点名这些名字;门禁用 TypeScript 编译器在合并基点和当前版本各读一次这个包的公开入口,核对「以前确实公开导出、现在确实没了」,确认它们都不是元数据,并确认 changeset 里的 FROM → TO 行恰好只写这些被点名的名字。只改了门禁脚本和 ADR 两个文件。为什么改:这类变更以前只能挂在兜底类
no-migration-prescription上,而且是靠检测器读不到「没有箭头的 FROM … TO 行」才过关(样例 15205),正是 D7 要淘汰的「靠漏检过关」。你 10-12 的裁决(Q1 B 收窄、Q2 A)要求给它一个能复跑、能正面证明的类别,并覆盖导出类型上的成员。风险与代价(含回滚):门禁多了一个
typescript依赖,但只在 changeset 点名这一类时才加载,其他 PR 的门禁耗时不变(实测中位数 3.85 秒对 3.80 秒)。不碰任何运行时代码,也不重评已有 changeset:存量 131 份破坏性 changeset 的审计输出前后逐字节相同。回滚就是 revert 本 PR。有两处按字面读的地方请你确认:「恰好」按双向执行(被点名的每个名字都必须有自己的 FROM 行);tsup 的.d.mts入口也算可映射,否则@objectstack/spec会被拒,与裁决引用的「70 个里 4 个映射不上」对不上。席位意见:
你要做的:读 ADR 新附录 D9 和上面两处读法;同意就在本 PR 上给 APPROVED review,席位随后落地。
Generated by Claude Code