resolve mechanical architecture review issues (C-01,C-02,C-03,W-01,W-09,W-10,W-12)

- C-01: fix broken README link (call-graph-runtime.md → call-graph.md)
- C-02: add CallEdgeAttrs union type alias in schema.md
- C-03/W-12: rename TypedEdgeAttrs → OperationEdgeAttrs for consistent
  {GraphType}EdgeAttrs naming pattern, update all references
- W-01: standardize terminology — prerequisites=structural/graph,
  preconditions=reactive/computed, rename WorkflowNode.prerequisites
  to preconditions, rename computePrerequisites to computePreconditions
- W-09: update ADR-001/002/003 status from Proposed to Accepted
- W-10: clarify call graph mutation API — addCall creates triggered
  edges automatically, addDependency creates depends_on edges
- update review checklist with resolved items
This commit is contained in:
2026-05-19 11:09:06 +00:00
parent 037dfec44b
commit c5e649cc9f
11 changed files with 47 additions and 35 deletions

View File

@@ -53,7 +53,7 @@ Flowgraph is in Phase 0/1 (exploration → architecture). No code exists yet. Th
|----------|---------| |----------|---------|
| [schema.md](schema.md) | TypeBox Module, TypeScript types, enums (CallStatus, EdgeType, NodeStatus), node/edge attribute schemas, SerializedGraph factory | | [schema.md](schema.md) | TypeBox Module, TypeScript types, enums (CallStatus, EdgeType, NodeStatus), node/edge attribute schemas, SerializedGraph factory |
| [operation-graph.md](operation-graph.md) | Static graph from OperationSpecs, type-compatibility edges, construction paths, validation | | [operation-graph.md](operation-graph.md) | Static graph from OperationSpecs, type-compatibility edges, construction paths, validation |
| [call-graph-runtime.md](call-graph-runtime.md) | Dynamic graph from call events, node lifecycle, abort cascading, fromCallEvents construction | | [call-graph.md](call-graph.md) | Dynamic graph from call events, node lifecycle, abort cascading, fromCallEvents construction |
| [workflow-templates.md](workflow-templates.md) | ujsx components (`<Operation>`, `<Sequential>`, `<Parallel>`, `<Conditional>`), template→DAG hydration, serialization | | [workflow-templates.md](workflow-templates.md) | ujsx components (`<Operation>`, `<Sequential>`, `<Parallel>`, `<Conditional>`), template→DAG hydration, serialization |
| [host-configs.md](host-configs.md) | Graphology HostConfig (template→DAG analysis), Reactive HostConfig (template→execution engine), Instance types | | [host-configs.md](host-configs.md) | Graphology HostConfig (template→DAG analysis), Reactive HostConfig (template→execution engine), Instance types |
| [reactive-execution.md](reactive-execution.md) | Signal-driven status propagation, computed preconditions, abort cascade via signals, ReactiveRoot integration | | [reactive-execution.md](reactive-execution.md) | Signal-driven status propagation, computed preconditions, abort cascade via signals, ReactiveRoot integration |
@@ -107,7 +107,7 @@ src/
schema/ schema/
enums.ts # CallStatus, NodeStatus, EdgeType, OperationType enums.ts # CallStatus, NodeStatus, EdgeType, OperationType
node.ts # OperationNodeAttributes, CallNodeAttributes node.ts # OperationNodeAttributes, CallNodeAttributes
edge.ts # TypeCompatEdgeAttrs, ParentChildEdgeAttrs, DependencyEdgeAttrs edge.ts # OperationEdgeAttrs, CallEdgeAttrs, TemplateEdgeAttrs
graph.ts # FlowGraphSerialized (graphology export format) graph.ts # FlowGraphSerialized (graphology export format)
index.ts index.ts
graph/ graph/

View File

@@ -25,7 +25,7 @@ Package structure, exports map, dependencies, and platform targets.
│ ├── schema/ │ ├── schema/
│ │ ├── enums.ts # CallStatus, EdgeType, NodeCategory, NodeStatus │ │ ├── enums.ts # CallStatus, EdgeType, NodeCategory, NodeStatus
│ │ ├── node.ts # OperationNodeAttrs, CallNodeAttrs │ │ ├── node.ts # OperationNodeAttrs, CallNodeAttrs
│ │ ├── edge.ts # TypedEdgeAttrs, CallEdgeAttrs, TemplateEdgeAttrs │ │ ├── edge.ts # OperationEdgeAttrs, CallEdgeAttrs, TemplateEdgeAttrs
│ │ ├── graph.ts # SerializedGraph, FlowGraphSerialized │ │ ├── graph.ts # SerializedGraph, FlowGraphSerialized
│ │ └── index.ts │ │ └── index.ts
│ ├── graph/ │ ├── graph/

View File

@@ -209,12 +209,14 @@ Payload fields (`input`, `output`, `error`) are stored as-is in the graph. The h
```typescript ```typescript
// Add a call node (from call.requested event) // Add a call node (from call.requested event)
// If attrs.parentRequestId is set, also creates a triggered edge from parent to child
addCall(attrs: CallNodeAttrs): void addCall(attrs: CallNodeAttrs): void
// Update call status (from call.responded/error/aborted/completed event) // Update call status (from call.responded/error/aborted/completed event)
updateStatus(requestId: string, status: CallStatus, extra?: Partial<CallNodeAttrs>): void updateStatus(requestId: string, status: CallStatus, extra?: Partial<CallNodeAttrs>): void
// Add a dependency edge (explicit, not auto-populated) // Add a dependency edge (explicit, not auto-populated by call protocol)
// Creates an edge with edgeType: "depends_on"
addDependency(source: string, target: string): void addDependency(source: string, target: string): void
// Remove a call node and its edges // Remove a call node and its edges
@@ -224,7 +226,7 @@ removeCall(requestId: string): void
updateCall(requestId: string, attrs: Partial<CallNodeAttrs>): void updateCall(requestId: string, attrs: Partial<CallNodeAttrs>): void
``` ```
`updateStatus` validates the transition. `addDependency` validates that both endpoints exist. `removeCall` removes the node and all attached edges (graphology cascade). `addCall` is the primary entry point for populating the call graph from call events. When `attrs.parentRequestId` is present, it automatically creates a `triggered` edge from the parent to the new node. `addDependency` creates explicit `depends_on` edges that represent data dependencies not captured by the parent-child hierarchy. `updateStatus` validates the transition. `addDependency` validates that both endpoints exist and that the edge would not create a cycle. `removeCall` removes the node and all attached edges (graphology cascade).
## Constraints ## Constraints

View File

@@ -2,7 +2,7 @@
## Status ## Status
Proposed Accepted
## Context ## Context

View File

@@ -2,7 +2,7 @@
## Status ## Status
Proposed Accepted
## Context ## Context

View File

@@ -2,7 +2,7 @@
## Status ## Status
Proposed Accepted
## Context ## Context

View File

@@ -172,7 +172,7 @@ interface WorkflowNode {
key: string; // Operation name or structural container ID key: string; // Operation name or structural container ID
type: "operation" | "sequential" | "parallel" | "conditional" | "map"; type: "operation" | "sequential" | "parallel" | "conditional" | "map";
status: Signal<NodeStatus>; // Reactive status signal status: Signal<NodeStatus>; // Reactive status signal
prerequisites: Computed<boolean>; // Computed: true when all prerequisites are met preconditions: Computed<boolean>; // Computed: true when all preconditions are met
operationId?: string; // For operation nodes: the fully qualified ID operationId?: string; // For operation nodes: the fully qualified ID
output?: Signal<unknown>; // For operation nodes: the call result (when completed) output?: Signal<unknown>; // For operation nodes: the call result (when completed)
children: WorkflowNode[]; // Child nodes (structural containers have children) children: WorkflowNode[]; // Child nodes (structural containers have children)
@@ -181,7 +181,7 @@ interface WorkflowNode {
Each `WorkflowNode` holds: Each `WorkflowNode` holds:
- A `signal<NodeStatus>` that tracks the call's lifecycle (`idle``waiting``ready``running``completed`/`failed`/`aborted`/`skipped`) - A `signal<NodeStatus>` that tracks the call's lifecycle (`idle``waiting``ready``running``completed`/`failed`/`aborted`/`skipped`)
- A `computed` that derives `prerequisites` from parent nodes' statuses - A `computed` that derives `preconditions` from parent nodes' statuses
- An optional `output` signal that holds the call result when completed - An optional `output` signal that holds the call result when completed
### ReactiveContext ### ReactiveContext
@@ -204,7 +204,7 @@ createInstance(tag: WorkflowTag, props, ctx: ReactiveContext, parent?: WorkflowN
key, key,
type: tag, type: tag,
status, status,
prerequisites: computed(() => computePrerequisites(node, ctx)), preconditions: computed(() => computePreconditions(node, ctx)),
children: [], children: [],
}; };
@@ -222,14 +222,14 @@ createInstance(tag: WorkflowTag, props, ctx: ReactiveContext, parent?: WorkflowN
### Prerequisite Computation ### Prerequisite Computation
The `prerequisites` computed signal for each node derives from its structural context: The `preconditions` computed signal for each node derives from its structural context:
- **Sequential child**: prerequisites = previous sibling is `completed` - **Sequential child**: preconditions = previous sibling is `completed`
- **Parallel child**: prerequisites = parent's prerequisites are met - **Parallel child**: preconditions = parent's preconditions are met
- **Conditional child**: prerequisites = parent's prerequisites are met AND condition evaluates to true - **Conditional child**: preconditions = parent's preconditions are met AND condition evaluates to true
```typescript ```typescript
function computePrerequisites(node: WorkflowNode, ctx: ReactiveContext): boolean { function computePreconditions(node: WorkflowNode, ctx: ReactiveContext): boolean {
// Sequential: previous sibling must be completed // Sequential: previous sibling must be completed
// Parallel: parent must be ready // Parallel: parent must be ready
// Conditional: condition must evaluate to true // Conditional: condition must evaluate to true
@@ -243,11 +243,11 @@ function computePrerequisites(node: WorkflowNode, ctx: ReactiveContext): boolean
### Status Propagation ### Status Propagation
When a node's `status` signal changes, its dependents' `prerequisites` computed automatically re-evaluate. If prerequisites are met, the node transitions to `ready`: When a node's `status` signal changes, its dependents' `preconditions` computed automatically re-evaluate. If preconditions are met, the node transitions to `ready`:
```typescript ```typescript
effect(() => { effect(() => {
if (node.prerequisites.value) { if (node.preconditions.value) {
node.status.value = "ready"; node.status.value = "ready";
} }
}); });
@@ -314,7 +314,7 @@ For flowgraph, this is acceptable in v1 because:
The current design where `Sequential`, `Parallel`, and `Conditional` don't create graph nodes is clean for the DAG, but creates complexity for the reactive engine — the "previous sibling" precondition depends on understanding the structural context, which isn't stored on the node itself. The current design where `Sequential`, `Parallel`, and `Conditional` don't create graph nodes is clean for the DAG, but creates complexity for the reactive engine — the "previous sibling" precondition depends on understanding the structural context, which isn't stored on the node itself.
Alternative: Create "virtual" nodes for structural containers that hold `signal<NodeStatus>` but don't correspond to graph nodes. This makes the reactive engine simpler (every node has a status and prerequisites) at the cost of a slightly larger node tree. Alternative: Create "virtual" nodes for structural containers that hold `signal<NodeStatus>` but don't correspond to graph nodes. This makes the reactive engine simpler (every node has a status and preconditions) at the cost of a slightly larger node tree.
### Conditional Test Evaluation ### Conditional Test Evaluation
@@ -331,7 +331,7 @@ The `Conditional.test` prop can be a function or a string. At the template level
## Open Questions ## Open Questions
1. **Should structural containers create "virtual" nodes in the reactive engine?** This would simplify prerequisite computation (every node has a status) but adds nodes that don't correspond to calls or operations. 1. **Should structural containers create "virtual" nodes in the reactive engine?** This would simplify precondition computation (every node has a status) but adds nodes that don't correspond to calls or operations.
2. **Should the GraphologyHostConfig produce a separate graph for edge types?** Currently all edge types (`sequential`, `conditional`, `typed`) share the same graph. An alternative is a separate graph per edge type, enabling type-specific queries without filtering. 2. **Should the GraphologyHostConfig produce a separate graph for edge types?** Currently all edge types (`sequential`, `conditional`, `typed`) share the same graph. An alternative is a separate graph per edge type, enabling type-specific queries without filtering.

View File

@@ -179,7 +179,7 @@ See [analysis.md](analysis.md) for the full type-compatibility algorithm.
## References ## References
- Schema: [schema.md](schema.md) — `OperationNodeAttrs`, `TypedEdgeAttrs`, `CallStatus`, `EdgeType` - Schema: [schema.md](schema.md) — `OperationNodeAttrs`, `OperationEdgeAttrs`, `CallStatus`, `EdgeType`
- Type compatibility: [analysis.md](analysis.md) - Type compatibility: [analysis.md](analysis.md)
- Call graph: [call-graph.md](call-graph.md) - Call graph: [call-graph.md](call-graph.md)
- Operation types: `@alkdev/operations/src/types.ts` - Operation types: `@alkdev/operations/src/types.ts`

View File

@@ -182,18 +182,20 @@ The node key is `requestId`. This matches the call protocol's correlation mechan
## Edge Attribute Schemas ## Edge Attribute Schemas
### TypedEdgeAttrs (Operation Graph) ### OperationEdgeAttrs (Operation Graph)
```typescript ```typescript
const TypedEdgeAttrs = Type.Object({ const OperationEdgeAttrs = Type.Object({
compatible: Type.Boolean({ description: "Whether the source output schema is compatible with the target input schema" }), compatible: Type.Boolean({ description: "Whether the source output schema is compatible with the target input schema" }),
compatibilityDetail: Type.Optional(Type.String({ description: "Human-readable description of compatibility or mismatch" })), compatibilityDetail: Type.Optional(Type.String({ description: "Human-readable description of compatibility or mismatch" })),
}); });
type TypedEdgeAttrs = Static<typeof TypedEdgeAttrs>; type OperationEdgeAttrs = Static<typeof OperationEdgeAttrs>;
``` ```
Type-compatibility edges carry a boolean `compatible` flag and optional detail. This allows the operation graph to include both compatible edges (green paths) and incompatible edges (red paths) for diagnostics. Type-compatibility edges carry a boolean `compatible` flag and optional detail. This allows the operation graph to include both compatible edges (green paths) and incompatible edges (red paths) for diagnostics.
**Naming note**: Previously named `TypedEdgeAttrs`. Renamed to follow the `{GraphType}EdgeAttrs` pattern used by `CallEdgeAttrs` and `TemplateEdgeAttrs`.
### TriggeredEdgeAttrs (Call Graph) ### TriggeredEdgeAttrs (Call Graph)
```typescript ```typescript
@@ -212,6 +214,14 @@ type DependencyEdgeAttrs = Static<typeof DependencyEdgeAttrs>;
Data dependency edges also carry no additional attributes. Future extensions may include `dataPath` (which field of the output feeds which field of the input). Data dependency edges also carry no additional attributes. Future extensions may include `dataPath` (which field of the output feeds which field of the input).
### CallEdgeAttrs (Call Graph Union)
```typescript
type CallEdgeAttrs = TriggeredEdgeAttrs | DependencyEdgeAttrs;
```
A union type used as the edge attribute type parameter for call graphs (`FlowGraph<CallNodeAttrs, CallEdgeAttrs>`). Call graph edges can be either `triggered` (parent-child) or `depends_on` (data dependency), distinguished by their edge type. The union type follows the `{GraphType}EdgeAttrs` naming pattern consistent with `OperationEdgeAttrs` and `TemplateEdgeAttrs`.
### TemplateEdgeAttrs (Workflow Templates) ### TemplateEdgeAttrs (Workflow Templates)
```typescript ```typescript
@@ -267,13 +277,13 @@ Two specialized serialization types, one for each graph type:
```typescript ```typescript
const OperationGraphSerialized = SerializedGraph( const OperationGraphSerialized = SerializedGraph(
OperationNodeAttrs, OperationNodeAttrs,
TypedEdgeAttrs, OperationEdgeAttrs,
Type.Object({}), // No graph-level attributes Type.Object({}), // No graph-level attributes
); );
const CallGraphSerialized = SerializedGraph( const CallGraphSerialized = SerializedGraph(
CallNodeAttrs, CallNodeAttrs,
Type.Union([TriggeredEdgeAttrs, DependencyEdgeAttrs]), CallEdgeAttrs,
Type.Object({}), // No graph-level attributes Type.Object({}), // No graph-level attributes
); );
``` ```

View File

@@ -165,7 +165,7 @@ The HostConfig maps ujsx component types to graphology operations:
### Edge creation rules ### Edge creation rules
- **Sequential**: For children C1, C2, ..., Cn, edges C1→C2, C2→C3, ..., C(n-1)→Cn are added. Within a sequential group, children have implicit `depends_on` edges. - **Sequential**: For children C1, C2, ..., Cn, edges C1→C2, C2→C3, ..., C(n-1)→Cn are added. Within a sequential group, children have implicit `depends_on` edges.
- **Parallel**: No edges between children. All children have the same prerequisites as the parallel group itself. - **Parallel**: No edges between children. All children have the same preconditions as the parallel group itself.
- **Conditional**: Edge from the conditional node's prerequisite to the first child of the branch, with `edgeType: "conditional"` and `condition` attribute. - **Conditional**: Edge from the conditional node's prerequisite to the first child of the branch, with `edgeType: "conditional"` and `condition` attribute.
- **Nested**: A `Sequential` inside a `Parallel` has its own internal edges. A `Parallel` inside a `Sequential` creates a subgraph where all parallel children share the same predecessor. - **Nested**: A `Sequential` inside a `Parallel` has its own internal edges. A `Parallel` inside a `Sequential` creates a subgraph where all parallel children share the same predecessor.
@@ -265,7 +265,7 @@ Validation returns an array of `ValidationError` objects (never throws). See [an
- **`Operation` props are workflow metadata** — `name`, `input`, `retries`, `timeout` are NOT passed to the HostConfig's `createInstance`. They're workflow-level configuration that the reactive execution engine uses to configure the call. - **`Operation` props are workflow metadata** — `name`, `input`, `retries`, `timeout` are NOT passed to the HostConfig's `createInstance`. They're workflow-level configuration that the reactive execution engine uses to configure the call.
- **Function props are not serializable** — `Conditional.test` with a function cannot be round-tripped through JSON. Use string references for stored templates. - **Function props are not serializable** — `Conditional.test` with a function cannot be round-tripped through JSON. Use string references for stored templates.
- **Sequential ordering is structural, not temporal** — a `Sequential` group means "these operations should complete in order", not "start the next only after the previous completes" (though the reactive engine implements this via preconditions). - **Sequential ordering is structural, not temporal** — a `Sequential` group means "these operations should complete in order", not "start the next only after the previous completes" (though the reactive engine implements this via preconditions).
- **Parallel has no structural edges** — a `Parallel` group produces no DAG edges between its children. The execution engine starts them concurrently when the group's prerequisites are met. - **Parallel has no structural edges** — a `Parallel` group produces no DAG edges between its children. The execution engine starts them concurrently when the group's preconditions are met.
- **Conditional branches are either/or** — a `Conditional` node renders to one branch or the `else` branch. There's no "both" evaluation. - **Conditional branches are either/or** — a `Conditional` node renders to one branch or the `else` branch. There's no "both" evaluation.
## Open Questions ## Open Questions

View File

@@ -270,16 +270,16 @@ Strong separation of concerns argument. The consequence "The hub must keep its s
When addressing these issues, use this checklist to track progress: When addressing these issues, use this checklist to track progress:
- [ ] C-01: Fix README cross-reference link - [x] C-01: Fix README cross-reference link
- [ ] C-02: Add `CallEdgeAttrs` type alias to schema.md - [x] C-02: Add `CallEdgeAttrs` type alias to schema.md
- [ ] C-03: Resolve `OperationEdgeAttrs` vs `TypedEdgeAttrs` naming - [x] C-03: Resolve `OperationEdgeAttrs` vs `TypedEdgeAttrs` naming (renamed `TypedEdgeAttrs``OperationEdgeAttrs`)
- [ ] C-04: Specify failure propagation semantics in reactive-execution.md - [ ] C-04: Specify failure propagation semantics in reactive-execution.md
- [ ] C-05: Create FlowGraph public API document - [ ] C-05: Create FlowGraph public API document
- [ ] C-06: Document `<Map>` component in workflow-templates.md - [ ] C-06: Document `<Map>` component in workflow-templates.md
- [ ] C-07: Specify `Conditional` else-branch behavior - [ ] C-07: Specify `Conditional` else-branch behavior
- [ ] C-08: Specify `WorkflowReactiveRoot``ReactiveHostConfig` ownership - [ ] C-08: Specify `WorkflowReactiveRoot``ReactiveHostConfig` ownership
- [ ] C-09: Create consumer integration guide - [ ] C-09: Create consumer integration guide
- [ ] W-01: Standardize `prerequisites` vs `preconditions` terminology - [x] W-01: Standardize `prerequisites` vs `preconditions` terminology (prerequisites=structural/graph, preconditions=reactive/computed)
- [ ] W-02: Add reactive error boundary semantics - [ ] W-02: Add reactive error boundary semantics
- [ ] W-03: Complete `ReactiveContext` interface definition - [ ] W-03: Complete `ReactiveContext` interface definition
- [ ] W-04: Add template composition rules - [ ] W-04: Add template composition rules
@@ -287,10 +287,10 @@ When addressing these issues, use this checklist to track progress:
- [ ] W-06: Document signal/effect disposal lifecycle - [ ] W-06: Document signal/effect disposal lifecycle
- [ ] W-07: Consider ADR-004 for "no schema version" - [ ] W-07: Consider ADR-004 for "no schema version"
- [ ] W-08: Specify type compatibility depth - [ ] W-08: Specify type compatibility depth
- [ ] W-09: Update ADR statuses to Accepted - [x] W-09: Update ADR statuses to Accepted
- [ ] W-10: Clarify call graph mutation API (`addDependencyEdge`) - [x] W-10: Clarify call graph mutation API (clarified `addCall` creates `triggered` edges automatically, `addDependency` creates `depends_on` edges)
- [ ] W-11: Add performance characteristics section - [ ] W-11: Add performance characteristics section
- [ ] W-12: Standardize edge attribute naming pattern - [x] W-12: Standardize edge attribute naming pattern (now `{GraphType}EdgeAttrs`: `OperationEdgeAttrs`, `CallEdgeAttrs`, `TemplateEdgeAttrs`)
- [ ] S-01: Getting Started walkthrough document - [ ] S-01: Getting Started walkthrough document
- [ ] S-02: Flow diagrams for template rendering pipeline - [ ] S-02: Flow diagrams for template rendering pipeline
- [ ] S-03: Node status state machine diagram - [ ] S-03: Node status state machine diagram