Skip to content

check-adr-0087-registration has no verifiable disposition for a published runtime-interface change that was concrete at base and ships a code prescription — every category refuses #13079's changeset #14502

Description

@os-trump

Found while landing the #13079 convergence (analytics.query / analytics.meta / analytics.explain / automation.trigger on unwrapResponse). Filed unassigned for triage; the convergence PR is not blocked by it (the changeset-check job is advisory), but it lands with that job red for a reason the gate's taxonomy cannot express.

The shape

A breaking change to four methods of a PUBLISHED runtime TypeScript class (packages/client/src/index.ts, ObjectStackClient), where:

  • the declared return types were CONCRETE at the merge base (envelope types: BaseResponse & { data: AnalyticsResult }, AnalyticsMetadataResponse, AnalyticsSqlResponse, BaseResponse & { data: AutomationResult }) and are concrete at HEAD (the payload types);
  • the wire body is byte-identical before and after — only the SDK's reader changed, so objectstack migrate meta has nothing to rewrite, no Zod schema moved, no packages/spec path is in the diff;
  • the maintainer ruling (client.analytics.query / meta / explain and automation.trigger hand callers the RAW dispatcher envelope while every sibling unwraps it — one SDK, two calling conventions #13079, 2026-08-31, verbatim: 「迁移说明 + changeset 标破坏性」) REQUIRES the changeset to carry a migration note — a ## Migration table of r.data.rowsr.rows rewrites addressed to TypeScript/JavaScript consumers of the SDK, delivered by the compiler at their call sites.

What the gate does with it (measured on .changeset/client-envelope-convergence.md, base 1dcb995f23)

The changeset states not-required (runtime-interface-only packages/client/src/index.ts#ObjectStackClient). node scripts/check-adr-0087-registration.mjs --base 1dcb995f23 exits 1:

So the class "published runtime interface, concrete-to-concrete, with a compiler-delivered prescription" has no honest disposition, which is the same failure #13080 named for the any-to-concrete class and closed by adding type-surface-only scoped to exactly that class. This is its sibling one step over.

Precedent: .changeset/adr0006-d2-client-environments-namespace.md (the projectsenvironments rename) landed with a recorded refusal in its own body rather than a swapped category — the same posture the #13079 changeset takes.

Options (not deciding here)

  1. Widen type-surface-only predicate 4 from "was any at base" to "the declared type of the named published symbol CHANGED between base and HEAD", keeping predicates 1–3 (no packages/spec path, no ADR-0087 shape surface in the diff). Smallest change; the exemption's justification (the compiler delivers the prescription to a TS consumer) holds identically for concrete-to-concrete moves.
  2. A sixth category (runtime-value-move or similar) verified like runtime-interface-only (steps 1–4, code-only reference scan) but NOT inheriting the prescription refusal when the diff moves no packages/spec path. More vocabulary; the ADR addendum would have to describe it (the CATEGORIES list is pinned to the ADR in both directions).
  3. Status quo: accept a red advisory changeset-check on this class case by case, with the refusal recorded in the changeset body. Costs a red per occurrence and invites the [finding] check-adr-0087-registration has no honest disposition for a published TYPE-surface narrowing — every category is refused, so the class is pushed to drop the **BREAKING** token instead #13080 move of dropping the **BREAKING** token.

Any of these changes the gate (scripts/check-adr-0087-registration.mjs) and its self-test fixtures, and option 2 also the ADR-0087 addendum — spec-tooling lane.


Triage — graded

Confirmed at origin/main 4a37870: the category vocabulary is where the card says it is, and scripts/check-adr-0087-registration.mjs:182-227 carries the runtime-interface-only (#8299) design note including the sentence that makes this card's whole argument — that the category "ALSO inherits the no-migration-prescription refusal, so it is a strict" subset. The taxonomy gap is real and it is structural, not a bug in the gate's reading of this particular changeset: the card is explicit that the gate reads its ## Migration table correctly.

Your lane call is right — this is spec-tooling. domain:spec.

Graded as a decision because every option changes a governance gate's vocabulary, and option 2 additionally amends ADR-0087, whose CATEGORIES list is pinned to the ADR in both directions. That is above the seat.

<!-- os-decision-facets -->

推荐:A = 选项 1。type-surface-only 的谓词 4 从「base 时是 any/unknown/无标注」放宽为「该已发布具名符号的声明类型在 base 与 HEAD 之间发生了变化」,谓词 1–3(不含 packages/spec 路径、diff 里没有 ADR-0087 形状面)原样保留。①(不加格)与④(不加词汇)同向,②有重复拉动,③要的是「尽快给出一条诚实的路」而选项 1 最快。
回退:B = 选项 2(新设第六类)。 若维护者认为 type-surface-only 这个名字放宽后名不副实、读的人会拿它去盖别的情形,那就宁可多一格也要名实相符 —— 代价是 ADR-0087 附录必须同批改,CATEGORIES 的双向钉死不允许只改一边。
不荐选项 3(维持现状)。 它的真实代价不是「每次多一个红」,而是③里那条歪路:它持续地奖励删掉破坏性标记的人,而那正是这道门禁存在的理由。
置信缺口(本分析看不见什么): 没有量放宽谓词 4 之后,有多少历史 changeset 会变成可 claim —— 也就是选项 1 会不会顺带把一些本该走 ADR-0087 注册的变更也放行。这是 A 唯一的真实风险。门禁自带自测夹具,应该跑得出这个回归;⛔ 必须在改之前跑,不是改完再看。

Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions