test(lint): loop fixtures 改拼 canonical 的 iteratorVariable 并上 schema pin (#5700) - #6103
Merged
Merged
Conversation
…in (#5700) 三处 pre-existing fixture 用 `itemVar` 绑定循环项,而 `LoopConfigSchema` 是 strictObject、声明键为 `iteratorVariable`,`itemVar` 既非声明键也非 alias,会被 报成 `unrecognized_keys`(#4001)。region 收集只读 `config.body`,所以这些 fixture 照常下潜、断言照常通过 —— 规则本身没问题,但 fixture 描述的是作者写不出来的 `loop`,等于把覆盖面讲得比实际强(#4966 在 trigger 描述符上的同类发现,下沉一层)。 改动: - `loopBodyFlow()` 共享 helper、#5383 嵌套用例、#5482 嵌套用例三处改拼 canonical; - body 节点补上 `FlowNodeSchema` 必需的 `label`(#5695 对自带 fixture 的同样处理); - 把三处 loop config 提成具名常量并各自 pin `LoopConfigSchema` 全绿。 嵌套用例为什么要各自 pin(实测,非推断):`FlowNodeSchema.config` 声明为 `z.record(z.string(), z.unknown())` 开放记录,外层 parse 会整块接受内层容器的 config —— 只 pin 外壳时,内层 `loop` 写 `itemVar` 外壳 pin 依然全绿。该盲区已作为 一条断言写进测试,免得后来者把顶层一条 pin 误当成整棵树的覆盖。 顺带的容器键位审计(本单 durable 半边):文件内 3 处 `parallel` fixture 全部只用 已声明键,0 处 `try_catch` fixture;审计断言按 key 级门槛(`refusedKeys`)落, 沿用 `validate-security-posture.test.ts` 已写下的「拒绝的 KEY 与拒绝的 VALUE 是 两回事」判据 —— 全文件 full-`FlowSchema`-green 是 #5700 明确另案的更大改动。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BDmDsu2575gDxeMCxXhDE3
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckNo hand-written docs reference the 0 changed package(s). ✅ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #5700
test-only,无 changeset(
skip-changeset)。文件面仅packages/lint/src/lint-flow-patterns.test.ts;未动packages/spec,未动packages/lint/src/下任何规则源。前提复核(基于 origin/main@be59695,已含 #5693 → PR #6060)
前提新鲜。三处 fixture 仍以
itemVar绑定循环项:loopBodyFlow()共享 helperLoopConfigSchema(packages/spec/src/automation/control-flow.zod.ts:163)是strictObject,声明键为iteratorVariable;itemVar既非声明键、也不在aliases(那里只登记了itemVariable,用途是压过 edit-distance 建议器,避免把想要 ITEM 的作者指向indexVariable)。实测:region 收集只读
config.body,所以这些 fixture 照常下潜、断言照常通过。规则本身没错,错的是 fixture 描述了一个作者写不出来的loop—— #4966 在 trigger 描述符上的同类发现,下沉一层。:518/:533(#5695 自带的 pin 与 near-miss)本来就正确,不在本单面内,未改动。改了什么
itemVar→iteratorVariable。label(FlowNodeSchema.label是必填,fix(lint):flow-runas-unscoped跨区域搜索它的数据节点证据 (#5633) #5695 对自带 fixture 的同样处理);flow lint rules never descend into aloopbody — the whole family is blind to nested nodes (8 real inert conditions shipped pastflow-inert-node-condition) #5383 嵌套用例的loop_touchpoints节点本身也缺label,一并补上。属于「补声明」而非「重拼」:fixture 本就不是 spec-valid,补齐后它只剩那一处故意埋的缺陷(decision 的惰性config.condition/reset的无 filtermulti: true)。LoopConfigSchema全绿。提成常量是为了让 pin 读到 fixture 真正下潜的那个对象,而不是一份会静默漂移的重抄副本。为什么嵌套用例要各自 pin(实测,不是推断)
FlowNodeSchema.config声明为z.record(z.string(), z.unknown())—— 开放记录。所以外层 parse 会整块接受内层容器的 config:这条盲区已经作为一条断言写进测试(
does NOT see into a nested container's config — the inner pins are load-bearing),免得后来者把顶层一条 pin 误当成整棵树的覆盖。门槛的选择:full green 还是 key 级
parallel@630:fixture 本身可做到完全可 authoring,用 fullsafeParsegreen —— 沿用 fix(lint):flow-runas-unscoped跨区域搜索它的数据节点证据 (#5633) #5695 写下的理由(这些规则判的是 VALUE 结论,证据节点必须真的可达于一个真的可写的容器内)。parallel:分支节点缺label,那是 Three pre-existing flow-lint fixtures bind the loop item withitemVar, a keyLoopConfigSchemarejects — the nested-region tests describe aloopno author can write #5700 正文明确另案的全文件约定。这里用 key 级门槛refusedKeys(...),判据沿用本仓validate-security-posture.test.ts:501-513已写下的那条:被拒的 KEY 与被拒的 VALUE 是两回事。对 key 级规则强行要求 full-parse-green 会删掉正当覆盖;反过来对 value 级规则只要unrecognized_keys干净则会养出幻检查。容器键位审计(本单 durable 半边)
按容器 slot 全表清点(
FLOW_REGION_SLOTS:loop.body/parallel.branches/try_catch.try/try_catch.catch):looploopConfig()@510 与两层嵌套 @622/627 早已 canonical 且实测全绿,未动paralleltry_catchparallel三处的name/nodes/edges,以及twin_regions分支边上的condition/isDefault,实测全部是已声明键。审计断言有牙:往一个分支塞
bogusKey: 1,断言按名报红 —— 详见下方回归验证第 4 段。全量测试
pnpm --filter @objectstack/lint test:基线(改动前,同一 worktree)为 1453 passed / 4 skipped;+4 恰为本 PR 新增的 4 条
it。回归验证(方向先声明,后运行)
预先声明的三条预期:(1) 还原 site 1 → 外壳 pin 报红;(2) 还原 site 2 → 只有它自己的内层 pin 报红,外壳 pin 保持绿(这才证明内层 pin 是承重的,而非冗余);(3) 还原 site 3 → 同理。三条全部命中。
1. 还原 site 1(
loopLeadsConfig改回itemVar)2. 还原 site 2(#5383 嵌套)
只红了内层那一条,外壳 pin 仍然绿 —— 与上面
FlowNodeSchema.config是开放记录的实测一致。3. 还原 site 3(#5482 嵌套)
4. 审计断言有牙(往
twin_regions分支塞未声明键)四处均已还原,末次全量为上面的 61 files / 1457 passed。
其余门禁
pnpm --filter @objectstack/lint typechecktsc --noEmit无输出)npx eslint packages/lint/src/lint-flow-patterns.test.tsnode scripts/check-nul-bytes.mjsOK (scanned 5839 tracked text file(s); ... no raw ASCII control bytes)grep -naP '[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]'不在本单范围
FlowSchema-green(每个 flow、每个节点补label):Three pre-existing flow-lint fixtures bind the loop item withitemVar, a keyLoopConfigSchemarejects — the nested-region tests describe aloopno author can write #5700 正文明确另案,未做。packages/spec未动;packages/lint/src/下任何规则源未动。Generated by Claude Code