Repository navigation
fix(lint): a flow node config-value finding carries the slot's key path, so Studio's Problems row selects the node - #28192
Conversation
…value finding (WIP) Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibxhpYpVUxgK5jbQMXT
validateStackExpressions located a finding on a top-level flow node's config value by its where prose alone, so a draft's _diagnostics path was prose and Studio's Problems row could not select the node. Each node arm now records the key it judged, and the node's findings carry flows[F].nodes[N].<block>.<path>, the edge shape. Nested-region nodes and map-form flows keep where alone, as edges do. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibxhpYpVUxgK5jbQMXT
…er scan Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L9qibxhpYpVUxgK5jbQMXT
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 1 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 4 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 58fbdb7297f9c1179016c6e7048409d7685242cb && git checkout 58fbdb7297f9c1179016c6e7048409d7685242cb
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin c48cd2c103a9dfa99313a67a3ec622291d793900 6360f96ec8ba5d6348886a9eb609b71403e17fad && git checkout -B drift-repro c48cd2c103a9dfa99313a67a3ec622291d793900 && git merge --no-ff 6360f96ec8ba5d6348886a9eb609b71403e17fad
node scripts/docs-audit/affected-docs.mjs --json c48cd2c103a9dfa99313a67a3ec622291d793900
|
|
domain:spec#1 · os-tesla · session_01L9qibwb6hBqszPTYJobitm 维护者速读
席位核对 · ACCEPT ·
|
Requested by Tesla · project thread
Fixes #27828
Clause-②: no
Metadata-protocol: none
维护者速读
flows[0].nodes[1].config.fields.status,草稿诊断里读作nodes.1.config.fields.status)。path字段,拒收与否、提示文字都不变;CLI 的rule: … at …一行会改印键路径(连线自 Studio: an expression field that says "Valid CEL" should read the draft's server verdict at its own path (RLS predicate, flow edge condition) #26858 起已是如此)。回滚即 revert 本 PR。packages/lint/src/validate-expressions.ts节点遍历末尾的路径标记段,packages/lint/src/validate-expressions.node-config-path.test.ts,packages/metadata-protocol/src/protocol.draft-publish-verdict.test.ts新增的[#27828]用例。pnpm --filter @objectstack/lint exec vitest run src/validate-expressions.node-config-path.test.ts,预期 7 条全过,其中 “every node-config arm locates its finding at the slot it judged” 覆盖六类节点发现。What changes
packages/lint/src/validate-expressions.ts, the flow node walk inrunStackExpressionPasses). Each node site that pushes a finding now also records, in a per-nodewhere→ key map, the key it judged:config.condition,config.KEY(the spec's node-config judge),BLOCK.SLOT_PATHfor a ledger slot and a value-template refusal (so aconnector_actioninput from automation: registration does not judge aconnector_actionnode'sconnectorConfig.inputvalue slot, because the spec expression ledger cannot address a sibling block ofconfig#27968 readsconnectorConfig.input.KEY),config.TEXT_SLOT, and for ascriptnode's callable checkconfig.function(or the first retired dispatch key the node still carries). At the end of the node's walk, every finding that node produced getspath: flows[F].nodes[N].KEY, the Studio: an expression field that says "Valid CEL" should read the draft's server verdict at its own path (RLS predicate, flow edge condition) #26858 edge spelling.Nindexes the authoredflow.nodeslist (anullmember before the node does not renumber it). A node inside a nested region (loopbody) and a map-formflowscollection have no index to spell, so their findings keepwherealone.whereandmessageare unchanged everywhere.authoring-rules.tsalready setspath: i.path ?? i.where(only its comment gains the node case), andmetadata-protocolitemRelativeIssuePathalready re-spellsflows[0].nodes[1].config.fields.statusasnodes.1.config.fields.status, whichuiflow-problems.tsserverTargetmaps onto the node.ui/is untouched.ExprIssue.pathdocblock names the node case.27828-flow-node-config-finding-path.md:@objectstack/lintpatch, both declaration lines.Tests
packages/lint/src/validate-expressions.node-config-path.test.ts(7 tests): the Update Records blank-expression finding carriesflows[0].nodes[1].config.fields.statuswithwhereunchanged; anullmember before the node and a second flow before this one index correctly; one fixture exercises six arms (nodecondition, value-template token, text-slot token, undeclared config key, script with nofunction,connector_actioninput) and asserts each node's path set; map-formflowsand a node inside aloopbody keeppathundefined; the runtime authoring gate's refusal is located at the node config value.packages/metadata-protocol/src/protocol.draft-publish-verdict.test.tsgains[#27828] a node config value refused by expression-invalid is located at the node, not in where prose: a draft with a blank Update Records value is stored, and its draft read's_diagnosticsreportsvalid: falsewith everyexpression-invalidentry atnodes.1.config.fields.name. Before the fix it readflow 'blank_value' · node 'set' (update_record) update_record field value at config.fields.name.validate-expressions.edge-condition-path.test.ts: the case "a finding off the edge condition gains no path" asserted that a nodeconditionfinding has no path. That is the behaviour this card changes, so it now asserts the node's own path (flows[0].nodes[0].config.condition), still no edge path.validate-expressions.test.tsreceiver meta-test (validate-expressions / validate-security-posture 也有同形的 spec 不声明键的??别名读法(#5009 建议 3 的核对结果) #5017): the new localnodeSlotKeysis excused with its reason (its keys areMapmethods, never metadata keys).Red before the fix, and the ablation
origin/main9f13ee81): the new lint file ran 5 failed | 2 passed (the twoundefined-path cases passed), and the metadata-protocol case failed with the prose path quoted above.e8b5683dwithscripts/ablation-replace.mjs: the stamp line (if (key !== undefined) issues[k] = { ...issues[k]!, path: ... }) replaced byvoid key;(anchor 0 left, replacement 1, counted on disk), lint rebuilt (OS_SKIP_DTS=1),ablation-dist-preflight.mjs @objectstack/lint 'nodes[${nodeIndex}]' --absentexit 0. Lint: 6 failed | 7 passed across the node and edge path files. metadata-protocol (reads lint'sdist/): the[#27828]case failed, 17 passed. Restored by the EXIT trap;git diff HEADempty and the blob hash matchedHEAD; lint rebuilt, preflight'void key;' --absentexit 0, metadata-protocol 18/18.Local runs
pnpm --filter @objectstack/lint exec vitest run: 180 files; 7655 passed and 1 failed on the first run (the validate-expressions / validate-security-posture 也有同形的 spec 不声明键的??别名读法(#5009 建议 3 的核对结果) #5017 receiver meta-test, fixed in the next commit), thenvalidate-expressions.test.ts440/440.pnpm --filter @objectstack/metadata-protocol exec vitest run src/protocol.draft-publish-verdict.test.ts: 18/18.pnpm --filter @objectstack/lint typecheck(withcheck:test-typecheck): exit 0.pnpm --filter @objectstack/metadata-protocol typecheck: exit 0.Acceptance notes
authoringFindingDetailLinesprintsrule: expression-invalid at PATH. For these findings that line now names the key path instead of repeating the prose; the verdict line above it still carrieswhere. The edge findings have printed this way since Studio: an expression field that says "Valid CEL" should read the draft's server verdict at its own path (RLS predicate, flow edge condition) #26858.path. Positional node paths compare across its passes the same way edge and validation-rule paths already do; no gate change was needed.validateStackExpressionsare unchanged (several, such asflow-api-trigger-secret-missing, already carry a key path). A nested-region node's finding could be located at its container (nodes.CONTAINER.config.body.nodes.I…); this PR follows the Studio: an expression field that says "Valid CEL" should read the draft's server verdict at its own path (RLS predicate, flow edge condition) #26858 edge precedent and leaves it onwhere.Verification
Head
6360f96e(merged withorigin/main3cc45cc4, which carries #28150). The gate sweep, the suites and the ablation ran on this tree.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 59 commands. All 59 ran with stdin from /dev/null, exit codes captured before any pipe: 56 exited 0 and 3 first exited 3 (PREREQUISITE NOT MET):check-plugin-teardown-shape --self-test(shallow clone; pinned commit621a4876fetched),check:dual-build-cjs-loadsandcheck:lean-entry-closure(unbuilt packages). After the prerequisite, all 3 exited 0.node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --ran FILE: "59 derived famil(ies) accounted for — 59 run, 0 NOT-MEASURED". Ran list:spec-seat-1/r2026-10-30/out/27828-gates-ran-6360f96e.listin the seat's folder.!in the title, no(narrowing)arm).test:repowas not run locally (CI's Test Core). CI on this PR: not yet read; the seat reads the check-runs.Generated by Claude Code