Skip to content

service-automation: evaluate a value-role CEL envelope in the assignment executor and validate it at registerFlow — the executor half of #14149 (spec half landed in PR #15113) #15137

Description

@claude

Filed by the domain:spec PM seat (session session_0174WZTU6XcFcS7g2kykC53i, seat post #6017) at 2026-09-04T02:54Z as the executor half of the maintainer's ruling A on objectstack#14149 (comment 5507504961, 「同意」 2026-09-02), whose spec half landed in PR #15113 (merge f3bbbef5). Cross-lane request into the domain:services lane; domain:* is triage's to set. Provenance: the #14149 dev's read-and-report (comment 5534552929) and the seat's contract review (PR #15113 comment 5534669909); director audit 5534406255.

What the spec now declares (on origin/main f3bbbef58)

  • FlowNodeExpressionRole has 'value'; FLOW_NODE_EXPRESSION_PATHS carries { nodeType: 'assignment', path: 'assignments.*', role: 'value' }; resolveFlowNodeExpressions emits only envelope-shaped objects (isExpressionEnvelopeShaped) for a value slot — a plain string stays {token} interpolation (packages/spec/src/automation/flow-node-expression-paths.ts).
  • AssignmentConfigSchema / AssignmentValueSchema / AssignmentExpressionValueSchema (builtin-node-config.zod.ts): an assignment value is a string (interpolation), a { dialect: 'cel', source } envelope, or any other literal; a malformed envelope is refused at the variable's path with ASSIGNMENT_VALUE_ENVELOPE_REFUSAL; the map value carries .meta({ xExpression: 'value' }), exposed to the ledger ratchet through LEDGER_DECLARED_NODE_CONFIG_SCHEMAS (schemaless-node-config.zod.ts); the ratchet config-expression-ledger.test.ts already knows ROLE_BY_MARKER.value.

The ask (executor half, packages/services/service-automation)

  1. Validate at registerFlow and objectstack validate: call validateExpression('value', …) on what the ledger resolves for assignment (the service-automation / lint consumers of the ledger; the engine's severity policy throws on a malformed predicate at registerFlow, the lint pass reports a located finding — apply the same policy to the value role).
  2. Evaluate at run time: the built-in assignment executor (logic-nodes.ts:135 via template.ts:346-368 interpolate) today writes an envelope object into the variable VERBATIM (interpolate() recurses into it as a literal object) and notify renders it as JSON (engine.ts:6901 skips every non-predicate slot). Evaluate a value-role envelope with the expression engine (the CEL engine already answers joinNonEmpty(rows.map(r, r.subject), "\n") for the ruling's example — measured on built formula dist) and assign the result; a plain string keeps today's interpolation.
  3. Decide the legacy array form before AssignmentConfigSchema is wired into parseNodeConfig: the schema refuses assignments: [{ variable, value }] with ASSIGNMENT_ARRAY_FORM_PRESCRIPTION while the executor still normalizes that shape (flagged by the director's audit 5534406255 — nothing parses a node config against this schema today, so no flow changes behaviour yet). Either refuse it at registerFlow (breaks any existing flow authored that way — needs an ADR-0087 conversion or a ruling) or accept it as untyped legacy (do not wire the schema for that shape). State the choice on this card's PR; a refusal is Clause ② and a ruling, not a lane's call.
  4. Pins for all three, and the liveness / ledger discipline the family uses. packages/spec is not this card's surface — if the contract needs to move, it goes back to the spec lane.

Consumer note: objectui's Studio form affordance for the envelope value is a separate objectui card (filed by the same seat).


Generated by Claude Code

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions