Repository navigation
feat(adr-0087): runtime-export-retired reads literal subpath keys - #33520
objectstack-fleet[bot] wants to merge 5 commits into
Conversation
The category's three operands take an optional LITERAL key of the package's `exports` map: `<package>/<subpath>#<Export>`, `#<Type>.<member>`, and `#*` for a key that left the map at HEAD while the package stays. The key's entry maps `dist/<p>.d.ts` (or a twin) to exactly one of `src/<p>.ts|tsx`. A wildcard key, a non-TypeScript key and an unmappable key are refused by name. ADR-0087 D9 is amended in place; the SP self-test battery pins each form and each refusal. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5kVi3STvGvJ9hHHAgS
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb Contract reviewServed-tier: Inputs read: card #30598 (body, triage comment 6684725634, ruling record 6885400963, claim 6885439323, os-dev-report 6885846856), PR #33520 (body, two-file list, net diff against Check-runs at render time: all 55 on this head completed, 29 success and 26 skipped, with no failure. The gate's own ① Derived judgments
② Semver levelNo changeset, labelled ③ Boundary flags
④ Design judgmentdocs/adr/0087-metadata-protocol-upgrade-contract.md (D9, the amendment note under the unmappable-entry paragraph, "What this does not decide", the Status line). Checked against its first consumer, the gate in this diff, and against the ruling as its execution plan. The note has the same shape as the two earlier D9 amendments: provenance, measurement, the three marker forms, the refusal list, and the three predicates for #. Every sentence has a matching branch in the gate: the
scripts/check-adr-0087-registration.mjs (implementing file). Checked sentence by sentence against D9 as amended, and probed with the five attacks the card names:
Findings:
Implemented-by: VERDICT: PASS One should-fix (the Adopted by the seat 2026-11-14T23:38Z · isolated sub-agent at CONTRACT_REVIEW_TIER · Ruling-ref: Leehom card cmsg_01TenzsRopZj4jMbvjX8uz1XFhuiZmTH8VFgMmHRmpiGAb, option A, tapped 2026-11-14T15:37Z |
`"exports": null` reads as absent to Node and TypeScript, so every file is importable by path and a key's absence proves nothing: the whole-key form now refuses it as it refuses a missing field. Three messages corrected: a member whose type left a subpath entry names the subpath export spelling, a key whose types condition is a TS source file is no declaration entry, and a package with no exports map at HEAD is no longer pointed at the whole-key spelling. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5kVi3STvGvJ9hHHAgS
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb Contract reviewServed-tier: Delta review. The earlier record is PR #33520 comment 6886012642, a PASS on head Inputs: comment 6886012642; card #30598 (body; triage 6684725634; ruling record 6885400963, 「A 收窄:只认字面子路径键」; claim 6885439323; the two os-dev-reports 6885846856 and 6886302050, which were listed but not taken as evidence); PR #33520 (body, two-file list, The merge brings only Gate verdicts at render: 43 check-runs exist on this head. 15 are success, 19 skipped and 9 still in progress, with 0 failed. The 9 running are Delta
The new self-test cases. SP's floor went from 61 to 73. Each
All four would fail on a revert. ① Derived judgments
② Semver levelUnchanged from the earlier record: there is no changeset, and ③ Boundary flags
④ Design judgmentdocs/adr/0087-metadata-protocol-upgrade-contract.md. It is unchanged since 27e5e2e and was re-checked against the ruling and against the gate as fixed.
scripts/check-adr-0087-registration.mjs. S1, N2, N3 and N4 hold, as set out under Delta. New findings:
Implemented-by: VERDICT: PASS The should-fix S1 is fixed and pinned. N2, N3 and N4 are fixed and pinned. N1 and N5 stand as accepted deviations. The five new findings are all nits, so this round ends. Nine check-runs, among them the lane that runs this gate's Adopted by the seat 2026-11-15T00:17Z · isolated sub-agent at CONTRACT_REVIEW_TIER · Ruling-ref: Leehom card cmsg_01TenzsRopZj4jMbvjX8uz1XFhuiZmTH8VFgMmHRmpiGAb, option A, tapped 2026-11-14T15:37Z |
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb 维护者速读
席位核对Verdict: ACCEPT, held for the maintainer · head
Implemented-by: |
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb Correction: contract-review tierThe contract-review record(s) 6886012642, 6886472906 on this PR say The seat re-runs the review at |
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb Contract reviewServed-tier: At-tier re-review of this head. The two earlier records on this PR (6886012642, 6886472906) were served off-tier and are not evidence here; the tree was judged from scratch, and ③ says which of their findings this record confirms. Inputs read: card #30598 (body, triage 6684725634, ruling record 6885400963, claim 6885439323, the two os-dev-reports, the ACCEPT note), PR #33520 (body, the two-file list, the net diff against Check-runs on this head: all completed, none failed. Success on every lane that ran, including ① Derived judgments
② Semver levelNo changeset, labelled ③ Boundary flags
④ Design judgmentdocs/adr/0087-metadata-protocol-upgrade-contract.md (Status line; the 2026-11-14 note under D9's unmappable-entry paragraph; "What this does not decide"). Judged against the ruling as its execution plan and the gate in this diff as its first consumer. The note follows the shape of the two 2026-10-27 notes: provenance, measurement, the three marker forms, the refusals, the three predicates for the whole-key form. It stops where the ruling stops: "A wildcard key is not resolved. That waits for a second case." Sentence by sentence against the gate:
Findings on the ADR:
scripts/check-adr-0087-registration.mjs (implementing file). The five attacks the card names:
Findings on the gate, all nits (none admits a claim the contract refuses):
Implemented-by: VERDICT: PASS One should-fix (A1, the whole-key predicate 2 sentence against the gate's in-package filter) earns a delta review of its fix. The other eight findings are nits: A2 to A4 are prose faces, G1 to G5 are accepted deviations or the next touch of the gate. Adopted by the seat 2026-11-15T00:42Z · isolated sub-agent at CONTRACT_REVIEW_TIER (served model verified by the seat) · Ruling-ref: Leehom card cmsg_01TenzsRopZj4jMbvjX8uz1XFhuiZmTH8VFgMmHRmpiGAb, option A, tapped 2026-11-14T15:37Z |
|
domain:skills#1 · os-project-manager · session_01FEkQ5pjSPT7ui2EUcunaVb ACCEPT 6886478218 withdrawn: the earlier records it rests on were served off-tier, and the at-tier review on head |
D9's whole-key predicate 2 now says what the gate reads: the package's own files the key's entry reaches, as for a whole package. A file of another workspace package the entry re-exports is judged when its name is an export operand. Pinned both ways (SP-G6, SP-R20), plus a missing exports field at HEAD (SP-R17c/d). The 2026-10-12 addendum points at the new note, the non-TS bullet names a TS-source types condition, and the sourceEntryAt docblock names noExportsMap. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FEkQ5kVi3STvGvJ9hHHAgS
Requested by Leehom · project thread
Fixes #30598
domain:skills#1 · os-project-manager · session_01FEkQ5kVi3STvGvJ9hHHAgS
Clause-②: no
Metadata-protocol: none
维护者速读
runtime-export-retired类别现在认包exports映射里的字面子路径键:包/子路径#导出、包/子路径#类型.成员、包/子路径#*(该键在 HEAD 离开映射、包还在)。子路径入口按dist/X.d.ts对应唯一的src/X.ts或src/X.tsx读;通配键、非 TS 键(./style.css)、对不上源文件的键都按名拒绝。ADR-0087 D9 原地加一条修订,自测加 SP 电池 80 例。no-migration-prescription并去掉箭头躲检测器,正是 D7 要消除的形态。你在决策卡上选了「A 收窄:只认字面子路径键」(卡上记录 6885400963)。scripts/check-adr-0087-registration.mjs的subpathSourceEntry与verifySubpathRetired;parseExportOperand;ADR-0087 D9 新增的 2026-11-14 修订段。node scripts/check-adr-0087-registration.mjs --self-test,预期✓ ... 819 assertions。What changes
scripts/check-adr-0087-registration.mjs, categoryruntime-export-retired.parseExportOperandsplits the operand at the package name (splitPackageSpecifier):@scope/pkg/a/b#Xreads the./a/bkey,@scope/pkg#Xthe.key as before. It returnssubpathandspecifierbeside the old fields. A subpath with a*anywhere is refused by name as a WILDCARD; an empty,.or..segment is refused; a subpath spelling a TS source file keeps the old "names a FILE" refusal.sourceEntryAttakes the key. The root branch is unchanged. A subpath key (subpathSourceEntry) reads its types entry withresolveTypesEntry(manifest, './sub')and mapsdist/P.d.ts(or a.d.mts/.d.ctstwin) to exactly one ofsrc/P.ts/src/P.tsx. Refused by name: a key only a wildcard key reaches (wildcardKeysMatching, which never resolves the pattern), a key that names no.d.ts(./style.css), an unmappable key, an ambiguous key, and an absent key (markedkeyAbsent).PACKAGE/SUB#*is new (verifySubpathRetired). Predicate 1: the key maps at the base; at HEAD the package is still a workspace member (a deleted one points atPACKAGE#*), it declares anexportsmap (a missing field and"exports": nullare both refused: Node and TypeScript read null as absent), the key is gone and no wildcard key reaches it. Predicate 2: none of the package's own files the key's entry reaches is a metadata surface (a file of another workspace package the entry re-exports is that package's, judged when its name is an export operand), and no metadata surface outside the package names the specifier in code (packageReference, shared withPACKAGE#*). Predicate 3: one FROM line names the specifier.SP (#30598), floor 80.docs/adr/0087-metadata-protocol-upgrade-contract.md, D9, plus one pointer in the 2026-10-12 addendum's opening. A third amendment note under the unmappable-entry paragraph, in the shape of the two 2026-10-27 notes (provenance, measurement, the three marker forms, the refusals, the three predicates for#*). The "What this does not decide" sentence now names the wildcard refusal. The Status line gets an Amended entry, and the 2026-10-12 addendum's opening sentence points at the new note.Why
Ruling: the maintainer chose A, narrowed, 「A 收窄:只认字面子路径键」, on a decision card at 2026-11-14T22:42Z; the option read 「新增 <pkg>/<sub>#Export、#Type.member、#*;通配键按名拒绝。改门禁并修订 D9,立一张 skills 卡。」 Recorded on the card as comment 6885400963. Analysis: project file
pm-orders/skills/30598-decision-analysis.md.Acceptance notes
f068cde8) with the newsourceEntryAtover every published package'sexportskeys: 110 published packages, 26 declare subpath keys, 78 keys besides./package.json. 68 map, 4 are unmappable (@objectstack/scenarios./score,./score/full,./runner,./export), 5 are not TS (@objectstack/spec./openapi.json, four./style.css), 1 is a wildcard (@object-ui/i18n./locales/*), 0 ambiguous. This matches the evaluation's 68 / 4 / 5 / 1.@objectstack/cli/consolemaps topackages/cli/src/console.ts;@object-ui/i18n/localesmaps toui/packages/i18n/src/locales/index.ts;@object-ui/i18n/locales/zhis refused through./locales/*.git grep runtime-export-retiredunderskills/**,.claude/**,content/**andAGENTS.mdhas no hit, so the order's third surface is empty. The gate's own refusal text (the HOW hint) names the subpath form.export *of one stays an unresolved star that refuses an absence claim, which is the conservative direction. Not in the ruling's scope.no-migration-prescriptionis refused only by a body carrying a prescription; since PR #32649 it is also refused on a changeset declaringMetadata-protocol: narrowed#32674) also edits ADR-0087, at the 2026-08-13 addendum's vocabulary paragraph, not D9. It had not merged when this branch was cut; the seat orders the landing.Verification
Changed: 2 files.
dispatch-gates --tier: MANDATORY contract-review tier (docs/adr/**, no one-line exit).check-governed-merges --branch: GOVERNED, Tier H (docs/adr/**×1), 508 changed lines, under 3000. Changeset: none, labelledskip-changeset: the diff isdocs/adr/**and a repo-rootscripts/gate, and no package'sfiles[]ships either.Local gates at head
6d1f3bce(round 3, after the at-tier contract review 6886775383; round 2 wasdc3d60c0merged withorigin/maine3f0cfd4as92259ce2). The derived list was taken and run on6d1f3bceitself; earlier rounds ran the same 44 families ondd6bc2a7and92259ce2, all exit 0.44 derived gate families on 6d1f3bc, all exit 0; `--ran` reconciliation 44 / 44, 0 NOT-MEASURED
Closure built first:
pnpm --filter "@objectstack/lint..." buildunder the verify lock,VERDICT command-exit 0.The gate's own self-test: 819 assertions
With the new code and before the new battery was added, the self-test printed 739 assertions, every existing battery green (the root operands are unchanged). With battery
SP (#30598)it prints✓ check-adr-0087-registration --self-test: 819 assertions over real temp git repos. SP registers 80 cases: G1 to G6 (export, member, whole key, root and subpath in one marker, arrow form, whole key over an entry that re-exports another package's root), R1 to R20 (wildcard reach, wildcard spelling, non-TS key, unmappable key, absent key, still exported, export on a gone key, key still in the map, wildcard at HEAD, package deleted, noexportsmap at HEAD, metadata surface importing the subpath, entry reaching a metadata surface, per-export FROM lines, ambiguous.ts/.tsx,"exports": nullat HEAD, no whole-key hint without anexportsmap, atypescondition naming a TS source, a member hint naming the subpath spelling, the re-exported name refused as an export operand; SP-R17c/d pin a missingexportsfield beside the null case), and unit pins U1 to U9 on the parser,splitPackageSpecifierandwildcardKeysMatching. One-off mutations, each restored and never committed: the null check back to an undefined-only test reds SP-R16; dropping the own-directory filter on the entry's files reds SP-G6. The gate has no separate*.test.ts;git grepof its file name in test files has no hit.🤖 Generated with Claude Code
https://claude.ai/code/session_01FEkQ5kVi3STvGvJ9hHHAgS