@hunter-harness/workflow-harness 0.2.26 → 0.2.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/harness/bundles/general/claude-code/.harness-build.json +1 -1
  2. package/harness/bundles/general/claude-code/harness-archive/SKILL.md +1 -1
  3. package/harness/bundles/general/claude-code/harness-archive/templates/render-summary.mjs +25 -6
  4. package/harness/bundles/general/claude-code/harness-archive/templates/summary-data-template.json +44 -0
  5. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
  6. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  7. package/harness/bundles/general/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +493 -74
  8. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  9. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +1 -1
  10. package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
  11. package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
  13. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +8 -4
  14. package/harness/bundles/general/claude-code/harness-sync/reference.md +28 -0
  15. package/harness/bundles/general/claude-code/harness-test/SKILL.md +1 -1
  16. package/harness/bundles/general/claude-code/scripts/harness_archive.py +2147 -189
  17. package/harness/bundles/general/claude-code/scripts/harness_change.py +8 -3
  18. package/harness/bundles/general/claude-code/scripts/harness_events.py +57 -9
  19. package/harness/bundles/general/claude-code/scripts/harness_gate.py +530 -8
  20. package/harness/bundles/general/claude-code/scripts/harness_integration.py +263 -6
  21. package/harness/bundles/general/claude-code/scripts/harness_phase.py +758 -1
  22. package/harness/bundles/general/claude-code/scripts/harness_plan_finalize.py +74 -0
  23. package/harness/bundles/general/claude-code/scripts/harness_retry.py +175 -0
  24. package/harness/bundles/general/claude-code/scripts/harness_test_guard.py +702 -22
  25. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  26. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  27. package/harness/bundles/general/codebuddy/harness-archive/templates/render-summary.mjs +25 -6
  28. package/harness/bundles/general/codebuddy/harness-archive/templates/summary-data-template.json +44 -0
  29. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  30. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  31. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +493 -74
  32. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  33. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
  34. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
  35. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
  36. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
  37. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +8 -4
  38. package/harness/bundles/general/codebuddy/harness-sync/reference.md +28 -0
  39. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
  40. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +2147 -189
  41. package/harness/bundles/general/codebuddy/scripts/harness_change.py +8 -3
  42. package/harness/bundles/general/codebuddy/scripts/harness_events.py +57 -9
  43. package/harness/bundles/general/codebuddy/scripts/harness_gate.py +530 -8
  44. package/harness/bundles/general/codebuddy/scripts/harness_integration.py +263 -6
  45. package/harness/bundles/general/codebuddy/scripts/harness_phase.py +758 -1
  46. package/harness/bundles/general/codebuddy/scripts/harness_plan_finalize.py +74 -0
  47. package/harness/bundles/general/codebuddy/scripts/harness_retry.py +175 -0
  48. package/harness/bundles/general/codebuddy/scripts/harness_test_guard.py +702 -22
  49. package/harness/bundles/general/codex/.harness-build.json +1 -1
  50. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  51. package/harness/bundles/general/codex/harness-archive/templates/render-summary.mjs +25 -6
  52. package/harness/bundles/general/codex/harness-archive/templates/summary-data-template.json +44 -0
  53. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  54. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  55. package/harness/bundles/general/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +493 -74
  56. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  57. package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
  58. package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
  59. package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
  60. package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
  61. package/harness/bundles/general/codex/harness-sync/SKILL.md +8 -4
  62. package/harness/bundles/general/codex/harness-sync/reference.md +28 -0
  63. package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
  64. package/harness/bundles/general/codex/scripts/harness_archive.py +2147 -189
  65. package/harness/bundles/general/codex/scripts/harness_change.py +8 -3
  66. package/harness/bundles/general/codex/scripts/harness_events.py +57 -9
  67. package/harness/bundles/general/codex/scripts/harness_gate.py +530 -8
  68. package/harness/bundles/general/codex/scripts/harness_integration.py +263 -6
  69. package/harness/bundles/general/codex/scripts/harness_phase.py +758 -1
  70. package/harness/bundles/general/codex/scripts/harness_plan_finalize.py +74 -0
  71. package/harness/bundles/general/codex/scripts/harness_retry.py +175 -0
  72. package/harness/bundles/general/codex/scripts/harness_test_guard.py +702 -22
  73. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  74. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  75. package/harness/bundles/general/cursor/harness-archive/templates/render-summary.mjs +25 -6
  76. package/harness/bundles/general/cursor/harness-archive/templates/summary-data-template.json +44 -0
  77. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  78. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  79. package/harness/bundles/general/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +493 -74
  80. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  81. package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
  82. package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
  83. package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
  84. package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
  85. package/harness/bundles/general/cursor/harness-sync/SKILL.md +8 -4
  86. package/harness/bundles/general/cursor/harness-sync/reference.md +28 -0
  87. package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
  88. package/harness/bundles/general/cursor/scripts/harness_archive.py +2147 -189
  89. package/harness/bundles/general/cursor/scripts/harness_change.py +8 -3
  90. package/harness/bundles/general/cursor/scripts/harness_events.py +57 -9
  91. package/harness/bundles/general/cursor/scripts/harness_gate.py +530 -8
  92. package/harness/bundles/general/cursor/scripts/harness_integration.py +263 -6
  93. package/harness/bundles/general/cursor/scripts/harness_phase.py +758 -1
  94. package/harness/bundles/general/cursor/scripts/harness_plan_finalize.py +74 -0
  95. package/harness/bundles/general/cursor/scripts/harness_retry.py +175 -0
  96. package/harness/bundles/general/cursor/scripts/harness_test_guard.py +702 -22
  97. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  98. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  99. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  100. package/harness/bundles/java/claude-code/harness-archive/templates/render-summary.mjs +25 -6
  101. package/harness/bundles/java/claude-code/harness-archive/templates/summary-data-template.json +44 -0
  102. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  103. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  104. package/harness/bundles/java/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +493 -74
  105. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  106. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  107. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
  108. package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
  109. package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
  110. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
  111. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +8 -4
  112. package/harness/bundles/java/claude-code/harness-sync/reference.md +28 -0
  113. package/harness/bundles/java/claude-code/harness-test/SKILL.md +1 -1
  114. package/harness/bundles/java/claude-code/scripts/harness_archive.py +2147 -189
  115. package/harness/bundles/java/claude-code/scripts/harness_change.py +8 -3
  116. package/harness/bundles/java/claude-code/scripts/harness_events.py +57 -9
  117. package/harness/bundles/java/claude-code/scripts/harness_gate.py +530 -8
  118. package/harness/bundles/java/claude-code/scripts/harness_integration.py +263 -6
  119. package/harness/bundles/java/claude-code/scripts/harness_phase.py +758 -1
  120. package/harness/bundles/java/claude-code/scripts/harness_plan_finalize.py +74 -0
  121. package/harness/bundles/java/claude-code/scripts/harness_retry.py +175 -0
  122. package/harness/bundles/java/claude-code/scripts/harness_test_guard.py +702 -22
  123. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  124. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  125. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  126. package/harness/bundles/java/codebuddy/harness-archive/templates/render-summary.mjs +25 -6
  127. package/harness/bundles/java/codebuddy/harness-archive/templates/summary-data-template.json +44 -0
  128. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  129. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  130. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +493 -74
  131. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  132. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  133. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
  134. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
  135. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
  136. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
  137. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +8 -4
  138. package/harness/bundles/java/codebuddy/harness-sync/reference.md +28 -0
  139. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
  140. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +2147 -189
  141. package/harness/bundles/java/codebuddy/scripts/harness_change.py +8 -3
  142. package/harness/bundles/java/codebuddy/scripts/harness_events.py +57 -9
  143. package/harness/bundles/java/codebuddy/scripts/harness_gate.py +530 -8
  144. package/harness/bundles/java/codebuddy/scripts/harness_integration.py +263 -6
  145. package/harness/bundles/java/codebuddy/scripts/harness_phase.py +758 -1
  146. package/harness/bundles/java/codebuddy/scripts/harness_plan_finalize.py +74 -0
  147. package/harness/bundles/java/codebuddy/scripts/harness_retry.py +175 -0
  148. package/harness/bundles/java/codebuddy/scripts/harness_test_guard.py +702 -22
  149. package/harness/bundles/java/codex/.harness-build.json +1 -1
  150. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  151. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  152. package/harness/bundles/java/codex/harness-archive/templates/render-summary.mjs +25 -6
  153. package/harness/bundles/java/codex/harness-archive/templates/summary-data-template.json +44 -0
  154. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  155. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  156. package/harness/bundles/java/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +493 -74
  157. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  158. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  159. package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
  160. package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
  161. package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
  162. package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
  163. package/harness/bundles/java/codex/harness-sync/SKILL.md +8 -4
  164. package/harness/bundles/java/codex/harness-sync/reference.md +28 -0
  165. package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
  166. package/harness/bundles/java/codex/scripts/harness_archive.py +2147 -189
  167. package/harness/bundles/java/codex/scripts/harness_change.py +8 -3
  168. package/harness/bundles/java/codex/scripts/harness_events.py +57 -9
  169. package/harness/bundles/java/codex/scripts/harness_gate.py +530 -8
  170. package/harness/bundles/java/codex/scripts/harness_integration.py +263 -6
  171. package/harness/bundles/java/codex/scripts/harness_phase.py +758 -1
  172. package/harness/bundles/java/codex/scripts/harness_plan_finalize.py +74 -0
  173. package/harness/bundles/java/codex/scripts/harness_retry.py +175 -0
  174. package/harness/bundles/java/codex/scripts/harness_test_guard.py +702 -22
  175. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  176. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  177. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  178. package/harness/bundles/java/cursor/harness-archive/templates/render-summary.mjs +25 -6
  179. package/harness/bundles/java/cursor/harness-archive/templates/summary-data-template.json +44 -0
  180. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  181. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  182. package/harness/bundles/java/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +493 -74
  183. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  184. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  185. package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
  186. package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
  187. package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
  188. package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
  189. package/harness/bundles/java/cursor/harness-sync/SKILL.md +8 -4
  190. package/harness/bundles/java/cursor/harness-sync/reference.md +28 -0
  191. package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
  192. package/harness/bundles/java/cursor/scripts/harness_archive.py +2147 -189
  193. package/harness/bundles/java/cursor/scripts/harness_change.py +8 -3
  194. package/harness/bundles/java/cursor/scripts/harness_events.py +57 -9
  195. package/harness/bundles/java/cursor/scripts/harness_gate.py +530 -8
  196. package/harness/bundles/java/cursor/scripts/harness_integration.py +263 -6
  197. package/harness/bundles/java/cursor/scripts/harness_phase.py +758 -1
  198. package/harness/bundles/java/cursor/scripts/harness_plan_finalize.py +74 -0
  199. package/harness/bundles/java/cursor/scripts/harness_retry.py +175 -0
  200. package/harness/bundles/java/cursor/scripts/harness_test_guard.py +702 -22
  201. package/harness/manifests/general/claude-code.json +28 -24
  202. package/harness/manifests/general/codebuddy.json +28 -24
  203. package/harness/manifests/general/codex.json +28 -24
  204. package/harness/manifests/general/cursor.json +28 -24
  205. package/harness/manifests/java/claude-code.json +30 -26
  206. package/harness/manifests/java/codebuddy.json +30 -26
  207. package/harness/manifests/java/codex.json +30 -26
  208. package/harness/manifests/java/cursor.json +30 -26
  209. package/hunter-workflow-family.json +2 -2
  210. package/package.json +1 -1
@@ -232,8 +232,13 @@ def read_concurrency_mode(project_root: Path) -> str:
232
232
  ``isolated-multi-active`` (allows multiple active Changes but all
233
233
  Change-scoped commands require ``--change``).
234
234
  """
235
- cfg = project_root / ".harness" / "config.json"
236
- if cfg.is_file():
235
+ configs = [
236
+ project_root / ".harness" / "config" / "harness.json",
237
+ project_root / ".harness" / "config.json",
238
+ ]
239
+ for cfg in configs:
240
+ if not cfg.is_file():
241
+ continue
237
242
  try:
238
243
  data = json.loads(cfg.read_text(encoding="utf-8"))
239
244
  if isinstance(data, dict):
@@ -244,7 +249,7 @@ def read_concurrency_mode(project_root: Path) -> str:
244
249
  }:
245
250
  return mode
246
251
  except (OSError, json.JSONDecodeError):
247
- pass
252
+ continue
248
253
  return "single-active"
249
254
 
250
255
 
@@ -883,6 +883,15 @@ def split_phase_attempts(phase_events: list[dict[str, Any]]) -> list[dict[str, A
883
883
  attempts: list[dict[str, Any]] = []
884
884
  current: dict[str, Any] | None = None
885
885
  next_attempt = 1
886
+ pre_start_metadata_types = {
887
+ "correction",
888
+ "decision",
889
+ "environment.wait",
890
+ "env.wait",
891
+ "external.wait",
892
+ "issue",
893
+ "ci.wait",
894
+ }
886
895
  for event in phase_events:
887
896
  if event.get("type") == "phase.start":
888
897
  if current is not None:
@@ -900,6 +909,11 @@ def split_phase_attempts(phase_events: list[dict[str, Any]]) -> list[dict[str, A
900
909
  if prior_type == "phase.end":
901
910
  attempts[-1]["warnings"].append("event recorded after phase.end")
902
911
  continue
912
+ if event.get("type") in pre_start_metadata_types:
913
+ # Decisions and diagnostics may be emitted while selecting or
914
+ # recovering a phase. They describe workflow context, not an
915
+ # execution attempt, so they must not manufacture an orphan.
916
+ continue
903
917
  raw_attempt = event.get("attempt")
904
918
  attempt = raw_attempt if isinstance(raw_attempt, int) and raw_attempt > 0 else next_attempt
905
919
  next_attempt = max(next_attempt, attempt + 1)
@@ -974,26 +988,40 @@ def _seal_timestamp_for_attempt(
974
988
  cutoff_ts: str | None,
975
989
  next_attempt_start: Any = None,
976
990
  ) -> tuple[Any, str | None]:
977
- """Pick INCOMPLETE seal time: next start, recovery, or report cutoff."""
991
+ """Pick a typed terminal and seal time for an unclosed attempt."""
978
992
  recovery_ts = None
993
+ explicit_terminal: tuple[Any, str] | None = None
979
994
  for event in events_in:
980
- if str(event.get("type") or "").lower() in {
995
+ event_type = str(event.get("type") or "").lower()
996
+ if event_type in {
981
997
  "recovery",
982
998
  "phase.recovery",
983
999
  "attempt.recovery",
984
1000
  }:
985
1001
  recovery_ts = event.get("timestamp") or recovery_ts
1002
+ terminal = {
1003
+ "attempt.abandoned": "ABANDONED",
1004
+ "phase.abandoned": "ABANDONED",
1005
+ "attempt.interrupted": "INTERRUPTED",
1006
+ "phase.interrupted": "INTERRUPTED",
1007
+ "attempt.orphaned": "ORPHANED",
1008
+ "phase.orphaned": "ORPHANED",
1009
+ }.get(event_type)
1010
+ if terminal and event.get("timestamp"):
1011
+ explicit_terminal = (event.get("timestamp"), terminal)
1012
+ if explicit_terminal is not None:
1013
+ return explicit_terminal
986
1014
  if next_attempt_start:
987
- return next_attempt_start, "INCOMPLETE"
1015
+ return next_attempt_start, "RECOVERED"
988
1016
  if recovery_ts:
989
- return recovery_ts, "INCOMPLETE"
1017
+ return recovery_ts, "RECOVERED"
990
1018
  if cutoff_ts:
991
- return cutoff_ts, "INCOMPLETE"
1019
+ return cutoff_ts, "INCOMPLETE_AT_CUTOFF"
992
1020
  # Fall back to last event timestamp so wall clock is not silently dropped.
993
1021
  for event in reversed(events_in):
994
1022
  if event.get("timestamp"):
995
- return event.get("timestamp"), "INCOMPLETE"
996
- return None, "INCOMPLETE"
1023
+ return event.get("timestamp"), "INTERRUPTED"
1024
+ return None, "ORPHANED"
997
1025
 
998
1026
 
999
1027
  def attempt_invocations(
@@ -1013,6 +1041,7 @@ def attempt_invocations(
1013
1041
  start_ts = None
1014
1042
  end_ts = None
1015
1043
  status = None
1044
+ terminal_status = None
1016
1045
  closed_by_end = False
1017
1046
  for event in events_in:
1018
1047
  if event.get("type") == "phase.start" and start_ts is None:
@@ -1021,7 +1050,9 @@ def attempt_invocations(
1021
1050
  end_ts = event.get("timestamp")
1022
1051
  if "status" in event:
1023
1052
  status = event.get("status")
1053
+ terminal_status = str(event.get("status") or "").upper() or None
1024
1054
  closed_by_end = True
1055
+ missing_start = start_ts is None
1025
1056
  sealed_incomplete = False
1026
1057
  if not closed_by_end:
1027
1058
  next_start = None
@@ -1038,7 +1069,12 @@ def attempt_invocations(
1038
1069
  if seal_ts is not None:
1039
1070
  end_ts = seal_ts
1040
1071
  status = seal_status
1072
+ terminal_status = seal_status
1041
1073
  sealed_incomplete = True
1074
+ elif missing_start:
1075
+ terminal_status = "ORPHANED"
1076
+ status = "ORPHANED"
1077
+ sealed_incomplete = True
1042
1078
  duration = None
1043
1079
  if start_ts and end_ts:
1044
1080
  duration = duration_ms_between(start_ts, end_ts)
@@ -1048,9 +1084,13 @@ def attempt_invocations(
1048
1084
  {
1049
1085
  "attempt": attempt.get("attempt"),
1050
1086
  "status": status,
1087
+ "terminalStatus": terminal_status,
1088
+ "startedAt": start_ts,
1089
+ "endedAt": end_ts,
1051
1090
  "durationMs": duration,
1052
1091
  "activeEligible": active_eligible,
1053
1092
  "sealedIncomplete": sealed_incomplete,
1093
+ "warnings": list(attempt.get("warnings") or []),
1054
1094
  }
1055
1095
  )
1056
1096
  return invocations
@@ -1066,7 +1106,13 @@ def phase_final_state(phase_events: list[dict[str, Any]]) -> dict[str, Any]:
1066
1106
  "attempt": latest.get("attempt"),
1067
1107
  "status": latest.get("status"),
1068
1108
  "durationMs": latest.get("durationMs"),
1069
- "closed": latest.get("status") is not None and latest.get("status") != "INCOMPLETE",
1109
+ "closed": latest.get("terminalStatus") not in {
1110
+ None,
1111
+ "INCOMPLETE",
1112
+ "INCOMPLETE_AT_CUTOFF",
1113
+ "ORPHANED",
1114
+ "INTERRUPTED",
1115
+ },
1070
1116
  }
1071
1117
 
1072
1118
 
@@ -1100,7 +1146,8 @@ def canonical_phase_timing(
1100
1146
  unclosed = sum(
1101
1147
  1
1102
1148
  for invocation in invocations
1103
- if invocation.get("sealedIncomplete") or invocation.get("status") == "INCOMPLETE"
1149
+ if invocation.get("terminalStatus")
1150
+ in {"INCOMPLETE", "INCOMPLETE_AT_CUTOFF", "ORPHANED", "INTERRUPTED"}
1104
1151
  )
1105
1152
  return {
1106
1153
  "activeExecutionMs": active,
@@ -1108,6 +1155,7 @@ def canonical_phase_timing(
1108
1155
  "lateEventCount": late["lateEventCount"],
1109
1156
  "lateEventSpanMs": late["lateEventSpanMs"],
1110
1157
  "unclosedAttemptCount": unclosed,
1158
+ "attempts": invocations,
1111
1159
  }
1112
1160
 
1113
1161