test_production_capture.py 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. from __future__ import annotations
  2. import json
  3. from pathlib import Path
  4. from production_build_agents.observability.production_capture import (
  5. collect_production_run_records,
  6. expand_production_node_output,
  7. summarize_production_state,
  8. )
  9. def test_production_run_record_scan_is_incremental(
  10. tmp_path: Path,
  11. ) -> None:
  12. run_dir = tmp_path / "production-run"
  13. candidate = run_dir / "segment_candidates" / "Segment1.v1.json"
  14. candidate.parent.mkdir(parents=True)
  15. candidate.write_text(
  16. json.dumps(
  17. {
  18. "summary": "完整 Candidate",
  19. "image_url": "https://internal.example/segment.png",
  20. },
  21. ensure_ascii=False,
  22. ),
  23. encoding="utf-8",
  24. )
  25. (run_dir / "video.mp4").write_bytes(b"\x00\x01")
  26. seen: dict[str, str] = {}
  27. first = collect_production_run_records(
  28. run_dir,
  29. seen_hashes=seen,
  30. changed_only=True,
  31. )
  32. second = collect_production_run_records(
  33. run_dir,
  34. seen_hashes=seen,
  35. changed_only=True,
  36. )
  37. candidate.write_text(
  38. json.dumps(
  39. {"summary": "更新后的完整 Candidate"},
  40. ensure_ascii=False,
  41. ),
  42. encoding="utf-8",
  43. )
  44. third = collect_production_run_records(
  45. run_dir,
  46. seen_hashes=seen,
  47. changed_only=True,
  48. )
  49. key = "segment_candidates/Segment1.v1.json"
  50. assert first[key]["content"]["summary"] == "完整 Candidate"
  51. assert "video.mp4" not in first
  52. assert second == {}
  53. assert third[key]["content"]["summary"] == "更新后的完整 Candidate"
  54. def test_production_node_output_keeps_segment_and_error_details(
  55. tmp_path: Path,
  56. ) -> None:
  57. report = tmp_path / "Segment1.v1.json"
  58. report.write_text(
  59. json.dumps(
  60. {"verdict": "FAIL", "reason": "真实验收原因"},
  61. ensure_ascii=False,
  62. ),
  63. encoding="utf-8",
  64. )
  65. state = {
  66. "run_id": "round-production",
  67. "status": "RUNNING",
  68. "current_segment_id": "Segment1",
  69. }
  70. update = {
  71. "status": "FAILED",
  72. "error": "真实 Production 错误",
  73. "current_segment_validation_report_path": str(report),
  74. }
  75. observed = expand_production_node_output(
  76. "validate_segment",
  77. state,
  78. update,
  79. run_records={},
  80. exception=RuntimeError("工具结果未知"),
  81. )
  82. assert observed["state_after"]["error"] == "真实 Production 错误"
  83. assert observed["exception"]["message"] == "工具结果未知"
  84. assert observed["referenced_records"][
  85. "current_segment_validation_report_path"
  86. ]["content"]["reason"] == "真实验收原因"
  87. def test_redacted_production_state_preserves_scheduling_facts() -> None:
  88. summary = summarize_production_state(
  89. {
  90. "run_id": "round-production",
  91. "protocol_version": "0.7",
  92. "status": "RUNNING",
  93. "phase": "EXECUTE_SEGMENT",
  94. "current_segment_id": "Segment2",
  95. "executor_calls": 3,
  96. "event_log": ["正文不会进入摘要"],
  97. "segment_records": {
  98. "Segment2": {
  99. "status": "ready",
  100. "active_plan_version": 2,
  101. "delivery_path": "/private/Delivery.json",
  102. }
  103. },
  104. }
  105. )
  106. assert summary["phase"] == "EXECUTE_SEGMENT"
  107. assert summary["counters"]["executor_calls"] == 3
  108. assert summary["segments"]["Segment2"]["status"] == "ready"
  109. assert summary["event_count"] == 1
  110. assert "/private/Delivery.json" not in json.dumps(summary)