You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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
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;
unpublished — false (@objectstack/client is published).
registered / already-registered — would need an ADR-0087 ledger entry in packages/spec/src/migrations/registry.ts, which serves METADATA upgraders (objectstack migrate meta, spec-changes.json, the upgrade guide) and has nothing to say about an SDK reader change; an entry there would be a false registration.
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 projects → environments 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)
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.
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).
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/main4a37870: 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.
Found while landing the #13079 convergence (
analytics.query/analytics.meta/analytics.explain/automation.triggeronunwrapResponse). Filed unassigned for triage; the convergence PR is not blocked by it (thechangeset-checkjob 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:BaseResponse & { data: AnalyticsResult },AnalyticsMetadataResponse,AnalyticsSqlResponse,BaseResponse & { data: AutomationResult }) and are concrete at HEAD (the payload types);objectstack migrate metahas nothing to rewrite, no Zod schema moved, nopackages/specpath is in the diff;client.analytics.query/meta/explainandautomation.triggerhand 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## Migrationtable ofr.data.rows→r.rowsrewrites 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, base1dcb995f23)The changeset states
not-required (runtime-interface-only packages/client/src/index.ts#ObjectStackClient).node scripts/check-adr-0087-registration.mjs --base 1dcb995f23exits 1:runtime-interface-only— refused: it inherits the prescription refusal (ADR-0087's changeset disposition has no category for published runtime TS interfaces with no metadata surface — the #8277 exemption argument is correct, unverifiable, and will be re-litigated #8299), and the body's## Migrationtable is read as a prescription (framed-sectionbranch). Correct reading of the body; the category simply cannot coexist with a prescription.no-migration-prescription— refused for the same reason.type-surface-only([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) — not claimable: predicate 4 requires the symbol to have beenany/unknown/ unannotated at the merge base. These four were concrete envelope types there (bound by A sixth client-SDK erasure spelling, larger than the other five combined: 43 exported methodsreturn res.json()directly, whose lib.dom type isPromise< any >#12104). The gate's own refusal text says so.unpublished— false (@objectstack/clientis published).registered/already-registered— would need an ADR-0087 ledger entry inpackages/spec/src/migrations/registry.ts, which serves METADATA upgraders (objectstack migrate meta,spec-changes.json, the upgrade guide) and has nothing to say about an SDK reader change; an entry there would be a false registration.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 addingtype-surface-onlyscoped to exactly that class. This is its sibling one step over.Precedent:
.changeset/adr0006-d2-client-environments-namespace.md(theprojects→environmentsrename) 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)
type-surface-onlypredicate 4 from "wasanyat base" to "the declared type of the named published symbol CHANGED between base and HEAD", keeping predicates 1–3 (nopackages/specpath, 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.runtime-value-moveor similar) verified likeruntime-interface-only(steps 1–4, code-only reference scan) but NOT inheriting the prescription refusal when the diff moves nopackages/specpath. More vocabulary; the ADR addendum would have to describe it (theCATEGORIESlist is pinned to the ADR in both directions).changeset-checkon 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/main4a37870: the category vocabulary is where the card says it is, andscripts/check-adr-0087-registration.mjs:182-227carries theruntime-interface-only(#8299) design note including the sentence that makes this card's whole argument — that the category "ALSO inherits theno-migration-prescriptionrefusal, 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## Migrationtable 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
CATEGORIESlist is pinned to the ADR in both directions. That is above the seat.<!-- os-decision-facets -->
**BREAKING**token instead #13080 已经为它的兄弟情形(any→ 具体)开过一格,理由一字不差。client.analytics.query/meta/explainandautomation.triggerhand callers the RAW dispatcher envelope while every sibling unwraps it — one SDK, two calling conventions #13079 的 changeset 今天就带着红的changeset-check落地,卡面还给出了同姿势的先例(adr0006-d2-client-environments-namespace.md)。这已经是第二次,不是孤例。**BREAKING**标记去掉,红就消失了。[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 已经点名过这个动作。一道逼着人删掉破坏性标记才能变绿的门禁,比没有门禁更危险 —— 它把「如实记录破坏性」悄悄换成了「让门禁闭嘴」,而且换得毫无痕迹。推荐: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