Repository navigation
finding(spec): EventNameSchema's only three binding schemas have no runtime consumer — the live event vocabulary is a closed enum that never touches it #13613
Description
Activity
- added and removed
on Aug 31, 2026 分诊定级 →
domain:spec·needs-user-decision· p3 · tooling。摘finding。锚定。
packages/spec/src/shared/identifiers.zod.ts及两条路线的落点(kernel/events/core.zod.ts·api/websocket.zod.ts·api/events.zod.ts)全在packages/spec⇒domain:spec。为什么交你裁。 ADR-0049 已经把原则定死(声明而不强制的必须强制或移除),所以要裁的是路线,而两条都动公共契约:路线 1(绑定
channel等开放事件面)是 accept 集收窄;路线 2(退役)是已发布 export 的移除,须走 ADR-0087 conversion。⛔ 分诊不代裁。定级 p3:无行为缺陷、无错误答案上线。危害在 ③ 轴且是真的 —— 一个读
EventNameSchema并据以生成事件名的 generator 满足了一个平台根本不检查的东西;而它若生成闭合枚举之外的任何名字,会被一条 identifier 文件从未提及的规则拒收。两个方向都误导,这是比单纯「死代码」更贵的形状。⭐ 与 #13612 是同族,建议同一次裁决一并给方向 —— 但不要合卡
三张卡出自同一次 #12245 普查,是同一种病的三个面:
卡 形状 本轮处置 本卡 EventNameSchema有三个绑定 schema,但那三个零运行期消费者needs-user-decisionp3#13612 六个 branded identifier 零绑定(+ 评论补的三个「绑定了但被绑定方无读者」) needs-user-decisionp3#13621 SystemIdentifierSchema散文声称覆盖 11 个面,实测只绑 1 个已入队 pm:queuep3(纯散文更正,零 accept 集变更)⇒ 裁 #13612 与本卡时,同一句「bind 还是 retire」可以覆盖两张,省你一次上下文切换。
⛔ 但两张不合并,因为 bind 路线的爆炸半径完全不同:#13612 的绑定会改 object name / field name 的 accept 集(内联正则允许前导下划线,
SnakeCaseIdentifierSchema不允许 ⇒ 存量元数据可能被拒);本卡的绑定动的是WebSocketEventSchema.channel(今天是裸z.string())⇒ 收窄一个从未被约束过的自由文本面,风险与代价都是另一回事。一句方向、两张各自评估半径。⚠️ 若裁 #13612 或本卡走 bind,#13621 的散文更正要跟着改(它现在的任务是「把散文写成今天的真相」;绑定会改变那个真相)。⇒ #13621 应排在两张裁决之后,或明确写成「按裁决后的绑定状态落笔」。本卡与 #13612 的评论里都记了这一条。派单/裁决时手上要有的三个读数(已复核口径,
origin/main @ e2debee6)- 三个绑定站点 ——
EventTypeDefinitionSchema.name(kernel/events/core.zod.ts:94)·EventSchema.name(:122)·EventMessageSchema.eventName(api/websocket.zod.ts:299),三者均无运行期消费者; - 平台实际校验事件名用的是闭合字面量枚举 ——
DataEventType/BulkDataEventType(api/events.zod.ts),且grep -c EventNameSchema packages/spec/src/api/events.zod.ts= 0; - 唯一开放的事件类面
WebSocketEventSchema.channel(api/websocket.zod.ts:468)是裸z.string(),其describe()自己举的合法拼法是"record.account.123"/"user.456"——⚠️ 这两个例子是否满足EventNameSchema的文法,是 bind 路线的第一道判据,裁决前值得实测一次,否则「绑定」可能当场拒掉平台自己文档里的示例。
Refs:#12245(普查)· #4673(同类,
DataEventType已退役成员data.field.changed)· ADR-0049。
Generated by Claude Code
- 三个绑定站点 ——
os-support-ai commented
on Sep 1, 2026 CollaboratorMore actionsClaim:
session_01Mciyv38maJ6HYVMiaM26T1(domain:spec execution seat, dispatch batch 3) · branchclaude/issue-13612-identifier-retirements· family-folded with #13612 per both cards' 2026-09-01 RULED comments (one dispatch, one PR, each member independently verifiable). Route: retire per the ruling —EventNameSchemaand its three bindings out under ADR-0049 enforce-or-remove + ADR-0087 conversion;DataEventType/BulkDataEventTypestand as the only event-name contract; ⛔WebSocketEventSchema.channelstays a deliberatez.string()— the ruling adds no constraint there. Premise re-verified onorigin/main @ c85a2657: exactly three binding sites (core.zod.ts:94,:122,websocket.zod.ts:299), no runtime consumer. Clause-② ⇒ contract-review tier; in-seat review before enqueue. ⛔ #13621 (the prose-correction sibling) is NOT part of this dispatch and proceeds after this lands.
Generated by Claude Code
- added a commit that references this issue
on Sep 1, 2026 os-support-ai commented
on Sep 1, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 13613, "status": "done", "branch": "claude/issue-13612-identifier-retirements", "pr": "https://github.com/objectstack-ai/objectstack/pull/14158", "premise_still_valid": true, "summary": "Retired EventNameSchema and its EventName type per the 2026-09-01 RULED comment (director batch C): removed from shared/identifiers.zod.ts with a retirement note; the three binding fields (EventTypeDefinitionSchema.name and EventSchema.name in kernel/events/core.zod.ts, EventMessageSchema.eventName in api/websocket.zod.ts) stay and widen to plain z.string() with describes pointing at the closed enums; retired-defs row shared/EventName registered under protocol major 18 plus D3 semantic entry event-name-schema-retired; manifest key deleted behind the #4725 gate; Iso499 isomorphism pin left with the schema (836 to 835, ledgered in the pin file per house style). DataEventType / BulkDataEventType byte-for-byte untouched and stand as the only event-name contract; WebSocketEventSchema.channel untouched as a deliberate bare z.string() per the ruling. Premise re-verified on origin/main at c85a2657 and again on the merged tree: exactly three binding sites, zero runtime consumers. #13621 untouched (the Event-keys line in SystemIdentifierSchema's docblock is that card's surface). Family-folded with #13612 in one PR; this card's increment is commit 928a373a plus its share of the changeset.", "files": [ "packages/spec/src/shared/identifiers.zod.ts (EventNameSchema + EventName removed, retirement note added)", "packages/spec/src/kernel/events/core.zod.ts (two name fields to z.string(), retirement note)", "packages/spec/src/api/websocket.zod.ts (eventName to z.string(), retirement note, import dropped)", "packages/spec/src/shared/identifiers.test.ts (EventNameSchema block removed)", "packages/spec/src/kernel/events.test.ts (reject-side grammar fixture repinned to the widening)", "packages/spec/src/type-alias-convention.pin.test.ts (Iso499 pin removed, count 836 to 835, ledger comment added)", "packages/spec/src/migrations/entries/retired-defs/18.shared__EventName.ts (new)", "packages/spec/src/migrations/entries/semantic/18.event-name-schema-retired.ts (new)", "packages/spec/src/migrations/registry.ts + json-schema.manifest/shared.json + api-surface/declaration-map/export-origins + content/docs/references/** + skills/*/references/_index.md (regenerated)", "packages/spec/ZOD_SCHEMA_AUDIT_REPORT.md (hand-maintained line corrected)", ".changeset/identifier-schemas-declared-unenforced-retired.md (shared with #13612)" ], "gates_and_tests": "Full readings on PR #14158 (shared with #13612), all at merged head a46ef310: spec suite 448 files / 12033 tests all passed (the pre-merge lap caught the events.test.ts fixture that pinned the deleted grammar branch - triaged and repinned as an acceptance pin holding the widening); spec typecheck green; dispatch gate list plus derived union all PASS. NOT MEASURED locally, CI-owed by their own printed verdicts: dual-build-cjs-loads, type-check-debt, test-completeness, dev-prereqs. Skills diff is generated refs only: 8 _index.md files, per-file line counts unchanged, SKILL.md bundle sum 10537 to 10537.", "derived_judgments": [ "Replacement shape for the three binding fields: plain z.string() with a describe naming the closed enums as the platform-checked vocabulary - a widening, deliberately NOT a binding to the enums (EventTypeDefinitionSchema declares custom event types; binding would be a new constraint the ruling did not order). Declared per-field in the PR body for contract review", "events.test.ts reject fixture pinned exactly the deleted grammar branch; repinned as an acceptance pin over the previously refused spellings so a silent grammar regression goes red", "EventName had no EventNameParsed sibling and no external type consumers - type removal is TS2305-only", "ZOD_SCHEMA_AUDIT_REPORT.md treated as hand-maintained (last touched by #13895) and its EventNameSchema mention corrected" ], "semver": "@objectstack/spec minor + BREAKING banner (launch-window grade, the ruling's own words); shared changeset carries the adr-0087 marker registering event-name-schema-retired", "open_questions": [], "out_of_scope_findings": [] }
Generated by Claude Code
os-support-ai commented
on Sep 1, 2026 CollaboratorMore actionsCollection review: ACCEPT · Clause-② contract review: PASS
Reviewed PR #14158 at head
881b685f(this card's increment is commit928a373a, independently verifiable per the family rule). Tier fuse read before review:last_served_model = claude-fable-5(= CONTRACT_REVIEW_TIER); in-seat review per the 2026-08-31 ruling.Contract judgment list (this card's increment):
- Derived judgments — verified from hunks.
EventNameSchema+EventNameremoved fromshared/identifiers.zod.tswith a tombstone note;SystemIdentifierSchema/SnakeCaseIdentifierSchema/MetadataItemNameSchemabyte-untouched. The three binding fields (EventTypeDefinitionSchema.name,EventSchema.name,EventMessageSchema.eventName) stay and widen to plainz.string()with describes naming the closed enums — exactly the ruled shape (DataEventType/BulkDataEventTypestand as the only event-name contract; both byte-untouched in the diff).WebSocketEventSchema.channeluntouched (the ruling adds no constraint there). Every previously-valid document stays valid (pure widening, no stored break). The widening is pinned inevents.test.ts: spellings the retired grammar refused now must parse, so a silent regression to a schema-level grammar becomes a deliberate ruling rather than drift — a judgment I endorse.retired-defs/18.shared__EventName.ts+ D3 semantic entryevent-name-schema-retired; the Iso pin ledgered 836→835. - Semver — covered by the family changeset (minor + BREAKING, launch-window grade), with this card's own section, FROM→TO mapping (including the no-action path for stored documents), and its semantic id in the ADR-0087 marker. Consistent.
- Boundary flags — the one declared judgment call (replacement shape at the three fields) confirmed against the ruling's text; no open flags.
Micro-patch audit and the NOT-governed (0/44, #11705-certified twice) landing reading are recorded on #13612's ACCEPT comment — same PR, same head.
PASS ⇒ stripping
needs:contract-review(both carriers) in this same stroke; ordinary queue landing proceeds (ready → auto-merge).
Generated by Claude Code
- Derived judgments — verified from hunks.
- added a commit that references this issue
on Oct 7, 2026
Observed while running the per-surface identifier census for #12245. Filed unassigned as a
finding, not a defect claim.What was observed
EventNameSchema(packages/spec/src/shared/identifiers.zod.ts) is bound by exactlythree schemas, and by nothing else in either repository:
EventTypeDefinitionSchema.namekernel/events/core.zod.ts:94EventSchema.namekernel/events/core.zod.ts:122EventMessageSchema.eventNameapi/websocket.zod.ts:299Reproduced on
origin/mainate2debee6: outsidekernel/events/core.zod.tsandapi/websocket.zod.tsthemselves, every reference to those three names is a generatedbaseline (
api-surface/*.json), the file's own test,type-alias-convention.pin.test.ts,CHANGELOG.md, orV3_MIGRATION_GUIDE.md. No plugin, service, driver, or app parsesthrough any of them.
What the platform actually validates event names with is a closed literal enum that
does not reference
EventNameSchemaat all —packages/spec/src/api/events.zod.ts:grep -c EventNameSchema packages/spec/src/api/events.zod.tsreturns0.The sibling free-text surface is unconstrained rather than schema-guarded:
WebSocketEventSchema.channelis a barez.string()(api/websocket.zod.ts:468) whoseown describe() documents
"record.account.123"and"user.456"as legitimate channelspellings.
Why it may matter
EventNameSchemais presented as the platform's event-name grammar — the docblock onSystemIdentifierSchemalists "Event keys" among the surfaces it governs, andEventNameSchemacarries its own worked examples. In practice it governs nothing thatruns: the real vocabulary is closed and enumerated, and the one open event-ish surface
(
channel) opted out intoz.string().That makes it the ADR-0049 declared-but-unenforced shape, with the usual consequence for
AI-authored metadata: a generator that reads
EventNameSchemaand emits an event namesatisfying it has satisfied nothing the platform will check, while a generator that emits
anything outside the closed enum is refused by a rule the identifier file never mentions.
Two routes, neither obvious and neither recommended here:
channel, and any futurecustom-event registration) run through
EventNameSchema, making the declared grammarthe enforced one.
DataEventType/BulkDataEventTypestand as the only event-name contract. This is a published-exportremoval, so it takes the ADR-0087 conversion.
Recording the measurement only; sizing and the route are a maintainer call.
Related: #12245 (the census that surfaced this) · #4673 (the same class, on
DataEventType's retireddata.field.changedmember) · ADR-0049.