fix build/distribution spec: npm deps not workspace, align configs with sibling projects, resolve review issues
- Replace workspace:* deps with published npm semver ranges (^0.34.49, ^0.1.0) - Expand package.json: add description, publishConfig, scripts, engines, devDependencies, conditional exports with types/default for import+require - Fix tsup entry names (path-prefixed like ujsx), add target: es2022, remove splitting:true (not used by sibling projects) - Align tsconfig with sibling projects: add lib, noUncheckedIndexedAccess, noUnusedLocals, noUnusedParameters, erasableSyntaxOnly, etc. - Expand vitest.config.ts with include, coverage, and path alias - Clarify @preact/signals-core as direct dep (not just transitive via ujsx) - Clarify @alkdev/pubsub is a consumer dependency, not flowgraph's dep - Fix edge key convention: document composite key format for call graph's multi-edge-type scenario (triggered + depends_on between same pair) - Align OperationEdgeAttrs field naming: use detail+mismatches consistently instead of compatibilityDetail - Add InvalidInputError to error hierarchy (referenced in flowgraph-api but was missing) - Fix undefined attrs.category reference in reactive-execution.md - Remove internal drafting note from host-configs.md - Fix ReactiveHostConfig constructor signature inconsistency across docs - Constrain TemplateEdgeAttrs.edgeType to sequential|conditional only
This commit is contained in:
@@ -148,7 +148,7 @@ Flowgraph's `fromCallEvents()` and `updateFromEvent()` accept this type directly
|
||||
|
||||
### EdgeType
|
||||
|
||||
The type of edge in a flowgraph. Matches the call graph storage schema's `edgeType` column:
|
||||
The type of edge in a flowgraph. Matches the call graph storage schema's `edgeType` column. This is a universal enum that covers all graph modes (operation, call, template), but each graph mode uses only a subset:
|
||||
|
||||
```typescript
|
||||
const EdgeTypeEnum = Type.Union([
|
||||
@@ -161,15 +161,19 @@ const EdgeTypeEnum = Type.Union([
|
||||
type EdgeType = Static<typeof EdgeTypeEnum>;
|
||||
```
|
||||
|
||||
The first three (`triggered`, `depends_on`) match the call graph storage schema. The last two (`sequential`, `conditional`) are template-specific and only exist in workflow template DAGs.
|
||||
|
||||
| Edge Type | Graph Type | Meaning |
|
||||
| Edge Type | Graph Mode | Meaning |
|
||||
|-----------|------------|---------|
|
||||
| `triggered` | Call graph | Parent call triggered child call. Corresponds to `parentRequestId`. |
|
||||
| `depends_on` | Call graph | Data dependency — source needs target's result. |
|
||||
| `typed` | Operation graph | Type compatibility — source's output schema is compatible with target's input schema. |
|
||||
| `sequential` | Template → DAG | Sequential ordering from `<Sequential>` component. |
|
||||
| `conditional` | Template → DAG | Conditional branch from `<Conditional>` component. |
|
||||
| `sequential` | Template DAG | Sequential ordering from `<Sequential>` component. |
|
||||
| `conditional` | Template DAG | Conditional branch from `<Conditional>` component. |
|
||||
|
||||
`EdgeTypeEnum` is the universal enumeration. Each graph mode constrains its edge types through its specific edge attribute schemas:
|
||||
|
||||
- **Operation graphs** only use `typed` edges (`OperationEdgeAttrs`)
|
||||
- **Call graphs** use `triggered` and `depends_on` edges (`CallEdgeAttrs`)
|
||||
- **Template DAGs** use `sequential` and `conditional` edges (`TemplateEdgeAttrs`)
|
||||
|
||||
## Node Attribute Schemas
|
||||
|
||||
@@ -236,21 +240,27 @@ The node key is `requestId`. This matches the call protocol's correlation mechan
|
||||
```typescript
|
||||
const OperationEdgeAttrs = Type.Object({
|
||||
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" })),
|
||||
detail: Type.Optional(Type.String({ description: "Human-readable description of compatibility or mismatch" })),
|
||||
mismatches: Type.Optional(Type.Array(Type.Object({ // Structured mismatch details (populated when compatible: false)
|
||||
path: Type.String(),
|
||||
expected: Type.String(),
|
||||
actual: Type.String(),
|
||||
}))),
|
||||
});
|
||||
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, an optional `detail` string, and optional structured `mismatches`. This allows the operation graph to include both compatible edges (green paths) and incompatible edges (red paths) for diagnostics. The `detail` field provides a human-readable summary, while `mismatches` provides machine-readable field-level diagnostics. The `TypeCompatResult` from `typeCompat()` populates both fields: `detail` for compatible edges and `mismatches` for incompatible ones.
|
||||
|
||||
**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.
|
||||
**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, detail, mismatches) 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
|
||||
detail: "classify.output → enrich.input", // OperationEdgeAttrs field
|
||||
mismatches: [] // Empty when compatible
|
||||
}
|
||||
```
|
||||
|
||||
@@ -286,7 +296,7 @@ A union type used as the edge attribute type parameter for call graphs (`FlowGra
|
||||
|
||||
```typescript
|
||||
const TemplateEdgeAttrs = Type.Object({
|
||||
edgeType: EdgeTypeEnum, // "sequential" or "conditional"
|
||||
edgeType: Type.Union([Type.Literal("sequential"), Type.Literal("conditional")]),
|
||||
condition: Type.Optional(Type.Unknown()), // For conditional edges: the condition function or expression
|
||||
});
|
||||
type TemplateEdgeAttrs = Static<typeof TemplateEdgeAttrs>;
|
||||
@@ -294,6 +304,8 @@ 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.
|
||||
|
||||
**Note**: `TemplateEdgeAttrs.edgeType` uses a constrained union of `"sequential" | "conditional"` rather than the full `EdgeTypeEnum`. Template DAGs never have `triggered`, `depends_on`, or `typed` edges — those belong to call graphs and operation graphs respectively.
|
||||
|
||||
### 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.
|
||||
@@ -372,14 +384,17 @@ ${source}->${target}
|
||||
|
||||
For the operation graph, this means keys like `"task.classify->task.enrich"`. For the call graph, keys like `"req_abc123->req_def456"`.
|
||||
|
||||
Since `multi: false`, there can be at most one edge between any (source, target) pair. When multiple edge types are needed between the same pair (e.g., both `triggered` and `depends_on` between two calls), the graph stores a single edge whose `edgeType` attribute captures the semantic relationship. This is a simplification from the storage schema, which allows multiple edges per (source, target, edgeType) triple — the in-memory graph collapses these into a single edge per (source, target) pair.
|
||||
When multiple edge types exist between the same (source, target) pair (e.g., in the call graph where both `triggered` and `depends_on` edges can connect the same calls), a composite key format is used:
|
||||
|
||||
This is acceptable because:
|
||||
- Operation graphs only have `typed` edges, so no multi-edge concern.
|
||||
- Call graphs rarely have both `triggered` and `depends_on` between the same pair.
|
||||
- Template DAGs only have `sequential` or `conditional` edges.
|
||||
```
|
||||
${source}->${target}:${edgeType}
|
||||
```
|
||||
|
||||
If multi-edge support becomes necessary, the `allowSelfLoops: false` constraint can be relaxed and a composite key format (`${source}->${target}:${edgeType}`) adopted.
|
||||
For example, a `depends_on` edge in the call graph uses `"req_abc123->req_def456:depends_on"` while the `triggered` edge between the same pair uses `"req_abc123->req_def456"`.
|
||||
|
||||
Since `multi: false`, there can be at most one edge per key. The composite key format ensures deterministic keys even when multiple edge types connect the same pair.
|
||||
|
||||
This is an exception to the simple `${source}->${target}` pattern, but it's necessary for the call graph's dual-edge-type scenario. If multi-edge support becomes more broadly needed, the constraint can be relaxed and a uniform composite key format adopted.
|
||||
|
||||
## Constraints
|
||||
|
||||
|
||||
Reference in New Issue
Block a user