feat(investigation): preserve cumulative reference graphs

Accumulate investigation paths and preserve failed attempts across rounds. Keep graph annotations separate from execution state, synchronize the API contract, and consolidate documentation.
This commit is contained in:
2026-11-11 19:10:41 +08:00
parent e47c61c121
commit b853b61a0b
38 changed files with 2445 additions and 147 deletions
@@ -0,0 +1,27 @@
import pytest
from pydantic import ValidationError
from app.domain.schemas.operational_task import InvestigationDiagramNodeRef, InvestigationGraphUpdate
@pytest.mark.parametrize("status", ["reference", "recorded", "needs_input", "failed", "not_taken"])
def test_graph_updates_only_describe_reference_steps_and_recorded_outcomes(status):
update = InvestigationGraphUpdate.model_validate({"nodes": [{"node_id": "check", "label": "核查", "status": status}]})
assert update.nodes[0].status == status
@pytest.mark.parametrize("legacy,expected", [
("pending", "reference"), ("running", "reference"), ("completed", "recorded"),
("waiting", "needs_input"), ("waiting_human", "needs_input"),
("skipped", "not_taken"), ("cancelled", "not_taken"),
])
def test_old_diagrams_are_read_as_reference_annotations_without_changing_stored_documents(legacy, expected):
document = {"node_id": "check", "label": "核查", "status": legacy}
assert InvestigationDiagramNodeRef.model_validate(document).status == expected
assert document["status"] == legacy
@pytest.mark.parametrize("status", ["running", "pending", "completed", "waiting", "waiting_human", "skipped", "cancelled"])
def test_new_incremental_writes_reject_execution_lifecycle_states(status):
with pytest.raises(ValidationError):
InvestigationGraphUpdate.model_validate({"nodes": [{"node_id": "check", "label": "核查", "status": status}]})