Repository navigation
retire(types): EventHandlersSchema — 公开导出的 z.record(z.string(), z.function()),每个值 JSON 不可作者、无任何组合消费、census 与 parity 台账双双结构性不可见(ADR-0049 enforce-or-remove) #6910
Description
Activity
- addeddomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Aug 30, 2026 - addedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
on Sep 2, 2026 pm:retriagefiled (spec@objectui seat, sessionsession_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/specpin 耦合"),packages/typesis 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:uiqueue holds ~50 unassigned cards. If triage keepsdomain:ui, this seat yields without further comment.
Generated by Claude Code
- addeddomain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec laneobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec laneand removedpm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatchdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Sep 3, 2026 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:queuewas 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 todomain:spec(contract surface), ⛔ notdomain:ui. Same re-route as #7455 this session, same reason.Verification — tree
origin/main2d3fe73, read 2026-09-03T15:00:55ZClaim Measured publicly exported ✅ declared packages/types/src/zod/base.zod.ts:394, re-exportedpackages/types/src/zod/index.zod.ts:60every value is a function ✅ z.record(z.string(), z.function()).describe('Event handlers')— verbatimno composition consumer ✅ no reference anywhere in packages/**outside its own teststhe ledgers see it ✅ zod-mirror-parity.test.ts:1502carries'base.zod.ts#EventHandlersSchema'⚠️ Control, since "no consumer" is an absence claim:BaseSchemareturns 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:- Whether
packages/typesruns a major-version ceremony for removing an export (changeset level, deprecation window). ⛔ Do not guess it frompackages/spec's rules — different package, possibly different policy. - 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-retirementplaybook for ADR-0049 removals. ⛔ I have not verified it covers objectui'spackages/typesrather than only objectstack'spackages/spec— read its scope before following it, but read it.
Generated by Claude Code
- Whether
Maintainer ruling recorded — retire
EventHandlersSchema(confirms the batch #8 direction).needs-user-decision→pm:queuein the same stroke.Director seat, summon 14 (
session_01LsEjuNMPitCHwEfYftZ1um, GitHubos-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, thez.record(z.string(), z.function())), its re-export inpackages/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:specseat- Consumer verification before claiming, with a positive control (
BaseSchemareturns 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-reviewon card and PR when the diff exists. Changeset perpackages/types' own policy for removing an export — ⛔ do not copypackages/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, orzod-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
- Consumer verification before claiming, with a positive control (
14 remaining items
Claim: PM loop round 9
Session:session_01L5xpA5q533BgTTNADibEFt
Branch:claude/issue-6910-retire-event-handlers-schema(exists already — tip0b99a5f423cd113e506db5fcc20081f778793c35, read bygit ls-remote --heads originat2026-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/main429 个提交(git rev-list --count 0b99a5f42..origin/main= 429,读数取于2026-09-15T02:30Z,
分支上领先 1 个)。把origin/mainmerge 进分支,⛔ 不 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.tsexport const EventHandlersSchema = z.record(z.string(), z.function()).describe('Event handlers');(现:723,卡面写:349/:394)WIP 已删并留 NOTE —— 核对,别重做 2 packages/types/src/zod/index.zod.tsbarrel 行 EventHandlersSchema,(现:83,卡面写:60)WIP 已删 —— 核对 3 packages/types/src/__tests__/zod-mirror-parity.test.tsEXCLUSIONS里自足的两行:键'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.tsMIRROR_FILES上方的文档块散文,原话:「base.zod.tsholds onlyEventHandlersSchema(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 上有一行
「EventHandlersSchemais 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
⛔ Correction to my own claim — the serial-constraint clearing was taken over the wrong population
domain:spec@ objectui execution seat, sessionsession_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 at02:44Zinstead of my own four turns up one I had not
looked at:PR #9541 (card objectui#7804,
domain:uilane, 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.tsand 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 EXCLUSIONSrow,:3078none handler-keys-json-refusal-6124.test.ts@@ -690,6 +758,21 @@the MIRROR_FILESdocblock,:415, between its@@ -346,6 @@and@@ -482,7 @@hunksnone Its patch mentions neither
EventHandlersSchema, norEXCLUSIONS, norMIRROR_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 mergeorigin/mainagain before pushing
if #9541 lands first.⚠️ What the dev must NOT do: touchpackages/types/src/objectql.tsor
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
PM acceptance — PR #9552 taken, carrier hung, review dispatched
domain:spec@ objectui execution seat, sessionsession_01L5xpA5q533BgTTNADibEFt, PM loop
round 9. Readings taken2026-09-15T02:54Z–02:55Z.needs:contract-reviewhung 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 asBaseSchema.events, an event-name string keyingActionSchema[]. Measured
against the tree, that is false:BaseSchemaCoredeclares noevents, andschema.events/
props.eventsread 0 across packages, apps and examples — against live controls
schema.className= 79 andschema.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.mdpublishes aBaseSchema.eventskey
that no schema declares and nothing reads, andBaseSchemaCoreis.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 todomain: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 (refsdaaac08/f598320, live substituted controls
@object-ui/*= 16 and 3 files, after the card's specified control@object-ui/typeswas 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
⛔ 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, sessionsession_01L5xpA5q533BgTTNADibEFt,
reading2026-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 ee48fcee7bat 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
Landed — PR #9552 merged, and the retirement verified as an absence rather than a count
Seat:
domain:spec@ objectui,os-sam, sessionsession_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 53df540f0847ca38db6b27586bda9238644840bcenqueued 2026-09-15T04:04:40Z merged 2026-09-15T04:23:17Z — queue transit 18 min 37 s squash commit 40f34b4ba77bddd9d7a56a3527f8fa6c3e1e4e50The merge
git rev-parse origin/main→40f34b4ba7, the squash commit itself. Parent count 1.--is-ancestorexit 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/srcreturns 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/main1 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-exportpresent GONE 3 __tests__/zod-mirror-parity.test.ts:3190— theEXCLUSIONSkey rowpresent GONE 4 __tests__/handler-keys-json-refusal-6124.test.ts:474— docblock prosepresent 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 atzod/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 #6910closed this card automatically at 04:22:50Z withstate_reason: completed.pm:dispatchedand 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-reviewcame off this card and the PR before gate ② was taken, deliberately and for the reason recorded in5674547457: while the carrier hangs,check-clause2-carrierscannot 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 (comment5674344635) 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
- added a commit that references this issue
on Sep 17, 2026
由维护者 2026-08-30 决裁批 #8 对 #6124 的裁定(verbatim「批次 #8 同意」)同笔立卡。
对象
packages/types/src/zod/base.zod.ts——:723(卡片原文:349、分诊5527705422的:394均已过时,2026-09-09 实测):测量(#6124 执行席 2026-08-30 于
fab4802e3,逐条已核)index.zod.ts:83(非原文:60);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)。
AUTH_SSO_PROVIDER_SCHEMA,同为零消费公开导出删除 + NOTE 保知识);⭐ 执行进度(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