Repository navigation
观察:@objectstack/spec 每个 entry 各打一份 schema 实例 —— 跨 entry 的 === 恒为 false,registerMetadataTypeSchema 的可见范围也被这条边界圈死 #5379
Description
Activity
分诊(cli 车道 PM,
session_016FNvXhtSdnEGEfLEsMmvxh,2026-08-05):持有(留finding)。为什么还留着:观察成立且有复现命令,但今日无用户可达故障;改动面(entry 拆分 / chunk 共享 /external策略)属packages/spec打包契约,是 spec 单一所有者面 —— 若晋级应按跨车道协议转 spec 车道,而非本车道派发。下轮分诊轮复核。
Generated by Claude Code
发现分诊轮:持有(留
finding)+ 补域domain:spec(前一轮判级由 cli 车道 PM 做出时未打域标签,本轮补齐 ——domain:*单一生产者是分诊座位)。- 域锚定:改动面是
packages/spec/package.json的 16 个 entry 与 tsup 打包策略(entry 拆分 / chunk 共享 /external)—— spec 打包契约,按「shared contract surfaces have one owner」归domain:spec座位。前一轮 cli 车道 PM 的判断(「若晋级应转 spec 车道」)本轮以标签兑现,不再靠读评论流。 - 为什么还留着(维持前一轮判级,理由未变):观察成立且有复现命令,但今日无用户可达故障。
registerMetadataTypeSchema()的可见范围今天安全,是因为注册表读写 API 只从./kernel导出、消费者拿的是同一份 —— 正文诚实地把这一点写成「巧合而非保证」,PM 同意该定性。 - 重启条件:① 任一 entry 再导出会读注册表的 helper(那一刻「看得见声明、读不到注册」立即变成可达故障);② 或 spec 打包契约因别的裁决被整体重开(entry 收敛 / chunk 共享),届时并入。
- 附带价值(已实现,无需动作):本条最大的即时收益是让「跨 entry
===」这类断言不再被重新推一遍 ——objectstack build/validate从不按 PageSchema 解析页面元数据:ADR-0089 D3a 早就该拒绝的键一路通过,#4001 的「三个示例应用 validate 全过」对 page 面是空证 #5000 的 PR 已把原因写进测试注释,后来者读到即止损。 - 查重:三仓比对,来源
objectstack build/validate从不按 PageSchema 解析页面元数据:ADR-0089 D3a 早就该拒绝的键一路通过,#4001 的「三个示例应用 validate 全过」对 page 面是空证 #5000 已收官;analyze-bundle-size.ts侧的体积重复观察无独立单。不重复。
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
- 域锚定:改动面是
Findings triage — verdict: HOLD stands (keeps
finding,domain:spec). Restart condition machine-checked this round rather than assumed.Restart condition ① re-measured on
origin/main@1363084— has not firedThe condition: any entry re-exports a helper that reads the metadata-type registry — at which moment "declaration visible, registration unreadable" turns from a coincidence into a live, very hard-to-diagnose failure.
Measured:
getMetadataTypeSchema/registerMetadataTypeSchema/EXTRA_METADATA_TYPE_SCHEMASare exported from exactly one place,packages/spec/src/kernel/index.ts:34(export * from './metadata-type-schemas'). Every other reference in the package is either insidekernel/itself or a test importing it by relative path (data/object-strictness-batch20.test.tsreaches into../kernel/metadata-type-schemas) — tests run from source, so they are not a bundle boundary. No second entry among the 16 inpackage.jsonexportsre-exports the registry API. ⇒ All registry consumers still share one instance; the safety remains real, and remains a coincidence rather than a guarantee, exactly as the body says.Why still held, not promoted: unchanged — no user-reachable failure today, and the fix surface (entry splitting / chunk sharing /
externalstrategy) is the spec packaging contract, not something to change opportunistically. Under "shared contract surfaces have one owner" that surface belongs to thedomain:specseat, which the label already reflects.Restart conditions (unchanged):
- any entry re-exports a registry-reading helper ⇒ promote immediately;
- the spec packaging contract is reopened for another reason (entry consolidation, chunk sharing) ⇒ fold this in.
Already-banked value, needing no action: the durable payoff here is that cross-entry
===is documented as non-assertable, with the reason written intopackages/cli/test/metadata-type-schema-gate.test.tsby #5000's PR. The next person writing an identity assertion reads it and stops, instead of watching it go red and suspecting their own change.Dedup: source #5000 is closed; the bundle-size duplication noted in the body has no separate issue and does not need one. No shadow in the sibling repos.
本评论来自分诊座位 Routine(#5474 试点),不构成认领。
Generated by Claude Code
os-project-manager commented
on Aug 8, 2026 CollaboratorMore actionsFindings sweep (maintainer-authorized one-off, 2026-08-07 — registered on #6015): closing, not planned. Documented build characteristic (per-entry schema instances); no consumer relies on cross-entry
===identity, and the record stays searchable here. Reopen freely if a real consumer hits it — maintainer veto window applies.
Generated by Claude Code
从 #5000 的核实工作里撞到的(写 CLI 侧 pin 测试时)。观察类:今天没有用户能碰到的故障,但它让一类看起来天经地义的断言/推理不成立,值得记下来。
事实
packages/spec的package.json声明了 16 个 entry(././kernel/./ui/ …),tsup 按 entry 分别打包,同一个 schema 在不同 entry 的产物里是不同的对象:源码里它们是同一个模块绑定(
stack.zod.ts与metadata-type-schemas.ts都 importui/page.zod.ts的PageSchema),只有从 src 直接跑(tsx / vitest 走源码)时===才成立;跨包消费的是 dist,就是各自一份。为什么记下来
它把「同一道门」这件事变成不可断言。
objectstack build/validate从不按 PageSchema 解析页面元数据:ADR-0089 D3a 早就该拒绝的键一路通过,#4001 的「三个示例应用 validate 全过」对 page 面是空证 #5000 问的正是「CLI 走的 schema 是不是写路径那一个」。最自然的证明是实例同一性;跨 entry 它恒为 false,所以只能退回到行为等价(同一个未声明键、两边同样拒绝)。我在 PR 里就是这么写的,并把原因写进了测试注释 —— 否则下一个人会先写一遍 identity 断言、看着它红、再怀疑是自己的改动。registerMetadataTypeSchema()的可见范围被这条边界圈死。 运行时 overlay 存在 kernel bundle 里的EXTRA_METADATA_TYPE_SCHEMAS。今天没事,因为注册表的读写 API 只从./kernel导出,所有消费者拿的是同一份;但这是个巧合而不是保证 —— 哪天某个 entry 再导出一个内部会读注册表的 helper,插件注册的类型对它就是不存在的,而且这种「看得见声明、读不到注册」的失败非常难查。顺带的:同一份 zod schema 在多个 entry 里各存一份,内存/体积上是重复的(
analyze-bundle-size.ts应该能量到)。不建议顺手改
改动面(entry 拆分 / chunk 共享 /
external策略)属于 spec 打包契约,不是随手能定的;记在这里让后来者不必重新推一遍即可。相关
objectstack build/validate从不按 PageSchema 解析页面元数据:ADR-0089 D3a 早就该拒绝的键一路通过,#4001 的「三个示例应用 validate 全过」对 page 面是空证 #5000(核实过程中发现;PR 里的packages/cli/test/metadata-type-schema-gate.test.ts注释记了这条约束)packages/spec/package.json的exports、packages/spec/scripts/analyze-bundle-size.ts