Repository navigation
Design: should FlowNodeSchema parse its ADR-0031 regions, instead of a post-parse pass callers must remember to run? #4415
Description
Activity
裁决(PM 代决,维护者可否决):「先量再改」,倾向方向 1 ——
第一步派测量任务:量清
FlowNodeSchema加.transform()(ZodObject→ZodPipe)后对z.toJSONSchema、form 生成、lazy-schema seen 表的实际影响(ADR-0089 D3a 有前科,.strict().transformpipe 曾打崩 toJSONSchema)。- 测量结论「可解」→ 落方向 1:schema 自解析 region,符合 Zod-First(PD Add metamodel interfaces for ObjectQL/ObjectUI contract #1),一次覆盖所有消费方,消灭「调用方必须记得跑后置 pass」的不成文规则(applyConversionsToFlow does not recurse into loop bodies — conditions inside a
loopare never converted to CEL and the gate silently never opens #4347 族缺陷的温床——AI 新增消费方时必漏)。 - 测量结论「不可解」→ 方向 2 + 3 组合:
FlowSchema层 transform +collectFlowGraphs/runRegion未归一化 warn 护栏。
注意:近期有 region-slots changeset 活动,测量以最新 main 为准;与 #4336(node config 上类型)大概率是同一机制两次应用,执行时互相知会。已入队待派(首派 = 测量)。
Generated by Claude Code
- 测量结论「可解」→ 落方向 1:schema 自解析 region,符合 Zod-First(PD Add metamodel interfaces for ObjectQL/ObjectUI contract #1),一次覆盖所有消费方,消灭「调用方必须记得跑后置 pass」的不成文规则(applyConversionsToFlow does not recurse into loop bodies — conditions inside a
分诊级别建议:本单是「Design: should…」形设计卡(FlowNodeSchema 是否内建解析 ADR-0031 regions),属公开契约形状取向,派发前需要维护者拍板——建议摘
pm:queue换needs-user-decision进决策箱。交分诊座位定夺。背景:维护者 2026-08-06 拍板 spec 车道缩盘方案,见 #5837。
Generated by Claude Code
标签落实(维护者 2026-08-06 指示,session_01LeEfA7CFwbJb7JJmXm2KM3):按 08-06 降级建议执行
pm:queue→needs-user-decision——「Design: should…」形设计卡(FlowNodeSchema 是否内建解析 ADR-0031 regions),进决策箱等拍板。
Generated by Claude Code
Maintainer ruling recorded (2026-08-07, in chat — 「按建议」 approving the premise-gated plan from the release-board audit):
Proceed measurement-first, one dispatch, two pre-ruled branches:
- Premise to verify BEFORE any implementation: the ZodPipe shape produced by
.transform()on the self-recursive FlowNodeSchema can be digested by the existing generators — the toJSONSchema walker and the lazy-schema path, i.e. exactly the shape that crashed before (ADR-0089 D3a). Verify by measurement (a minimal spike against the real generators), not by reading. - Premise holds → implement direction 1: FlowNodeSchema parses its ADR-0031 regions itself; the post-parse pass retires.
- Premise falsified → ⛔ do not force it; implement directions 2+3 (FlowSchema-level transform + warn guardrails) and record the measurement evidence in the PR.
Neither branch returns to the maintainer — both are pre-ruled. Dispatching now.
Generated by Claude Code
- Premise to verify BEFORE any implementation: the ZodPipe shape produced by
Claim: PM session (maintainer-directed dispatch, 2026-08-07 「按建议」 — premise-gated plan recorded in the ruling comment above)
Session:session_01BickTBKm2JYSNnrtPT8ysa
Branch:claude/issue-4415-flownode-regions-parse
Worktree:objectstack-issue-4415
Domain:domain:spec(maintainer-directed from chat; spec seat may sequence/veto — no collision intended with in-flight spec work)
File surface:packages/spec/src/**flow schema modules (flow.zod.tsfamily) + the ADR-0031 regions post-parse pass module + spec generators ONLY if the premise measurement requires adapting them; spec build regenerates its own baselines (os-regen discipline applies)
Container judgment: M (spec build + test verification) →mode:subagent, shared container
Serial constraints cleared: no open PR touches the flow schema family per the open-PR list; duplicate-claim CI gate backstops. Measurement-first per the ruling — premise falsified ⇒ branch 2+3, never forced.
Generated by Claude Code
Review: ACCEPT → PR #6333, flipped ready, auto-merge enabled. (PM session
claude/rc4-release-tasks-analysis-2d8euw)Verified independently, not from the dev report alone:
- Premise gate honored — the PR body documents the measurement-first spike against the real generators (toJSONSchema walker under
OS_EAGER_SCHEMAS=1, form-generation gates, lazy-schema seen-table viagen:openapi+ reused-Proxy probe) before implementation, exactly as the 2026-08-07 ruling required. Premise held → direction 1 landed; the post-parse pass retires with its call site. - Changeset level checked by hand (the one thing CI can't judge):
@objectstack/spec: minor+@objectstack/service-automation: patch— correct for the v17 train; does not derail the version PR to 18.0.0-rc.0. Migration section covers both thenormalizeControlFlowRegionsremoval and the ZodObject→ZodPipe shape change (.def.inguidance). - CI converged, read from check runs: 24/24 complete, 23 success + 1 skipped (Console Pin Gate — normal when
.objectui-shauntouched). Zero red; Check Changeset genuinely green (real changeset ships, no skip label). - Reverse verification ran in the honest direction: both reverts predicted RED before running, both confirmed, including the wholesale replacement of the one assertion that pinned the old defect by design.
Out-of-scope finding correctly filed unassigned as #6267 (pre-existing TDZ, reproduced on pristine main).
Note for the spec-surface lane: once this merges, #6094 unblocks (it was premise-gated on this landing).
Generated by Claude Code
- Premise gate honored — the PR body documents the measurement-first spike against the real generators (toJSONSchema walker under
- added a commit that references this issue
on Oct 7, 2026
设计讨论,不是 bug —— 现状能工作,问的是它能不能不依赖调用方的记性。接 #4347 / #4381 / #4399 / #4401。
现状
FlowSchema.parse归一化 flow 自己的nodes[]/edges[],但够不到 region,因为 region 住在FlowNodeSchema.config里 —— 一个刻意开放的z.record。#4381 用一道后置 pass 补上:问题
「parse 完拿到的就该是规范形状」是 Zod-First(PD #1)的默认预期。现在多了一条不成文规则:拿到
FlowParsed之后还得再调一个函数,否则嵌套 region 里的边条件还是裸字符串、节点还没过.strict()。今天只有一个消费方(
registerFlow),所以没出事。但这正是 #4347 那一族缺陷的生成条件 —— 一个新消费方(Studio 发布路径、未来的 MCP 工具、某个批量校验脚本)拿到FlowParsed就直接用,就又是一次「看起来解析过了、其实只解析了一半」。为什么 #4381 当时没做
评估过、刻意没做,理由是 blast radius:
FlowNodeSchema挂.transform()会把它从ZodObject变成ZodPipe,而它被 form 生成、z.toJSONSchema、以及FlowRegionSchema/ParallelBranchSchema反过来引用;lazy-schema.ts的注释里已经记着.strict().transform(…)pipe 曾经把toJSONSchema的seen表打崩过(ADR-0089 D3a 时FormFieldSchema/PageComponentSchema踩过),现在靠一个_zodfacade 兜着;FlowNodeSchema→FlowRegionSchema→FlowNodeSchema),transform 里再套一层解析要小心构造期递归。把这些混进一个 bugfix PR 里,会让那个 PR 的风险说不清 —— 所以当时选了后置 pass,并在函数注释里写明了这笔债。
可选方向(未定)
FlowNodeSchema自解析 region。 最符合 PD Add metamodel interfaces for ObjectQL/ObjectUI contract #1,一次解决所有消费方。代价见上,需要先确认toJSONSchema/ form 生成不受影响。FlowSchema层挂 transform。 比 1 影响面小(FlowNodeSchema保持ZodObject),但嵌套递归得自己写,且绕过FlowSchema直接FlowNodeSchema.parse的调用方仍然漏。collectFlowGraphs/runRegion在遇到未归一化的 region 时 warn,把「忘了调」变成有声音的。成本最低,但没有消除那条不成文规则。倾向 1,前提是先量清楚
toJSONSchema的影响 —— 不该在没有这个数之前动手,这和 #4389 「先量再改」是同一个道理。相关
#4336 的建议修复 #3(「给 node config 上类型」)是邻近但不同的一件事:那条针对表达式归一化够不到
config.condition,这条针对 region 子结构。两者如果都做,大概率是同一个机制的两次应用。