Files
flowgraph/tasks/reactive-workflow-root.md

50 lines
2.8 KiB
Markdown

---
id: reactive/workflow-root
name: Implement WorkflowReactiveRoot — signal graph, EventLogProjection, lifecycle, abort, dispose
status: completed
depends_on:
- graph/flowgraph-class
- schema/enums
- schema/node-attrs
- setup/test-infrastructure
scope: broad
risk: high
impact: phase
level: implementation
---
## Description
Implement the `WorkflowReactiveRoot` class that wraps reactive state for an entire workflow execution. It takes the structural DAG, creates signal-backed state for each operation node, and implements the `EventLogProjection` interface from ADR-005. The reactive root owns all signals and is responsible for their lifecycle.
## Acceptance Criteria
- [ ] `src/reactive/workflow.ts` exports `WorkflowReactiveRoot` class implementing `EventLogProjection`
- [ ] `EventLogProjection` interface: `append(event)`, `getStatus(nodeId)`, `getResult(nodeId)`, `getEvents(nodeId)`
- [ ] Constructor takes `DirectedGraph` and optional `{ failurePolicy?: FailurePolicy }`, calls `initializeSignals()`
- [ ] `FailurePolicy`: `"continue-running" | "abort-dependents"` (default: `"continue-running"`)
- [ ] `initializeSignals()`: iterates all DAG nodes, creates `signal<NodeStatus>("idle")`, `computed<boolean>` preconditions (all predecessors completed/skipped), `computed<boolean>` blockedByFailure (any predecessor failed/aborted), `computed<CallResult | undefined>` result from event log
- [ ] `nodeKeyToRequestId: Map<string, string>` — maps template node keys to call protocol requestIds
- [ ] `statusMap: Map<string, Signal<NodeStatus>>`, `preconditions`, `blockedByFailure` — owned by this class
- [ ] `append(event: CallEventMapValue)`: processes event, updates status via projection (idempotent)
- [ ] `getStatus(nodeId)`: hybrid model — checks event log first for call-level statuses, falls back to signal map for workflow-level statuses
- [ ] `getResult(nodeId)`: derives from most recent `call.responded`/`call.error`/`call.aborted` event per node
- [ ] `abortAll()`: sets all non-terminal nodes (not completed/failed) to `"aborted"`
- [ ] `abortNode(nodeId)`: aborts a specific node
- [ ] `dispose()`: calls all effect disposers, clears all maps (critical for preventing signal leaks)
- [ ] `isComplete(): boolean` — all nodes in terminal state
- [ ] `getAggregateStatus()`: count breakdown by status
- [ ] Unit tests: signal initialization for known DAG, append event → status update, getResult derived from events, abort cascade, dispose clears all, failurePolicy behavior
## References
- docs/architecture/reactive-execution.md — WorkflowReactiveRoot full specification, EventLogProjection, lifecycle, ownership, disposal
- docs/architecture/host-configs.md — ReactiveContext structure, signal-graph → WorkflowNode wiring
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion