Metadata-Version: 2.4
Name: dr-graph
Version: 0.1.1
Summary: Hashable graph configs with deterministic traversal and caller-supplied node behavior.
Project-URL: Repository, https://github.com/danielle-rothermel/dr-graph
Project-URL: Issues, https://github.com/danielle-rothermel/dr-graph/issues
Author-email: Danielle Rothermel <danielle.rothermel@gmail.com>
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: dr-serialize<0.2.0,>=0.1.2
Requires-Dist: pydantic>=2.13.4
Description-Content-Type: text/markdown

# dr-graph

[![CI](https://github.com/danielle-rothermel/dr-graph/actions/workflows/ci.yml/badge.svg)](https://github.com/danielle-rothermel/dr-graph/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/dr-graph.svg)](https://pypi.org/project/dr-graph/)

| [Terms and contracts](https://danielle-rothermel.github.io/dr-graph/) | [Terms TOML](https://github.com/danielle-rothermel/dr-graph/blob/main/.defs/terms.toml) | [Contracts TOML](https://github.com/danielle-rothermel/dr-graph/blob/main/.defs/contracts.toml) | [dr-serialize](https://github.com/danielle-rothermel/dr-serialize) |
| --- | --- | --- | --- |

**dr-graph represents hashable computation graphs as data and interprets them
deterministically.** Graph structure is separate from caller-supplied node
behavior.

- **[Definitions](https://github.com/danielle-rothermel/dr-graph/tree/main/src/dr_graph/definitions)**
  describe reusable graph topology, node fields, dependencies, and variable
  requirements.
- **[Configuration](https://github.com/danielle-rothermel/dr-graph/tree/main/src/dr_graph/configuration)**
  models concrete variable values and validates the resulting graph.
- **[Identity](https://github.com/danielle-rothermel/dr-graph/tree/main/src/dr_graph/identity)**
  gives every complete graph configuration a stable, versioned identity.
- **[Execution](https://github.com/danielle-rothermel/dr-graph/tree/main/src/dr_graph/execution)**
  interprets a graph in topological order while delegating node behavior to
  the caller.
- **[Results](https://github.com/danielle-rothermel/dr-graph/tree/main/src/dr_graph/results)**
  models per-node and graph-level outcomes, including reuse of completed node
  outputs when continuing execution.
- **Infra**
  - **[Assembly](https://github.com/danielle-rothermel/dr-graph/tree/main/src/dr_graph/assembly)**
    creates graphs programmatically, including deterministic namespacing and
    rewiring of subgraphs.
  - **[Core](https://github.com/danielle-rothermel/dr-graph/tree/main/src/dr_graph/core)**
    contains shared errors, field and input-source models, topology helpers,
    and strict-JSON validation.

The following sketches show the public contract shapes. Validation and
implementation details are omitted.

## Definitions

Definitions describe reusable graph topology before concrete variable values
are supplied. Materialization binds those values and produces an executable
graph configuration.

```python
class NodeDefinition(BaseModel):
    node_id: str
    node_type: str
    fields: tuple[NodeFieldSpec, ...]
    input_sources: dict[str, NodeInputSourceRef]
    output_field: str
    variable_names: frozenset[str]


class GraphDefinition(BaseModel):
    schema_version: Literal[1] = 1
    nodes: tuple[NodeDefinition, ...]
    terminal_node_id: str
```

```python
def materialize(
    self,
    variable_assignments: Mapping[str, Mapping[str, Any]] | None = None,
) -> GraphConfig: ...
```

## Configuration

Configurations are complete, validated graphs with concrete values. Their
dependency structure has a deterministic topological order.

```python
class NodeConfig(BaseModel):
    node_id: str
    node_type: str
    fields: tuple[NodeFieldSpec, ...]
    input_sources: dict[str, NodeInputSourceRef]
    output_field: str
    variables: dict[str, Any]


class GraphConfig(BaseModel):
    nodes: tuple[NodeConfig, ...]
    terminal_node_id: str

    def topological_order(self) -> tuple[NodeConfig, ...]: ...
```

```python
def validate_graph_external_inputs(
    graph: GraphConfig,
    *,
    allowed_fields: Collection[str],
) -> None: ...
```

## Identity

Every static configuration field participates in a versioned canonical
identity document. `dr-serialize` turns that document into the graph's full
SHA-256 hash.

```python
GRAPH_CONFIG_IDENTITY_SCHEMA = "dr_graph.graph_config"
GRAPH_CONFIG_IDENTITY_SCHEMA_VERSION = 1


def graph_config_identity_document(
    graph: GraphConfig,
) -> IdentityDocument: ...


def graph_hash(graph: GraphConfig) -> str: ...
```

## Execution

Execution owns graph traversal and dependency wiring while the caller owns
node behavior. A dependency-closed set of completed node outputs may be
supplied to continue execution.

```python
type RunNode = Callable[
    [NodeConfig, Mapping[str, Any]],
    NodeOutput | Mapping[str, Any],
]
```

```python
def execute_graph(
    *,
    graph: GraphConfig,
    inputs: Mapping[str, Any],
    run_node: RunNode,
    completed: Mapping[str, NodeOutput | Mapping[str, Any]] | None = None,
) -> GraphRunResult: ...
```

## Results

Results distinguish node outcomes from the aggregate graph outcome and retain
enough structured state to inspect or continue a run.

```python
class NodeOutcomeStatus(StrEnum):
    SUCCESS = "success"
    ERROR = "error"
    BLOCKED = "blocked"


class GraphRunStatus(StrEnum):
    SUCCESS = "success"
    ERROR = "error"
    BLOCKED = "blocked"
```

```python
class NodeOutput(BaseModel):
    values: dict[str, Jsonable]
    metadata: dict[str, Jsonable]


class NodeOutcome(BaseModel):
    node_id: str
    status: NodeOutcomeStatus
    output: NodeOutput | None
    error: NodeError | None
    blocked_by: tuple[str, ...]
```

```python
class GraphRunResult(BaseModel):
    graph_hash: str
    external_inputs: dict[str, Jsonable]
    status: GraphRunStatus
    outcomes: dict[str, NodeOutcome]
    execution_order: tuple[str, ...]
    terminal_node_id: str
    terminal_output: Jsonable
    terminal_error: TerminalError | None
    attempt_evidence_refs: tuple[str, ...]
    provenance: dict[str, Jsonable]
```
