test_store.py 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. from pathlib import Path
  2. from visualization.web.store import FileRunStore
  3. PROJECT_ROOT = Path(__file__).resolve().parents[2]
  4. def test_discovers_current_global_and_production_runs() -> None:
  5. store = FileRunStore(PROJECT_ROOT / "demo_output")
  6. refs = store.discover()
  7. kinds = {ref.kind for ref in refs}
  8. assert "global_data" in kinds
  9. assert "segment" in kinds
  10. def test_global_run_projects_upstream_compatible_views() -> None:
  11. store = FileRunStore(PROJECT_ROOT / "demo_output")
  12. ref = next(
  13. item for item in store.discover()
  14. if item.key == "global-data-stage-live-v22"
  15. )
  16. brief = store.brief(ref)
  17. detail = store.detail(ref)
  18. snapshots = store.snapshots(ref)
  19. flat = store.flat(ref, 0)
  20. assert brief["status"] == "success"
  21. assert brief["raw_status"] == "COMPLETED"
  22. assert brief["business_label"] == "Global Data · 4 个资料任务"
  23. assert brief["business_progress"] == "4 已通过"
  24. assert brief["cost_status"] in {"reported", "unavailable"}
  25. assert detail["steps"]
  26. assert detail["overview"] == {
  27. "plan_rounds": 1,
  28. "execute_rounds": 4,
  29. "task_count": 4,
  30. "passed": 4,
  31. "failed": 0,
  32. "retries": 0,
  33. }
  34. assert snapshots["snapshots"]
  35. assert flat["root"]["module_key"] == "production.global_data.workflow"
  36. assert flat["round_count"] >= 1
  37. assert flat["rounds"][0]["instances"]
  38. executor = next(
  39. item
  40. for item in flat["rounds"][0]["instances"]
  41. if item["module_key"] == "production.global_data.execute"
  42. and item["task_id"] == "Task1"
  43. )
  44. assert executor["output"]["images"]
  45. def test_production_run_reads_latest_versioned_plan_without_terminal_report() -> None:
  46. store = FileRunStore(PROJECT_ROOT / "demo_output")
  47. ref = next(
  48. item for item in store.discover()
  49. if item.key == "v22-production-v06-live-v3"
  50. )
  51. detail = store.detail(ref)
  52. flat = store.flat(ref, 0)
  53. assert detail["agent_name"] == "segment_production"
  54. assert detail["input_payload"]["schema_version"] == "0.6"
  55. assert detail["overview"]["plan_rounds"] == 1
  56. assert detail["overview"]["task_count"] == 4
  57. assert detail["overview"]["execute_rounds"] > 0
  58. assert flat["round_count"] == 1
  59. assert flat["rounds"][0]["instances"][0]["module_key"] == (
  60. "production.segment.execute"
  61. )
  62. assert (
  63. flat["rounds"][0]["instances"][0]["input"]["blocks"][0]["source"]
  64. == "segment_packages/Segment1.v1.json"
  65. )
  66. assert flat["root"]["module"]["fingerprint"] == "0.6"
  67. def test_failed_production_run_uses_formal_summary_and_explains_failure() -> None:
  68. store = FileRunStore(PROJECT_ROOT / "demo_output")
  69. ref = next(
  70. item for item in store.discover()
  71. if item.key == "v23-context-production-from-v22-01"
  72. )
  73. brief = store.brief(ref)
  74. detail = store.detail(ref)
  75. story = detail["business_story"]
  76. assert brief["raw_status"] == "FAILED"
  77. assert brief["status"] == "failed"
  78. assert brief["business_label"] == "Production · 4 个 Segment"
  79. assert brief["business_progress"] == "停在 Segment1 · EXECUTE_SEGMENT"
  80. assert detail["error_message"].startswith("Segment Executor 连续 3 次")
  81. assert story["protocol_version"] == "0.7"
  82. assert story["status"] == "failed"
  83. assert story["failure"]["code"] == "SEGMENT_EXECUTION_FAILED"
  84. segment = story["rounds"][0]["steps"][0]
  85. assert segment["id"] == "Segment1"
  86. assert segment["status"] == "failed"
  87. assert segment["judgment"]["verdict"] == "FAIL"
  88. assert "正式音色参考 Artifact" in segment["judgment"]["summary"]
  89. assert len(segment["tools"]) == 12
  90. def test_global_business_story_exposes_reason_basis_judgment_and_output() -> None:
  91. store = FileRunStore(PROJECT_ROOT / "demo_output")
  92. ref = next(
  93. item for item in store.discover()
  94. if item.key == "v23-context-global-data-01"
  95. )
  96. story = store.detail(ref)["business_story"]
  97. task = next(
  98. item for item in story["rounds"][0]["steps"]
  99. if item["id"] == "Task1"
  100. )
  101. assert story["headline"].startswith("把 Production 需要的")
  102. assert task["reason"] == "确认核心人物素材的身份一致性与技术完整性"
  103. assert any(item["label"] == "业务来源" for item in task["basis"])
  104. assert task["judgment"]["verdict"] == "PASS"
  105. assert task["judgment"]["criteria"]
  106. assert task["outputs"][0]["media_url"].startswith("/api/runs/")
  107. assert task["tools"][0]["name"] == "probe_media"
  108. def test_production_tool_operations_are_not_duplicated_across_segments() -> None:
  109. store = FileRunStore(PROJECT_ROOT / "demo_output")
  110. ref = next(
  111. item for item in store.discover()
  112. if item.key == "v23-context-production-from-v22-01"
  113. )
  114. flat = store.flat(ref, 0)
  115. executors = [
  116. item for item in flat["rounds"][0]["instances"]
  117. if item["module_key"] == "production.segment.execute"
  118. ]
  119. assert len(executors[0]["flow"]) == 12
  120. assert all(not item["flow"] for item in executors[1:])
  121. def test_completed_global_run_without_summary_uses_stage_delivery_status() -> None:
  122. store = FileRunStore(PROJECT_ROOT / "demo_output")
  123. ref = next(
  124. item for item in store.discover()
  125. if item.key == "global-data-stage-live-v19"
  126. )
  127. brief = store.brief(ref)
  128. assert brief["raw_status"] == "GLOBAL_DATA_COMPLETED"
  129. assert brief["status"] == "success"
  130. def test_media_path_cannot_escape_run_directory() -> None:
  131. store = FileRunStore(PROJECT_ROOT / "demo_output")
  132. ref = next(
  133. item for item in store.discover()
  134. if item.key == "global-data-stage-live-v22"
  135. )
  136. try:
  137. store.media_path(ref, "../v22-production-plan.v1.json")
  138. except FileNotFoundError:
  139. pass
  140. else:
  141. raise AssertionError("media path traversal must be rejected")