Link Progeny signals to execution graph lineage

This commit is contained in:
Daniel Maddern 2026-08-15 17:11:41 +07:00
parent 090aa32583
commit 4699ca667c
3 changed files with 55 additions and 0 deletions

View file

@ -0,0 +1,29 @@
from __future__ import annotations
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("agents", "0004_progenysignal"),
("graph", "0003_graphapproval"),
]
operations = [
migrations.AddField(
model_name="progenysignal",
name="execution_graph_version",
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="graph.executiongraphversion"),
),
migrations.AddField(
model_name="progenysignal",
name="graph_node_run",
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="graph.graphnoderun"),
),
migrations.AddField(
model_name="progenysignal",
name="graph_run",
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to="graph.graphrun"),
),
]

View file

@ -88,6 +88,9 @@ class ProgenySignal(TimestampedModel):
task = models.ForeignKey("projects.Task", on_delete=models.SET_NULL, null=True, blank=True) task = models.ForeignKey("projects.Task", on_delete=models.SET_NULL, null=True, blank=True)
milestone = models.ForeignKey("projects.Milestone", on_delete=models.SET_NULL, null=True, blank=True) milestone = models.ForeignKey("projects.Milestone", on_delete=models.SET_NULL, null=True, blank=True)
agent_version = models.ForeignKey(AgentVersion, on_delete=models.SET_NULL, null=True, blank=True) agent_version = models.ForeignKey(AgentVersion, on_delete=models.SET_NULL, null=True, blank=True)
graph_run = models.ForeignKey("graph.GraphRun", on_delete=models.SET_NULL, null=True, blank=True)
graph_node_run = models.ForeignKey("graph.GraphNodeRun", on_delete=models.SET_NULL, null=True, blank=True)
execution_graph_version = models.ForeignKey("graph.ExecutionGraphVersion", on_delete=models.SET_NULL, null=True, blank=True)
source = models.CharField(max_length=80) source = models.CharField(max_length=80)
severity = models.CharField(max_length=32, default="INFO") severity = models.CharField(max_length=32, default="INFO")
failure_category = models.CharField(max_length=80, blank=True) failure_category = models.CharField(max_length=80, blank=True)

View file

@ -2,6 +2,7 @@ from __future__ import annotations
import pytest import pytest
from control_plane.agents.models import ProgenySignal
from graph.models import ExecutionGraphDefinition, ExecutionGraphVersion, ExecutionGraphVersionStatus, GraphRun, GraphRunStatus from graph.models import ExecutionGraphDefinition, ExecutionGraphVersion, ExecutionGraphVersionStatus, GraphRun, GraphRunStatus
from graph.registry import NodeHandlerRegistry, NodeResult from graph.registry import NodeHandlerRegistry, NodeResult
from graph.spec import ExecutionGraphSpec, outgoing_edges from graph.spec import ExecutionGraphSpec, outgoing_edges
@ -67,3 +68,25 @@ def test_graph_models_persist_versioned_run_state() -> None:
assert run.execution_graph_version.graph.name == "task_execution" assert run.execution_graph_version.graph.name == "task_execution"
assert run.execution_graph_version.status == ExecutionGraphVersionStatus.CHAMPION assert run.execution_graph_version.status == ExecutionGraphVersionStatus.CHAMPION
assert run.metadata["node_count"] == 12 assert run.metadata["node_count"] == 12
def test_progeny_signal_can_reference_graph_lineage() -> None:
spec = task_execution_graph_v1()
definition = ExecutionGraphDefinition.objects.create(name="lineage_graph", graph_type=spec.graph_type)
version = ExecutionGraphVersion.objects.create(graph=definition, version=1, status=ExecutionGraphVersionStatus.CHAMPION, graph_spec=spec.to_dict())
run = GraphRun.objects.create(execution_graph_version=version, current_node=spec.entry)
node_run = run.node_runs.create(node_id="coder", node_type="coder", visit_index=1)
signal = ProgenySignal.objects.create(
source="runtime",
severity="high",
failure_category="MODEL_OUTPUT_INVALID",
summary="Malformed model JSON",
graph_run=run,
graph_node_run=node_run,
execution_graph_version=version,
)
assert signal.graph_run == run
assert signal.graph_node_run == node_run
assert signal.execution_graph_version == version