观察类发现,来自 #6098 收尾时对四个同族 walker 的逐格对照。今天两格都被 fail-closed 兜住(解不出 shape 时 reachableVia 返回 'root-graph',宁可多要一个 tombstone),没有已知错误产物。记录在案,免得下一轮把「补齐了吗」当成已答之问。
#6098 补掉的是 union 分支与 prefault,这两格补完之后 zodShapeOf 与三个同族 walker 的包装器集合、lazy、pipe 方向、union 键面已经一致。剩下的不一致有两处,都不是 #6098 的范围。
格 1 —— 不下探 array element / record valueType
| walker |
array → element |
record → valueType |
scripts/lib/zod-graph.ts zodShapeOf |
❌ |
❌ |
scripts/liveness/check-liveness.mts unwrap |
❌ |
❌ |
src/kernel/metadata-authoring-lint.ts unwrap |
❌ |
❌ |
src/system/metadata-form-zod-reconciliation.test.ts unwrap |
✅ d.element |
✅ d.valueType |
所以这一格三比一,而且是唯一一个下探的那位跟另外三个不同——不能直接说「zodShapeOf 窄」。真正要先答的是语义问题:对 z.array(SomeObject) 这样的节点,「作者在这个节点上写的 shape」到底是不是元素的 shape?
现存标本:data/FilterArray(一个 lazy → array 的 emitted def,visited=false)今天 zodShapeOf 解不出 shape,落在 fail-closed 兜底上答 root-graph。#6098 实测的 1610 个 def 里只有它一个属于这一类。
格 2 —— depth 上限 12,是四个里最窄的
scripts/lib/zod-graph.ts 12 (zodShapeOf 与 pipeInIsTransform 各一处)
scripts/liveness/check-liveness.mts 16
src/kernel/metadata-authoring-lint.ts 25
src/system/metadata-form-zod-reconciliation.test.ts 25
#6098 之后这一格的重要性上升了一点:union 分支是逐成员递归的(mergedUnionShape 对每个成员 depth + 1),嵌套 union 会比以前更快吃掉预算。今天没有截断——view 这条最深的链在 depth ≤ 3 就解完了——但「最窄的那个上限」正好落在喂删除门禁的这个 walker 上,方向不理想。
超限的后果同样是 return null → fail-closed,所以是保守而非错答。
#6098 的正文只点名了两格(union、prefault),这两格已随 PR #6222 合入并完成 #5056 测量轮。本条是那一轮收尾对照时发现的剩余项,单独记录而不是塞进那个 PR——因为格 1 会动桥表,必须有自己的测量轮。
建议
参考:#6098 · PR #6222 · #5317 · #5056 · #6221
观察类发现,来自 #6098 收尾时对四个同族 walker 的逐格对照。今天两格都被 fail-closed 兜住(解不出 shape 时
reachableVia返回'root-graph',宁可多要一个 tombstone),没有已知错误产物。记录在案,免得下一轮把「补齐了吗」当成已答之问。#6098 补掉的是 union 分支与
prefault,这两格补完之后zodShapeOf与三个同族 walker 的包装器集合、lazy、pipe 方向、union 键面已经一致。剩下的不一致有两处,都不是 #6098 的范围。格 1 —— 不下探
arrayelement /recordvalueTypearray→elementrecord→valueTypescripts/lib/zod-graph.tszodShapeOfscripts/liveness/check-liveness.mtsunwrapsrc/kernel/metadata-authoring-lint.tsunwrapsrc/system/metadata-form-zod-reconciliation.test.tsunwrapd.elementd.valueType所以这一格三比一,而且是唯一一个下探的那位跟另外三个不同——不能直接说「zodShapeOf 窄」。真正要先答的是语义问题:对
z.array(SomeObject)这样的节点,「作者在这个节点上写的 shape」到底是不是元素的 shape?keysOf的问题(「这条路径下声明了哪些键」)答案显然是「是」;.describe()共享 def 对象,任意单属性 bridge 把无关形状连起来 #5056 明确要求单独测量的那类改动。现存标本:
data/FilterArray(一个lazy→array的 emitted def,visited=false)今天zodShapeOf解不出 shape,落在 fail-closed 兜底上答root-graph。#6098 实测的 1610 个 def 里只有它一个属于这一类。格 2 —— depth 上限 12,是四个里最窄的
#6098 之后这一格的重要性上升了一点:union 分支是逐成员递归的(
mergedUnionShape对每个成员depth + 1),嵌套 union 会比以前更快吃掉预算。今天没有截断——view这条最深的链在 depth ≤ 3 就解完了——但「最窄的那个上限」正好落在喂删除门禁的这个 walker 上,方向不理想。超限的后果同样是
return null→ fail-closed,所以是保守而非错答。与 #6098 的关系
#6098 的正文只点名了两格(union、
prefault),这两格已随 PR #6222 合入并完成 #5056 测量轮。本条是那一轮收尾对照时发现的剩余项,单独记录而不是塞进那个 PR——因为格 1 会动桥表,必须有自己的测量轮。建议
gen:schema前后 diff 才算数(理论上零移动,实测才能这么说)。.describe()共享 def 对象,任意单属性 bridge 把无关形状连起来 #5056 的完整测量协议(逐条解释新增桥项 + 逐条解释判定移动,两个方向都要看——fix(spec): zodShapeOf 补齐 union 分支与prefault,并附 #5056 测量轮 (#6098) #6222 实测到的主要移动方向是root-graph → null这个放宽方向,不是root-graph → derived-clone)。参考:#6098 · PR #6222 · #5317 · #5056 · #6221