Graph#

Layer 4: Extend Framework

Placing Component contracts into execution order and data relationships produces a ComponentGraph. ComponentGraph is an immutable graph holding that placement. ComponentContract, which holds the contract tree, and ComponentGraph, which holds execution relationships between nodes, are separate structures.

ComponentGraph’s role#

ComponentGraph owns the boundary that places Component contracts into execution order and data relationships. It separates the contract tree held by ComponentContract from the node relationships held by the Graph and passes a self-contained structure to the Compiler.

Nodes and references#

ComponentNode holds a Component instance, component ID, role, resolved services, and a contract snapshot for compilation. NodeRef references a node by component ID and optional role, normalizing endpoints for edges and StateBindings. NodeRef distinguishes connection targets even when the same Component is placed under different roles.

Edges and state#

DataEdge is a data connection from a source port to a target port. ControlEdge passes no data; it is a control dependency that makes source completion precede target execution. StateBinding connects a node to actual typed StateKeys, mapping the contract’s state declarations to runtime state.

The Graph holds nodes, edges, state bindings, and entry points as values.

Structured regions#

StructuredRegion holds nested Sequence, Repeat, Loop, and Branch structures together with the state effects read by the region. A Loop is not represented as an ordinary Graph cycle; it is held in a form whose condition and region effects the Compiler can verify. After lowering a structured region, the mapping between the execution tree passed to ExecutablePlan and its state effects remains intact.

Construction time and use time#

The Graph is created when a Pipeline or Graph builder places Components. The Compiler reads contract snapshots and verifies entry points, edge endpoints, port compatibility, state bindings, and structured regions. When a Compiler rule changes the Graph during Resolution, it declares the changed locations as claims; undeclared changes and conflicts become Diagnostics.

Invariants and diagnostics#

The Graph holds nodes, edges, state bindings, and entry points as values; endpoints referring to unknown nodes become Diagnostics such as invalid_graph_edge or invalid_entry_point. Undeclared changes or conflicts from resolution rules become unclaimed_rewrite or conflicting_rewrite Diagnostics.

Extension points#

from saealib.core import ComponentContract, ComponentGraph
from saealib.core import ComponentNode


class Empty:
    def contract(self) -> ComponentContract:
        return ComponentContract()


node = ComponentNode(component_id="root", component=Empty())
graph = ComponentGraph(nodes=(node,), entry_points=("root",))

This example creates a Graph with one node as its entry point. See the API reference for building actual ports and edges with the public API. See Framework extensions when adding Graph connection rules. Preserve endpoint and entry-point invariants and do not bypass Compiler verification.

References#