decompose architecture into 38 atomic tasks across 12 parallel generations

Decompose the reviewed architecture specs into taskgraph-managed tasks:
- 2 setup tasks (project init, test infrastructure)
- 4 schema tasks (enums, node attrs, edge attrs, graph schemas)
- 1 error hierarchy task
- 6 graph tasks (FlowGraph class, 3 construction paths, queries, validation)
- 5 analysis tasks (type-compat, build-type-edges, ordering, template-validation, defaults)
- 5 component tasks (Operation, Sequential, Parallel, Conditional, Map)
- 2 host config tasks (GraphologyHostConfig, ReactiveHostConfig)
- 4 reactive tasks (WorkflowRoot, node-status, max-concurrency, retry-semantics)
- 3 review tasks (foundation, reactive-and-hosts, complete-library)
- 5 meta cluster tasks (schema, graph, component, reactive, analysis layers)
- 1 API exports task

Validated with taskgraph: zero cycles, 38 tasks, 12 parallel generations.
Critical path: 12 tasks through reactive execution layer.
This commit is contained in:
2026-05-21 20:24:44 +00:00
parent 907c33650f
commit 466b121f77
38 changed files with 1623 additions and 0 deletions

View File

@@ -0,0 +1,40 @@
---
id: analysis/build-type-edges
name: Implement buildTypeEdges — populate operation graph with type-compatibility edges
status: pending
depends_on:
- analysis/type-compat
- graph/construction-operation
scope: narrow
risk: medium
impact: component
level: implementation
---
## Description
Implement `buildTypeEdges()` which iterates over all operation pairs in the graph and adds type-compatibility edges based on `typeCompat()` results. Called internally by `fromSpecs()` and callable manually for incremental construction.
## Acceptance Criteria
- [ ] `buildTypeEdges(graph: FlowGraph<OperationNodeAttrs, OperationEdgeAttrs>): void` — standalone function in `src/analysis/type-compat.ts`
- [ ] For each pair (A, B): call `typeCompat(A.outputSchema, B.inputSchema)`, add edge with result
- [ ] Compatible edges: `edgeType: "typed", compatible: true, detail: "A.output → B.input"`
- [ ] Incompatible edges: `edgeType: "typed", compatible: false, detail describing mismatch, mismatches array`
- [ ] Unknown compatibility (either schema is Unknown): no edge added
- [ ] O(n²) in worst case — documented, acceptable for 10-200 operations
- [ ] Function is callable after incremental `addOperation()` calls
- [ ] Unit tests: known operation specs produce expected edges, incompatible pairs get compatible: false edges, unknown schemas produce no edges
## References
- docs/architecture/analysis.md — buildTypeEdges specification
- docs/architecture/operation-graph.md — edge construction, compatible: false edges rationale
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,39 @@
---
id: analysis/defaults
name: Implement default value resolution for CallStatus, EdgeType, and node attributes
status: pending
depends_on:
- schema/enums
- schema/node-attrs
- schema/edge-attrs
scope: single
risk: trivial
impact: isolated
level: implementation
---
## Description
Implement the defaults module that provides default values and resolution functions for categorical enums and node attributes. Used by construction and mutation methods to fill in unspecified fields.
## Acceptance Criteria
- [ ] `src/analysis/defaults.ts` exports default status, edge type, and attribute resolution functions
- [ ] `defaultCallStatus: CallStatus` = `"pending"`
- [ ] `defaultNodeStatus: NodeStatus` = `"idle"`
- [ ] `defaultEdgeType(edgeType?: string): EdgeType` — returns the provided type or `"typed"` (operation graph default)
- [ ] `resolveDefaultNodeAttrs(attrs: Partial<...>, defaults): NodeAttrs` — fills in missing required fields
- [ ] Unit tests: each default value is correct, resolution with partial input
## References
- docs/architecture/analysis.md — defaults section
- docs/architecture/schema.md — default values for NodeStatus, CallStatus
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,40 @@
---
id: analysis/ordering
name: Implement execution ordering functions (topologicalOrder, parallelGroups, criticalPath, reachableFrom)
status: pending
depends_on:
- graph/flowgraph-class
- graph/queries
scope: narrow
risk: low
impact: component
level: implementation
---
## Description
Implement the standalone analysis functions for execution ordering. These are pure functions operating on FlowGraph instances, delegating to graphology-dag algorithms.
## Acceptance Criteria
- [ ] `topologicalOrder(graph: FlowGraph): string[]` — uses graphology-dag topologicalSort, throws CycleError on cycles
- [ ] `parallelGroups(graph: FlowGraph): string[][]` — groups by dependency depth (group 0 = roots, group 1 = dependents of group 0, etc.)
- [ ] `criticalPath(graph: FlowGraph): string[]` — longest path through DAG
- [ ] `reachableFrom(graph: FlowGraph, nodeIds: string[]): Set<string>` — BFS/DFS from starting nodes
- [ ] `ancestors(graph: FlowGraph, nodeId: string): string[]` and `descendants(graph: FlowGraph, nodeId: string): string[]`
- [ ] All functions are standalone (not FlowGraph methods), in `src/analysis/`
- [ ] O(V + E) complexity for all — documented in JSDoc
- [ ] Unit tests: known DAGs produce expected orderings, parallel groups, critical paths
## References
- docs/architecture/analysis.md — execution ordering functions, performance characteristics
- docs/architecture/flowgraph-api.md — convenience delegation from FlowGraph to standalone functions
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,39 @@
---
id: analysis/template-validation
name: Implement validateTemplate and validatePreconditions
status: pending
depends_on:
- analysis/type-compat
- graph/queries
- schema/edge-attrs
scope: moderate
risk: medium
impact: component
level: implementation
---
## Description
Implement the template validation functions that check workflow templates against operation graphs, and the precondition validation that verifies all required inputs are provided by predecessors.
## Acceptance Criteria
- [ ] `validatePreconditions(graph: FlowGraph<OperationNodeAttrs, OperationEdgeAttrs>): ValidationError[]` — for each node, checks input required fields are provided by predecessor outputs; returns `ValidationError[]`
- [ ] `validateTemplate(template: UNode, operationGraph: FlowGraph<OperationNodeAttrs, OperationEdgeAttrs>): AnyValidationError[]` — validates template against operation graph
- [ ] Template validation checks: (1) all Operation names exist in registry/graph, (2) no cycles in rendered DAG, (3) type compatibility between sequential operations, (4) reachability from start, (5) no orphan nodes
- [ ] Template validation is advisory — returns warnings AND errors, never throws
- [ ] Both functions follow the "collect all errors" pattern
- [ ] Unit tests: valid template returns empty, missing operation, cycle in template, type incompatibility, unreachable nodes, orphan nodes
## References
- docs/architecture/analysis.md — validatePreconditions, validateTemplate specifications
- docs/architecture/workflow-templates.md — validation checks
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,46 @@
---
id: analysis/type-compat
name: Implement typeCompat function — deep structural schema compatibility checking
status: pending
depends_on:
- schema/node-attrs
- schema/edge-attrs
- error/hierarchy
- setup/test-infrastructure
scope: moderate
risk: high
impact: phase
level: implementation
---
## Description
Implement the `typeCompat` function that performs deep recursive structural comparison between two TypeBox schemas to determine if an output schema is compatible with an input schema. This is the core of the operation graph's type-compatibility edge construction.
## Acceptance Criteria
- [ ] `typeCompat(outputSchema: TSchema, inputSchema: TSchema): TypeCompatResult` — standalone function in `src/analysis/type-compat.ts`
- [ ] `TypeCompatResult`: `{ compatible: boolean; detail?: string; mismatches?: TypeMismatch[] }`
- [ ] `TypeMismatch`: `{ path: string; expected: string; actual: string }`
- [ ] Exact match → `compatible: true`
- [ ] Output is superset of input (output has extra fields beyond input requirements) → `compatible: true`
- [ ] Output is subset of input (output missing required fields) → `compatible: false` with mismatches
- [ ] Type mismatch at field level → `compatible: false` with mismatches at that path
- [ ] Either schema is `Type.Unknown()` → return nothing / undefined (no edge should be created, compatibility unknown)
- [ ] Handles: nested objects (recursive), arrays (element type comparison), optional fields, union types (subtype checking)
- [ ] Subtype checking: output must be at least as specific as input (string compatible with string|number, but NOT reverse)
- [ ] `mismatches` array provides JSON-path level diagnostics for incompatible results
- [ ] Unit tests: exact match, superset, subset, type mismatch, unknown passthrough, nested objects, arrays, unions, optional fields, complex realistic schemas
## References
- docs/architecture/analysis.md — typeCompat contract, compatibility rules, depth of checking, subtype rules
- docs/architecture/schema.md — TypeCompatResult, TypeMismatch interfaces
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,49 @@
---
id: api/public-exports
name: Wire barrel exports and verify exports map resolves correctly for all sub-paths
status: pending
depends_on:
- review/reactive-and-hosts
- analysis/type-compat
- analysis/build-type-edges
- analysis/ordering
- analysis/template-validation
- analysis/defaults
scope: moderate
risk: low
impact: phase
level: implementation
---
## Description
Wire all barrel exports (`src/index.ts` and module `index.ts` files) and verify the package.json exports map resolves correctly for every sub-path. This is the integration check that all modules are properly connected and importable.
## Acceptance Criteria
- [ ] `src/index.ts` re-exports from all modules: graph, schema, component, host, reactive, analysis, error
- [ ] Each module's `index.ts` exports the correct public API per [flowgraph-api.md](../docs/architecture/flowgraph-api.md) exports map table
- [ ] Sub-path `@alkdev/flowgraph` → all public types
- [ ] Sub-path `@alkdev/flowgraph/graph` → FlowGraph, FlowGraphOptions
- [ ] Sub-path `@alkdev/flowgraph/schema` → all schemas, enums, types, CallResult
- [ ] Sub-path `@alkdev/flowgraph/component` → Operation, Sequential, Parallel, Conditional, Map
- [ ] Sub-path `@alkdev/flowgraph/host` → GraphologyHostConfig, ReactiveHostConfig
- [ ] Sub-path `@alkdev/flowgraph/reactive` → WorkflowReactiveRoot, WorkflowNode, ReactiveContext, EventLogProjection
- [ ] Sub-path `@alkdev/flowgraph/analysis` → typeCompat, buildTypeEdges, validateGraph, validateTemplate, topologicalOrder, parallelGroups, criticalPath, reachableFrom
- [ ] Sub-path `@alkdev/flowgraph/error` → all error classes
- [ ] `npm run build` produces correct ESM + CJS + declarations for all entry points
- [ ] Import resolution test: each sub-path is importable after build
- [ ] TypeScript compilation succeeds: `npx tsc --noEmit`
## References
- docs/architecture/flowgraph-api.md — complete exports map
- docs/architecture/build-distribution.md — exports map, tsup configuration
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,42 @@
---
id: component/conditional
name: Implement <Conditional> ujsx component
status: pending
depends_on:
- schema/edge-attrs
- setup/project-init
scope: narrow
risk: low
impact: component
level: implementation
---
## Description
Implement the `Conditional` ujsx component function. Represents conditional branching — children only execute if the test passes. Supports an optional `else` prop for the alternative branch.
## Acceptance Criteria
- [ ] `src/component/conditional.ts` exports `Conditional` component function
- [ ] `Conditional` produces `UElement` with `type: "conditional"`
- [ ] Props: `test: ((results: Record<string, CallResult>) => boolean) | string` (required), optional `else: UNode`
- [ ] `children` of Conditional are the then-branch
- [ ] `else` prop is the alternative branch
- [ ] String condition: operation name whose completion status determines the branch
- [ ] Function condition: receives predecessor results, returns boolean
- [ ] Conditional.test cannot reference an Operation inside the Conditional itself (would create circular dependency)
- [ ] Re-exported from `src/component/index.ts`
- [ ] Unit tests: correct UElement shape with test as function, test as string, else prop
## References
- docs/architecture/workflow-templates.md — Conditional component, else-branch behavior, string condition resolution
- docs/architecture/schema.md — TemplateEdgeAttrs.condition representation
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

39
tasks/component-map.md Normal file
View File

@@ -0,0 +1,39 @@
---
id: component/map
name: Implement <Map> ujsx component
status: pending
depends_on:
- schema/edge-attrs
- setup/project-init
scope: narrow
risk: low
impact: component
level: implementation
---
## Description
Implement the `Map` ujsx component function. Represents mapping over an array — creates one child instance per array item. Structurally equivalent to a dynamically-generated Parallel group.
## Acceptance Criteria
- [ ] `src/component/map.ts` exports `Map` component function
- [ ] `Map` produces `UElement` with `type: "map"`
- [ ] Props: `over: Signal<unknown[]> | unknown[] | ((results: Record<string, CallResult>) => unknown[])` (required), `as: string` (required), `children: UNode` (required — template rendered per item)
- [ ] The `as` prop names the variable each item is bound to
- [ ] Aggregate completion semantics: all mapped nodes must reach satisfying terminal state for Map to be "completed"; any failed/aborted child makes Map failed/aborted
- [ ] Re-exported from `src/component/index.ts`
- [ ] Unit tests: correct UElement shape with each over form (static, function), as prop preserved
## References
- docs/architecture/workflow-templates.md — Map component, aggregate completion semantics, edge type
- docs/architecture/reactive-execution.md — Map reactive behavior, maxConcurrency interaction
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,38 @@
---
id: component/operation
name: Implement <Operation> ujsx component
status: pending
depends_on:
- schema/node-attrs
- setup/project-init
scope: single
risk: low
impact: component
level: implementation
---
## Description
Implement the `Operation` ujsx component function. It's a `UComponent` that produces a `UElement` with `type: "operation"` and workflow-specific props. Operation is a leaf node — it has no children.
## Acceptance Criteria
- [ ] `src/component/operation.ts` exports `Operation` component function
- [ ] `Operation` produces `UElement` with `type: "operation"`
- [ ] Props: `name: string` (required), optional `input`, optional `retries: number`, optional `timeout: number`
- [ ] Operation has no children (leaf node — documented as validation error if children provided)
- [ ] Re-exported from `src/component/index.ts`
- [ ] Unit tests: produces correct UElement shape, type guard works
## References
- docs/architecture/workflow-templates.md — Operation component definition, props
- docs/architecture/host-configs.md — component-to-tag mapping
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,37 @@
---
id: component/parallel
name: Implement <Parallel> ujsx component
status: pending
depends_on:
- setup/project-init
scope: single
risk: trivial
impact: component
level: implementation
---
## Description
Implement the `Parallel` ujsx component function. Structural container where all children execute simultaneously with no inter-child edges.
## Acceptance Criteria
- [ ] `src/component/parallel.ts` exports `Parallel` component function
- [ ] `Parallel` produces `UElement` with `type: "parallel"`
- [ ] Props: optional `id: string`, optional `maxConcurrency: number`
- [ ] `maxConcurrency` is a runtime scheduling hint, not a structural constraint (not encoded in DAG)
- [ ] Valid children: Operation, Sequential, Parallel, Conditional, Map
- [ ] Re-exported from `src/component/index.ts`
- [ ] Unit tests: correct UElement shape, maxConcurrency prop preserved
## References
- docs/architecture/workflow-templates.md — Parallel component, maxConcurrency semantics
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,37 @@
---
id: component/sequential
name: Implement <Sequential> ujsx component
status: pending
depends_on:
- setup/project-init
scope: single
risk: trivial
impact: component
level: implementation
---
## Description
Implement the `Sequential` ujsx component function. Structural container that renders children in order with sequential edges between consecutive siblings.
## Acceptance Criteria
- [ ] `src/component/sequential.ts` exports `Sequential` component function
- [ ] `Sequential` produces `UElement` with `type: "sequential"`
- [ ] Props: optional `id: string`
- [ ] Valid children: Operation, Sequential, Parallel, Conditional, Map
- [ ] Single-child Sequential is valid but degenerate (produces no edges)
- [ ] Re-exported from `src/component/index.ts`
- [ ] Unit tests: correct UElement shape
## References
- docs/architecture/workflow-templates.md — Sequential component, composition rules
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

46
tasks/error-hierarchy.md Normal file
View File

@@ -0,0 +1,46 @@
---
id: error/hierarchy
name: Implement FlowgraphError hierarchy with all error classes and validation result types
status: pending
depends_on:
- setup/project-init
scope: narrow
risk: low
impact: component
level: implementation
---
## Description
Implement the complete error hierarchy per [error-handling.md](../docs/architecture/error-handling.md). This includes thrown error classes (for construction invariant violations) and structured result types (for validation functions that never throw).
## Acceptance Criteria
- [ ] `src/error/index.ts` exports all error classes and result types
- [ ] `FlowgraphError` base class extending `Error` with `name: "FlowgraphError"`
- [ ] `ConstructionError` extending `FlowgraphError` — base for construction-time errors
- [ ] `DuplicateNodeError` extending `ConstructionError``key` property
- [ ] `DuplicateEdgeError` extending `ConstructionError``source`, `target` properties
- [ ] `NodeNotFoundError` extending `ConstructionError``key` property
- [ ] `CycleError` extending `ConstructionError``cycles: string[][]` property
- [ ] `InvalidInputError` extending `ConstructionError``errors: ValidationError[]` property
- [ ] `InvalidTransitionError` extending `FlowgraphError``requestId`, `from: CallStatus`, `to: CallStatus` properties
- [ ] `ValidationError` interface — `{ type: "schema", nodeKey, field, message, value? }`
- [ ] `GraphValidationError` interface — `{ type: "graph", category: "cycle" | "dangling-reference" | "orphan-node" | "status-inconsistency", details: unknown }`
- [ ] `TypeIncompatError` interface — `{ type: "type-compat", sourceKey, targetKey, compatible: false, mismatches: TypeMismatch[] }`
- [ ] `TypeMismatch` interface — `{ path, expected, actual }`
- [ ] `AnyValidationError` union type — `ValidationError | GraphValidationError | TypeIncompatError`
- [ ] Throwing vs returning contract clearly documented in JSDoc
- [ ] Unit tests: each error class constructs correctly, result types validate, `instanceof` checks work
## References
- docs/architecture/error-handling.md — complete error hierarchy, throwing vs returning contract
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,44 @@
---
id: graph/construction-call
name: Implement call graph construction (fromCallEvents, updateFromEvent, addCall, addDependency, updateStatus)
status: pending
depends_on:
- graph/flowgraph-class
- schema/enums
scope: broad
risk: high
impact: phase
level: implementation
---
## Description
Implement the construction and mutation methods for call graphs: `FlowGraph.fromCallEvents()`, `updateFromEvent()`, `addCall()`, `addDependency()`, `updateStatus()`, `updateCall()`, and `removeCall()`. These handle the dynamic call graph populated from call protocol events.
## Acceptance Criteria
- [ ] `FlowGraph.fromCallEvents(events: CallEventMapValue[]): CallGraph` — processes events in order, idempotent (duplicate events have no effect)
- [ ] Event processing: `call.requested` → add node (status: "pending", add triggered edge if parentRequestId), `call.responded` → status: "completed" + output + completedAt, `call.error` → status: "failed" + error + completedAt, `call.aborted` → status: "aborted" + completedAt, `call.completed` → status: "completed" + completedAt
- [ ] `updateFromEvent(event: CallEventMapValue): void` — single event processing for real-time subscription
- [ ] `addCall(attrs: CallNodeAttrs): void` — adds call node; if `parentRequestId` present, creates triggered edge from parent to child
- [ ] `addDependency(source, target): void` — creates depends_on edge with composite key `${source}->${target}:depends_on`
- [ ] `updateStatus(requestId, status, extra?): void` — validates transition per state machine, throws `InvalidTransitionError` on invalid transition
- [ ] `updateCall(requestId, attrs): void` — partial merge of call attributes
- [ ] `removeCall(requestId): void` — removes node and all attached edges
- [ ] Status transition validation: pending→running→completed/failed, pending→aborted, running→aborted (terminal states: completed, failed, aborted)
- [ ] Call graph errors are resilient: unknown requestId in responded/error/aborted → log warning, ignore; unknown operationId → create node anyway with status "pending"
- [ ] Unit tests: fromCallEvents with full event sequences, updateFromEvent real-time pattern, addCall with/without parent, status transitions valid/invalid, addDependency, idempotency
## References
- docs/architecture/call-graph.md — fromCallEvents, updateFromEvent, status lifecycle, mutations, abort cascading
- docs/architecture/schema.md — CallEventMapValue mapping to CallNodeAttrs, edge key convention
- docs/architecture/error-handling.md — call graph error boundary, InvalidTransitionError
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,40 @@
---
id: graph/construction-json
name: Implement fromJSON and export/toJSON serialization for FlowGraph
status: pending
depends_on:
- graph/flowgraph-class
- schema/graph-schemas
scope: narrow
risk: medium
impact: component
level: implementation
---
## Description
Implement the serialization boundary: `FlowGraph.fromJSON()` for deserialization and `export()`/`toJSON()`/`toString()` for serialization. The round-trip `fromSpecs() → export() → fromJSON()` must be lossless.
## Acceptance Criteria
- [ ] `FlowGraph.fromJSON(data: FlowGraphSerialized): FlowGraph` — validates input against schema using `Value.Check()`, throws `InvalidInputError` (with `errors` array) on validation failure
- [ ] `fromJSON()` validates DAG invariants after deserialization — runs cycle detection, throws `CycleError` if cycles found (per ADR-002, even externally-provided data cannot produce cyclic graphs)
- [ ] `export(): FlowGraphSerialized` — returns graphology native JSON format
- [ ] `toJSON(): FlowGraphSerialized` — alias for export()
- [ ] `toString(): string``JSON.stringify(export())`
- [ ] Round-trip guarantee: `fromSpecs() → export() → fromJSON()` is lossless
- [ ] Round-trip guarantee: `fromCallEvents() → export() → fromJSON()` is lossless
- [ ] Unit tests: valid round-trips, invalid input throws InvalidInputError, cyclic input throws CycleError, empty graph round-trip
## References
- docs/architecture/flowgraph-api.md — fromJSON, export, toJSON, toString signatures
- docs/architecture/schema.md — SerializedGraph factory, FlowGraphSerialized variants
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,38 @@
---
id: graph/construction-operation
name: Implement operation graph construction (fromSpecs, addOperation, addTypedEdge)
status: pending
depends_on:
- graph/flowgraph-class
scope: moderate
risk: medium
impact: phase
level: implementation
---
## Description
Implement the construction methods specific to operation graphs: `FlowGraph.fromSpecs()`, `addOperation()`, and `addTypedEdge()`. These build the static type-compatibility graph from `OperationSpec` arrays.
## Acceptance Criteria
- [ ] `FlowGraph.fromSpecs(specs: OperationSpec[]): OperationGraph` — creates nodes for each operation (key: `${namespace}.${name}`), adds type-compatibility edges via `buildTypeEdges()`, throws `CycleError` if resulting graph has cycles
- [ ] `addOperation(spec: OperationSpec): void` — adds operation node, key is `${spec.namespace}.${spec.name}`, throws `DuplicateNodeError` if key exists
- [ ] `addTypedEdge(source, target, attrs: { compatible, detail?, mismatches? }): void` — adds edge with `edgeType: "typed"`, validates endpoints exist, validates no cycle created
- [ ] `fromSpecs()` calls `buildTypeEdges()` internally after adding all operation nodes
- [ ] `buildTypeEdges()` must be callable separately for incremental construction after `addOperation()`
- [ ] Operation graph is conventionally immutable after `fromSpecs()` — documented in JSDoc
- [ ] Unit tests: fromSpecs with valid specs, duplicate operations, cycle detection, incremental addOperation + buildTypeEdges
## References
- docs/architecture/operation-graph.md — fromSpecs construction, incremental construction, immutability
- docs/architecture/flowgraph-api.md — fromSpecs, addOperation, addTypedEdge signatures
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,58 @@
---
id: graph/flowgraph-class
name: Implement FlowGraph class skeleton wrapping graphology DirectedGraph
status: pending
depends_on:
- schema/enums
- schema/node-attrs
- schema/edge-attrs
- schema/graph-schemas
- error/hierarchy
- setup/project-init
scope: moderate
risk: medium
impact: phase
level: implementation
---
## Description
Create the `FlowGraph` class that wraps a graphology `DirectedGraph` and enforces DAG invariants. This is the core data class. At this stage, implement the constructor, generic type parameters, the `_graph` instance, the `graph` getter, `FlowGraphOptions`, and the `_edgeKey()` helper. Construction factory methods come in dependent tasks.
## Acceptance Criteria
- [ ] `src/graph/construction.ts` exports `FlowGraph` class (or `src/graph/index.ts` if preferred, matching source structure)
- [ ] Class has type parameters: `NodeAttrs extends TSchema`, `EdgeAttrs extends TSchema`
- [ ] Constructor creates internal `graphology.DirectedGraph` with options `{ type: "directed", multi: false, allowSelfLoops: false }`
- [ ] `FlowGraphOptions` interface: `type?: "directed"`, `multi?: false`, `allowSelfLoops?: false`
- [ ] `get graph(): DirectedGraph` returns the underlying graphology instance
- [ ] `_edgeKey(source, target): string` produces deterministic keys `${source}->${target}`
- [ ] `addNode(key, attrs)` — adds node, throws `DuplicateNodeError` on duplicate
- [ ] `removeNode(key)` — removes node and edges, throws `NodeNotFoundError` if missing
- [ ] `updateNode(key, attrs)` — partial merge of attributes, throws `NodeNotFoundError` if missing
- [ ] `hasNode(key): boolean`
- [ ] `getNodeAttributes(key): NodeAttrs` — throws `NodeNotFoundError` if missing
- [ ] `addEdge(source, target, attrs?)` — throws `NodeNotFoundError` for missing endpoints, `CycleError` if edge creates cycle, `DuplicateEdgeError` if edge exists
- [ ] `removeEdge(source, target)` — no-op if edge doesn't exist
- [ ] `hasEdge(source, target): boolean`
- [ ] `getEdgeAttributes(source, target): EdgeAttrs` — throws if edge doesn't exist
- [ ] `nodes(): string[]`, `edges(): string[]`, `order: number`, `size: number`
- [ ] `forEachNode(callback)`, `forEachEdge(callback)`
- [ ] `predecessors(nodeId)`, `successors(nodeId)` delegating to `graph.inNeighbors`/`graph.outNeighbors`
- [ ] Static construction methods (`fromSpecs`, `fromCallEvents`, `fromJSON`) are stubs (throw "not implemented")
- [ ] Re-exported from `src/graph/index.ts` and `src/index.ts`
- [ ] Unit tests: constructor, node operations, edge operations, cycle detection on addEdge
## References
- docs/architecture/flowgraph-api.md — FlowGraph class full API surface, delegation model
- docs/architecture/schema.md — edge key convention
- docs/architecture/error-handling.md — throwing contract for mutations
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

45
tasks/graph-queries.md Normal file
View File

@@ -0,0 +1,45 @@
---
id: graph/queries
name: Implement graph query methods (topologicalOrder, ancestors, descendants, call graph queries)
status: pending
depends_on:
- graph/flowgraph-class
scope: moderate
risk: low
impact: component
level: implementation
---
## Description
Implement the query methods on FlowGraph that delegate to graphology and graphology-dag, plus the call-graph-specific observability queries.
## Acceptance Criteria
- [ ] `topologicalOrder(): string[]` — delegates to `graphology-dag.topologicalSort`, throws `CycleError` if cycles exist (should never happen after validated construction)
- [ ] `hasCycles(): boolean` — delegates to `graphology-dag.hasCycle`
- [ ] `findCycles(): string[][]` — delegates to graphology cycle detection (debugging)
- [ ] `ancestors(nodeId): string[]` — delegates to `graphology-dag.ancestors`
- [ ] `descendants(nodeId): string[]` — delegates to `graphology-dag.descendants`
- [ ] `predecessors(nodeId): string[]` — delegates to `graph.inNeighbors`
- [ ] `successors(nodeId): string[]` — delegates to `graph.outNeighbors`
- [ ] `reachableFrom(nodeIds): Set<string>` — custom BFS/DFS traversal from starting nodes
- [ ] Call graph queries: `filterByStatus(status): string[]`, `getRoots(): string[]`, `children(requestId): string[]`, `duration(requestId): number`, `lineage(requestId): string[]`
- [ ] `filterByStatus`: O(n) filter over `forEachNode()` — documented as sufficient for expected sizes
- [ ] `getRoots()`: returns nodes with `parentRequestId === undefined`
- [ ] `lineage()`: ancestor chain from root to target
- [ ] Unit tests for each query method with known graph structures
## References
- docs/architecture/flowgraph-api.md — query methods, call graph queries
- docs/architecture/operation-graph.md — query delegation to graphology-dag
- docs/architecture/call-graph.md — observability queries
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

39
tasks/graph-validation.md Normal file
View File

@@ -0,0 +1,39 @@
---
id: graph/validation
name: Implement graph validation functions (validateSchema, validateGraph, validate)
status: pending
depends_on:
- graph/flowgraph-class
- error/hierarchy
scope: narrow
risk: low
impact: component
level: implementation
---
## Description
Implement the validation functions that check graph integrity. These never throw — they collect issues and return structured error arrays. This follows the returning (not throwing) contract per error-handling.md.
## Acceptance Criteria
- [ ] `validateSchema<NodeAttrs>(graph, NodeAttrsSchema): ValidationError[]` — checks each node's attributes against the TypeBox schema using `Value.Errors()`, returns `ValidationError[]`
- [ ] `validateGraph(graph): GraphValidationError[]` — checks for cycles, dangling references, orphan nodes, status inconsistencies; returns `GraphValidationError[]`
- [ ] `validate(graph): AnyValidationError[]` — runs both schema and graph validation, returns combined `AnyValidationError[]`
- [ ] All validation functions use the "collect all errors" pattern — never throw, never short-circuit
- [ ] `GraphValidationError` categories: `cycle` (with cycle paths), `dangling-reference` (with source/target), `orphan-node` (with node key), `status-inconsistency` (with node/parent status details)
- [ ] Unit tests: valid graph returns empty array, each category of error detected, multiple errors collected
## References
- docs/architecture/error-handling.md — validation result types, collecting errors
- docs/architecture/analysis.md — validateGraph, validate functions
- docs/architecture/flowgraph-api.md — validate convenience method
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

55
tasks/host-graphology.md Normal file
View File

@@ -0,0 +1,55 @@
---
id: host/graphology
name: Implement GraphologyHostConfig — render ujsx template to graphology DAG
status: pending
depends_on:
- component/operation
- component/sequential
- component/parallel
- component/conditional
- component/map
- graph/flowgraph-class
- schema/edge-attrs
scope: broad
risk: high
impact: phase
level: implementation
---
## Description
Implement the `GraphologyHostConfig` that renders a ujsx workflow template (`UNode` tree) into a graphology `DirectedGraph` DAG. This is the structural analysis rendering path — it validates templates by producing a DAG that can be checked for cycles, type compatibility, and topological ordering.
## Acceptance Criteria
- [ ] `src/host/graphology.ts` exports `GraphologyHostConfig` implementing ujsx `HostConfig<WorkflowTag, GraphNode, GraphContext>`
- [ ] `WorkflowTag: "operation" | "sequential" | "parallel" | "conditional" | "map"`
- [ ] `GraphNode`: `{ key: string; attributes: OperationNodeAttrs | TemplateNodeAttrs }`
- [ ] `GraphContext`: `{ graph: DirectedGraph; parentStack: string[]; operationRegistry?: OperationRegistry }`
- [ ] `createRootContext`: creates fresh `DirectedGraph` with DAG constraints, empty parentStack
- [ ] `createInstance("operation", props, ctx)`: adds graph node with `OperationNodeAttrs`, returns `GraphNode`
- [ ] `createInstance` for structural containers: returns `GraphNode` with synthetic key `__${tag}_${counter++}`, no graph node created (containers are transparent)
- [ ] `appendChild` for Sequential children: creates sequential edges between consecutive siblings (manages `parentStack`)
- [ ] `appendChild` for Parallel children: no inter-child edges, pushes parallel group marker for successor connections
- [ ] `appendChild` for Conditional: creates conditional edge with `dataFlow: true`
- [ ] Edge attributes include `edgeType` and `dataFlow` inference (conservative strategy: conditional always dataFlow: true, sequential with result references → dataFlow: true, otherwise dataFlow: false)
- [ ] `finalizeInstance`: cleans up parentStack after container children are rendered
- [ ] `removeChild`: removes edge between parent and child (structural containers are transparent)
- [ ] `removeChildFromHost`: removes child node from graph and all attached edges
- [ ] Cycle detection after rendering: if `hasCycle()` returns true, throw `CycleError`
- [ ] Re-exported from `src/host/index.ts`
- [ ] Integration tests: render Sequential → assert node/edge structure, render Parallel → assert no inter-child edges, render Conditional → assert conditional edges with dataFlow, nested compositions, cycle detection
## References
- docs/architecture/host-configs.md — GraphologyHostConfig full specification
- docs/architecture/workflow-templates.md — edge creation rules, root node handling, template→DAG conversion
- docs/architecture/schema.md — TemplateEdgeAttrs, dataFlow inference
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

50
tasks/host-reactive.md Normal file
View File

@@ -0,0 +1,50 @@
---
id: host/reactive
name: Implement ReactiveHostConfig — render ujsx template to reactive execution engine
status: pending
depends_on:
- component/operation
- component/sequential
- component/parallel
- component/conditional
- component/map
- reactive/workflow-root
- reactive/node-status
- schema/edge-attrs
scope: broad
risk: critical
impact: phase
level: implementation
---
## Description
Implement the `ReactiveHostConfig` that renders a ujsx workflow template into a reactive execution engine with signal-backed `NodeStatus` tracking, computed preconditions, and failure propagation. This is the runtime execution rendering path.
## Acceptance Criteria
- [ ] `src/host/reactive.ts` exports `ReactiveHostConfig` implementing ujsx `HostConfig<WorkflowTag, WorkflowNode, ReactiveContext>`
- [ ] `WorkflowNode`: `{ key, type, status: Signal<NodeStatus>, preconditions: Computed<boolean>, blockedByFailure: Computed<boolean>, operationId?, output?: Signal<unknown>, children: WorkflowNode[] }`
- [ ] `ReactiveContext`: `{ operationRegistry, nodes: Map, statusSignals: Map, preconditions: Map, blockedByFailure: Map, resultProjection: EventLogProjection, parentMap, siblingMap, results: Map }`
- [ ] `createInstance("operation", props, ctx)`: creates `WorkflowNode` with status signal from `ReactiveContext`, registers in context maps
- [ ] `createInstance` for structural containers: creates WorkflowNode tracking children but no graph node
- [ ] Prerequisite computation: Sequential child → previous sibling completed/skipped; Parallel child → parent's preconditions met; Conditional child → condition evaluates to true
- [ ] Status propagation: effects on `preconditions` and `blockedByFailure` drive state transitions
- [ ] `removeChild`: removes parent-child dependency, preconditions/blockedByFailure auto-re-evaluate (reactive)
- [ ] `removeChildFromHost`: disposes node's signal references from context maps
- [ ] Re-exported from `src/host/index.ts`
- [ ] Integration tests: render template → assert signal initial states, transition predecessor → assert dependent precondition updates, failure propagation, Conditional as error boundary
## References
- docs/architecture/host-configs.md — ReactiveHostConfig full specification, WorkflowNode, ReactiveContext
- docs/architecture/reactive-execution.md — signal-backed execution model, precondition computation, status propagation
- docs/architecture/workflow-templates.md — template→reactive execution conversion
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,37 @@
---
id: meta/analysis-layer
name: Complete analysis layer — type compatibility, ordering, template/graph validation, defaults
status: pending
depends_on:
- analysis/type-compat
- analysis/build-type-edges
- analysis/ordering
- analysis/template-validation
- analysis/defaults
scope: moderate
risk: medium
impact: component
level: planning
---
## Description
Meta task that clusters all analysis tasks. Once complete, the analysis layer provides type compatibility checking, execution ordering, precondition/template/graph validation, and default value resolution.
## Acceptance Criteria
- [ ] All analysis tasks completed
- [ ] `@alkdev/flowgraph/analysis` exports all analysis functions
- [ ] Analysis functions are pure, standalone, and composable
## References
- docs/architecture/analysis.md
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,37 @@
---
id: meta/component-layer
name: Complete component layer — all five ujsx workflow components
status: pending
depends_on:
- component/operation
- component/sequential
- component/parallel
- component/conditional
- component/map
scope: moderate
risk: low
impact: component
level: planning
---
## Description
Meta task that clusters all ujsx component tasks. Once complete, the `@alkdev/flowgraph/component` sub-path provides all five workflow components for template authoring.
## Acceptance Criteria
- [ ] All component tasks completed
- [ ] `@alkdev/flowgraph/component` exports Operation, Sequential, Parallel, Conditional, Map
- [ ] Each component produces correct UElement shape with WorkflowTag type
## References
- docs/architecture/workflow-templates.md
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

39
tasks/meta-graph-layer.md Normal file
View File

@@ -0,0 +1,39 @@
---
id: meta/graph-layer
name: Complete graph layer — FlowGraph class, all construction paths, queries, validation
status: pending
depends_on:
- graph/flowgraph-class
- graph/construction-operation
- graph/construction-call
- graph/construction-json
- graph/queries
- graph/validation
scope: system
risk: medium
impact: phase
level: planning
---
## Description
Meta task that clusters all graph module tasks. Once complete, the core FlowGraph class supports operation graph construction, call graph construction from events, JSON serialization, all query methods, and graph validation.
## Acceptance Criteria
- [ ] All graph tasks completed
- [ ] FlowGraph class works for both `OperationGraph` and `CallGraph` type parameterizations
- [ ] JSON round-trip is lossless
- [ ] DAG invariants enforced at construction time
## References
- docs/architecture/flowgraph-api.md, docs/architecture/operation-graph.md, docs/architecture/call-graph.md
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,38 @@
---
id: meta/reactive-layer
name: Complete reactive execution layer — WorkflowRoot, node-status, maxConcurrency, retries
status: pending
depends_on:
- reactive/workflow-root
- reactive/node-status
- reactive/max-concurrency
- reactive/retry-semantics
scope: broad
risk: high
impact: phase
level: planning
---
## Description
Meta task that clusters all reactive execution tasks. Once complete, the reactive layer provides signal-backed execution with automatic precondition resolution, failure propagation, and event-log-driven state management.
## Acceptance Criteria
- [ ] All reactive tasks completed
- [ ] WorkflowReactiveRoot implements EventLogProjection correctly
- [ ] Preconditions drive automatic state transitions
- [ ] Failure follows dependency edges, not structural scope
- [ ] dispose() prevents signal leaks
## References
- docs/architecture/reactive-execution.md
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,37 @@
---
id: meta/schema-layer
name: Complete schema layer — all enums, node/edge attributes, graph schemas, and CallResult
status: pending
depends_on:
- schema/enums
- schema/node-attrs
- schema/edge-attrs
- schema/graph-schemas
scope: broad
risk: low
impact: component
level: planning
---
## Description
Meta task that clusters all schema tasks. Once all schema tasks are complete, the entire type-safe foundation of the library is in place. Schema tasks can be executed in sequence (each depends on the prior) or with some parallelism (node-attrs depends on enums, edge-attrs depends on both, graph-schemas depends on all).
## Acceptance Criteria
- [ ] All schema tasks completed
- [ ] `@alkdev/flowgraph/schema` sub-path exports all schemas, types, and enums correctly
- [ ] `Value.Check()` validates against all schemas
- [ ] TypeScript types are correctly derived via `Static<typeof>`
## References
- docs/architecture/schema.md
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,53 @@
---
id: review/reactive-and-hosts
name: Review reactive execution and host configs — signal graph, preconditions, HostConfig implementations
status: pending
depends_on:
- reactive/workflow-root
- reactive/node-status
- reactive/max-concurrency
- reactive/retry-semantics
- host/graphology
- host/reactive
- component/operation
- component/sequential
- component/parallel
- component/conditional
- component/map
- review/foundation
scope: broad
risk: medium
impact: phase
level: review
---
## Description
Review the reactive execution layer and host config implementations before final integration. Verify signal-backed state management is correct, preconditions drive proper state transitions, failure propagation follows dependency edges, and both HostConfig implementations render templates correctly.
## Acceptance Criteria
- [ ] WorkflowReactiveRoot initializes signals correctly for all DAG nodes
- [ ] EventLogProjection correctly derives status and results from event log per ADR-005
- [ ] Computed preconditions: correct for Sequential, Parallel, Conditional, and join scenarios
- [ ] blockedByFailure: correctly propagates failures along dependency edges, NOT structural scope
- [ ] GraphologyHostConfig: Sequential → sequential edges, Parallel → no inter-child edges, Conditional → conditional edges with dataFlow
- [ ] ReactiveHostConfig: creates WorkflowNodes with correct signal references
- [ ] Conditional as error boundary: then-branch skipped, else-branch activated, downstream sees completed
- [ ] maxConcurrency semaphore limits parallel starts correctly
- [ ] Retry semantics: new requestId, projection reflects latest attempt
- [ ] dispose() cleans up all signals and effects — no leaks
- [ ] All tests pass: `npm test`
- [ ] TypeScript strict mode compilation succeeds: `npx tsc --noEmit`
## References
- docs/architecture/reactive-execution.md, docs/architecture/host-configs.md, docs/architecture/workflow-templates.md
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,38 @@
---
id: reactive/max-concurrency
name: Implement maxConcurrency semaphore for Parallel groups
status: pending
depends_on:
- reactive/node-status
- component/parallel
scope: narrow
risk: medium
impact: component
level: implementation
---
## Description
Implement the reactive counting semaphore that enforces `maxConcurrency` on Parallel groups. When the root initializes signals for nodes in a Parallel group with `maxConcurrency: N`, a node's effective `ready` transition requires both `preconditions.value === true` AND `runningCount < maxConcurrency`.
## Acceptance Criteria
- [ ] For each node in a Parallel group with `maxConcurrency`, the `canStart` computed wraps preconditions: `preconditions.value && runningSiblingCount < maxConcurrency`
- [ ] `runningSiblingCount` is a reactive computed derived from counting sibling nodes currently in `"running"` state
- [ ] When a sibling completes and a slot opens, the next ready node transitions to ready/startable
- [ ] Parallel groups without `maxConcurrency` (default): all siblings start immediately when preconditions met — no semaphore
- [ ] `maxConcurrency` is a runtime scheduling hint — the DAG doesn't encode it
- [ ] Unit tests: parallel group with maxConcurrency: 2 limits to 2 running at a time, slot opens → next node starts, no maxConcurrency → all start immediately
## References
- docs/architecture/reactive-execution.md — maxConcurrency, counting semaphore
- docs/architecture/workflow-templates.md — Parallel.maxConcurrency prop
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,42 @@
---
id: reactive/node-status
name: Implement node status signal management and computed preconditions + blockedByFailure
status: pending
depends_on:
- reactive/workflow-root
- schema/enums
scope: moderate
risk: high
impact: component
level: implementation
---
## Description
Implement the reactive node status management layer: `signal<NodeStatus>` per-node lifecycle tracking, `computed<boolean>` precondition resolution, `computed<boolean>` blockedByFailure detection, and the effects that wire them together to drive automatic state transitions.
## Acceptance Criteria
- [ ] `src/reactive/node-status.ts` exports precondition computation, blockedByFailure computation, and status transition effects
- [ ] `computePreconditions(node, ctx): boolean` — Sequential: previous sibling completed/skipped; Parallel: parent preconditions met; Conditional: condition evaluates; root nodes: true (no predecessors)
- [ ] `computeBlockedByFailure(node, ctx): boolean` — any predecessor is failed/aborted
- [ ] Start effect: `if (preconditions.value && (status === "idle" || "waiting")) → transition to "ready"`
- [ ] Abort effect: `if (blockedByFailure.value && (status === "idle" || "waiting")) → transition to "aborted"`
- [ ] `skipped` satisfies preconditions — a skipped predecessor is treated as "completed for precondition purposes"
- [ ] `failed` and `aborted` block preconditions — dependents can never become ready
- [ ] Failure follows dependency edges, not structural scope — sibling branches in Parallel are independent
- [ ] Effects are tracked by `WorkflowReactiveRoot.effectDisposers` and cleaned up by `dispose()`
- [ ] Unit tests: sequential preconditions, parallel preconditions, join (fork-join) preconditions, blockedByFailure cascade, skipped satisfies preconditions, failure isolation in parallel branches
## References
- docs/architecture/reactive-execution.md — computed preconditions, blockedByFailure, status propagation effects, failure isolation
- docs/architecture/host-configs.md — WorkflowNode, prerequisite computation
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,37 @@
---
id: reactive/retry-semantics
name: Implement retry semantics — event log append with new requestId, status projection respects retries
status: pending
depends_on:
- reactive/workflow-root
scope: narrow
risk: medium
impact: component
level: implementation
---
## Description
Implement the retry semantics where retries are natural append events. A retry creates a new `call.requested` with a new requestId, and the status projection derives the current state by scanning for the most recent event per node. No `retried` status or state mutation needed.
## Acceptance Criteria
- [ ] `nodeKeyToRequestId.set(nodeKey, newRequestId)` overwrites the previous requestId — the projection tracks the latest attempt
- [ ] `getResult()` derives from the most recent terminal event (responded/error/aborted) for the current requestId
- [ ] Retry sequence: `call.error(requestId=1)``call.requested(requestId=2)``call.responded(requestId=2)` → status is "completed" (from latest event)
- [ ] Previous attempt events preserved in `eventLog` — full history maintained
- [ ] Conditional.test and Map.over see the latest result including retry outcomes
- [ ] Unit tests: retry sequence produces correct final status, getResult reflects latest attempt, event log preserves full history
## References
- docs/architecture/reactive-execution.md — retry semantics, event-to-status mapping
- docs/architecture/schema.md — CallEventMapValue
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,50 @@
---
id: reactive/workflow-root
name: Implement WorkflowReactiveRoot — signal graph, EventLogProjection, lifecycle, abort, dispose
status: pending
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

View File

@@ -0,0 +1,51 @@
---
id: review/complete-library
name: Final review — validate full library against architecture docs, build, and exports
status: pending
depends_on:
- api/public-exports
- review/foundation
- review/reactive-and-hosts
scope: broad
risk: low
impact: project
level: review
---
## Description
Final review of the complete library. Verify the full API surface matches architecture docs, all construction paths work, reactive execution is correct, and the library achieves its purpose: DAG-based operation orchestration with ujsx template composition and reactive execution.
## Acceptance Criteria
- [ ] Public API matches [flowgraph-api.md](../docs/architecture/flowgraph-api.md) exactly — no missing exports, no extra exports
- [ ] All construction paths work: fromSpecs, fromCallEvents, fromJSON, incremental
- [ ] Operation graph: correct node and edge structure, type-compatibility edges
- [ ] Call graph: correct event processing, status transitions, abort cascading
- [ ] Analysis functions: typeCompat produces correct results for compatible/incompatible/unknown schemas
- [ ] Template validation: catches missing operations, cycles, type mismatches
- [ ] GraphologyHostConfig: renders templates to correct DAG structure
- [ ] ReactiveHostConfig: renders templates to correct signal graph
- [ ] WorkflowReactiveRoot: signal lifecycle, event log projection, abort, dispose all work
- [ ] Conditional as error boundary: failure caught, else-branch activated
- [ ] Consumer integration walkthrough per [consumer-integration.md](../docs/architecture/consumer-integration.md) is executable
- [ ] `npm run build` produces correct ESM + CJS + declarations for all entry points
- [ ] `npm pack` produces valid package with correct exports
- [ ] All tests pass: `npm test`
- [ ] TypeScript strict mode compilation succeeds: `npx tsc --noEmit`
- [ ] No gray-matter, no js-yaml, no Zod in dependencies
- [ ] Test coverage > 90% for src/
## References
- docs/architecture/README.md — full overview
- docs/architecture/consumer-integration.md — end-to-end walkthrough
- docs/architecture/build-distribution.md — package structure, build configuration
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,51 @@
---
id: review/foundation
name: Review foundation layer — schemas, errors, FlowGraph class, construction
status: pending
depends_on:
- schema/enums
- schema/node-attrs
- schema/edge-attrs
- schema/graph-schemas
- error/hierarchy
- graph/flowgraph-class
- graph/construction-operation
- graph/construction-call
- graph/construction-json
- graph/queries
- graph/validation
scope: broad
risk: low
impact: phase
level: review
---
## Description
Review the foundation layer before proceeding to analysis components, host configs, and reactive execution. Verify schemas match architecture docs, errors are correctly structured, and FlowGraph construction preserves DAG invariants.
## Acceptance Criteria
- [ ] All TypeBox schemas match [schema.md](../docs/architecture/schema.md) — no missing fields, no extra fields
- [ ] Error hierarchy matches [error-handling.md](../docs/architecture/error-handling.md) — all classes have correct properties
- [ ] FlowGraph class wraps graphology correctly per [flowgraph-api.md](../docs/architecture/flowgraph-api.md)
- [ ] Operation graph construction: fromSpecs builds correct nodes and edges
- [ ] Call graph construction: fromCallEvents and updateFromEvent process all event types correctly
- [ ] JSON round-trip is lossless for both operation and call graphs
- [ ] All query methods delegate correctly to graphology-dag
- [ ] Validation functions return structured errors, never throw
- [ ] All tests pass: `npm test`
- [ ] TypeScript strict mode compilation succeeds: `npx tsc --noEmit`
## References
- docs/architecture/schema.md, docs/architecture/error-handling.md, docs/architecture/flowgraph-api.md
- docs/architecture/operation-graph.md, docs/architecture/call-graph.md
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,43 @@
---
id: schema/edge-attrs
name: Define edge attribute schemas (Operation, Triggered, Dependency, Template) and CallResult
status: pending
depends_on:
- schema/enums
- schema/node-attrs
scope: narrow
risk: low
impact: component
level: implementation
---
## Description
Define all edge attribute schemas and the CallResult schema. Edge schemas are mode-specific (they do NOT include the universal `edgeType` field — that's stored separately in graphology alongside the mode-specific attributes). TemplateNodeAttrs is a type alias for OperationNodeAttrs.
## Acceptance Criteria
- [ ] `src/schema/edge.ts` exports all edge schemas and types
- [ ] `OperationEdgeAttrs`: `compatible` (boolean), optional `detail` (string), optional `mismatches` (Array of {path, expected, actual})
- [ ] `TriggeredEdgeAttrs`: empty object `Type.Object({})`
- [ ] `DependencyEdgeAttrs`: empty object `Type.Object({})`
- [ ] `CallEdgeAttrs`: union type `TriggeredEdgeAttrs | DependencyEdgeAttrs` (discriminated by `edgeType` at runtime)
- [ ] `TemplateEdgeAttrs`: `edgeType` (union of "sequential" | "conditional"), optional `condition` (Unknown), optional `negated` (boolean), optional `dataFlow` (boolean with default false)
- [ ] `TemplateNodeAttrs`: type alias for `OperationNodeAttrs` (template nodes carry the same attributes as operation nodes)
- [ ] `CallResultSchema`: `status` (NodeStatusEnum), `output` (Unknown), optional `error` ({code, message, details?})
- [ ] `CallResult`: type alias via `Static<typeof CallResultSchema>`
- [ ] `src/schema/index.ts` re-exports all edge schemas, CallResult, and TemplateNodeAttrs
- [ ] Unit tests for each schema: valid/invalid shapes, optional fields
## References
- docs/architecture/schema.md — full edge attribute definitions, CallResultSchema, TemplateNodeAttrs, edge key conventions
- docs/architecture/workflow-templates.md — TemplateEdgeAttrs.condition semantics (string vs function)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

44
tasks/schema-enums.md Normal file
View File

@@ -0,0 +1,44 @@
---
id: schema/enums
name: Define TypeBox categorical enum schemas and type aliases
status: pending
depends_on:
- setup/project-init
scope: narrow
risk: trivial
impact: component
level: implementation
---
## Description
Define all categorical enum schemas using `Type.Union([Type.Literal(...)])` pattern per [schema.md](../docs/architecture/schema.md). Each enum gets a schema constant (PascalCase + `Enum` suffix) and a `Static<typeof>` type alias (PascalCase, no suffix). Also include the `Nullable` helper.
The enums: `CallStatusEnum`, `NodeStatusEnum`, `OperationTypeEnum`, `EdgeTypeEnum`.
## Acceptance Criteria
- [ ] `src/schema/enums.ts` exports all four enum schemas and their type aliases
- [ ] Each enum uses `Type.Union([Type.Literal("value"), ...])` pattern per typebox conventions
- [ ] `CallStatusEnum`: `"pending" | "running" | "completed" | "failed" | "aborted"` with transitions documented in JSDoc
- [ ] `NodeStatusEnum`: `"idle" | "waiting" | "ready" | "running" | "completed" | "failed" | "skipped" | "aborted"`
- [ ] `OperationTypeEnum`: `"query" | "mutation" | "subscription"`
- [ ] `EdgeTypeEnum`: `"triggered" | "depends_on" | "typed" | "sequential" | "conditional"`
- [ ] Type aliases derived via `Static<typeof>`: `CallStatus`, `NodeStatus`, `OperationType`, `EdgeType`
- [ ] Naming convention matches spec: `Enum` suffix on schema constants only, never on type aliases
- [ ] `Nullable` helper exported: `const Nullable = <T extends TSchema>(schema: T) => Type.Union([schema, Type.Null()])`
- [ ] `src/schema/index.ts` re-exports all schemas and types
- [ ] Unit tests for each enum: `Value.Check()` validation, compile-time type alias verification
## References
- docs/architecture/schema.md — enum definitions, naming convention, nullable helper
- docs/architecture/reactive-execution.md — NodeStatus semantics and transitions
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,39 @@
---
id: schema/graph-schemas
name: Define SerializedGraph factory and OperationGraphSerialized/CallGraphSerialized schemas
status: pending
depends_on:
- schema/node-attrs
- schema/edge-attrs
scope: narrow
risk: low
impact: component
level: implementation
---
## Description
Define the generic `SerializedGraph` factory function that produces graphology native JSON format schemas, and the two specialized serialization types for operation graphs and call graphs.
## Acceptance Criteria
- [ ] `src/schema/graph.ts` exports `SerializedGraph` factory function
- [ ] `SerializedGraph<N, E, G>`: generic factory producing `Type.Object` with `attributes` (GraphAttrs), `options` ({type: "directed", multi: false, allowSelfLoops: false}), `nodes` (Array of {key, attributes}), `edges` (Array of {key, source, target, attributes})
- [ ] `OperationGraphSerialized`: `SerializedGraph(OperationNodeAttrs, OperationEdgeAttrs, Type.Object({}))` — no graph-level attributes
- [ ] `CallGraphSerialized`: `SerializedGraph(CallNodeAttrs, CallEdgeAttrs, Type.Object({}))` — no graph-level attributes
- [ ] `FlowGraphSerialized` type alias for the general case (used by `fromJSON`)
- [ ] Edge key convention documented: `${source}->${target}` for simple cases, `${source}->${target}:${edgeType}` for call graph depends_on edges
- [ ] `src/schema/index.ts` re-exports graph schemas
- [ ] Unit tests: `Value.Check()` against valid and invalid serialized graph data
## References
- docs/architecture/schema.md — SerializedGraph factory, FlowGraphSerialized variants, edge key convention
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,37 @@
---
id: schema/node-attrs
name: Define OperationNodeAttrs and CallNodeAttrs TypeBox schemas
status: pending
depends_on:
- schema/enums
scope: narrow
risk: trivial
impact: component
level: implementation
---
## Description
Define the node attribute schemas for both operation graph nodes and call graph nodes. These are the TypeBox schemas that serve as single source of truth for runtime validation and TypeScript type derivation.
## Acceptance Criteria
- [ ] `src/schema/node.ts` exports `OperationNodeAttrs` and `CallNodeAttrs` schemas with `Static<typeof>` type aliases
- [ ] `OperationNodeAttrs`: `name` (string), `namespace` (string), `version` (string), `type` (OperationTypeEnum), `inputSchema` (Unknown), `outputSchema` (Unknown), optional `description`, optional `tags` (Array<String>)
- [ ] `CallNodeAttrs`: `requestId` (string), `operationId` (string), `status` (CallStatusEnum), optional `parentRequestId` (string), `input` (Unknown), optional `output` (Unknown), optional `error` (Object with code/message/optional details), optional `identity` (Object with id/scopes/optional resources), optional `startedAt` (string), optional `completedAt` (string)
- [ ] Both schemas produce correct TypeScript types via `Static<typeof>`
- [ ] `src/schema/index.ts` re-exports all node schemas and types
- [ ] Unit tests: `Value.Check()` against valid and invalid attribute shapes
## References
- docs/architecture/schema.md — OperationNodeAttrs, CallNodeAttrs full definitions
- docs/architecture/call-graph.md — CallNodeAttrs field mappings to call events
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,50 @@
---
id: setup/project-init
name: Initialize project with package.json, tsconfig, build tooling, and source skeleton
status: pending
depends_on: []
scope: moderate
risk: low
impact: project
level: implementation
---
## Description
Set up the TypeScript project from scratch. The repo currently has only `AGENTS.md` and `docs/`. Initialize everything needed for a pure TypeScript ESM library targeting DAG-based workflow orchestration.
Per [build-distribution.md](../docs/architecture/build-distribution.md):
- Package name: `@alkdev/flowgraph`
- ESM primary, CJS compat via tsup
- Targets: Node 18+, Deno, Bun, Browser (pure JS, no native addons)
- Build: `tsup` for ESM + CJS + declarations
- Dependencies: `graphology`, `graphology-dag`, `@alkdev/typebox`, `@alkdev/ujsx`, `@preact/signals-core`
- Peer dependencies: `@alkdev/operations`
## Acceptance Criteria
- [ ] `package.json` exists with name `@alkdev/flowgraph`, ESM primary (`"type": "module"`), full exports map per build-distribution spec
- [ ] All production dependencies listed: `graphology`, `graphology-dag`, `@alkdev/typebox`, `@alkdev/ujsx`, `@preact/signals-core`
- [ ] Peer dependency: `@alkdev/operations`
- [ ] Dev dependencies include: `typescript`, `vitest`, `@vitest/coverage-v8`, `tsup`, `@types/node`
- [ ] `tsconfig.json` configured for ES2022 target, Node16 module resolution, strict mode with `noUncheckedIndexedAccess`, `noUnusedLocals`, `noUnusedParameters`, `noFallthroughCasesInSwitch`, `erasableSyntaxOnly`
- [ ] `tsup.config.ts` with named entry points matching exports map (index, component/index, host/index, schema/index, graph/index, reactive/index, analysis/index, error/index)
- [ ] `vitest.config.ts` with `@` alias, globals, V8 coverage
- [ ] `.gitignore` covers `node_modules/`, `dist/`, `*.js.map`
- [ ] `src/` directory skeleton created per build-distribution spec with all module directories and empty index.ts barrel files
- [ ] `test/` directory with placeholder test files per module structure
- [ ] `npm install` succeeds without errors
- [ ] `npx tsc --noEmit` succeeds (empty source files, but config is valid)
- [ ] `npm run build` succeeds via tsup (produces dist/ output with ESM + CJS + .d.ts)
## References
- docs/architecture/build-distribution.md — project structure, dependencies, exports map, tsup config, tsconfig, vitest config
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion

View File

@@ -0,0 +1,39 @@
---
id: setup/test-infrastructure
name: Set up vitest test infrastructure with fixtures, helpers, and reactive test patterns
status: pending
depends_on:
- setup/project-init
scope: narrow
risk: low
impact: component
level: implementation
---
## Description
Create the test infrastructure that all downstream test files will depend on: shared fixtures, helper functions for graph construction, and the reactive test pattern (create root → transition → assert → dispose). This ensures consistent test setup across all modules.
Per [build-distribution.md](../docs/architecture/build-distribution.md) testing strategy section.
## Acceptance Criteria
- [ ] `test/helpers/` directory with shared test utilities
- [ ] `test/helpers/graph-factory.ts` — helpers to build test operation graphs and call graphs with known structures
- [ ] `test/helpers/reactive.ts` — helper to create `WorkflowReactiveRoot` instances for testing: setup → transition → assert → dispose pattern
- [ ] `test/helpers/schemas.ts` — sample TypeBox schemas for testing `typeCompat()` (compatible pairs, incompatible pairs, unknown schemas)
- [ ] All helpers are importable from `test/helpers/`
- [ ] `vitest.config.ts` includes `test/helpers/` in setup or alias configuration
## References
- docs/architecture/build-distribution.md — testing strategy, reactive test patterns
- docs/architecture/reactive-execution.md — WorkflowReactiveRoot lifecycle (setup → assert → dispose)
## Notes
> To be filled by implementation agent
## Summary
> To be filled on completion