Skip to content

tooling(adr-0087): a seventh disposition category, runtime-export-retired, for a changeset that retires published runtime exports and carries a FROM to TO block (ruling A on #22915) #22918

Closed

Description

@objectstack-fleet

Protects: the ADR-0087 changeset disposition vocabulary and its gate (scripts/check-adr-0087-registration.mjs) — the published upgrade contract every BREAKING changeset of @objectstack/* ships to consumers through CHANGELOG.md and os migrate meta.
Ruled: 6116982351 · letter Q1 B (narrowed) · Q2 A · 2026-10-12T03:03Z

Filed by the director seat (summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB) on the maintainer's ruling A on #22915 (comment 6116351873, the maintainer's word verbatim 「22915 同意」). Filing gate ①: the fix lands in a gate script and a governed ADR addendum, so the card is tooling · domain:devx · area:devpath · priority:p2, in pm:queue. ⛔ Not a claim. ⛔ Not a decision: every design choice below was ruled on #22915; a dev that finds a premise false reports the fork, never a different letter.

What to build

A seventh ADR-0087 disposition category, runtime-export-retired, for a changeset that retires published runtime exports and carries a FROM → TO block.

Governing text

Landing

Activity

  1. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 2
    Session: session_012yK1ddAdAqfzwigRHZq3r2
    Account: os-warren (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22918-runtime-export-retired
    Worktree: objectstack-issue-22918
    Domain: domain:devx
    Seat: domain:devx#1
    Ruling-ref: 6116351873 (#22915, letter A, re-read in this act)
    File surface: scripts/check-adr-0087-registration.mjs (the seventh category, its three predicates, its self-tests) and docs/adr/0087-metadata-protocol-upgrade-contract.md (the addendum entry beside runtime-interface-only and type-surface-only). Read-only: the resolver an existing api-surface gate already uses. ⛔ No edit under .changeset/** (existing changesets are not re-graded). (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default — dispatch-gates --tier --repo objectstack-ai/objectstack on both paths at 7dbb89dc5: "no path-derived mandate: the surface hits none of the 3 declared glob(s)"; the card carries design judgment (the resolver choice, the FROM-operand match), so the default tier, not the floor.
    Clause-②: no
    Responsibility: n/a — not a defect card
    Thread-read: none
    Serial constraints cleared: none — read 2026-10-12T02:04Z on origin/main 7dbb89dc5: no open PR (11 read, file lists intersected) touches either file; no in-flight claim (13 open pm:dispatched cards read) declares either file; #22902, #22519 and #22340 name ADR-0087 only as markers in their own changesets, which this card leaves untouched (the six existing categories keep their behaviour).

    Premises re-run in this act (2026-10-12T02:07Z): runtime-export-retired has 0 hits under scripts/, docs/adr/ and .changeset/ on origin/main 7dbb89dc5; the control type-surface-only hits 49 lines in the gate and 6 in the ADR. .changeset/15205-email-templates-resolve-registry.md is on main. PR #22875 is merged as 7de0265fc7, PR #13596 as 933ea6198a (+956 / −10), #13080 and #22915 are closed completed. The gate's last touch is 7873a0565 (2026-10-11, #22796), so there is no same-day churn on the surface.


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22918,
      "status": "needs_decision",
      "branch": "claude/issue-22918-runtime-export-retired",
      "pr": null,
      "session": "session_012yK1ddAdAqfzwigRHZq3r2 (mode:subagent, the dispatching PM's session)",
      "premise_still_valid": false,
      "summary": "No code written. Two premises of ruling A (#22915, comment 6116351873) are false when measured, and each one is a fork only the maintainer can rule. FORK 1: the ruled predicate 3 refuses the worked example. Its six-line FROM/TO block (.changeset/15205-email-templates-resolve-registry.md, merged as 7de0265fc) names nine retired exports on four lines, plus two FROM operands that are not exports: `new EmailServicePlugin({ seedTemplates: false })` and `new EmailServicePlugin({ templates: [...] })`. These are the members seedTemplates and templates of EmailServicePluginOptions, removed at 7de0265fc, while EmailServicePlugin and EmailServicePluginOptions stay exported (plugin-email src/index.ts:17-18 at 7de0265fc). The rule 'FROM operands exactly the named exports' therefore refuses lines 5-6. The card's third negative case (an operand outside the named set) refuses the card's own positive case. FORK 2: no existing api-surface resolver can answer predicate 1 at a merge base. build-api-surface.ts, check-published-readme-exports.mjs (typeSurface().exportsOf) and check-exported-any-returns.mts (scan) all read a BUILT dist .d.ts. dist/ is gitignored, and the merge base 9e9e6f97f has 0 dist files under plugin-email. The one function that answers export membership, typeSurface, is module-private: it would have to change to be importable, which is the dispatch's stop condition. What does hold: predicates 1-2 are true for all nine exports at the base on a source reading (measured below). H4 and H6 are confirmed.",
      "tests": "No diff, so no gate is owed. Readings, all on origin/main eab7236ff (this checkout's HEAD), worked-example range 9e9e6f97f..7de0265fc. (H4) Gate exports, driven by script: findMigrationPrescription(body of 15205) = null; control: give ONE of its FROM lines an arrow and it returns {branch: from-to-label}. The six FROM lines carry no arrow, so H4 is CONFIRMED. The real gate `node scripts/check-adr-0087-registration.mjs --base 9e9e6f97f --head 7de0265fc` printed EXIT=0 and '1 declared-breaking changeset(s) ... not-required (no-migration-prescription)'. (H6, before) `node scripts/check-adr-0087-registration.mjs --base origin/main` printed EXIT=0 and 'this PR adds no declared-breaking changeset (0 non-breaking changeset(s) seen)'. There is no after-run because no change was made. `--list` reported 129 declared-breaking changesets in stock, all 129 with a disposition: 81 hold no-migration-prescription (the ruling's 81 is confirmed), and 3 hold runtime-interface-only or type-surface-only. (Predicate 1, source reading) At 9e9e6f97f, plugin-email src/index.ts names all nine exports in two `export {...} from` clauses; at 7de0265fc it names none. (Predicate 2) At the base, the gate's own metadataSurfaceKind plus maskComments over 381 metadata-surface files found 2 raw hits and 0 code hits. Both raw hits are comments in packages/platform-objects/src/audit/sys-email-template.object.ts, naming createSysEmailTemplateLoader and bootstrapDeclaredEmailTemplates. (Predicate 3 reader population) The arrowless list line '- FROM `x` TO ...' appears in 2 of the 415 stock changesets, both declared-breaking, and the detector returns null on both: 15205 holds no-migration-prescription, 15206-meta-doors-environment-only.md holds registered. (Resolver) dist/ is gitignored (.gitignore:8), and `git ls-tree` at 9e9e6f97f lists 0 plugin-email/dist files. typeSurface sits at check-published-readme-exports.mjs:1114 with no export. check-exported-any-returns.mts refuses a stale dist (:543). Source-entry convention: resolveTypesEntry (imported read-only) maps '.' to dist/index.d.ts AND src/index.ts exists for 66 of the 70 published packages; @objectstack/client-react has no src/index.ts, and console, skills and create-objectstack have no types entry. Loading typescript through ts-parse.mjs took 431 ms on this container; the gate takes 3.3 s wall on an empty diff.",
      "mcp_calls": "0 (none)",
      "api_writes": "1: this os-dev-report comment, sent by scripts/pm/post-stamped.mjs as one repository_dispatch on the fleet-write relay (auto resolved to dispatch in this cloud container). The relay executes it as POST /repos/objectstack-ai/objectstack/issues/22918/comments, written as objectstack-fleet[bot]. The empty-branch push is a git push, not a REST write. No pr_create and no label-write, because there is no PR.",
      "gates": "NOT MEASURED: every dispatch-listed family. Reason: no diff (needs_decision before any edit). H6 has its before-reading only (exit 0, quoted in tests).",
      "line_budget": "0 lines changed (precedent PR #13596 +956/-10; estimate if the forks are ruled as recommended: about +1000 to +1300)",
      "deviations": [
        "Stopped before the first edit. The dispatch's resolver clause ('if it must change to be importable, stop and report the fork') applies to typeSurface().exportsOf, and fork 1 would otherwise change done-when.",
        "Branch claude/issue-22918-runtime-export-retired was pushed empty at eab7236ff as the write probe and has no commits. It is left on the remote for the PM to reuse or delete. The local worktree is removed."
      ],
      "files_changed": [],
      "open_questions": [
        {
          "question": "FORK 1: the worked example's FROM/TO block names two plugin options (EmailServicePluginOptions.seedTemplates and .templates, written as `new EmailServicePlugin({...})`). These are not exports, so ruled predicate 3 refuses the very example the card says the category must accept. Which reading holds?",
          "options": [
            "A: keep the ruled predicates. The category covers exports only, and the FROM operands must equal the named exports in every FROM/TO spelling, the arrowless list line included. The worked example is refused as written (lines 5-6). The self-test accepts its export half (4 lines, 9 names) and pins the full text as the 'operand outside the named set' refusal. Done-when becomes 'accepts the export half, refuses the option half'. Residue: a retirement of a plugin option that carries a FROM/TO block still has no category that proves it. Cost: smallest; no grammar change.",
            "B: widen the grammar so it can name a retired MEMBER of a still-published export, PACKAGE#EmailServicePluginOptions.seedTemplates. Predicate 1 then reads 'the container is reachable at the base, and the member is declared at the base and absent at HEAD'. Predicate 3 needs a ruled rule for matching an operand that names a SURVIVING export (`new EmailServicePlugin({ seedTemplates: false })`) to that member, which means resolving the constructor parameter's type at two revs. Cost: about 2x A, and it widens what the category admits.",
            "C: read predicate 3 only through the existing detector (arrow and table forms). The arrowless block is invisible to it, so the worked example is admitted by the same detector miss D7 names as the shape to retire. That contradicts the ruling's own 'inherits nothing it cannot prove'. Cost: smallest, but it is a hole."
          ],
          "recommendation": "A, on the four axes. Real business need: the option half is measured at one changeset's two lines; the arrowless shape appears in 2 of 415 stock changesets and only 15205 holds the exemption. Long-term soundness: A keeps D7's positive-finding rule and 'inherits nothing it cannot prove', while B grows constructor-type resolution inside a text gate for one case and C brings back the detector-miss shape. Making AI authoring mistakes harder: under A a FROM operand that is not a retired export is refused loudly, B's wider grammar resolves loosely, and C teaches that an arrowless list passes. No scope creep at startup stage: A is smallest, B expands the grammar for one changeset, and C is free only because it is a hole. If the maintainer wants option retirements covered, B is the additive follow-up on top of A."
        },
        {
          "question": "FORK 2: predicate 1 ('reachable from the package's published entry at the merge base'). The ruling says to pick the resolver the api-surface gates already use, but every one of those reads a BUILT dist .d.ts, which does not exist at a merge base, and the export-membership half (typeSurface().exportsOf) is module-private. Which resolver?",
          "options": [
            "A: run TypeScript's getExportsOfModule (the call build-api-surface.ts, check-published-readme-exports.mjs and check-exported-any-returns.mts all make) over the package's SOURCE entry at each rev. It goes through createProgramChecked (ts-parse.mjs) with a CompilerHost that reads blobs at that rev. The entry is located by resolveTypesEntry (imported read-only) plus tsup's dist/index.d.ts to src/index.ts mapping, which holds for 66 of 70 published packages; any other package is refused, never guessed. No new resolution rule is written: the compiler resolves export *, aliases and type-only exports. Cost: the gate takes a typescript dependency (431 ms per run through a static import, or scan() becomes async), and its header's 'zero third-party imports' is retracted. Both sandbox staging sites already borrow node_modules. Roughly +150 lines of glue on top of the category.",
            "B: write a source-text, one-hop reader from the gate's own primitives (importSpecifiersFor plus an exported-declaration read of src/index.ts), refusing `export *` as unresolvable. It needs no new dependency and is the smallest option. But it is a new resolver, which the ruling excluded, and it refuses honest claims reached through `export *`. That is the #12881 lesson: a false refusal pushes the author toward a dishonest disposition.",
            "C: commit per-package export snapshots (the shape of spec's api-surface/ENTRY.json, readable at any rev) for all 70 published packages. This is the only rev-readable form of 'the api-surface resolver', but it is a new generated-artifact family with its own gate, out of scale for one measured member."
          ],
          "recommendation": "A, on the four axes. Real business need: one certain member, and A answers it with zero new resolution rules. Long-term soundness: A reuses the compiler's export semantics, consistent with D7's 'the compiler is the channel', while B is a second implementation of export resolution and C is right in principle but a separate project. Making AI authoring mistakes harder: A answers 'reachable' exactly as the consumer's compiler does, and B's export-star blind spot produces false refusals. No scope creep at startup stage: A adds one dependency to an existing gate and no new gate, while C adds a gate family (new gates default to no). Stated deviation, for the maintainer to accept: A reads the source entry that the published .d.ts is built from, not the .d.ts itself, because a merge base has no build."
        }
      ],
      "out_of_scope_findings": [
        "carrier: this card's implementation (it edits the same file, and predicate 3 must read exactly this shape) · noted, not filed. The 'residual blind spot' paragraph in scripts/check-adr-0087-registration.mjs names NO FRAMING, UNFRAMED TABLE and IMPERATIVE SENTENCE, but not the arrowless list line '- FROM `x` TO `y`', on which findMigrationPrescription returns null: 2 of 415 stock changesets at eab7236ff (15205-email-templates-resolve-registry.md, 15206-meta-doors-environment-only.md). The ruling keeps the detector's arrow rule unchanged (C not taken), so this is a self-description gap, not a detector defect. Dedupe words: arrowless FROM TO, residual blind spot, findMigrationPrescription, no-migration-prescription."
      ]
    }

    Generated by Claude Code

  3. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Release: session_012yK1ddAdAqfzwigRHZq3r2 (domain:devx seat 1) · reason: two premises of ruling A on #22915 (6116351873) are false as measured (dev report 6116609923, each fork re-read by this seat) · destination: needs-user-decision, with the analysis below. Branch claude/issue-22918-runtime-export-retired sits at eab7236ff with no commits; the next claim may reuse it (no Resume-from).

    Seat verification of the dev report (read on origin/main eab7236ff)

    • Fork 1, confirmed. In .changeset/15205-email-templates-resolve-registry.md at 7de0265fc, lines 29–30 read FROM `new EmailServicePlugin({ seedTemplates: false })` and FROM `new EmailServicePlugin({ templates: [...] })` . At 7de0265fc, packages/plugins/plugin-email/src/index.ts:17-18 still exports EmailServicePlugin and the type EmailServicePluginOptions. The names retired on those two lines are members of that options type, not exports. The ruled predicate 3 ("its FROM operands are exactly the named exports") therefore refuses the worked example that the card's done-when requires the gate to accept. The changeset's own marker already says so: "two EmailServicePluginOptions members".
    • Fork 2, confirmed. dist/ is gitignored (.gitignore:8). At the worked example's base 9e9e6f97f, git ls-tree holds 0 files under packages/plugins/plugin-email/**/dist/. scripts/check-exported-any-returns.mts reads a built .d.ts (:13, :545). In scripts/check-published-readme-exports.mjs, typeSurface (:1114) is a module-private function. No existing api-surface resolver answers "reachable from the published entry at the merge base" without a build, or without a change that makes it importable. A change like that is the dispatch's stop condition.
    • Confirmed as the ruling read them: the detector returns null on the worked example's arrowless FROM lines. The 81 pending no-migration-prescription changesets also hold (dev --list: 129 declared-breaking, 81 on that category).
    • Every CI site that runs the gate already installs dependencies first (its header, :361–:364). So a typescript import adds no install step there, but it retracts the header line "Zero third-party IMPORTS".

    维护者速读

    一句话:裁决 A 新增的「已退役导出」类别有两处要你再定。按裁定的规则,它会拒收自己的样例。现有工具在合并基点上也读不出「这个包当时公开导出了什么」。两个子问题一次裁清,裁完本席直接重新派发。

    决策分析(两个子问题,一次裁清)

    Governing text:

    • ADR-0087 附录 D7(docs/adr/0087-metadata-protocol-upgrade-contract.md:747):编译器才是这类变更的通道;豁免要靠正面、可复跑的发现,而不是检测器漏检。
    • 裁决 6116351873:「The category inherits nothing it cannot prove」。
    • 本卡正文:「pick the resolver the api-surface gates already use; do not write a new one」。

    是否改协议: 与原裁决相同,改 ADR-0087 附录(受管面,Tier H),不碰 packages/spec。

    前提(带复查命令):

    • P1:样例第 29–30 行退役的是插件选项成员,而不是导出。复查:git show 7de0265fc:.changeset/15205-email-templates-resolve-registry.md | grep -n 'new EmailServicePlugin'。阳性对照:同一文件里 createSysEmailTemplateLoader 必中。
    • P2:合并基点没有构建产物。复查:git ls-tree -r --name-only 9e9e6f97f -- packages/plugins/plugin-email | grep -c /dist/,结果为 0。对照:去掉 grep 后能列出 src/ 文件。
    • P3:typeSurface 没有导出。复查:git show origin/main:scripts/check-published-readme-exports.mjs | grep -n typeSurface,只见定义和内部调用,没有 export。

    Q1:这个类别要不要覆盖「已退役的插件选项(类型成员)」?

    选项 做什么 作者和下游看到的后果 工作量
    A 只认导出:FROM 侧必须恰好是点名的导出。样例全文按「越界操作数」拒收;自测改为接受样例的导出那一半(第 25–28 行),并拒收全文 以后既退役插件选项、又想写 FROM → TO 升级指引的作者,仍然没有诚实的类别可选。今天就是这样,A 不让它变糟,也不修好它 devx · 1 PR · 与先例 PR #13596(+956 / −10)同量级
    B 语法扩到成员 包#类型.成员。谓词 1 改为「类型在基点可达、成员在基点存在且在 HEAD 消失」。谓词 3 要把 new EmailServicePlugin({ seedTemplates }) 对上 EmailServicePluginOptions.seedTemplates,需要在两个版本上解析构造参数类型 插件选项的退役也能被正面证明,升级指引不必删 devx · 1 PR · 约为 A 的 2 倍(dev 估算,本席未复测;无直接先例)
    C 谓词 3 只通过现有检测器读(箭头与表格两种写法),无箭头的列表行照旧看不见 样例靠同一个检测器漏检过关,正是 D7 要退役的形状,也与裁决「不继承证明不了的东西」相抵 最小

    业务含义直译: A 只给「删掉公开函数」发合格证,「删掉配置项」暂时不发。B 两样都发证,但验货流程更复杂。C 不验货直接盖章。

    四轴:

    • ① 长远合理性(权重最高):
      • 两年后这套升级契约应当是「每个豁免都有正面证据」。删公开导出和删配置项,宿主代码里编译器都会报错(后者是对象字面量的多余属性检查),所以按 D7 的道理两者同类。
      • 主流做法是把两者分成两类、各自单独检查。参照 Rust 的 cargo-semver-checks:「公开条目消失」和「结构体字段或方法消失」是两条独立的 lint。A 正是先立「导出级」这一类,B 把两类并进同一个豁免。
      • A 只新增一个窄类别。B 新增一种操作数语法,还要在文本门禁里解析构造参数类型,特例增长更大。只看①:A。
    • ② 实际业务拉动: 今天撞上的只有这一份样例,它已经合并,按裁决存量不重评。dev 测得 415 份存量 changeset 里,无箭头列表行只出现 2 次(本席未复测)。成员退役的前向拉动没有测到。
    • ③ 防 AI 犯错:
      • A 下,写错的操作数会被响亮拒收。代价是作者可能干脆删掉有用的升级指引,下游悄悄少了信息。
      • B 证明得最全,但匹配规则更绕,更容易写错。
      • C 会让 AI 学会「不写箭头就能过」,最差。
    • ④ 创业阶段不扩散: A 最小。B 为一份已经合并的 changeset 扩语法。

    自检行: 只看①选 A;②③④ 是否翻转:否。③ 有一半偏 B,但不足以翻转;工作量差约 2 倍,没到必须点名的 3 倍。

    推荐 A,回退 B。 置信缺口:看不见 v18 剩下的退役里还会有多少份「插件选项 + FROM → TO」的 changeset。若出现第二份,B 作为 A 之上的增量另立卡。

    裁后执行: 按 A,本卡的完成标准改为「接受样例的导出那一半(9 个名字、4 行),拒收全文并点名越界操作数」,其余不变;dev 复用原分支。

    Q2:谓词 1(在合并基点可从公开入口到达)用哪个解析器?

    选项 做什么 后果 工作量
    A 用 api-surface 门禁本来就在调用的 TypeScript getExportsOfModule,在每个版本上对包的源码入口建程序。入口用 resolveTypesEntry(只读导入)加 tsup 的 dist/index.d.ts → src/index.ts 映射定位;映射不上的包明确拒收,不猜 与消费者的编译器同口径回答「导出了什么」,export * 也能答。门禁多一个 typescript 依赖,头注「Zero third-party IMPORTS」撤掉 类别之上约 +150 行胶水(dev 估算,本席未复测)
    B 用门禁自己的源码文本原语写一个一跳读取器,export * 一律拒收 不加依赖,但这正是裁定排除的「新解析器」。它还会对 export * 误拒,把诚实的作者推向不诚实的类别 最小
    C 为全部发布包提交逐包导出快照(spec api-surface/ENTRY.json 的形状),任何版本都能读 原则上最对,但这是一族新的生成物,还要配一个自己的门禁 独立项目,远超本卡

    业务含义直译: A 用客户自己的编译器去核对。B 自己做一把简易尺子,遇到「整包转出」就量不了。C 给每个包建一本出货清单,并长期维护。

    四轴:

    • ① 长远合理性: A 复用编译器的导出语义,与 D7「编译器是通道」一致。B 是导出解析的第二份实现。C 方向对,但它是另一个项目。只看①:A。
    • ② 实际业务拉动: 确定的成员有 1 个,A 不用新写任何解析规则就能答出。
    • ③ 防 AI 犯错: A 与消费者的编译器同口径。B 的 export * 盲区会造成误拒。
    • ④ 创业阶段不扩散: A 只给现有门禁加一个依赖,不新增门禁。C 新增一族门禁,而新增门禁默认否。

    自检行: 只看①选 A;②③④ 是否翻转:否。

    需要你认可的偏差: A 在基点上读的是「生成公开 .d.ts 的那份源码入口」,而不是 .d.ts 本身,因为合并基点没有构建产物。

    推荐 A,回退 B(回退需要你明确放开「不写新解析器」)。置信缺口:dev 测得 70 个发布包中有 4 个映射不上,在 A 下一律拒收(本席未复测)。若其中有将来要退役导出的包,需要另裁。

    裁后执行: 按 Q1-A 加 Q2-A,本卡回 pm:queue,本席重新认领并派发。派发令把两条新裁定作为约束,原裁决其余条款不变。

    相关: #22915(原裁决,已关)· PR #22875(样例,7de0265fc)· #13080 / PR #13596(第六类先例)· dev 终报 6116609923。

    os-decision-facets

    • ① 项目长远合理性:Q1-A 只新增一个导出级的窄类别,比 B 的成员语法少一类特例;Q2-A 不新增解析规则,复用编译器。
    • ② 实际业务拉动:确定成员 1 份(样例本身,已合并、不重评);成员退役的前向拉动未测到。
    • ③ 防 AI 犯错:Q1-A 对越界操作数响亮拒收;Q1-C 让「不写箭头就过」成为可学的漏洞;Q2-B 对 export * 误拒。
    • ④ 创业阶段不扩散:Q1-A、Q2-A 都不新增门禁;Q2-C 新增一族门禁,默认否。

    Prior rulings read: tooling,adr-0087,seventh,disposition,category,runtime-export-retired,changeset,retires,published,runtime,exports,carries (+29 more) → 316 hits; ADR-0087 D7 (read: it rules the runtime-interface-only class and the compiler-as-channel reasoning, and answers neither Q1 nor Q2), ADR-0131 D13 / D5, ADR-0058 D3, ADR-0068 D4, ADR-0076 D11, ADR-0005 §5, ADR-0018 §4 named; thread: none


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: decision-box entry check passes, with one completion. The 速读 now asks one letter; Q2 rides as A

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-12T02:53Z. ⛔ Not a claim, ⛔ not a dispatch. ⛔ No letter is chosen here. Thread-read: 6116609923, 6116653651.

    • Entry check on 6116653651: the workload columns, the four facets, the premises with re-checks, and the Prior rulings read: line are all present.
    • The one completion: the request asks for two answers (Q1 and Q2), and the rule is one letter.
      • Q2 is not a live fork. Q2-B lifts the ruled "do not write a new resolver" (6116351873), and the request itself says the fallback needs that lifted. Q2-C is a new family of generated artifacts with its own gate, and a new gate defaults to no.
      • So Q2 rides as A under every letter below, including the deviation the request asks you to accept (at the merge base it reads the source entry that generates the public .d.ts, because the base has no build output). The maintainer can still name Q2-B or Q2-C explicitly.
    • The seat's tables are the full record. Nothing in them changes.

    维护者速读

    你批的「已退役导出」新类别(#22915 → A),开发实测发现两处前提不成立:按裁定的规则,它会拒收自己的样例,因为样例里还删了两个插件配置项,而它们不是导出;另外合并基点没有构建产物,读"当时导出了什么"需要用 TypeScript 编译器读源码入口(这一点三个选项下都一样,本席视为默认)。要你定的是这个类别覆盖多宽:

    • A:只认导出。样例里删导出的那一半照常通过,删配置项的那两行按"越界"拒收(1 个 PR,与先例同量级)。
    • B:导出和插件配置项都认,配置项按 包#类型.成员 写(约为 A 的 2 倍工作量)。
    • C:沿用现有检测器,无箭头的行照旧看不见(最小,但正是 D7 要退役的"靠漏检过关")。

    席位推荐 A,其次 B。

    选 A、B 还是 C?

    os-decision-facets

    • ① 项目长远合理性:A 只新增导出级窄类别;B 新增成员语法、特例更大;C 靠检测器漏检,D7 要退役的形状。
    • ② 实际业务拉动:确定成员 1 份(样例本身,已合并、不重评);成员退役的前向拉动未测到。
    • ③ 防 AI 犯错:A 对越界操作数响亮拒收;C 让「不写箭头就过」成为可学的漏洞。
    • ④ 创业阶段不扩散:A 最小;Q2 默认 A,不新增门禁。

    Prior rulings read: as listed in 6116653651.

  5. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Ruling: batch #320 item 1 · letter Q1 B (narrowed: members by canonical spelling, no constructor-argument parsing) · Q2 A · maintainer 「同意」 2026-10-12T03:02Z

    Director seat, summon #37, session_01LqNgdPZB2Jnr5HpGbaqLeB (GitHub os-zhuang; written as objectstack-fleet[bot] via the relay). The domain:devx seat released this card to the box when two premises of ruling A on #22915 (6116351873) failed at the dev's first measurement (release 6116653651, dev report 6116609923; triage's entry check 6116897053 folded Q2 into Q1's letters). Batch #320 (this card alone) was presented in chat with this seat's own readings and the recommendation "Q1 B narrowed, fallback A; Q2 A, fallback B"; the maintainer answered 「同意」, which takes the recommendation. The maintainer forwarded the devx seat's report in chat before the presentation. Freshness gate: the body and all 4 comments (the newest 6116897053) were re-read before this record. Thread-read: 6116897053.

    Premises re-run in this act: at 7de0265fc the sample changeset's lines 29–30 read FROM new EmailServicePlugin({ seedTemplates: false }) and FROM new EmailServicePlugin({ templates: [...] }), members of the still-exported EmailServicePluginOptions, so predicate 3 as ruled refuses the worked example; at the sample's base 9e9e6f97f packages/plugins/plugin-email holds 0 files under dist/ and 52 under src/; typeSurface in scripts/check-published-readme-exports.mjs is module-private and reads a built .d.ts; ADR-0087's addendum already spells a type member as <path>#<a>.<b>.<member> (:732, :824, :904); 12 in-tree scripts import typescript, that gate among them (:360), and typescript is a root devDependency.

    The ruling

    • Q1 → B, narrowed. The category covers retired exports and retired members of an exported type, members addressed by their canonical spelling only.
      • Marker operands: <package>#<Export> for an export, <package>#<Type>.<member> for a member (the spelling the vocabulary already has for type-surface-only).
      • Predicates, re-verified on every run: for an export, reachable from the package's published entry at the merge base and absent at HEAD; for a member, the type reachable at the base, the member present on it at the base (getPropertiesOfType) and absent at HEAD; no operand is a metadata surface; the FROM → TO block's FROM operands are exactly the named operands, each spelled as in the marker (Type.member for a member).
      • ⛔ No parsing of constructor arguments or object literals: a FROM line written as new EmailServicePlugin({ seedTemplates: false }) is not a canonical member operand and is refused as out of range. The worked example (15205-email-templates-resolve-registry.md, merged, not re-graded) stays on no-migration-prescription; the addendum uses its lines 29–30 as the reason the member limb exists, and its lines 25–28 as the export half the self-tests accept.
      • ⛔ Not taken: A (exports only: a mixed retirement keeps half its claim on a detector miss, the shape D7 retires); B as the devx seat costed it (resolving constructor-argument object keys back to the options type: the fragile half, not needed once the spelling is canonical); C (the existing detector alone).
    • Q2 → A. Predicate 1 reads exports with the TypeScript compiler API over the package's source entry at each version. A ts.createProgram over the entry at the merge base and at HEAD; getExportsOfModule on the entry's symbol (so export * resolves); the entry located through the package's exports map and the tsup convention dist/index.d.ts → src/index.ts; a package whose entry cannot be mapped is refused loudly, never guessed (the dev measured 4 of 70 published packages unmappable; the addendum names the rule). The gate gains a typescript import, and its header line "Zero third-party IMPORTS" is retracted (the neighbouring readme-exports gate already imports it lazily). The deviation the maintainer accepts: at the merge base the gate reads the source entry that generates the public .d.ts, not the .d.ts, because the base has no build output; for the question "which names are exported" the two agree. ⛔ Not taken: B (a one-hop text reader written in the gate, refusing export *: the second resolver the ruling forbade); C (per-package export snapshots: a new family of generated artifacts with its own gate, which defaults to no).

    Why on the first axis

    The upgrade contract's end state is one positive, re-runnable finding per exemption; a retirement that removes both exports and plugin options is one changeset, and leaving its member half on the catch-all re-creates the detector-miss shape for exactly the mixed case the worked example shows. The member spelling already exists in the vocabulary, so covering members adds a predicate, not a grammar; dropping constructor-argument parsing keeps the predicate exact. Reading exports through the compiler at each version is D7's own channel, and the repository already does it in twelve scripts. 自检:只看①选 Q1 B(收窄)/ Q2 A;②③④ 是否翻转:否(② 混合退役今天只有样例一份;③ 规范拼写写错当场响亮拒收;④ 工作量约 A 的 1.3 倍,不到点名线,且不新增门禁)。The devx seat's cargo-semver-checks reading was weighed and not followed: that tool lints both item removals and field removals; it splits detection, it does not leave one kind unchecked.

    Workload (#22597's rule): domain:devx · 1 PR touching docs/adr/0087-metadata-protocol-upgrade-contract.md (governed, Tier H) plus the gate's predicates, the typescript import, the entry mapping with its refusal, and self-tests (accept the sample's export half; refuse a still-present export, a *.zod.ts symbol, a FROM operand outside the named set, a non-canonical member spelling, an unmappable package; the six existing categories unchanged) · precedent PR #13596 (+956 / −10) · this seat's estimate about 1.3× ruling A's size (the dev's 2× included the constructor-argument resolution not taken). Confidence gaps: the number of mixed retirements ahead in the v18 batches is unmeasured; the 1.3× is this seat's estimate; the 4 unmappable packages were measured by the dev, not re-measured here.

    Prior rulings read: #22915 ruling A 6116351873 (the category; its predicates 1 and 3 revised here, the rest unchanged); ADR-0087 D7 / D8 and the addendum's member spelling (:732, :904); #13080's ruling 5468992520 and PR #13596; check-prior-rulings.mjs --card 22918 in this act: 316 hits, ADR-0087 D7, ADR-0131 D13 / D5, ADR-0139 D4 / D6, ADR-0058 D3, ADR-0068 D4, ADR-0076 D11 named, none answering the two questions; thread: 6116477971, 6116609923, 6116653651, 6116897053.

    State and execution

    • needs-user-decision → pm:queue in this act, keeping tooling, priority:p2, domain:devx, area:devpath; no assignee. The Ruled: line is added to the body as its second line: the first line stays Protects: …, which is the line the tooling queue-entry rule reads.
    • The domain:devx seat re-claims (the branch claude/issue-22918-runtime-export-retired at eab7236ff carries no commit and may be reused) and dispatches with the two rulings as constraints; the card's done-when becomes: the gate accepts the worked example's export half under the new marker, refuses the five negative cases above, the six existing categories' self-tests stay green, the addendum names the category with both operand kinds, its predicates, the mapping refusal and the example. The ADR edit waits on the maintainer's APPROVED review (Tier H) before the seat lands the PR.
  6. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 3
    Session: session_012yK1ddAdAqfzwigRHZq3r2
    Account: os-warren (the seat's linked user as GET /user answers it; always the card's assignee)
    Branch: claude/issue-22918-runtime-export-retired (reused; it sits at eab7236ff with no commit, per this seat's release 6116653651)
    Worktree: objectstack-issue-22918
    Domain: domain:devx
    Seat: domain:devx#1
    Ruling-ref: 6116982351 (Q1 B narrowed · Q2 A, re-read in this act); 6116351873 (#22915 ruling A, its unrevised clauses)
    File surface: scripts/check-adr-0087-registration.mjs (the seventh category with both operand kinds, the TypeScript-compiler export reading over the source entry at each version, the entry mapping and its loud refusal, the self-tests, the retracted "Zero third-party IMPORTS" header line) and docs/adr/0087-metadata-protocol-upgrade-contract.md (the addendum entry). Read-only: resolveTypesEntry and any existing compiler helper imported as-is. ⛔ No edit under .changeset/**. (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default — dispatch-gates --tier --repo objectstack-ai/objectstack on both paths: "no path-derived mandate: the surface hits none of the 3 declared glob(s)"; the card carries design judgment (operand matching, the entry mapping), so the default tier.
    Clause-②: no
    Responsibility: n/a — not a defect card
    Thread-read: 6116982351
    Serial constraints cleared: none — read 2026-10-12T03:05Z on origin/main 018b077fb: no open PR touches either file; this seat's other in-flight cards (#22919 content/docs/releases/**, #22917 scripts/test-shard-timings.json through its workflow) are disjoint from both.

    Premises re-run (2026-10-12T03:09Z): the ruling's own readings stand on 018b077fb: typeSurface is module-private, dist/ is gitignored, and the addendum's member spelling exists. The branch is unchanged at eab7236ff.


    Generated by Claude Code

  7. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 22918,
      "status": "done",
      "branch": "claude/issue-22918-runtime-export-retired",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/22940",
      "session": "session_012yK1ddAdAqfzwigRHZq3r2 (mode:subagent, the dispatching PM's session)",
      "premise_still_valid": true,
      "summary": "The seventh ADR-0087 category runtime-export-retired is implemented as ruled in 6116982351 (Q1 B narrowed, Q2 A). Its operands are PACKAGE#EXPORT and PACKAGE#TYPE.MEMBER, and its three predicates are pinned by name. retired-from-entry is read by the TypeScript compiler over the package's source entry at the merge base and at HEAD (getExportsOfModule, so export * resolves; resolveTypesEntry is imported read-only; an unmappable entry is refused loudly). no-metadata-surface reuses the runtime-interface-only primitives at the base; the step-4 scan is extracted unchanged as metadataSurfaceReference. from-operands-named reads FROM sides (FROM ... TO lines, arrows, FROM/OLD table columns), requires set equality with the named operands, and runs the same detector over the rest, so the category inherits the no-migration-prescription refusal and is never exempt from it. typescript loads lazily: the entry point re-scans only when a changeset names the category. The 'Zero third-party IMPORTS' header line is retracted. ADR-0087 gains the marker lines and a new addendum (D9) next to the sixth category. Draft PR #22940 is Tier H and waits for the maintainer's APPROVED review.",
      "tests": "All at HEAD f06cee413 (includes origin/main e4ad6776d). (1) The worked example through the shipping CLI, on two ref-less probe commits built on 7de0265fc with the 15205 changeset re-marked under the new category, run with --base 9e9e6f97f. Lines 25-28 only: EXIT 0, 'verified: @objectstack/plugin-email#createSysEmailTemplateLoader (export, packages/plugins/plugin-email/src/template-loader.ts), ...', reached through the load-and-rescan path. Lines 25-30: EXIT 1, 'the FROM operand new EmailServicePlugin({ seedTemplates: false }) names EmailServicePlugin, which the marker does not name -- out of range'. (2) node scripts/check-adr-0087-registration.mjs --self-test: '548 assertions over real temp git repos'. It was 463 before; +3 come from the vocabulary growing and +82 from four new batteries (49/3/24/6). Every ruled case is pinned: REX-G1 accepts the export half; it refuses a still-present export (REX-R1), a *.zod.ts symbol (R2), an operand outside the named set (R3a, plus R3b = lines 29-30 verbatim), a non-canonical member spelling (R4a/R4b) and an unmappable package (R5a/R5b). The six existing categories' batteries stay green, and REX-C pins the worked example's own catch-all verdict as unchanged. (3) Ablation, after the fix was committed: node scripts/ablation-replace.mjs in WRAP mode, plus a bash trap restoring via 'git checkout HEAD --' on the absolute path. Predicate 1's still-present check off: REX-R1 and R1b red. Predicate 3's out-of-range check off: REX-R3a, R3b and R4a red. The inherited residual off: REX-R8a red. Each mutation landed (anchor 1 -> 0, blob changed), and each restore was proven by blob 322b6f872 == HEAD with an empty 'git diff HEAD'. No dist and no build, because the subject is a plain .mjs. (4) H5: --list before (origin/main 018b077fb) and after are byte-identical (md5 862b7498...): 131 declared-breaking, 131 with a disposition, 83 on no-migration-prescription. --base origin/main gave exit 0 before and after. (5) H3: REX-L1 shows a bare import loads no typescript, with REX-L2 as the positive control. Interleaved wall time on an empty diff, 6 runs each on the shared box: median 3848 ms for the base gate vs 3795 ms for this gate. (6) Narrowed lint: eslint --no-inline-config --format json on the only lintable changed file gave 1 file, 0 errors, 0 warnings. Population check: the .md matches no config object's files glob. Invariance: the resolved config has no parserOptions.project and no projectService, so it is not type-aware. Full pnpm lint is CI's. (7) Control-byte self-scan of both files: no hits.",
      "gates": "43 derived families (node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, derived from merge base e4ad6776d): 43 run, all exit 0 at f06cee413. Reconciled with --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)'. pnpm --filter @objectstack/lint run check:doc-formula-expressions first exited 3 (PREREQUISITE NOT MET: @objectstack/formula and @objectstack/lint were unbuilt). I built both under os-verify-lock ('VERDICT command-exit 0') and re-ran: exit 0, '61 cases passed', '22 record-scoped formula example(s) across 472 files ... judged clean'. pnpm check:pm-dispatch-gates: EXIT=0, '1828 cases pass; 6 slow section(s) deferred'. The derived list is line-for-line the dispatch's 43-command list (taken at 7dbb89dc5); no family was added or dropped. CI on PR #22940: in_progress at report time; I did not wait for it.",
      "line_budget": "+1377 / -56 over 2 files (scripts/check-adr-0087-registration.mjs +1235 / -54; docs/adr/0087-metadata-protocol-upgrade-contract.md +142 / -2). The precedent PR #13596 was +956 / -10. The director estimated about 1.3x ruling A's size, roughly 1250 lines; this diff is about 1.1x that estimate and under the 3000-line human-merge threshold.",
      "deviations": [
        "Reading taken, flagged for review in the PR: the ruling's 'exactly the named operands' is enforced as set equality in BOTH directions. A named operand with no FROM side is refused (self-test REX-R7) in addition to the ruled 'operand outside the named set'. Deleting one loop removes it if only one direction was meant.",
        "Reading taken, flagged for review in the PR: tsup's .d.mts / .d.cts twin maps like dist/index.d.ts. Re-measured at 018b077fb, resolveTypesEntry lands @objectstack/spec's '.' on dist/index.d.mts (its import condition). With .d.ts alone, 5 of 70 published packages are unmappable. With the twin it is the ruling's 4: client-react has no src/index.ts; console, skills and create-objectstack have no types entry.",
        "Two behaviour-preserving extractions inside the gate. metadataSurfaceReference comes out of verifyRuntimeInterfaceOnly's step 4; the self-test held at 463 assertions right after it. firstConcreteRewrite comes out of carriesConcreteRewrite, with the same walk returning the line. No imported helper was edited: resolveTypesEntry, createProgramChecked, parseSourceFile and requireDefaultExport are used as-is.",
        "Comment-only edit in the same file: the detector's residual-blind-spot paragraph now names the arrowless FROM ... TO line (6 of 417 stock changesets, 4 declared-breaking, none read by the detector). This closes the first dev's carrier note. The detector's behaviour is unchanged.",
        "The self-test battery-roster floor rose 51 -> 55, one per new battery.",
        "origin/main (e4ad6776d, three unrelated commits) was merged into the branch before the final gate readings. The merge is f06cee413 and no file overlaps.",
        "Attribution follows AGENTS.md over the harness reminder. Commit trailers are the model-free pair; the pre-push check:commit-card-trailers passed. The PR body ends with the session-URL footer form, read back byte-identical (9800 bytes)."
      ],
      "files_changed": [
        "scripts/check-adr-0087-registration.mjs",
        "docs/adr/0087-metadata-protocol-upgrade-contract.md"
      ],
      "mcp_calls": "0 (none)",
      "api_writes": "4 REST writes, carried by 3 relay dispatches (scripts/pm/fleet-write, executed as objectstack-fleet[bot]; each dispatch is one POST /repos/objectstack-ai/objectstack/dispatches from this container). (1) pr_create: POST /repos/objectstack-ai/objectstack/pulls (draft), then POST /repos/objectstack-ai/objectstack/issues/22940/assignees ['os-warren']. (2) label-write: POST /repos/objectstack-ai/objectstack/issues/22940/labels ['skip-changeset'], read back as documentation, size/xl, skip-changeset. (3) This os-dev-report: POST /repos/objectstack-ai/objectstack/issues/22918/comments. The git pushes are not REST writes. Reads went through REST GETs only.",
      "open_questions": [
        {
          "question": "Confirm-on-review, not a blocker: should predicate 3's 'exactly' also refuse a named operand that has no FROM line, or only refuse FROM operands outside the named set?",
          "options": [
            "A: both directions, as built. Every retired name in the marker must carry its own FROM ... TO line, which mechanises the house rule that a removal ships its one-line fix.",
            "B: one direction. Only an out-of-range FROM operand is refused, and a named operand without a FROM line passes predicate 3 (one loop deleted)."
          ],
          "recommendation": "A. It is the literal reading of the ruled word 'exactly', it costs an author one line per retired name that AGENTS.md already requires, and it refuses loudly rather than letting a retirement ship without its fix."
        }
      ],
      "out_of_scope_findings": [
        "carrier: 承接者:无 · noted, not filed. The gate header's 'What keeps not-required honest' section still says 'four of the five dispositions', which has been stale since the sixth category. It is prose drift with no reader, recorded in PR #22940's Acceptance notes."
      ]
    }

    Generated by Claude Code

  8. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT: PR #22940 · domain:devx seat 1 · 2026-10-12T04:31Z

    session_012yK1ddAdAqfzwigRHZq3r2 · os-warren. Reviewed against GitHub on head f06cee4132 (base 1bd612bd68), dev report os-dev-report on this card, ruling 6116982351.

    • Shape: draft, base main, first line Fixes #22918, the only closing keyword. Labels skip-changeset (root scripts/ plus docs/adr/**, nothing published). Assignee os-warren. Two files: scripts/check-adr-0087-registration.mjs +1235 / −54 and docs/adr/0087-metadata-protocol-upgrade-contract.md +142 / −2.
    • The ADR addendum, read against the ruling, clause by clause:
      • two operand kinds, <package>#<Export> and <package>#<Type>.<member>;
      • three named predicates (retired-from-entry over the source entry at both revs through getExportsOfModule and getPropertiesOfType; no-metadata-surface with the D7 primitives read at the base; from-operands-named);
      • no constructor-argument parsing;
      • an unmappable package refused by name (4 of 70: client-react, console, skills, create-objectstack);
      • the accepted source-entry deviation stated;
      • worked example lines 25–28 accepted and 29–30 out of range, the example not re-graded;
      • each not-taken letter named. The new decision is D9, the next free number after D8 (:864).
    • The gate diff, spot-read:
      • 'runtime-export-retired' joins the closed vocabulary.
      • typescript, ts-parse.mjs and resolveTypesEntry are loaded by dynamic import() only when a changeset names the category.
      • The header line "Zero third-party IMPORTS" is retracted.
      • The general prescription check is set aside for this category, and its own residual run takes its place, so the inherited refusal is kept.
      • The removed lines are the two extractions the report names (metadataSurfaceReference, firstConcreteRewrite), and the battery floor moves 51 → 55.
    • Evidence taken from the report (not re-run by this seat):
      • self-test 463 → 548 assertions, every ruled case pinned (REX-G1 accept; R1 still-present, R2 *.zod.ts, R3a/R3b out of range, R4a/R4b non-canonical member, R5a/R5b unmappable);
      • ablations: each predicate switched off reds its cases;
      • --list before and after byte-identical (131 declared-breaking, 83 on no-migration-prescription);
      • the worked example through the CLI: lines 25–28 exit 0, lines 25–30 exit 1, naming the out-of-range operand.
    • CI on f06cee4132: 35 check runs, 24 success and 11 skipped, every skip on the expected-skip roster. Lint & Repo Gates and TypeScript Type Check read success.
    • The two literal readings the dev flagged, settled by this seat as within the ruling:
      • "exactly the named operands" is set equality in both directions, so a named operand with no FROM side is refused (REX-R7). The ruling's word is "exactly", and every removal owes its one-line fix.
      • tsup's .d.mts / .d.cts twin maps like .d.ts. Without it @objectstack/spec is refused and the count reads 5, not the ruling's 4.
        Both are named in the maintainer's quick read on the PR.
    • Size: 1433 changed lines, against the precedent PR feat(scripts,adr): a published TYPE-surface narrowing gets an honest ADR-0087 disposition — the sixth category, paid for by a base-side type reading #13596 (+956 / −10) and the director's ~1.3× estimate; under the 3000-line threshold.
    • Landing class: Tier H (check-governed-merges.mjs --pr 22940: docs/adr/**). The PR stays draft with needs-user-decision, the final 速读 is posted on it, and review is requested from os-zhuang and hotlong. After an authorized APPROVED review, this seat runs the pre-landing checks, clears the label, flips it ready and enables auto-merge.
    • Acceptance notes: the gate header's "four of the five dispositions" sentence has been stale since the sixth category; it is recorded in the PR's own Acceptance notes, a prose drift with no reader (not filed).

    Generated by Claude Code

  9. objectstack-fleet commented on Oct 12, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed: PR #22940 merged · 2026-10-12T05:36Z

    domain:devx seat 1 · os-warren · session_012yK1ddAdAqfzwigRHZq3r2. ACCEPT on this card is the review record.

    • Route: Tier H. The maintainer's quick read was posted on the PR, and review was requested from os-zhuang and hotlong. os-zhuang approved at 04:33Z on f06cee4132, the head the seat reviewed, flipped the PR ready and enqueued it. The seat cleared needs-user-decision from the PR. Every merge-group build of it read success while other PRs were ejected ahead of it, and it merged at the time above. The PR's Fixes #22918 closed this card. The seat removes pm:dispatched in this act.
    • On main: runtime-export-retired is in the gate's closed vocabulary, and ADR-0087's addendum carries decision D9.
    • What it changes for authors: a changeset that retires published exports, or members of an exported type, can now claim not-required (runtime-export-retired <package>#<Export>|<package>#<Type>.<member>, …) instead of riding no-migration-prescription on a detector miss. Existing changesets are not re-graded.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedomain:devxpriority:p2Medium: important, M3tooling

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions