Hierarchical Graphs¶
TopoExec provides a phase-1 hierarchy contract for organizing larger in-process graphs without introducing nested runtime schedulers.
Phase-1 model¶
subgraphs[] are compile-time namespace expansions:
- each subgraph has an
id; - local
components[],edges[], and optionalcomposite_loops[]are parsed with the same schema-v1 rules as top-level graph entries; - component, edge, and CompositeLoop ids expand to
<subgraph>.<local_id>; - edge endpoints expand by prefixing the component part only, so
source.outbecomescell.source.out; depends_oncomponent references and subgraph-local CompositeLoop component references expand the same way;- lanes remain top-level and runtime execution sees one flat
GraphSpec.
This is intentionally not a CompositeComponent runtime, nested executor, dynamic
graph loader, or adapter boundary. Reusable snippets are handled separately by
Graph templates; future components[].graph_ref or runtime
template loading must be a separate compatibility decision.
Example¶
schema_version: 1
graph: {name: hierarchical_preview, kind: internal_test}
lanes: {main: {type: event_loop}}
components: []
edges: []
subgraphs:
- id: cell
components:
- id: source
type: topoexec.test.Source
event_sources: [{type: manual}]
trigger_policy: {type: manual}
execution: {lane: main}
- id: sink
type: topoexec.test.Sink
event_sources: [{type: message, inputs: [in]}]
trigger_policy: {type: any_input, inputs: [in]}
execution: {lane: main}
depends_on: [source]
edges:
- id: source_sink
kind: immediate
from: source.out
to: sink.in
policy: {mode: latest, copy_policy: shared_view}
The loader expands this to components cell.source and cell.sink, edge
cell.source_sink, endpoints cell.source.out and cell.sink.in, and a
hierarchy entry in plan JSON.
Validation and tooling¶
Hierarchy never hides graph semantics:
- immediate-cycle validation runs after expansion, so a feedback loop inside or across a subgraph is rejected unless a matching expanded CompositeLoop owns the SCC;
- descriptor-backed port validation uses the last
.as the endpoint separator, allowing namespaced component ids while preservingcomponent.portbehavior; - runtime metrics, trace events, ticked components, and channel ids use expanded
ids such as
cell.sinkandcell.source_sink; - plan JSON includes a
hierarchy[]section with expanded component, edge, and CompositeLoop ids; - Mermaid rendering groups expanded components under
Subgraph: <id>while still showing expanded component-level edges.
Phase 1 keeps hierarchy observable and semantic, but deliberately avoids runtime nesting or hidden feedback-loop policy.