feat(investigations): refine report authoring and replay flushing
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
"""New publications are readable; historical reports keep their original evidence."""
|
||||
from copy import deepcopy
|
||||
|
||||
import pytest
|
||||
|
||||
from app.domain.schemas.operational_task import (
|
||||
InvestigationProgress,
|
||||
InvestigationProgressInput,
|
||||
InvestigationReport,
|
||||
InvestigationReportInput,
|
||||
)
|
||||
|
||||
|
||||
def report():
|
||||
return {
|
||||
"title": "压力异常恢复复核报告",
|
||||
"current_conclusion": "恢复复核通过。7 月 16 日 13:15,13 台复核设备均处于历史正常范围。",
|
||||
"conclusion_boundary": "依据完工后的一个采样时刻判断恢复,长期稳定性继续由日常监测跟踪。",
|
||||
"stage": "final", "outcome": "concluded", "data_gaps": [],
|
||||
"evidence_refs": ["recovery:sha256:stored-evidence"],
|
||||
"recommendations": ["继续监测压力与流量。"], "pending_items": [],
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("text", [
|
||||
"恢复复核 status=passed,13 台设备 normal。",
|
||||
"第 3 轮 execution_generation=3,handling_context.phase=verification_ready。",
|
||||
"完工后 required_samples=1,interval_seconds=900,verified_through=13:15。",
|
||||
"已读取 recovery:sha256:01234567,复核通过。",
|
||||
"Skill scada-anomaly v1.0.16 已按 Server 分发执行。",
|
||||
"query_scada_readings 已执行,query_complete=true。",
|
||||
"关联工单 60000000-0000-4000-8000-000000000002 已完工。",
|
||||
"恢复采样时间为 2026-07-16T05:15:00Z。",
|
||||
"恢复采样时间为 2026-07-16 13:15(UTC+8)。",
|
||||
"恢复采样时间为 2026-07-16 13:15+08:00。",
|
||||
"**恢复复核通过**,其余设备正常。",
|
||||
"<strong>恢复复核通过</strong>。",
|
||||
])
|
||||
def test_new_report_and_progress_reject_execution_details_and_raw_display_markup(text):
|
||||
legacy = {**report(), "current_conclusion": text}
|
||||
assert InvestigationReport.model_validate(legacy).current_conclusion == text
|
||||
assert InvestigationProgress.model_validate({"summary": text}).summary == text
|
||||
with pytest.raises(ValueError):
|
||||
InvestigationReportInput.model_validate(legacy)
|
||||
with pytest.raises(ValueError):
|
||||
InvestigationProgressInput.model_validate({"summary": text})
|
||||
|
||||
|
||||
@pytest.mark.parametrize(("field", "limit"), [
|
||||
("title", 80), ("current_conclusion", 300), ("conclusion_boundary", 240),
|
||||
])
|
||||
def test_new_report_bounds_summary_fields_without_truncating_history(field, limit):
|
||||
valid = {**report(), field: "测" * limit}
|
||||
assert getattr(InvestigationReportInput.model_validate(valid), field) == valid[field]
|
||||
too_long = {**valid, field: "测" * (limit + 1)}
|
||||
assert getattr(InvestigationReport.model_validate(too_long), field) == too_long[field]
|
||||
with pytest.raises(ValueError):
|
||||
InvestigationReportInput.model_validate(too_long)
|
||||
|
||||
|
||||
def test_progress_summary_is_short_and_keeps_technical_references_structured():
|
||||
progress = {"summary": "测" * 300, "graph_update": {"nodes": [{
|
||||
"node_id": "recovery", "label": "恢复监测复核通过", "status": "recorded",
|
||||
"evidence_refs": ["recovery:sha256:stored-evidence"],
|
||||
}]}}
|
||||
assert InvestigationProgressInput.model_validate(progress).summary == progress["summary"]
|
||||
with pytest.raises(ValueError):
|
||||
InvestigationProgressInput.model_validate({**progress, "summary": "测" * 301})
|
||||
|
||||
|
||||
def test_asset_ids_measurements_and_evidence_linked_tables_remain_publishable():
|
||||
value = report()
|
||||
value["current_conclusion"] = "05:00-08:00 的候选管段 515870(DN600)相似度 97.08%,尚待现场核验。压力测点 170486 回升至 26.12 m。"
|
||||
value["ui_blocks"] = [{"evidence_refs": value["evidence_refs"], "block": {
|
||||
"version": "answer-ui@1", "block_id": "recovery-table", "phase": "final",
|
||||
"fallback_text": "压力测点 170486 恢复至 26.12 m。",
|
||||
"spec": {"root": "table", "elements": {"table": {
|
||||
"type": "Table", "children": [], "props": {
|
||||
"title": "恢复监测明细", "columns": ["测点", "修复后", "正常范围"],
|
||||
"rows": [["170486", "26.12 m", "26.02 至 26.30 m"]],
|
||||
},
|
||||
}}},
|
||||
}}]
|
||||
assert InvestigationReportInput.model_validate(value).ui_blocks
|
||||
leaked = deepcopy(value)
|
||||
leaked["ui_blocks"][0]["block"]["spec"]["elements"]["table"]["props"]["rows"][0][2] = "status=passed"
|
||||
assert InvestigationReport.model_validate(leaked).ui_blocks
|
||||
with pytest.raises(ValueError):
|
||||
InvestigationReportInput.model_validate(leaked)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("field", ["recommendations", "pending_items"])
|
||||
def test_follow_up_is_business_prose(field):
|
||||
value = {**report(), field: ["等待 handling_context.phase=waiting_scada。"]}
|
||||
with pytest.raises(ValueError):
|
||||
InvestigationReportInput.model_validate(value)
|
||||
Reference in New Issue
Block a user