Repository navigation
全仓唯一一条 PageNodeSchema['type'] === 'page' 的钉扎,住在一个已不引用它的包里 #3227
Description
Activity
xuyushun441-sys commented
on Aug 3, 2026 ContributorMore actions认领:PM 循环第 1 轮
会话:session_01NVPjPzmmAJ2Ngtvgg5MSRa(objectui 分片 PM,账号xuyushun441-sys,已在 objectstack#4604 登记)
分支:claude/issue-3227-move-pagenode-pin
Worktree:objectui-issue-3227复核记录:前提成立,且「唯一性」实测属实
origin/main@ca58e45:- 断言仍在
packages/layout/src/__tests__/spec-symbol-batch7.test.ts:97(type _NodeIsATaggedNode = Assert<Equal<PageNodeSchema['type'], 'page'>>); packages/layout对PageNodeSchema的引用只剩这个测试文件本身(第 31/49/89/95/97 行)加一条CHANGELOG.md历史记录 —— 即原单说的「住在一个已不引用它的包里」成立,没有被后续提交推翻;- 同文件第 95 行还有一条
_DocumentIsNotNode(钉SpecPage ≠ PageNodeSchema),它与被搬的这条是同一件事的两面,搬迁时要一起考虑,不要只搬一条把另一条留在原地。
归属裁定(PM,可否决)
原单倾向
packages/types,给了两个候选。按packages/types,理由是原单那条即成立:这钉的是类型契约,而packages/types正是 re-export spec 类型的那一层;放到@object-ui/components的PageRenderer注册点旁边会让「类型契约」与「某渲染器行为」两件事混住,下一个读者仍要猜它为什么在那儿。⛔ 硬约束(原单已写明,派发时再钉一次):不得在搬迁中放宽或删除这条断言。搬完必须 sabotage 验证 —— 故意把 spec 侧判别式改错,确认新住处的断言真的红;贴输出。
Generated by Claude Code
- 断言仍在
xuyushun441-sys commented
on Aug 3, 2026 ContributorMore actions派发失败记录(第 1 轮)—— 认领保留,零代码产出
派给本单的开发 agent 在动任何文件之前就被掐断,原因是账号级会话配额:
Agent terminated early due to an API error: You've hit your session limit · resets 10:30am (UTC)它最后的动作是「开始读 AGENTS.md」,此后没有任何写操作。
当前真实状态(请以此为准,不要按「已派发」理解)
项 状态 分支 claude/issue-3227-move-pagenode-pin❌ 不存在(远端已核) Worktree / 提交 / PR ❌ 无 代码改动 ❌ 零 认领 ✅ 保留( session_01NVPjPzmmAJ2Ngtvgg5MSRa)pm:dispatched标签保留的含义是「本轮已派过且失败」,不是「有活在飞」。为什么保留认领而不是退回队列
SKILL.md 的僵尸认领回收条件是「认领超 ~24h 且分支不存在、无 PR」。本条才几分钟,且失败原因与本单内容完全无关(配额,不是任务有问题)。退回队列只会让下一个扫描者重做我已经做完的复核 —— 上面那条前提复核(断言仍在
layout第 97 行、该包已不引用PageNodeSchema、同文件第 95 行还有一条_DocumentIsNotNode需一并考虑)仍然有效,重派时直接用。重派条件
配额 10:30 UTC 恢复后重派,派发内容不变(目的地
packages/types;⛔ 不得放宽或删除断言;必须 sabotage 验证,并先确认目的地包真的对测试文件做类型检查 —— 参见 objectstack#4642 记录的「编译期 pin 空转」形态)。若在此之前有其它会话想接手:请先在本单评论声明,我立即让行并撤掉认领。
Generated by Claude Code
xuyushun441-sys commented
on Aug 3, 2026 ContributorMore actionsPM 验收:ACCEPT — PR #3246,已入合并队列(等剩余检查转绿自动落地)
重派后一次成功。按 GitHub 实况核对:
项 结果 PR targets main、Fixes objectstack-ai/objectui#3227✅ 改动范围 ✅ 3 个文件(+122/−24),全部在 packages/layout+packages/types内content/docs/releases/零改动✅ CI 已完成的全绿、零失败; Type Check/Lint/ 4 个 test shard /Bundle Analysis仍在跑,已开 auto-merge 由队列在全绿后落地三处做得比我要求的更到位
1. 四条 pin 一起搬,而不是只搬点名的那条。 我在派发里提醒了同文件第 95 行的
_DocumentIsNotNode是同一契约的另一面;它不仅搬了这两条,还识别出_PageIsReal是承重的——Equal<any, X>恒为false、keyof anyadmits 一切,所以一个any的SpecPage会让两条主 pin 同时空转通过而什么都没检查。这条不搬过去,新住处的 pin 就是纸糊的。这是我没写进派发要求的。2. 回答了原单那句「若发现别处已有等价覆盖,核实后再决定」。 结论是没有等价覆盖,而且论证方式对:
p1-spec-alignment.test.ts里三处const page: PageNodeSchema = { type: 'page', … }是可赋值性检查,只能证明'page'被接受;把判别式放宽成'page' | 'page-node'之后它们全都还是绿的,只有Equal<>会红。所以Equal绝不能软化成Extends—— 这一点被写进了新文件的文件头。3. 先证明目的地不空转,再搬。 这正是我引 objectstack#4642 时担心的:
packages/types的tsconfig.json排除测试文件(它们不能进dist),但tsconfig.test.json又把它们收回来,并且type-check脚本是tsc --noEmit && tsc -p tsconfig.examples.json && tsc -p tsconfig.test.json,CI 跑pnpm type-check。链路完整,pin 是真的。这条依赖关系也写进了文件头:「若本包哪天不再跑tsc -p tsconfig.test.json,下面这些就静默变成注释」。sabotage 验证是决定性的
把判别式放宽成
'page' | 'page-node'之后:src/__tests__/page-node-type-contract.test.ts(95,38): error TS2344: Type 'false' does not satisfy the constraint 'true'.全包只有这一条错误,就是被搬的那条 pin。 比改成
'page-node'那次(会连带p1-spec-alignment报 3 条 TS2322)更能说明问题:放宽才是实践中真正会发生的漂移(生产者仍可合法发出注册表没有条目的键),而那种情况下只有这条 pin 拦得住。两处收尾也对
packages/layout那份文件头改写成了对剩下内容成立的描述(batch 7 唯一幸存的PageHeaderProps → PageHeaderComponentProps),并留了指向新住处的指针和一句 「不要在这里加回来,去那边扩展」;- 在
PageNodeSchema声明本身加了Tripwire:反向引用(沿用同文件PageNodeRegion已有的写法),让守卫从被守的类型出发就能找到 —— 这正好治了原单说的病:下一个人看到守卫时能知道它为什么在。
新文件从 barrel(
../index)导入而非../layout,理由写明了:barrel 才是@object-ui/components等消费者看见的表面。changeset:同意不加
两个测试文件 + 一处纯文档注释改动(
PageNodeSchema的结构一字未动),dist对消费者逐字节相同。Changeset Fixed Group Check判绿,与该判断一致。
Generated by Claude Code
xuyushun441-sys commented
on Aug 3, 2026 ContributorMore actions更正一条我引用的证据(结论不变)
我在上面的验收里写过:
changeset:同意不加。……
Changeset Fixed Group Check判绿,与该判断一致。这条引用应当撤回,与 #3207 上那条同因:#3212(PR #3253)查明
changeset-check跑的是scripts/check-changeset-fixed.mjs,校验的是 changesetfixed组的成员资格,不检查 PR 有没有加 changeset —— 加不加都会绿,因此它对"该不该加"零信息量。不加 changeset 的真实依据不受影响:本 PR 是两个测试文件加一处纯文档注释改动(
PageNodeSchema结构一字未动),消费者编译依赖的dist逐字节相同。
Generated by Claude Code
在 objectui#3223(删除
@object-ui/layout的死渲染器PageNodeRenderer)验收时记下的后续,不在该 PR 处理(超出那单的packages/layout/范围)。现状
packages/layout/src/__tests__/spec-symbol-batch7.test.ts里有一条编译期断言,钉住 spec 的页面节点判别式:它是全仓唯一一条钉这件事的断言,而它守的那个键正是
@object-ui/components的PageRenderer注册的键。#3223 删掉PageNodeRenderer时刻意保留了它:被删的是组件,活下来的是 wire 契约。问题
保留是对的,但它现在的住处不对:
@object-ui/layout已经完全不引用PageNodeSchema了。于是这条断言处在一个尴尬位置——spec-symbol-batch7(一次已完成的改名批次)的测试文件里,文件名说的是历史,不是它现在的职责;packages/layout测试的人,看到一个不引用PageNodeSchema的包里有一条关于PageNodeSchema的断言,合理的反应是"这是上一轮重构的残留",然后删掉——全仓对这个 wire 判别式的唯一保护就没了,且没有任何东西会报红。这就是"守卫本身没有守卫"的形态:一条覆盖不会被测试发现其消失。
建议
搬到
packages/types(它 re-export spec 的类型,是这条断言的自然归属),或搬到@object-ui/components里PageRenderer注册点旁边(它是这个键的实际拥有者)。两处都比现在合理;倾向packages/types,因为这条钉的是类型契约而非某个渲染器的行为。搬迁时把注释写清楚它钉的是什么、为什么不能删——现在
packages/layout那份注释已经被 #3223 改写过一轮("重命名的对象已被删除,活下来的是分层拆分本身"),搬过去要再改一次,让它对新住处成立。不要在搬迁中顺手放宽或删除这条断言。 若发现别处已有等价覆盖(我查的时候没有),核实后再决定是否合并两处。
关联:objectui#3223、objectui#3161 / objectstack#4115 batch 7。