resolve architecture review round 2: criticals, warnings, suggestions
- C-05: Add flowgraph-api.md with complete public API surface - C-06: Document <Map> component in workflow-templates.md - C-07: Specify Conditional else-branch behavior - C-08: Add lifecycle/ownership section to reactive-execution.md - C-09: Add consumer-integration.md end-to-end walkthrough - W-02: Add reactive error boundary semantics (3 levels) - W-03: Complete ReactiveContext interface definition - W-04: Add template composition rules (8 rules) - W-05: Document removeChild for both HostConfigs - W-06: Document signal/effect disposal lifecycle - W-07: Add ADR-004 (no schema version field) - W-08: Add type compatibility depth/contract to analysis.md - W-11: Add performance characteristics section - S-01: Getting Started merged into consumer-integration.md - S-02: Add flow diagrams for template rendering pipeline - S-03: Add node status state machine diagram - S-04: Add testing strategy section - S-06: Validate source structure cross-references Review round 2 fixes: - Define TemplateNodeAttrs as alias for OperationNodeAttrs - Document CallEventMapValue and CallResult types in schema.md - Standardize CycleError naming (replace CircularDependencyError) - Add function form to Map.over type definition - Define Map aggregate completion/failure semantics - Fix immutability claim for fromCallEvents - Clarify edgeType storage alongside OperationEdgeAttrs - Clarify WorkflowNode.status === statusMap (same Signal) - Add component-to-tag mapping for WorkflowTag
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
---
|
||||
status: draft
|
||||
last_updated: 2026-05-19
|
||||
last_updated: 2026-05-20
|
||||
---
|
||||
|
||||
# Schema
|
||||
@@ -99,6 +99,53 @@ type NodeStatus = Static<typeof NodeStatusEnum>;
|
||||
|
||||
**Precondition semantics**: A predecessor in `completed` or `skipped` status satisfies a dependent's preconditions. A predecessor in `failed` or `aborted` status does NOT satisfy preconditions — it blocks the dependent and triggers failure propagation (the dependent transitions to `aborted`). This enables partial success: independent parallel branches continue running even when one branch fails.
|
||||
|
||||
### CallResult
|
||||
|
||||
The result of a completed call, used by `Conditional.test` and `Map.over` to access predecessor outputs:
|
||||
|
||||
```typescript
|
||||
interface CallResult {
|
||||
status: NodeStatus; // Status of the call (completed, failed, aborted, skipped)
|
||||
output: unknown; // Call output (if completed)
|
||||
error?: { // Call error (if failed)
|
||||
code: string;
|
||||
message: string;
|
||||
details?: unknown;
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
`CallResult` is the value in the `results` map passed to `Conditional.test` and `Map.over` functions. It's derived from `CallNodeAttrs` but simplified for template use — it omits `requestId`, `operationId`, `identity`, and timestamps, preserving only what template logic needs.
|
||||
|
||||
### OperationTypeEnum
|
||||
|
||||
The type of an operation, determining its call semantics:
|
||||
|
||||
```typescript
|
||||
const OperationTypeEnum = Type.Union([
|
||||
Type.Literal("query"), // Read-only, idempotent
|
||||
Type.Literal("mutation"), // Side effects, not idempotent
|
||||
Type.Literal("subscription"), // Streaming, produces multiple results
|
||||
]);
|
||||
type OperationType = Static<typeof OperationTypeEnum>;
|
||||
```
|
||||
|
||||
This enum is used in `OperationNodeAttrs.type` to classify operations by their call behavior.
|
||||
|
||||
### CallEventMapValue
|
||||
|
||||
`CallEventMapValue` is imported from `@alkdev/operations` (peer dependency). It represents a single call protocol event — the union type of all event types (`CallRequestedEvent | CallRespondedEvent | CallErrorEvent | CallAbortedEvent | CallCompletedEvent`). The full definition lives in `@alkdev/operations/src/call.ts`.
|
||||
|
||||
Flowgraph's `fromCallEvents()` and `updateFromEvent()` accept this type directly. The mapping from `CallEventMapValue` to `CallNodeAttrs` is:
|
||||
|
||||
| Event type | Action |
|
||||
|------------|--------|
|
||||
| `call.requested` | Add node with `status: "pending"`, add `triggered` edge if `parentRequestId` present |
|
||||
| `call.responded` | Update node status to `completed`, set `output` and `completedAt` |
|
||||
| `call.error` | Update node status to `failed`, set `error` and `completedAt` |
|
||||
| `call.aborted` | Update node status to `aborted`, set `completedAt` |
|
||||
| `call.completed` | Update node status to `completed`, set `completedAt` (if not already set) |
|
||||
|
||||
### EdgeType
|
||||
|
||||
The type of edge in a flowgraph. Matches the call graph storage schema's `edgeType` column:
|
||||
@@ -196,6 +243,17 @@ 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.
|
||||
|
||||
**Edge type storage**: Operation graph edges always have `edgeType: "typed"` stored on the edge as a separate attribute alongside `OperationEdgeAttrs`. Graphology edges carry both the `OperationEdgeAttrs` (compatible, compatibilityDetail) and the `edgeType` field. The `edgeType` is not inside `OperationEdgeAttrs` because it's a universal edge classification that applies to all edge types across all graph modes (operation, call, template). The `OperationEdgeAttrs` schema only defines the mode-specific attributes.
|
||||
|
||||
```typescript
|
||||
// How operation graph edges are stored in graphology:
|
||||
{
|
||||
edgeType: "typed", // Universal classification (stored alongside attrs)
|
||||
compatible: true, // OperationEdgeAttrs field
|
||||
compatibilityDetail: "..." // OperationEdgeAttrs field
|
||||
}
|
||||
```
|
||||
|
||||
**Naming note**: Previously named `TypedEdgeAttrs`. Renamed to follow the `{GraphType}EdgeAttrs` pattern used by `CallEdgeAttrs` and `TemplateEdgeAttrs`.
|
||||
|
||||
### TriggeredEdgeAttrs (Call Graph)
|
||||
@@ -236,6 +294,18 @@ type TemplateEdgeAttrs = Static<typeof TemplateEdgeAttrs>;
|
||||
|
||||
Template edges carry an `edgeType` to distinguish sequential flow from conditional branching. Conditional edges optionally store a `condition` that determines whether the target node executes.
|
||||
|
||||
### TemplateNodeAttrs (Workflow Templates)
|
||||
|
||||
Template DAGs use `OperationNodeAttrs` for their operation nodes — the template doesn't need a separate node type because every node in a template DAG corresponds to an operation invocation. The template's structural information (`Sequential`, `Parallel`, `Conditional`, `Map`) is expressed through edges, not through special node types.
|
||||
|
||||
```typescript
|
||||
// Template DAGs use OperationNodeAttrs for operation nodes
|
||||
type TemplateNodeAttrs = OperationNodeAttrs;
|
||||
// This alias makes the intent explicit: a template node represents an operation invocation
|
||||
```
|
||||
|
||||
The separation between `OperationNodeAttrs` and `TemplateNodeAttrs` is a type alias for clarity. In the template context, each node carries the same attributes as an operation node (name, namespace, type, input/output schemas), but with template-specific edges (sequential, conditional) rather than type-compatibility edges (typed).
|
||||
|
||||
## SerializedGraph Factory
|
||||
|
||||
Following the taskgraph pattern, a generic factory for graphology native JSON format:
|
||||
|
||||
Reference in New Issue
Block a user