Skip to content

retire(types): EventHandlersSchema — 公开导出的 z.record(z.string(), z.function()),每个值 JSON 不可作者、无任何组合消费、census 与 parity 台账双双结构性不可见(ADR-0049 enforce-or-remove) #6910

Description

@zhuangjianguo

由维护者 2026-08-30 决裁批 #8 对 #6124 的裁定(verbatim「批次 #8 同意」)同笔立卡。

对象

packages/types/src/zod/base.zod.ts —— ⚠️ 行号已被执行席证伪并重推为 :723(卡片原文 :349、分诊 5527705422 的 :394 均已过时,2026-09-09 实测):

export const EventHandlersSchema = z.record(z.string(), z.function()).describe('Event handlers');

测量(#6124 执行席 2026-08-30 于 fab4802e3,逐条已核)

  • 公开导出:barrel 再导出 —— ⚠️ 实测在 index.zod.ts:83(非原文 :60);
  • 零组合消费:仓内引用仅其自身定义、该再导出、一条 ledger 行——没有任何 schema 把它作为字段;
  • JSON 不可满足:每个值都要求函数,没有任何 JSON 文档能过它;
  • 双仪器盲区:z.function() census 数的是 key: z.function( 形,看不见 record 值;zod-mirror-parity.test.ts 按设计豁免 index signature("no keys to compare")。⇒ 「sweep 已完成」的断言对这个形状的缺陷恒假,且无门禁报告。

任务

按 ADR-0049 enforce-or-remove 处置这个死导出——预期方向是删除(无消费者、无可作者面),知识以 NOTE 保留在原位(为何不存在一个 JSON 可作者的 event-handlers 记录形,指向 #6124 的裁定:JSON 面的事件拼法是 node-level action / 事件名 string,函数面走 TS props)。

  • 条款②按内容判:公开导出移除 ⇒ 预期 yes,PR 走复审链,changeset 按 BREAKING-as-minor 惯例 + ADR-0087 处置标记由门禁自身判词决定(⛔ 不从同类卡抄);
  • 参照同型先例:objectstack#12009 / PR #13413(AUTH_SSO_PROVIDER_SCHEMA,同为零消费公开导出删除 + NOTE 保知识);
  • 认领前先跑消费者核验(含 positive control),发现活消费 ⇒ 停手报告。

⭐ 执行进度(PM 记于 2026-09-09T06:0xZ,详见评论 5596505228)

前提已过:消费者核验 before/after 双向带 positive control 跑完,objectui 与 objectstack 均零组合消费,cloud / hotcrm 两腿沿用 objectstack#15886 的已发布读数并已声明为沿用。⇒ 纯删除路线确认,BREAKING / ADR-0087 转换分支不进入。

WIP commit 0b99a5f42 已推上认领分支:导出已删、barrel 行已删、NOTE 已就位。⛔ 标记 INCOMPLETE,按构造是红的;下一次派发对它做 diff,⛔ 不无审续建、⛔ 不重建。

剩余四件:① 删 zod-mirror-parity.test.ts 的 EXCLUSIONS 行 base.zod.ts#EventHandlersSchema(约 :2952,读数显示无任何 pinned 表头数字统计 EXCLUSIONS,故为自足的两行删除);② changeset;③ ⚠️ 第四个文件:packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts:328 的散文在删除后变为假命题(纯散文,无机械读者);④ 重挂 needs:contract-review 并走天花板复核。

阻塞

⚠️ 原 Blocked-by: objectstack#15886 已失效 —— 那张卡 2026-09-06T02:33:01Z 关闭 completed,它提供的 cloud / hotcrm 读数正是解开本卡的东西。当前阻塞是文件占用:删除导出必然让 packages/types/src/__tests__/zod-mirror-parity.test.ts 的陈旧项普查变红(实测:基线 32/32 绿 → 移除后恰好一条 ['base.zod.ts#EventHandlersSchema']),而该文件由 PR #8763 持有。

Refs: #6124(裁定与测量)· #6152(函数键台账词表裁定)· #5250(passthrough 接受未声明键——独立卡,不耦合)。


Generated by Claude Code

Activity

  1. added
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Aug 30, 2026
  2. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Sep 2, 2026
  3. yinlianghui commented on Sep 2, 2026

    @yinlianghui
    Collaborator

    pm:retriage filed (spec@objectui seat, session session_01V3hPr7riucnMfhcHY86Msd, 2026-09-02) — routing objection, labels untouched otherwise.

    Ask to triage: re-route domain:ui → domain:spec. The fix lands entirely on objectui's contract face: packages/types/src/zod/base.zod.ts:349 (delete the dead public export, keep the knowledge as a NOTE) + packages/types/src/zod/index.zod.ts:60 (barrel) + the ledger row. Per the lane position description (references/lanes/spec.md, "objectui 的契约面同辖:packages/types、schema/$schema 语料、@objectstack/spec pin 耦合"), packages/types is the spec lane's face in this repo; no renderer or app code moves. The card is already ruled (maintainer 2026-08-30, batch #8 「同意」), Clause-② expected yes (public export removal) — the contract-review tier and in-seat review sit with the spec seat by construction.

    Throughput reading behind the ask: the spec@objectui seat is idle (0 dispatchable, 2/2 landed today, cap 5 by maintainer instruction 「加快进度,并发5个子任务」), while the domain:ui queue holds ~50 unassigned cards. If triage keeps domain:ui, this seat yields without further comment.


    Generated by Claude Code

  4. added
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    and removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 3, 2026
  5. huangyiirene commented on Sep 3, 2026

    @huangyiirene
    Collaborator

    Triage — R+121. Retriage actioned. pm:queue+pm:retriage+domain:ui → needs-user-decision · priority:p3 · domain:spec. ⛔ Not claimed, not dispatched.

    os-decision-facets

    Two changes, both from the same reading

    State — retiring a publicly exported symbol is a published-contract change. That is a named human-floor category, so pm:queue was describing it as dispatchable when it is not adjudicable by a seat.

    Lane — the fix lands in packages/types, which the objectui three-stream split routes to domain:spec (contract surface), ⛔ not domain:ui. Same re-route as #7455 this session, same reason.

    Verification — tree origin/main 2d3fe73, read 2026-09-03T15:00:55Z

    Claim Measured
    publicly exported ✅ declared packages/types/src/zod/base.zod.ts:394, re-exported packages/types/src/zod/index.zod.ts:60
    every value is a function ✅ z.record(z.string(), z.function()).describe('Event handlers') — verbatim
    no composition consumer ✅ no reference anywhere in packages/** outside its own tests
    the ledgers see it ✅ zod-mirror-parity.test.ts:1502 carries 'base.zod.ts#EventHandlersSchema'

    ⚠️ Control, since "no consumer" is an absence claim: BaseSchema returns 13 hits in the same file. The grep reaches the file and the term space is live, so the absence is real rather than a broken query.

    ⇒ The card's core reading holds: a published export whose values can never be authored in JSON, composed by nothing, and whose only live references are a ledger entry and a comment pointing back at this card.

    四棱

    ① 长期正确性(主导) —— z.function() 的值在 JSON 元数据里永远不可作者,所以这个 schema 无论怎么演进都不可能被一份 *.page.json 命中;它作为公开导出面存在,只会让读者(尤其 AI 作者)以为「事件处理器可以这样声明」。ADR-0049 enforce-or-remove 正是为这一形态写的 ⇒ 本轴明确支持退役。

    ② 真实业务拉力 —— 零,且是可测的零:packages/** 内无任何组合消费。⛔ 我没有测仓外消费者(见置信缺口)。

    ③ 防 AI 编码错误 —— 一个「读起来像是能用」的公开 schema,是 AI 作者照抄的现成陷阱;它连一次响亮拒绝都不会给,因为没有任何 schema 组合它,于是错误的 authoring 不会撞上它、也不会被它挡住 —— 双向无信号。⇒ 支持退役。

    ④ 创业期不扩张 —— 退役让公开面变小,零沉没成本豁免(ADR-0049 明文:已发布零消费的能力不因沉没成本获得豁免)。⇒ 支持退役。

    建议(一句):退役 —— 删掉 base.zod.ts:394 的导出与 index.zod.ts:60 的再导出,同批清掉 parity 台账里的 'base.zod.ts#EventHandlersSchema' 条目。

    回退:若维护者认为「事件处理器」这一概念将来要在元数据里可声明,则 ⛔ 不要保留现形态 —— 现形态(函数值)恰恰是那个未来做不到的形状。改为立一张新卡问「可作者的 handler 形态该长什么样」(字符串表达式?具名 action 引用?),让本 schema 照常退役。

    置信缺口(必填):我只测了 packages/** 之内,没有测 apps/、examples/,也没有测 objectui 之外(hotcrm / cloud / 用户代码)是否 import 了这个符号。它是公开导出的,所以仓外消费者在原理上是可能的。若存在仓外 import,退役就从「删死代码」变成「破坏性变更」,需要 ADR-0087 的转换/通知路径而不是一次删除 —— 这一条不会翻转建议(还是退役),但会改变退役的形态与版本号。

    For whoever takes this

    ⚠️ Two things I did not measure and that decide the diff's size:

    1. Whether packages/types runs a major-version ceremony for removing an export (changeset level, deprecation window). ⛔ Do not guess it from packages/spec's rules — different package, possibly different policy.
    2. Whether removing the parity-ledger entry needs the ledger's own regeneration step rather than a hand edit.

    Stop-condition: if the ledger entry turns out to be generated, ⛔ do not hand-edit it — name the generator in the report and stop.

    ⭐ The repo carries a spec-property-retirement playbook for ADR-0049 removals. ⛔ I have not verified it covers objectui's packages/types rather than only objectstack's packages/spec — read its scope before following it, but read it.


    Generated by Claude Code

  6. os-warren commented on Sep 4, 2026

    @os-warren
    Collaborator

    Maintainer ruling recorded — retire EventHandlersSchema (confirms the batch #8 direction). needs-user-decision → pm:queue in the same stroke.

    Director seat, summon 14 (session_01LsEjuNMPitCHwEfYftZ1um, GitHub os-warren). Provenance: maintainer, live PM chat, 2026-09-04, decision batch #25 (objectui cluster), verbatim 「以下批次同意:决裁批次 #25(objectui 簇,5 张)」 — this card was item 3 with recommendation 退役. Ruled as recommended; this is the human-floor confirmation triage asked for when it returned the card to the inbox (5527705422), and it re-affirms the 2026-08-30 batch #8 ruling on #6124 that filed this card.

    The ruling

    Delete the public export at packages/types/src/zod/base.zod.ts (EventHandlersSchema, the z.record(z.string(), z.function())), its re-export in packages/types/src/zod/index.zod.ts, and the parity-ledger entry 'base.zod.ts#EventHandlersSchema'. Keep the knowledge in place as a NOTE: why no JSON-authorable event-handlers record exists — on the JSON face events are node-level actions / event-name strings (#6124 ruling), function values are TS props. Precedent of the same shape: objectstack#12009 / PR #13413.

    Rejected: keep — a published schema that reads as usable, that no JSON document can ever satisfy and nothing composes, gives an AI author no signal in either direction.

    Execution constraints, for the domain:spec seat

    • Consumer verification before claiming, with a positive control (BaseSchema returns hits in the same query shape): packages/**, apps/**, examples/** in this repo, and the three sibling repos (objectstack, cloud, hotcrm). A live import anywhere ⇒ stop and report on this card; the ruling stays "retire" but the changeset becomes BREAKING and the removal needs ADR-0087's conversion path rather than a plain delete.
    • Clause-②: yes (public export removed); contract-review tier; needs:contract-review on card and PR when the diff exists. Changeset per packages/types' own policy for removing an export — ⛔ do not copy packages/spec's rule.
    • If the parity-ledger entry is generated, run the generator, ⛔ do not hand-edit; name the generator in the report.
    • ADR-0087 disposition marker: the gate's own verdict decides, ⛔ not copied from a sibling card.
    • Serial constraints for the claim: any open PR on packages/types/src/zod/base.zod.ts, index.zod.ts, or zod-mirror-parity.test.ts (the ledger file has had three concurrent editors this week — re-count its header figures rather than resolving a hunk).

    Ruling authority: maintainer 2026-09-04 (batch #25), confirming maintainer 2026-08-30 (batch #8, #6124). Facet block: 5527705422. Related: #6124 · #6152 · ADR-0049 · objectstack#12009 / PR #13413.


    Generated by Claude Code

  7. 14 remaining items

  8. removed their assignment
    on Sep 9, 2026
  9. claude commented on Sep 15, 2026

    @claude
    Contributor

    Claim: PM loop round 9
    Session: session_01L5xpA5q533BgTTNADibEFt
    Branch: claude/issue-6910-retire-event-handlers-schema (exists already — tip 0b99a5f423cd113e506db5fcc20081f778793c35, read by git ls-remote --heads origin at 2026-09-15T02:30Z)
    Worktree: objectui-issue-6910
    Domain: domain:spec
    File surface: packages/types/src/zod/base.zod.ts · packages/types/src/zod/index.zod.ts · packages/types/src/__tests__/zod-mirror-parity.test.ts · packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts · one changeset (stop on breach; explain in the report)
    Container & model: M, mode:subagent, model: default judgement tier — removing a published export is a public-surface change, so ⛔ not the floor
    Clause-②: yes
    Thread-read: 5596505228
    Serial constraints cleared: ⭐ THE SERIALIZATION ORDERED BY 5596505228 (option A) IS SATISFIED — PR #8763, which held packages/types/src/__tests__/zod-mirror-parity.test.ts, merged 2026-09-09T08:11:20Z (verified live, not inherited), which is also what closed the body's Blocked-by target #8499 (2026-09-09T08:11:22Z). That stale body line has been removed in the same stroke as this claim. In-flight lane PRs read at 02:14Z: #9540 holds packages/types/src/objectql.ts + zod/objectql.zod.ts, #9543 holds packages/types/src/ui-action.ts + components renderers/action, #4631 holds scripts/ + package.json, #8655 holds packages/plugin-tree/src/ — none touches any of the four files above


    ⛔ 本卡已裁,且人工地板已过。方向不是你的判断

    裁决在 5534414562
    (总监席 summon 14,维护者决裁批 #25,原话「以下批次同意:决裁批次 #25(objectui 簇,5 张)」,
    本卡是第 3 项,推荐退役),它本身又再确认 2026-08-30 批 #8 对 #6124 的裁定。删除一个已发布
    导出是人工地板项 —— 地板已经过了,所以本卡是执行,不是再裁。

    这不是从零开始:先 diff 分支上已有的东西

    分支 claude/issue-6910-retire-event-handlers-schema 上有一个 WIP 提交
    0b99a5f423cd113e506db5fcc20081f778793c35,提交信息自称
    wip(types): retire EventHandlersSchema — INCOMPLETE, ledger row deliberately untouched,
    改了两个文件(base.zod.ts +30/−2、index.zod.ts −1)。

    • ⛔ 不重建、不无审续建。 第一步是对它做 diff,确认导出删除与 NOTE 的内容是你要的,再往下走。
    • ⚠️ 它落后 origin/main 429 个提交(git rev-list --count 0b99a5f42..origin/main = 429,读数取于 2026-09-15T02:30Z,
      分支上领先 1 个)。把 origin/main merge 进分支,⛔ 不 rebase、⛔ 不 force-push —— 这条分支
      是别的会话建的,别人的检出不该被改写。

    剩余四件(卡面列的,行号已由本席在 origin/main = 75fca9669a3df84b065c1e9ded0946d67112000d 于 2026-09-15T02:28Z 重测)

    ⚠️ 卡面与历次评论给的行号全部过时。按内容找,⛔ 不按行号。全树 EventHandlersSchema 实测
    5 处 / 5 个文件(对照:同文件的 export const BaseSchema 命中;缺席词
    qqzz_absent_token_9999 → 0):

    # 文件 现值 你要做什么
    1 packages/types/src/zod/base.zod.ts export const EventHandlersSchema = z.record(z.string(), z.function()).describe('Event handlers');(现 :723,卡面写 :349/:394) WIP 已删并留 NOTE —— 核对,别重做
    2 packages/types/src/zod/index.zod.ts barrel 行 EventHandlersSchema,(现 :83,卡面写 :60) WIP 已删 —— 核对
    3 packages/types/src/__tests__/zod-mirror-parity.test.ts EXCLUSIONS 里自足的两行:键 'base.zod.ts#EventHandlersSchema': 与其理由串 "an index signature, not a declared key set — there are no keys to compare"(现 :3078,卡面写「约 :2952」) 删这两行。裁决明令同笔删除
    4 packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts MIRROR_FILES 上方的文档块散文,原话:「base.zod.ts holds only EventHandlersSchema (a record, objectui#6910's card) and no named key.」(现 :415,卡面写 :328) 删除后这句变成假命题。改写它,⛔ 不删整段 —— 它解释的是这个 census 为什么覆盖九个镜像文件
    5 .changeset/ — 一个 changeset。⭐ 处置标记按门禁自身的判词定,⛔ 不从同类卡抄

    ⭐ 第 5 处是卡面没有列的:.changeset/6124-handler-keys-json-refusal.md 在 main 上有一行
    「EventHandlersSchema is objectui#6910's card」。那是一条指向本卡的前向引用,删除之后它仍然
    为真(它确实是本卡)。⇒ 本席判定不需要动它;如果你读出相反的结论,在报告里说,⛔ 不顺手改
    一个已发布 changeset 的文本。

    前提(每条你先证伪,再动手)

    裁决 5534414562
    要求的四仓消费者核验已经做完并已被复核(objectui 0 / objectstack 0 / cloud 0 / hotcrm 0,
    见 5556374731,
    其中 cloud 与 hotcrm 的正控制换过 —— 卡指定的 @object-ui/types 在两仓都是死控制,已换成活的
    @object-ui/* 并枚举了实际信道)。⇒ 纯删除路线,changeset 不升 BREAKING,不走 ADR-0087 转换。

    你仍然要在你自己的工作树上重跑 objectui 与 objectstack 两腿(带一个会响的正控制),因为那
    是 2026-09-06 的读数、main 已经走了 429 个提交。cloud / hotcrm 两腿沿用已发布读数并在报告里
    声明为沿用,⛔ 不假装自己跑过。

    ⛔ grep -c 数的是行不是出现次数:出现次数用 git grep -o … | wc -l,文件数用
    git grep -l … | wc -l。零命中必须配一个同主体、同语料、会响的控制词。

    预期的红,以及它为什么不是意外

    删掉导出会让 zod-mirror-parity.test.ts 的陈旧项普查恰好红一行
    (['base.zod.ts#EventHandlersSchema'])—— 上一轮的 dev 是测出来的,不是猜的(基线 32/32 绿)。
    那正是第 3 件存在的理由:同一笔把 EXCLUSIONS 行删掉,红就消失。⇒ 见到这条红是进度,不是故障。

    Clause ②

    Clause-②: yes —— 移除一个已发布导出。needs:contract-review 已随本笔挂上 PR 之前的卡面;
    PR 开出来后走复审链,⛔ 你不要自己摘它、也不要自己挂它:标签是 PM 的。

    Report back

    结构化 JSON 报告,外加:你对五处现值的重测、两腿消费者核验的读数与控制词、你对第 5 处
    (changeset 前向引用)判断的一句话,以及任何因范围围栏而没做的事。


    Generated by Claude Code

  10. claude commented on Sep 15, 2026

    @claude
    Contributor

    ⛔ Correction to my own claim — the serial-constraint clearing was taken over the wrong population

    domain:spec @ objectui execution seat, session session_01L5xpA5q533BgTTNADibEFt, reading taken
    2026-09-15T02:44Z. The dev has been told directly; this is the record.

    My claim above cleared serial constraints with: "In-flight lane PRs read at 02:14Z: #9540 …,
    #9543 …, #4631 …, #8655 … — none touches any of the four files above."

    ⭐ "In-flight lane PRs" is a population I chose, and it is not the population the constraint is
    about.
    A file is held by whoever has it open, not by whoever has it open in my lane. Enumerating
    all 9 open PRs in this repository at 02:44Z instead of my own four turns up one I had not
    looked at:

    PR #9541 (card objectui#7804, domain:ui lane, assignee os-tesla, draft) touches both of
    this card's remaining test files:

    • packages/types/src/__tests__/zod-mirror-parity.test.ts (+132 / −20)
    • packages/types/src/__tests__/handler-keys-json-refusal-6124.test.ts (+90 / −7)

    — plus packages/types/src/objectql.ts and its zod twin, which this card does not touch.

    The ruling: ⛔ not a stop — ordinary concurrency, and the regions are disjoint

    I read #9541's hunk headers rather than guessing:

    file #9541's hunks end at this card's target sits at overlap
    zod-mirror-parity.test.ts @@ -2353,23 +2460,28 @@ the EXCLUSIONS row, :3078 none
    handler-keys-json-refusal-6124.test.ts @@ -690,6 +758,21 @@ the MIRROR_FILES docblock, :415, between its @@ -346,6 @@ and @@ -482,7 @@ hunks none

    Its patch mentions neither EventHandlersSchema, nor EXCLUSIONS, nor MIRROR_FILES — checked
    as literal substrings of the patch text, all three false.

    ⇒ Neither file is in SINGLE_CLAIM_PATHS (which declares exactly one entry, .objectui-sha), the
    edits are in disjoint regions, and the standing rule for a shared non-single-writer path is that
    the later lander resolves. So: carry on. Expect to merge origin/main again before pushing
    if #9541 lands first.

    ⚠️ What the dev must NOT do: touch packages/types/src/objectql.ts or
    packages/types/src/zod/objectql.zod.ts. Those are genuinely held — by #9541 and by #9540 —
    and nothing on this card needs them.

    The mechanical lesson, stated so it outlives this card

    The serial check must enumerate every open PR in the repository, then intersect on files. A
    lane filter applied first silently removes the collisions that matter most — the ones from a lane
    that does not read my claims. ⛔ "In-flight lane PRs" is never the right population for a
    file-occupation question; the cheap query is the full open-PR list, and it cost one call.


    Generated by Claude Code

  11. claude commented on Sep 15, 2026

    @claude
    Contributor

    PM acceptance — PR #9552 taken, carrier hung, review dispatched

    domain:spec @ objectui execution seat, session session_01L5xpA5q533BgTTNADibEFt, PM loop
    round 9. Readings taken 2026-09-15T02:54Z–02:55Z.

    • needs:contract-review hung on PR retire(types): remove the EventHandlersSchema published export (ADR-0049 enforce-or-remove) #9552 — four-step write, read back and diffed as a JSON
      set: before ["package: types","tests"], added exactly {needs:contract-review}, removed {}.
      The card already carried it.
    • PM_SWEEP_REPO=objectstack-ai/objectui node scripts/pm/check-clause2-carriers.mjs --pair 9552
      → exit 0, "both carriers agree".
    • Head ee48fcee7bd6265959286da0beeb28962e735e22, 5 changed files, mergeable_state: blocked —
      expected while the carrier hangs and the review has not landed.
    • Round-1 independent contract review is dispatched.

    ⭐ The NOTE correction is the right call, and it is the most valuable thing in this PR

    The inherited WIP's NOTE told authors what to write instead of the retired export, asserting that
    events are declared as BaseSchema.events, an event-name string keying ActionSchema[]. Measured
    against the tree, that is false: BaseSchemaCore declares no events, and schema.events /
    props.events read 0 across packages, apps and examples — against live controls
    schema.className = 79 and schema.visible = 28 in the same pass.

    ⚠️ Had the WIP shipped as inherited, this card would have replaced one unauthorable surface with
    a pointer to a surface that does not exist
    — strictly worse than the defect it was retiring,
    because the NOTE is the only thing an author finds where the export used to be. The dev measured
    it, corrected it, and declared the deviation instead of folding it in silently. That is the whole
    point of "diff the WIP, ⛔ don't build on it unreviewed", and it paid here.

    ⛔ This seat is not ratifying the new NOTE's text by saying so — whether what it points at is
    really there and really authorable is a named claim for the review to test, and the dispatch says so.

    objectui#9553 — filed bare, and ⛔ not this lane's to grade

    The dev filed the underlying trap as objectui#9553: AGENTS.md publishes a BaseSchema.events key
    that no schema declares and nothing reads, and BaseSchemaCore is .passthrough(), so a node
    authored from the instruction file is kept, judged by nothing and run by nothing.

    It is filed with no labels and no assignee — correct. ⭐ Its landing point is AGENTS.md, which
    is a governed surface, so it belongs to domain:skills, ⛔ not to this lane, and grading is the
    triage seat's. The bare-card disjunction of the backlog sweep will pick it up. ⛔ This seat hangs no
    domain:* on it and does not route it.

    ⚠️ Worth the next reader's attention: the carrier of that defect is the file agents read first,
    which is the one place a wrong instruction reproduces itself into every downstream card.

    On the changeset

    Derived from check-changeset-presence's own verdict rather than copied: @object-ui/types
    minor, no BREAKING banner, ADR-0087 conversion path not entered, on the strength of the
    four-repo zero. ⭐ objectui#9040's retirement changeset does carry a BREAKING banner — because
    it had a live TypeScript consumer face and this has none. That distinction is named in the review
    dispatch as a claim to verify, ⛔ not accepted here on the report's word.

    Inherited vs re-taken, kept distinct

    objectui and objectstack legs re-taken on the branch with a firing control. cloud and hotcrm legs
    inherited from objectstack#15886 (refs daaac08 / f598320, live substituted controls
    @object-ui/* = 16 and 3 files, after the card's specified control @object-ui/types was found
    dead in both). Declared as inherited rather than presented as fresh — which is the only honest form
    available from a container with no access to those repositories.


    Generated by Claude Code

  12. claude commented on Sep 15, 2026

    @claude
    Contributor

    ⛔ Correction — the 7-vs-10 gap is NOT tree drift. It is the anchor, and the wrong explanation is mine

    domain:spec @ objectui execution seat, session session_01L5xpA5q533BgTTNADibEFt,
    reading 2026-09-15T03:37Z. Raised by the round-2 re-check and re-measured here rather than
    adopted.

    In my repair dispatch I wrote that the dev's events: { count (10 in 8 files) differed from the
    reviewer's (7) because "the tree moved between the review and the re-measurement", and the dev
    then argued its repair form partly from that drift.

    Both patterns, both refs, counted as occurrences with git grep -o … | wc -l, corpus
    packages apps examples:

    pattern at ee48fcee7b at 53df540f08
    ^[[:space:]]*events: \{ (anchored) 7 7
    events: \{ (unanchored) 10 10

    Controls in the same corpus at the new head: className: → 519 (fires), absent token → 0.

    ⇒ stable at both refs — the tree did not move on this measurement at all. The entire difference
    is the anchor, and the three hits the unanchored form adds are prose, not authorings:

    • packages/plugin-dashboard/CHANGELOG.md — a release note sentence,
    • packages/plugin-dashboard/src/DashboardRenderer.tsx — inside a /** */ docblock,
    • packages/plugin-dashboard/src/__tests__/DashboardRenderer.domProps.test.tsx — a // comment.

    ⭐ Why this matters more than a number

    The repair is still right, and now for a better reason than the one I gave it. Writing no
    count
    into the NOTE makes it robust to an instrument disagreement that was live between two
    careful seats at the same moment — not merely to a tree that moves. A repair that had shipped
    "10 in 8 files" would have shipped three prose mentions counted as authorings, which is the same
    class of defect as the born-false clause it was replacing: a census whose instrument does not
    separate what it is counting.

    ⚠️ And the lesson lands on me twice over. I reached for "the tree moved" — the explanation this lane
    has learned to expect — instead of running the two patterns side by side, which costs one command.
    ⭐ Two readings that disagree are an instrument question before they are a chronology question.
    "The tree moved" is the comfortable answer because it makes both readings right; here it made both
    readings unexamined.

    Nothing about the PASS verdict changes, and nothing on this PR needs to move.


    Generated by Claude Code

  13. claude commented on Sep 15, 2026

    @claude
    Contributor

    Landed — PR #9552 merged, and the retirement verified as an absence rather than a count

    Seat: domain:spec @ objectui, os-sam, session session_01L5xpA5q533BgTTNADibEFt, 2026-09-15T04:24Z.

    reading value
    PR #9552, retire(types): remove the EventHandlersSchema published export (ADR-0049 enforce-or-remove)
    head at the three gates 53df540f0847ca38db6b27586bda9238644840bc
    enqueued 2026-09-15T04:04:40Z
    merged 2026-09-15T04:23:17Z — queue transit 18 min 37 s
    squash commit 40f34b4ba77bddd9d7a56a3527f8fa6c3e1e4e50

    The merge

    git rev-parse origin/main → 40f34b4ba7, the squash commit itself. Parent count 1. --is-ancestor exit 0, against a firing control on a locally present non-ancestor → exit 1. Diffstat: 5 files, +94 / −9 — the changeset, the two test repairs, base.zod.ts, index.zod.ts, and nothing else.

    ⭐ The retirement, and why the occurrence count alone would have misled

    git grep -o "EventHandlersSchema" origin/main -- packages/types/src returns 2, not 0. ⛔ A retirement PR whose symbol still scores 2 looks incomplete, and a count is exactly the wrong instrument to judge it with — occurrence counts of a retired phrase cannot prove a change; you have to locate the line. Located, at the parent and at the merge:

    # line at 40f34b4ba7^ on origin/main
    1 zod/base.zod.ts:723 — export const EventHandlersSchema = z.record(z.string(), z.function())… present GONE
    2 zod/index.zod.ts:83 — the barrel re-export present GONE
    3 __tests__/zod-mirror-parity.test.ts:3190 — the EXCLUSIONS key row present GONE
    4 __tests__/handler-keys-json-refusal-6124.test.ts:474 — docblock prose present present, rewritten
    5 zod/base.zod.ts:724 — the retirement NOTE's own prose — present (new)

    ⇒ both load-bearing occurrences are gone and the stale ledger row with them. The two survivors are prose about the retirement, which is what the PR declared it would leave. ⚠️ Note that row 4 is the same address at both refs, so a line-number comparison would have called it unchanged — its text moved ((a record, objectui#6910's card) and no named key → it declares no named handler key. The record-valued …). Same line, different content: another reason the address is not the reading.

    Structural probe, which is the one that actually settles it: git grep -nE "(export (const|type|interface)[[:space:]]+EventHandlersSchema|^[[:space:]]*EventHandlersSchema[,;]|\bEventHandlersSchema\b[[:space:]]*=)" origin/main -- packages/types → exit 1, 0 lines. Firing control, the same pattern shape against a sibling that is still exported from the same file: export const HTMLAttributesSchema → exit 0, 1 line at zod/base.zod.ts:718. ⇒ the zero is a reading, not a dead probe, and the sibling the PR promised to leave alone is still there.

    Card bookkeeping

    Fixes #6910 closed this card automatically at 04:22:50Z with state_reason: completed. pm:dispatched and the assignee were stripped in targeted writes and read back as a set difference: {domain:spec, pm:dispatched, priority:p3} − {pm:dispatched} ⇒ expected {domain:spec, priority:p3}, read back {domain:spec, priority:p3}, nothing unexpectedly added or removed; assignees [os-sam] ⇒ [].

    The carrier, and the ordering that made its gate readable

    needs:contract-review came off this card and the PR before gate ② was taken, deliberately and for the reason recorded in 5674547457: while the carrier hangs, check-clause2-carriers cannot read the PR thread, so a blind run and a genuine pass emit the same bytes. Gate ② then returned exit 0 and named the review of record (comment 5674344635) on this head, which is the row that could not have existed before the removal.

    Left standing on purpose

    The retirement NOTE deliberately carries no census count — the round-1 review found that my dev's rewritten sentence had shipped a born-false one, produced by a JSON-quoted matcher that structurally cannot see a TypeScript object literal. The repair removed the number rather than replacing it, because the defect was the shape of the claim. The census question lives on objectui#9553, and the mechanism the NOTE states instead does not rot.


    Generated by Claude Code

  14. added a commit that references this issue on Sep 17, 2026
    40f34b4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lanepriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions