feat: publish structured workflow node results #337

Closed
opened 2026-07-15 15:49:24 +02:00 by dries · 1 comment
Owner

Problem Statement

Workflow node types currently expose incompatible outputs: commands use string collectors, agents use raw JSON collectors, approvals expose no result, and map/join nodes expose partial status data. Dependent nodes cannot consistently consume prior results in command arguments, environment values, or agent prompts.

Solution

Every workflow node publishes one canonical Node Result envelope: {id, name, started, ended, status, output}. Ocman owns execution metadata; each node supplies a JSON output matching its node-type schema. Dependent nodes explicitly interpolate results from declared transitive dependencies.

User Stories

  1. As a workflow author, I want every node to expose the same result envelope, so that dependencies are predictable.
  2. As a workflow author, I want command stdout parsed as one JSON value, so that later nodes receive typed data.
  3. As a workflow author, I want agent final messages parsed as JSON, so that agent and command results behave consistently.
  4. As a workflow author, I want an invalid agent result corrected once in the same session, so that formatting mistakes can recover cheaply.
  5. As a workflow author, I want a second invalid agent result to fail, so that workflows do not retry forever.
  6. As a workflow author, I want invalid command JSON to fail immediately, so that commands are not rerun unexpectedly.
  7. As a workflow author, I want explicit interpolation in command arguments, environment values, and agent prompts, so that data flow is visible in the definition.
  8. As a workflow author, I want interpolation limited to declared transitive dependencies, so that hidden cross-branch coupling is rejected.
  9. As a workflow author, I want interpolated values JSON-serialized, so that objects, arrays, strings, numbers, booleans, and null preserve their JSON meaning.
  10. As a workflow author, I want missing interpolation paths to fail before execution, so that bad references never become empty strings.
  11. As a workflow author, I want approval results to include the decision and audit time, so that downstream nodes can branch on approval.
  12. As a workflow author, I want map results to include each child key, index, status, and output, so that mapped work can be consumed.
  13. As a workflow author, I want join results to include policy counts and mapped item outputs, so that aggregation is complete.
  14. As a workflow operator, I want failure diagnostics inside output, so that recovery branches can inspect failures.
  15. As a workflow operator, I want RFC 3339 UTC timestamps or null, so that execution timing is unambiguous.
  16. As a workflow operator, I want existing node statuses preserved, so that the feature does not introduce another state vocabulary.
  17. As a maintainer, I want retries hidden behind one final Node Result, so that downstream references remain stable.
  18. As a maintainer, I want collectors replaced by the sole result channel, so that there is one authoritative output model.

Implementation Decisions

  • A Node Result has exactly id, name, started, ended, status, and output.
  • started and ended are RFC 3339 UTC strings when known and null otherwise.
  • Status uses the existing node vocabulary: pending, ready, running, successful, failed, canceled, skipped, and unknown.
  • Ocman supplies all envelope metadata. Commands and agents supply only the JSON value assigned to output.
  • A command must write exactly one valid JSON value to stdout. Empty or malformed output fails the node without rerunning it.
  • An agent must finish with one valid JSON value. On invalid JSON, ocman sends one corrective message in the same session: Your previous response was not valid JSON. Reply once with only a valid JSON value for the workflow result. A second invalid result fails the node.
  • Per-node output collectors are removed. Immutable artifacts and persisted attempt data must converge on the Node Result as the authoritative result representation.
  • Explicit interpolation is supported in command arguments, environment values, and agent prompts. References use the nodes.<node-id> result namespace and may target nested fields.
  • Only declared transitive dependencies are addressable. A missing, malformed, or inaccessible reference fails the consuming node before execution.
  • Every interpolated selection is encoded with standard JSON serialization, including quoted strings.
  • Failure output is an object containing at least error.
  • Approval output is {approved, approvedBy, approvedAt}. approvedBy is null until user identity exists.
  • Map output is {items:[{key,index,status,output}]} where output is the mapped child workflow final result.
  • Join output is {policy,success,failed,total,items:[{key,index,status,output}]}.
  • Subworkflows remain inlined and therefore do not create a runtime result of their own.
  • One final Node Result is published per node; attempt history remains internal.

Testing Decisions

  • Primary seam: workflow service integration tests that execute complete runs through existing fake command and agent executors. Assertions cover only persisted/public run behavior, not helper implementation.
  • Verify envelopes and timestamp/null behavior for every runtime node type and terminal state.
  • Verify JSON type preservation and explicit interpolation in command arguments, environment values, and agent prompts.
  • Verify inaccessible and missing interpolation paths fail before executor invocation.
  • Verify malformed command JSON fails once without rerun.
  • Add one server-level agent executor test proving one corrective message is sent and a second malformed response fails.
  • Extend existing map/join and approval integration tests to verify their output schemas.
  • Follow existing table-driven Go test patterns and preserve the coverage ratchet.

Out of Scope

  • Adding user identity solely to populate approvedBy.
  • Implicit interpolation or raw, unquoted string interpolation.
  • Arbitrary access to unrelated workflow branches.
  • Configurable JSON repair retry counts.
  • A runtime result for authored subworkflow nodes, which remain inlined.

Further Notes

The canonical domain terms are Node Result, Output, and Interpolation. Existing workflow definitions using collectors require migration or explicit compatibility handling during implementation.

## Problem Statement Workflow node types currently expose incompatible outputs: commands use string collectors, agents use raw JSON collectors, approvals expose no result, and map/join nodes expose partial status data. Dependent nodes cannot consistently consume prior results in command arguments, environment values, or agent prompts. ## Solution Every workflow node publishes one canonical Node Result envelope: `{id, name, started, ended, status, output}`. Ocman owns execution metadata; each node supplies a JSON `output` matching its node-type schema. Dependent nodes explicitly interpolate results from declared transitive dependencies. ## User Stories 1. As a workflow author, I want every node to expose the same result envelope, so that dependencies are predictable. 2. As a workflow author, I want command stdout parsed as one JSON value, so that later nodes receive typed data. 3. As a workflow author, I want agent final messages parsed as JSON, so that agent and command results behave consistently. 4. As a workflow author, I want an invalid agent result corrected once in the same session, so that formatting mistakes can recover cheaply. 5. As a workflow author, I want a second invalid agent result to fail, so that workflows do not retry forever. 6. As a workflow author, I want invalid command JSON to fail immediately, so that commands are not rerun unexpectedly. 7. As a workflow author, I want explicit interpolation in command arguments, environment values, and agent prompts, so that data flow is visible in the definition. 8. As a workflow author, I want interpolation limited to declared transitive dependencies, so that hidden cross-branch coupling is rejected. 9. As a workflow author, I want interpolated values JSON-serialized, so that objects, arrays, strings, numbers, booleans, and null preserve their JSON meaning. 10. As a workflow author, I want missing interpolation paths to fail before execution, so that bad references never become empty strings. 11. As a workflow author, I want approval results to include the decision and audit time, so that downstream nodes can branch on approval. 12. As a workflow author, I want map results to include each child key, index, status, and output, so that mapped work can be consumed. 13. As a workflow author, I want join results to include policy counts and mapped item outputs, so that aggregation is complete. 14. As a workflow operator, I want failure diagnostics inside `output`, so that recovery branches can inspect failures. 15. As a workflow operator, I want RFC 3339 UTC timestamps or null, so that execution timing is unambiguous. 16. As a workflow operator, I want existing node statuses preserved, so that the feature does not introduce another state vocabulary. 17. As a maintainer, I want retries hidden behind one final Node Result, so that downstream references remain stable. 18. As a maintainer, I want collectors replaced by the sole result channel, so that there is one authoritative output model. ## Implementation Decisions - A Node Result has exactly `id`, `name`, `started`, `ended`, `status`, and `output`. - `started` and `ended` are RFC 3339 UTC strings when known and null otherwise. - Status uses the existing node vocabulary: pending, ready, running, successful, failed, canceled, skipped, and unknown. - Ocman supplies all envelope metadata. Commands and agents supply only the JSON value assigned to `output`. - A command must write exactly one valid JSON value to stdout. Empty or malformed output fails the node without rerunning it. - An agent must finish with one valid JSON value. On invalid JSON, ocman sends one corrective message in the same session: `Your previous response was not valid JSON. Reply once with only a valid JSON value for the workflow result.` A second invalid result fails the node. - Per-node output collectors are removed. Immutable artifacts and persisted attempt data must converge on the Node Result as the authoritative result representation. - Explicit interpolation is supported in command arguments, environment values, and agent prompts. References use the `nodes.<node-id>` result namespace and may target nested fields. - Only declared transitive dependencies are addressable. A missing, malformed, or inaccessible reference fails the consuming node before execution. - Every interpolated selection is encoded with standard JSON serialization, including quoted strings. - Failure output is an object containing at least `error`. - Approval output is `{approved, approvedBy, approvedAt}`. `approvedBy` is null until user identity exists. - Map output is `{items:[{key,index,status,output}]}` where output is the mapped child workflow final result. - Join output is `{policy,success,failed,total,items:[{key,index,status,output}]}`. - Subworkflows remain inlined and therefore do not create a runtime result of their own. - One final Node Result is published per node; attempt history remains internal. ## Testing Decisions - Primary seam: workflow service integration tests that execute complete runs through existing fake command and agent executors. Assertions cover only persisted/public run behavior, not helper implementation. - Verify envelopes and timestamp/null behavior for every runtime node type and terminal state. - Verify JSON type preservation and explicit interpolation in command arguments, environment values, and agent prompts. - Verify inaccessible and missing interpolation paths fail before executor invocation. - Verify malformed command JSON fails once without rerun. - Add one server-level agent executor test proving one corrective message is sent and a second malformed response fails. - Extend existing map/join and approval integration tests to verify their output schemas. - Follow existing table-driven Go test patterns and preserve the coverage ratchet. ## Out of Scope - Adding user identity solely to populate `approvedBy`. - Implicit interpolation or raw, unquoted string interpolation. - Arbitrary access to unrelated workflow branches. - Configurable JSON repair retry counts. - A runtime result for authored subworkflow nodes, which remain inlined. ## Further Notes The canonical domain terms are Node Result, Output, and Interpolation. Existing workflow definitions using collectors require migration or explicit compatibility handling during implementation.
Author
Owner

Resolved by merged PR #338 through #339-#343: every runtime node now publishes the canonical Node Result, interpolation consumes it, and collectors are retired.

Resolved by merged PR #338 through #339-#343: every runtime node now publishes the canonical Node Result, interpolation consumes it, and collectors are retired.
dries closed this issue 2026-07-16 00:56:11 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dries/ocman#337
No description provided.