Document execution graph architecture

This commit is contained in:
Daniel Maddern 2026-08-15 17:12:47 +07:00
parent 4699ca667c
commit e300e13e1a

View file

@ -0,0 +1,204 @@
# Execution Graph Architecture
Date: 2026-08-15
## Implemented Architecture
Artifex now has two intentionally separate graph concepts.
Project DAG remains the canonical representation of what work exists:
- `Project`
- `Milestone`
- `Feature`
- `Task`
- `TaskDependency`
Execution Graph is now the canonical representation of how autonomous work is performed. It is runtime-neutral and persisted in Django/Postgres.
## Graph Domain Models
Implemented graph domain models:
- `ExecutionGraphDefinition`
- `ExecutionGraphVersion`
- `GraphRun`
- `GraphNodeRun`
- `GraphEdgeTraversal`
- `GraphApproval`
Execution graph version statuses:
- `DRAFT`
- `CHALLENGER`
- `CHAMPION`
- `RETIRED`
Graph run statuses:
- `PENDING`
- `RUNNING`
- `PAUSED`
- `COMPLETE`
- `FAILED`
- `CANCELLED`
Node runs persist status, timing, input/output metadata, failure evidence, telemetry, optional agent version, and optional model request reference.
Edge traversals persist selected conditional transitions.
## Graph Specification
Graph specs are serializable dictionaries with:
- name
- version
- graph type
- entry node
- nodes
- edges
- conditional edge labels
- terminal nodes
- metadata
Specs do not execute arbitrary Python. Node execution resolves through `NodeHandlerRegistry`.
## TaskExecutionGraph V1
`TaskExecutionGraph v1` mirrors the prior `AutonomousTaskLoop` behavior.
Nodes:
- `claim_task`
- `prepare_worktree`
- `build_context`
- `coder`
- `run_tests`
- `review`
- `judge`
- `commit`
- `retry_or_fail`
- `cleanup`
- `complete`
- `fail`
Important semantics preserved:
- deterministic test failure still reaches Reviewer
- Reviewer failure goes to retry/fail
- Judge failure goes to retry/fail
- maximum semantic task attempts remains three total attempts
- commit is guarded against duplicate commits on resume
- CoderToolLoop remains inside the `coder` node
## NativeGraphRuntime
`NativeGraphRuntime` is the reference implementation.
It supports:
- conditional edges
- loops
- persisted graph runs
- persisted node runs
- edge traversal history
- checkpoint/resume at major node boundaries
- terminal success/failure
- pause state
- cancellation
- graph events
- bounded metadata
Django/Postgres remains canonical for task, attempt, worktree, test, review, judge, commit, event, agent, and Progeny state.
## AutonomousTaskLoop Delegation
`AutonomousTaskLoop` still uses `TaskScheduler` to claim Project DAG work.
After a task is claimed, it now creates a `GraphRun` for the champion `TaskExecutionGraph v1` and delegates task lifecycle execution to `NativeGraphRuntime`.
The scheduler remains Project-DAG-oriented. The execution runtime handles task-attempt workflow.
## LangGraphRuntime
`LangGraphRuntime` is no longer a pure placeholder. It builds a LangGraph `StateGraph` from Artifex graph definitions when the `langgraph` package is installed.
Artifex remains runtime-neutral:
- Artifex owns graph definitions
- Artifex owns persisted graph state
- Artifex owns node contracts
- LangGraph is an execution backend
Current limitation: the local environment used during implementation did not have `langgraph` installed, so deterministic tests validate the adapter boundary and missing-dependency behavior. Full LangGraph execution parity requires installing the declared `langgraph>=0.2,<0.3` dependency in local/Spark environments.
## Checkpoint And Resume
Coarse checkpointing is implemented at graph node boundaries.
Resume behavior avoids repeating a completed interrupted node. Loop re-entry creates a new `GraphNodeRun` visit via `visit_index`.
Irreversible commit behavior is guarded by checking for an existing `CommitRecord` for the task before creating a new commit.
## Human Approval
Graph approval support is implemented with `GraphApproval`.
A node can pause the graph with `AWAITING_APPROVAL`. A signal can approve pending graph approvals and resume execution.
This is intentionally minimal and prepares future gates for risky migrations, deployment, Progeny promotion, destructive infrastructure changes, and project plan approvals.
## Subgraph Support
The graph spec supports runtime-neutral subgraph representation through node metadata.
CoderToolLoop is not moved into a subgraph yet. It remains inside the `coder` node.
## Graph Inspection
`graph_run_inspection()` exposes UI-ready JSON containing:
- graph/version
- node list
- edges
- node statuses
- current node
- durations
- failures
- selected edge traversals
This is sufficient for a future visual execution graph UI.
## Progeny Integration
`ProgenySignal` can now reference:
- `graph_run`
- `graph_node_run`
- `execution_graph_version`
This enables future investigations such as:
- failures by graph version
- failures by node type
- patch success rate by workflow version
- Reviewer rework changes after inserting a verification node
## Migrations
New migrations:
- `graph/0001_initial.py`
- `graph/0002_graphnoderun_visit_index.py`
- `graph/0003_graphapproval.py`
- `projects/0003_commitrecord_graph_run.py`
- `agents/0005_progenysignal_graph_lineage.py`
## Known Limitations
- Full LangGraph parity execution is implemented but not exercised in this environment because `langgraph` is not installed.
- Parallel branch execution is represented by the graph model but not executed concurrently by `NativeGraphRuntime`.
- Subgraph support is represented in the spec but not yet expanded into nested `GraphRun` execution.
- CoderToolLoop remains attempt-granularity for checkpointing.
- Graph telemetry is persisted at node level, but model request references are not yet automatically linked to individual node runs.
- Event Bus records graph facts but is not an orchestration engine.