fix(investigation): persist large results and require graph links
Generic Container CI/CD / test-build-publish (push) Successful in 4m15s
Server CI/CD v2 / build-test-publish-and-deploy (push) Successful in 4m15s

Full-network pressure comparisons exceeded the worker limit before saved-result previews could run. Preserve complete calculation results and keep read-time summaries and pagination.

Incremental graph publication accepted isolated nodes after flow-authoring rules were lost. Require new steps to connect explicitly while retaining historical snapshots and status-only patches. Regression tests reproduce both failures on the previous code.
This commit is contained in:
2026-11-15 13:51:43 +08:00
parent d3a4433386
commit 4b47ae00d1
7 changed files with 173 additions and 5 deletions
+79
View File
@@ -239,6 +239,85 @@ def test_graph_renderer_escapes_labels_and_keeps_explicit_parallel_and_failed_pa
assert graph.node_refs[2].status == "reference"
@pytest.mark.parametrize("edges", [[], [{"source": "check", "target": "check"}]])
def test_new_multistep_graph_requires_relationships_instead_of_isolated_nodes(edges):
with pytest.raises(DomainError) as error:
update_investigation_graph(None, InvestigationGraphUpdate.model_validate({
"nodes": [{"node_id": "read", "label": "观测核验"},
{"node_id": "check", "label": "异常判断"}],
"edges": edges,
}))
assert error.value.code == "GRAPH_RELATION_REQUIRED"
assert "check" in str(error.value)
def test_new_branch_must_connect_to_the_saved_narrative_without_inventing_edges():
original = update_investigation_graph(None, InvestigationGraphUpdate.model_validate({
"nodes": [{"node_id": "root", "label": "调查起点"}],
}))
with pytest.raises(DomainError) as error:
update_investigation_graph(original, InvestigationGraphUpdate.model_validate({
"nodes": [{"node_id": "left", "label": "独立核查"},
{"node_id": "right", "label": "核查发现"}],
"edges": [{"source": "left", "target": "right"}],
}))
assert error.value.code == "GRAPH_RELATION_REQUIRED"
assert original.edges == []
assert len(original.node_refs) == 1
def test_connected_parallel_branches_and_join_render_top_down():
graph = update_investigation_graph(None, InvestigationGraphUpdate.model_validate({
"nodes": [{"node_id": key, "label": label} for key, label in (
("start", "异常核验"), ("isolation", "隔离分析"),
("impact", "爆管影响"), ("summary", "汇总判断"))],
"edges": [{"source": source, "target": target, "label": label}
for source, target, label in (
("start", "isolation", "并行核查"), ("start", "impact", "并行核查"),
("isolation", "summary", "汇总依据"), ("impact", "summary", "汇总依据"))],
}))
assert graph.mermaid.startswith("flowchart TD\n")
assert len(graph.edges) == 4
assert 'start -->|"并行核查"| impact' in graph.mermaid
patched = update_investigation_graph(graph, InvestigationGraphUpdate.model_validate({
"nodes": [{"node_id": "impact", "status": "recorded"}],
}))
assert patched.edges == graph.edges
def test_existing_disconnected_snapshot_remains_readable_and_patchable():
original = InvestigationDiagram.model_validate({
"title": "已保存的旧图", "mermaid": 'flowchart TD\n read["观测"]\n check["判断"]',
"edges": [], "node_refs": [{"node_id": "read", "label": "观测"},
{"node_id": "check", "label": "判断"}],
})
patched = update_investigation_graph(original, InvestigationGraphUpdate.model_validate({
"nodes": [{"node_id": "check", "status": "recorded"}],
}))
assert patched.mermaid == original.mermaid
assert patched.edges == original.edges == []
assert original.node_refs[1].status is None
@pytest.mark.anyio
async def test_publication_rejects_missing_links_and_accepts_a_corrected_graph():
task, repo, service = setup_service()
first = await publish(service, repo, task["task_id"], nodes=[
{"node_id": "read", "label": "观测核验"},
])
original = first.task.latest_progress.progress.diagram.model_dump(mode="json")
with pytest.raises(DomainError) as error:
await publish(service, repo, task["task_id"], nodes=[
{"node_id": "check", "label": "异常判断"},
])
assert error.value.code == "GRAPH_RELATION_REQUIRED"
assert (await service.detail(task["task_id"])).latest_progress.progress.diagram.model_dump(mode="json") == original
corrected = await publish(service, repo, task["task_id"], nodes=[
{"node_id": "check", "label": "异常判断"},
], edges=[{"source": "read", "target": "check", "label": "核验依据"}])
assert 'read -->|"核验依据"| check' in corrected.task.latest_progress.progress.diagram.mermaid
def test_first_structured_update_preserves_an_existing_mermaid_without_reinterpreting_it():
original = InvestigationDiagram.model_validate({
"title": "原调查路线", "mermaid": 'flowchart LR\nA{核查条件} -->|具备| B[原路径]\nA --> C[另一分支]',