@hunter-harness/workflow-harness 0.3.1 → 0.4.1

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 (402) 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/reference.md +30 -1
  4. package/harness/bundles/general/claude-code/harness-archive/templates/summary-data-template.json +1 -0
  5. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
  6. package/harness/bundles/general/claude-code/harness-execute/SKILL.md +1 -1
  7. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  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-pull/SKILL.md +1 -1
  11. package/harness/bundles/general/claude-code/harness-push/SKILL.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
  13. package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
  14. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
  15. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  16. package/harness/bundles/general/claude-code/harness-test/SKILL.md +1 -1
  17. package/harness/bundles/general/claude-code/scripts/harness_archive.py +146 -8
  18. package/harness/bundles/general/claude-code/scripts/harness_deploy.py +1 -1
  19. package/harness/bundles/general/claude-code/scripts/harness_knowledge_candidates.py +538 -4
  20. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  21. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  22. package/harness/bundles/general/codebuddy/harness-archive/reference.md +30 -1
  23. package/harness/bundles/general/codebuddy/harness-archive/templates/summary-data-template.json +1 -0
  24. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  25. package/harness/bundles/general/codebuddy/harness-execute/SKILL.md +1 -1
  26. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  27. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  28. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
  29. package/harness/bundles/general/codebuddy/harness-pull/SKILL.md +1 -1
  30. package/harness/bundles/general/codebuddy/harness-push/SKILL.md +1 -1
  31. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
  32. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
  33. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
  34. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  35. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
  36. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +146 -8
  37. package/harness/bundles/general/codebuddy/scripts/harness_deploy.py +1 -1
  38. package/harness/bundles/general/codebuddy/scripts/harness_knowledge_candidates.py +538 -4
  39. package/harness/bundles/general/codex/.harness-build.json +1 -1
  40. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  41. package/harness/bundles/general/codex/harness-archive/reference.md +30 -1
  42. package/harness/bundles/general/codex/harness-archive/templates/summary-data-template.json +1 -0
  43. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  44. package/harness/bundles/general/codex/harness-execute/SKILL.md +1 -1
  45. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  46. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  47. package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
  48. package/harness/bundles/general/codex/harness-pull/SKILL.md +1 -1
  49. package/harness/bundles/general/codex/harness-push/SKILL.md +1 -1
  50. package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
  51. package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
  52. package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
  53. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  54. package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
  55. package/harness/bundles/general/codex/scripts/harness_archive.py +146 -8
  56. package/harness/bundles/general/codex/scripts/harness_deploy.py +1 -1
  57. package/harness/bundles/general/codex/scripts/harness_knowledge_candidates.py +538 -4
  58. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  59. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  60. package/harness/bundles/general/cursor/harness-archive/reference.md +30 -1
  61. package/harness/bundles/general/cursor/harness-archive/templates/summary-data-template.json +1 -0
  62. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  63. package/harness/bundles/general/cursor/harness-execute/SKILL.md +1 -1
  64. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  65. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  66. package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
  67. package/harness/bundles/general/cursor/harness-pull/SKILL.md +1 -1
  68. package/harness/bundles/general/cursor/harness-push/SKILL.md +1 -1
  69. package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
  70. package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
  71. package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
  72. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  73. package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
  74. package/harness/bundles/general/cursor/scripts/harness_archive.py +146 -8
  75. package/harness/bundles/general/cursor/scripts/harness_deploy.py +1 -1
  76. package/harness/bundles/general/cursor/scripts/harness_knowledge_candidates.py +538 -4
  77. package/harness/bundles/general/pi/.harness-build.json +6 -0
  78. package/harness/bundles/general/pi/CONTEXT.md +98 -0
  79. package/harness/bundles/general/pi/README.md +478 -0
  80. package/harness/bundles/general/pi/contracts/build-profile-v3.schema.json +302 -0
  81. package/harness/bundles/general/pi/contracts/ci-metrics.schema.json +36 -0
  82. package/harness/bundles/general/pi/contracts/doctor-capability.schema.json +43 -0
  83. package/harness/bundles/general/pi/contracts/external-platform-observation.schema.json +62 -0
  84. package/harness/bundles/general/pi/contracts/fixtures/managed-execution.json +341 -0
  85. package/harness/bundles/general/pi/contracts/process-identity.schema.json +132 -0
  86. package/harness/bundles/general/pi/contracts/run-session.schema.json +142 -0
  87. package/harness/bundles/general/pi/contracts/service-retirement-receipt.schema.json +85 -0
  88. package/harness/bundles/general/pi/contracts/service-session.schema.json +147 -0
  89. package/harness/bundles/general/pi/contracts/workflow-policy.json +574 -0
  90. package/harness/bundles/general/pi/harness-archive/SKILL.md +322 -0
  91. package/harness/bundles/general/pi/harness-archive/checklist.md +71 -0
  92. package/harness/bundles/general/pi/harness-archive/reference.md +150 -0
  93. package/harness/bundles/general/pi/harness-archive/scripts/gen-manifest.ps1 +31 -0
  94. package/harness/bundles/general/pi/harness-archive/templates/summary-data-template.json +218 -0
  95. package/harness/bundles/general/pi/harness-codebase-map/SKILL.md +116 -0
  96. package/harness/bundles/general/pi/harness-codebase-map/checklist.md +126 -0
  97. package/harness/bundles/general/pi/harness-codebase-map/reference.md +364 -0
  98. package/harness/bundles/general/pi/harness-codebase-map/templates/ARCHITECTURE.md +57 -0
  99. package/harness/bundles/general/pi/harness-codebase-map/templates/CONCERNS.md +49 -0
  100. package/harness/bundles/general/pi/harness-codebase-map/templates/CONVENTIONS.md +57 -0
  101. package/harness/bundles/general/pi/harness-codebase-map/templates/INTEGRATIONS.md +52 -0
  102. package/harness/bundles/general/pi/harness-codebase-map/templates/STACK.md +55 -0
  103. package/harness/bundles/general/pi/harness-codebase-map/templates/STRUCTURE.md +69 -0
  104. package/harness/bundles/general/pi/harness-codebase-map/templates/TESTING.md +64 -0
  105. package/harness/bundles/general/pi/harness-codebase-map/templates/map-manifest.schema.json +73 -0
  106. package/harness/bundles/general/pi/harness-codebase-map/templates/map-summary.md +64 -0
  107. package/harness/bundles/general/pi/harness-execute/SKILL.md +170 -0
  108. package/harness/bundles/general/pi/harness-knowledge-ingest/SKILL.md +103 -0
  109. package/harness/bundles/general/pi/harness-knowledge-query/SKILL.md +97 -0
  110. package/harness/bundles/general/pi/harness-plan/SKILL.md +158 -0
  111. package/harness/bundles/general/pi/harness-plan/checklist.md +243 -0
  112. package/harness/bundles/general/pi/harness-plan/protocols.md +133 -0
  113. package/harness/bundles/general/pi/harness-plan/reference.md +468 -0
  114. package/harness/bundles/general/pi/harness-pull/SKILL.md +55 -0
  115. package/harness/bundles/general/pi/harness-push/SKILL.md +83 -0
  116. package/harness/bundles/general/pi/harness-review/SKILL.md +175 -0
  117. package/harness/bundles/general/pi/harness-review/checklist.md +124 -0
  118. package/harness/bundles/general/pi/harness-review/protocols.md +69 -0
  119. package/harness/bundles/general/pi/harness-review/reference.md +114 -0
  120. package/harness/bundles/general/pi/harness-run/SKILL.md +188 -0
  121. package/harness/bundles/general/pi/harness-run/checklist.md +279 -0
  122. package/harness/bundles/general/pi/harness-run/protocols.md +141 -0
  123. package/harness/bundles/general/pi/harness-run/reference.md +886 -0
  124. package/harness/bundles/general/pi/harness-submit/SKILL.md +182 -0
  125. package/harness/bundles/general/pi/harness-submit/checklist.md +452 -0
  126. package/harness/bundles/general/pi/harness-submit/reference.md +152 -0
  127. package/harness/bundles/general/pi/harness-sync/SKILL.md +72 -0
  128. package/harness/bundles/general/pi/harness-sync/reference.md +176 -0
  129. package/harness/bundles/general/pi/harness-test/SKILL.md +250 -0
  130. package/harness/bundles/general/pi/harness-test/checklist.md +359 -0
  131. package/harness/bundles/general/pi/harness-test/pitfalls-java.md +14 -0
  132. package/harness/bundles/general/pi/harness-test/pitfalls.md +307 -0
  133. package/harness/bundles/general/pi/harness-test/reference.md +880 -0
  134. package/harness/bundles/general/pi/harness-test/scripts/runtime-helpers.mjs +216 -0
  135. package/harness/bundles/general/pi/protocols/archive-report-protocol.md +196 -0
  136. package/harness/bundles/general/pi/protocols/ci-layering-protocol.md +22 -0
  137. package/harness/bundles/general/pi/protocols/evidence-based-reporting-protocol.md +134 -0
  138. package/harness/bundles/general/pi/protocols/execution-session-protocol.md +52 -0
  139. package/harness/bundles/general/pi/protocols/external-platform-protocol.md +27 -0
  140. package/harness/bundles/general/pi/protocols/ledger-protocol.md +365 -0
  141. package/harness/bundles/general/pi/protocols/memory-closeout-protocol.md +21 -0
  142. package/harness/bundles/general/pi/protocols/model-routing-protocol.md +22 -0
  143. package/harness/bundles/general/pi/protocols/powershell-protocol.md +238 -0
  144. package/harness/bundles/general/pi/protocols/registry-governance-protocol.md +31 -0
  145. package/harness/bundles/general/pi/protocols/report-pipeline-protocol.md +172 -0
  146. package/harness/bundles/general/pi/protocols/sensitive-info-protocol.md +110 -0
  147. package/harness/bundles/general/pi/protocols/state-layout-protocol.md +209 -0
  148. package/harness/bundles/general/pi/protocols/submit-protocol.md +78 -0
  149. package/harness/bundles/general/pi/protocols/verification-graph-protocol.md +32 -0
  150. package/harness/bundles/general/pi/scripts/harness_adoption_metrics.py +391 -0
  151. package/harness/bundles/general/pi/scripts/harness_apidoc.py +53 -0
  152. package/harness/bundles/general/pi/scripts/harness_archive.py +11345 -0
  153. package/harness/bundles/general/pi/scripts/harness_change.py +1626 -0
  154. package/harness/bundles/general/pi/scripts/harness_check_gate.py +113 -0
  155. package/harness/bundles/general/pi/scripts/harness_context.py +1774 -0
  156. package/harness/bundles/general/pi/scripts/harness_deploy.py +968 -0
  157. package/harness/bundles/general/pi/scripts/harness_efficiency.py +443 -0
  158. package/harness/bundles/general/pi/scripts/harness_environment.py +1690 -0
  159. package/harness/bundles/general/pi/scripts/harness_events.py +2234 -0
  160. package/harness/bundles/general/pi/scripts/harness_events_sync.py +1425 -0
  161. package/harness/bundles/general/pi/scripts/harness_execution_contracts.py +596 -0
  162. package/harness/bundles/general/pi/scripts/harness_fixback.py +1975 -0
  163. package/harness/bundles/general/pi/scripts/harness_gate.py +3816 -0
  164. package/harness/bundles/general/pi/scripts/harness_headless.py +37 -0
  165. package/harness/bundles/general/pi/scripts/harness_integration.py +2564 -0
  166. package/harness/bundles/general/pi/scripts/harness_knowledge_candidates.py +796 -0
  167. package/harness/bundles/general/pi/scripts/harness_ledger.py +3556 -0
  168. package/harness/bundles/general/pi/scripts/harness_migration_head.py +220 -0
  169. package/harness/bundles/general/pi/scripts/harness_orchestration.py +344 -0
  170. package/harness/bundles/general/pi/scripts/harness_paths.py +676 -0
  171. package/harness/bundles/general/pi/scripts/harness_phase.py +1726 -0
  172. package/harness/bundles/general/pi/scripts/harness_plan_aggregate.py +249 -0
  173. package/harness/bundles/general/pi/scripts/harness_plan_finalize.py +1016 -0
  174. package/harness/bundles/general/pi/scripts/harness_preflight.py +650 -0
  175. package/harness/bundles/general/pi/scripts/harness_process.py +1065 -0
  176. package/harness/bundles/general/pi/scripts/harness_profile.py +1817 -0
  177. package/harness/bundles/general/pi/scripts/harness_report_model.py +442 -0
  178. package/harness/bundles/general/pi/scripts/harness_retry.py +175 -0
  179. package/harness/bundles/general/pi/scripts/harness_review.py +631 -0
  180. package/harness/bundles/general/pi/scripts/harness_runtime.py +2243 -0
  181. package/harness/bundles/general/pi/scripts/harness_service.py +3355 -0
  182. package/harness/bundles/general/pi/scripts/harness_state.py +365 -0
  183. package/harness/bundles/general/pi/scripts/harness_sync.py +407 -0
  184. package/harness/bundles/general/pi/scripts/harness_test_cleanup.py +175 -0
  185. package/harness/bundles/general/pi/scripts/harness_test_guard.py +1899 -0
  186. package/harness/bundles/general/pi/scripts/harness_test_runner.py +1586 -0
  187. package/harness/bundles/general/pi/scripts/harness_verification.py +593 -0
  188. package/harness/bundles/general/pi/scripts/harness_workflow_policy.py +266 -0
  189. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  190. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  191. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  192. package/harness/bundles/java/claude-code/harness-archive/reference.md +30 -1
  193. package/harness/bundles/java/claude-code/harness-archive/templates/summary-data-template.json +1 -0
  194. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  195. package/harness/bundles/java/claude-code/harness-execute/SKILL.md +1 -1
  196. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  197. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  198. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  199. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
  200. package/harness/bundles/java/claude-code/harness-pull/SKILL.md +1 -1
  201. package/harness/bundles/java/claude-code/harness-push/SKILL.md +1 -1
  202. package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
  203. package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
  204. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
  205. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  206. package/harness/bundles/java/claude-code/harness-test/SKILL.md +1 -1
  207. package/harness/bundles/java/claude-code/scripts/harness_archive.py +146 -8
  208. package/harness/bundles/java/claude-code/scripts/harness_deploy.py +1 -1
  209. package/harness/bundles/java/claude-code/scripts/harness_knowledge_candidates.py +538 -4
  210. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  211. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  212. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  213. package/harness/bundles/java/codebuddy/harness-archive/reference.md +30 -1
  214. package/harness/bundles/java/codebuddy/harness-archive/templates/summary-data-template.json +1 -0
  215. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  216. package/harness/bundles/java/codebuddy/harness-execute/SKILL.md +1 -1
  217. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  218. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  219. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  220. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
  221. package/harness/bundles/java/codebuddy/harness-pull/SKILL.md +1 -1
  222. package/harness/bundles/java/codebuddy/harness-push/SKILL.md +1 -1
  223. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
  224. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
  225. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
  226. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  227. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
  228. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +146 -8
  229. package/harness/bundles/java/codebuddy/scripts/harness_deploy.py +1 -1
  230. package/harness/bundles/java/codebuddy/scripts/harness_knowledge_candidates.py +538 -4
  231. package/harness/bundles/java/codex/.harness-build.json +1 -1
  232. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  233. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  234. package/harness/bundles/java/codex/harness-archive/reference.md +30 -1
  235. package/harness/bundles/java/codex/harness-archive/templates/summary-data-template.json +1 -0
  236. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  237. package/harness/bundles/java/codex/harness-execute/SKILL.md +1 -1
  238. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  239. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  240. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  241. package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
  242. package/harness/bundles/java/codex/harness-pull/SKILL.md +1 -1
  243. package/harness/bundles/java/codex/harness-push/SKILL.md +1 -1
  244. package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
  245. package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
  246. package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
  247. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  248. package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
  249. package/harness/bundles/java/codex/scripts/harness_archive.py +146 -8
  250. package/harness/bundles/java/codex/scripts/harness_deploy.py +1 -1
  251. package/harness/bundles/java/codex/scripts/harness_knowledge_candidates.py +538 -4
  252. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  253. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  254. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  255. package/harness/bundles/java/cursor/harness-archive/reference.md +30 -1
  256. package/harness/bundles/java/cursor/harness-archive/templates/summary-data-template.json +1 -0
  257. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  258. package/harness/bundles/java/cursor/harness-execute/SKILL.md +1 -1
  259. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  260. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  261. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  262. package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
  263. package/harness/bundles/java/cursor/harness-pull/SKILL.md +1 -1
  264. package/harness/bundles/java/cursor/harness-push/SKILL.md +1 -1
  265. package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
  266. package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
  267. package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
  268. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  269. package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
  270. package/harness/bundles/java/cursor/scripts/harness_archive.py +146 -8
  271. package/harness/bundles/java/cursor/scripts/harness_deploy.py +1 -1
  272. package/harness/bundles/java/cursor/scripts/harness_knowledge_candidates.py +538 -4
  273. package/harness/bundles/java/pi/.harness-build.json +6 -0
  274. package/harness/bundles/java/pi/CONTEXT.md +98 -0
  275. package/harness/bundles/java/pi/README.md +478 -0
  276. package/harness/bundles/java/pi/contracts/build-profile-v3.schema.json +302 -0
  277. package/harness/bundles/java/pi/contracts/ci-metrics.schema.json +36 -0
  278. package/harness/bundles/java/pi/contracts/doctor-capability.schema.json +43 -0
  279. package/harness/bundles/java/pi/contracts/external-platform-observation.schema.json +62 -0
  280. package/harness/bundles/java/pi/contracts/fixtures/managed-execution.json +341 -0
  281. package/harness/bundles/java/pi/contracts/process-identity.schema.json +132 -0
  282. package/harness/bundles/java/pi/contracts/run-session.schema.json +142 -0
  283. package/harness/bundles/java/pi/contracts/service-retirement-receipt.schema.json +85 -0
  284. package/harness/bundles/java/pi/contracts/service-session.schema.json +147 -0
  285. package/harness/bundles/java/pi/contracts/workflow-policy.json +574 -0
  286. package/harness/bundles/java/pi/harness-apidoc/SKILL.md +97 -0
  287. package/harness/bundles/java/pi/harness-apidoc/checklist.md +142 -0
  288. package/harness/bundles/java/pi/harness-apidoc/reference.md +233 -0
  289. package/harness/bundles/java/pi/harness-archive/SKILL.md +322 -0
  290. package/harness/bundles/java/pi/harness-archive/checklist.md +71 -0
  291. package/harness/bundles/java/pi/harness-archive/reference.md +150 -0
  292. package/harness/bundles/java/pi/harness-archive/scripts/gen-manifest.ps1 +31 -0
  293. package/harness/bundles/java/pi/harness-archive/templates/summary-data-template.json +218 -0
  294. package/harness/bundles/java/pi/harness-codebase-map/SKILL.md +116 -0
  295. package/harness/bundles/java/pi/harness-codebase-map/checklist.md +126 -0
  296. package/harness/bundles/java/pi/harness-codebase-map/reference.md +364 -0
  297. package/harness/bundles/java/pi/harness-codebase-map/templates/ARCHITECTURE.md +57 -0
  298. package/harness/bundles/java/pi/harness-codebase-map/templates/CONCERNS.md +49 -0
  299. package/harness/bundles/java/pi/harness-codebase-map/templates/CONVENTIONS.md +57 -0
  300. package/harness/bundles/java/pi/harness-codebase-map/templates/INTEGRATIONS.md +52 -0
  301. package/harness/bundles/java/pi/harness-codebase-map/templates/STACK.md +55 -0
  302. package/harness/bundles/java/pi/harness-codebase-map/templates/STRUCTURE.md +69 -0
  303. package/harness/bundles/java/pi/harness-codebase-map/templates/TESTING.md +64 -0
  304. package/harness/bundles/java/pi/harness-codebase-map/templates/map-manifest.schema.json +73 -0
  305. package/harness/bundles/java/pi/harness-codebase-map/templates/map-summary.md +64 -0
  306. package/harness/bundles/java/pi/harness-execute/SKILL.md +170 -0
  307. package/harness/bundles/java/pi/harness-knowledge-ingest/SKILL.md +103 -0
  308. package/harness/bundles/java/pi/harness-knowledge-query/SKILL.md +97 -0
  309. package/harness/bundles/java/pi/harness-package/SKILL.md +94 -0
  310. package/harness/bundles/java/pi/harness-package/checklist.md +322 -0
  311. package/harness/bundles/java/pi/harness-package/reference.md +210 -0
  312. package/harness/bundles/java/pi/harness-plan/SKILL.md +158 -0
  313. package/harness/bundles/java/pi/harness-plan/checklist.md +243 -0
  314. package/harness/bundles/java/pi/harness-plan/protocols.md +133 -0
  315. package/harness/bundles/java/pi/harness-plan/reference.md +468 -0
  316. package/harness/bundles/java/pi/harness-pull/SKILL.md +55 -0
  317. package/harness/bundles/java/pi/harness-push/SKILL.md +83 -0
  318. package/harness/bundles/java/pi/harness-review/SKILL.md +175 -0
  319. package/harness/bundles/java/pi/harness-review/checklist.md +124 -0
  320. package/harness/bundles/java/pi/harness-review/protocols.md +69 -0
  321. package/harness/bundles/java/pi/harness-review/reference.md +114 -0
  322. package/harness/bundles/java/pi/harness-run/SKILL.md +206 -0
  323. package/harness/bundles/java/pi/harness-run/checklist.md +252 -0
  324. package/harness/bundles/java/pi/harness-run/protocols.md +141 -0
  325. package/harness/bundles/java/pi/harness-run/reference.md +820 -0
  326. package/harness/bundles/java/pi/harness-submit/SKILL.md +189 -0
  327. package/harness/bundles/java/pi/harness-submit/checklist.md +452 -0
  328. package/harness/bundles/java/pi/harness-submit/reference.md +152 -0
  329. package/harness/bundles/java/pi/harness-sync/SKILL.md +72 -0
  330. package/harness/bundles/java/pi/harness-sync/reference.md +176 -0
  331. package/harness/bundles/java/pi/harness-test/SKILL.md +264 -0
  332. package/harness/bundles/java/pi/harness-test/checklist.md +320 -0
  333. package/harness/bundles/java/pi/harness-test/pitfalls-java.md +16 -0
  334. package/harness/bundles/java/pi/harness-test/pitfalls.md +307 -0
  335. package/harness/bundles/java/pi/harness-test/reference.md +792 -0
  336. package/harness/bundles/java/pi/harness-test/scripts/runtime-helpers.mjs +216 -0
  337. package/harness/bundles/java/pi/protocols/archive-report-protocol.md +196 -0
  338. package/harness/bundles/java/pi/protocols/ci-layering-protocol.md +22 -0
  339. package/harness/bundles/java/pi/protocols/evidence-based-reporting-protocol.md +134 -0
  340. package/harness/bundles/java/pi/protocols/execution-session-protocol.md +52 -0
  341. package/harness/bundles/java/pi/protocols/external-platform-protocol.md +27 -0
  342. package/harness/bundles/java/pi/protocols/ledger-protocol.md +365 -0
  343. package/harness/bundles/java/pi/protocols/memory-closeout-protocol.md +21 -0
  344. package/harness/bundles/java/pi/protocols/model-routing-protocol.md +22 -0
  345. package/harness/bundles/java/pi/protocols/powershell-protocol.md +238 -0
  346. package/harness/bundles/java/pi/protocols/registry-governance-protocol.md +31 -0
  347. package/harness/bundles/java/pi/protocols/report-pipeline-protocol.md +172 -0
  348. package/harness/bundles/java/pi/protocols/sensitive-info-protocol.md +110 -0
  349. package/harness/bundles/java/pi/protocols/state-layout-protocol.md +209 -0
  350. package/harness/bundles/java/pi/protocols/submit-protocol.md +78 -0
  351. package/harness/bundles/java/pi/protocols/verification-graph-protocol.md +32 -0
  352. package/harness/bundles/java/pi/scripts/harness_adoption_metrics.py +391 -0
  353. package/harness/bundles/java/pi/scripts/harness_apidoc.py +53 -0
  354. package/harness/bundles/java/pi/scripts/harness_archive.py +11345 -0
  355. package/harness/bundles/java/pi/scripts/harness_change.py +1626 -0
  356. package/harness/bundles/java/pi/scripts/harness_check_gate.py +113 -0
  357. package/harness/bundles/java/pi/scripts/harness_context.py +1774 -0
  358. package/harness/bundles/java/pi/scripts/harness_deploy.py +968 -0
  359. package/harness/bundles/java/pi/scripts/harness_efficiency.py +443 -0
  360. package/harness/bundles/java/pi/scripts/harness_environment.py +1690 -0
  361. package/harness/bundles/java/pi/scripts/harness_events.py +2234 -0
  362. package/harness/bundles/java/pi/scripts/harness_events_sync.py +1425 -0
  363. package/harness/bundles/java/pi/scripts/harness_execution_contracts.py +596 -0
  364. package/harness/bundles/java/pi/scripts/harness_fixback.py +1975 -0
  365. package/harness/bundles/java/pi/scripts/harness_gate.py +3816 -0
  366. package/harness/bundles/java/pi/scripts/harness_headless.py +37 -0
  367. package/harness/bundles/java/pi/scripts/harness_integration.py +2564 -0
  368. package/harness/bundles/java/pi/scripts/harness_knowledge_candidates.py +796 -0
  369. package/harness/bundles/java/pi/scripts/harness_ledger.py +3556 -0
  370. package/harness/bundles/java/pi/scripts/harness_migration_head.py +220 -0
  371. package/harness/bundles/java/pi/scripts/harness_orchestration.py +344 -0
  372. package/harness/bundles/java/pi/scripts/harness_paths.py +676 -0
  373. package/harness/bundles/java/pi/scripts/harness_phase.py +1726 -0
  374. package/harness/bundles/java/pi/scripts/harness_plan_aggregate.py +249 -0
  375. package/harness/bundles/java/pi/scripts/harness_plan_finalize.py +1016 -0
  376. package/harness/bundles/java/pi/scripts/harness_preflight.py +650 -0
  377. package/harness/bundles/java/pi/scripts/harness_process.py +1065 -0
  378. package/harness/bundles/java/pi/scripts/harness_profile.py +1817 -0
  379. package/harness/bundles/java/pi/scripts/harness_report_model.py +442 -0
  380. package/harness/bundles/java/pi/scripts/harness_retry.py +175 -0
  381. package/harness/bundles/java/pi/scripts/harness_review.py +631 -0
  382. package/harness/bundles/java/pi/scripts/harness_runtime.py +2243 -0
  383. package/harness/bundles/java/pi/scripts/harness_service.py +3355 -0
  384. package/harness/bundles/java/pi/scripts/harness_state.py +365 -0
  385. package/harness/bundles/java/pi/scripts/harness_sync.py +407 -0
  386. package/harness/bundles/java/pi/scripts/harness_test_cleanup.py +175 -0
  387. package/harness/bundles/java/pi/scripts/harness_test_guard.py +1899 -0
  388. package/harness/bundles/java/pi/scripts/harness_test_runner.py +1586 -0
  389. package/harness/bundles/java/pi/scripts/harness_verification.py +593 -0
  390. package/harness/bundles/java/pi/scripts/harness_workflow_policy.py +266 -0
  391. package/harness/manifests/general/claude-code.json +19 -19
  392. package/harness/manifests/general/codebuddy.json +19 -19
  393. package/harness/manifests/general/codex.json +19 -19
  394. package/harness/manifests/general/cursor.json +19 -19
  395. package/harness/manifests/general/pi.json +475 -0
  396. package/harness/manifests/java/claude-code.json +21 -21
  397. package/harness/manifests/java/codebuddy.json +21 -21
  398. package/harness/manifests/java/codex.json +21 -21
  399. package/harness/manifests/java/cursor.json +21 -21
  400. package/harness/manifests/java/pi.json +499 -0
  401. package/hunter-workflow-family.json +2 -2
  402. package/package.json +1 -1
@@ -0,0 +1,443 @@
1
+ #!/usr/bin/env python3
2
+ """Summarize execution efficiency without assigning blame."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import argparse
7
+ import datetime as dt
8
+ import json
9
+ import sys
10
+ from collections import Counter
11
+ from pathlib import Path
12
+ from statistics import median
13
+ from typing import Any, Iterable
14
+
15
+ SCRIPTS_DIR = Path(__file__).resolve().parent
16
+ if str(SCRIPTS_DIR) not in sys.path:
17
+ sys.path.insert(0, str(SCRIPTS_DIR))
18
+
19
+ from harness_paths import resolve_state_dir_for_contract
20
+
21
+
22
+ SCHEMA_VERSION = 1
23
+ FAILURE_CLASSES = ("launcher", "environment", "test", "external", "unknown")
24
+
25
+
26
+ def _integer(value: Any) -> int:
27
+ try:
28
+ return max(0, int(value or 0))
29
+ except (TypeError, ValueError):
30
+ return 0
31
+
32
+
33
+ def _timestamp(value: Any) -> dt.datetime | None:
34
+ if isinstance(value, dt.datetime):
35
+ parsed = value
36
+ elif value:
37
+ try:
38
+ parsed = dt.datetime.fromisoformat(str(value).replace("Z", "+00:00"))
39
+ except (TypeError, ValueError):
40
+ return None
41
+ else:
42
+ return None
43
+ if parsed.tzinfo is None:
44
+ parsed = parsed.replace(tzinfo=dt.timezone.utc)
45
+ return parsed.astimezone(dt.timezone.utc)
46
+
47
+
48
+ def _now_timestamp(value: Any = None) -> dt.datetime:
49
+ return _timestamp(value) or dt.datetime.now(dt.timezone.utc)
50
+
51
+
52
+ def _seconds(value: Any) -> float | None:
53
+ try:
54
+ parsed = float(value)
55
+ except (TypeError, ValueError):
56
+ return None
57
+ return parsed if parsed > 0 else None
58
+
59
+
60
+ def classify_progress(
61
+ session: dict[str, Any],
62
+ *,
63
+ now: Any = None,
64
+ historical_durations: list[int | float] | None = None,
65
+ ) -> dict[str, Any]:
66
+ """Classify observable run state without changing execution policy.
67
+
68
+ The classifier is intentionally conservative: incomplete clock/heartbeat
69
+ data produces explicit ``INCOMPLETE``/``NO_BUDGET`` facts instead of an
70
+ invented ETA or a guessed failure cause.
71
+ """
72
+ status = str(session.get("status") or "RUNNING").upper()
73
+ terminal = {
74
+ "OK": "COMPLETED",
75
+ "PASS": "COMPLETED",
76
+ "COMPLETED": "COMPLETED",
77
+ "FAIL": "FAILED",
78
+ "FAILED": "FAILED",
79
+ "CANCELLED": "CANCELLED",
80
+ "CANCELED": "CANCELLED",
81
+ "INCOMPLETE": "INCOMPLETE",
82
+ }
83
+ started = _timestamp(session.get("startedAt") or session.get("createdAt"))
84
+ current = _now_timestamp(now)
85
+ elapsed_seconds: float | None = None
86
+ if started is not None:
87
+ elapsed_seconds = max(0.0, (current - started).total_seconds())
88
+
89
+ timeout_seconds = _seconds(session.get("timeoutSeconds"))
90
+ expected_seconds = _seconds(
91
+ session.get("expectedDurationSeconds")
92
+ or session.get("estimatedDurationSeconds")
93
+ )
94
+ budget_seconds = _seconds(
95
+ session.get("budgetSeconds")
96
+ or session.get("maxDurationSeconds")
97
+ or expected_seconds
98
+ or timeout_seconds
99
+ )
100
+ if elapsed_seconds is None or budget_seconds is None:
101
+ budget_state = "NO_BUDGET"
102
+ elif elapsed_seconds >= budget_seconds:
103
+ budget_state = "OVER_BUDGET"
104
+ else:
105
+ budget_state = "WITHIN_BUDGET"
106
+
107
+ progress_state = terminal.get(status)
108
+ diagnostic_required = False
109
+ heartbeat_grace = _seconds(
110
+ session.get("heartbeatGraceSeconds")
111
+ or session.get("heartbeatTimeoutSeconds")
112
+ or 60
113
+ ) or 60
114
+ heartbeat = _timestamp(session.get("lastHeartbeatAt"))
115
+ output = _timestamp(
116
+ session.get("lastOutputAt") or session.get("lastLogAt")
117
+ )
118
+ heartbeat_gap = (
119
+ max(0.0, (current - heartbeat).total_seconds())
120
+ if heartbeat is not None
121
+ else None
122
+ )
123
+ output_gap = (
124
+ max(0.0, (current - output).total_seconds()) if output is not None else None
125
+ )
126
+
127
+ if progress_state is None:
128
+ progress_state = "RUNNING"
129
+ if timeout_seconds is not None and elapsed_seconds is not None and elapsed_seconds >= timeout_seconds:
130
+ progress_state = "TIMEOUT"
131
+ elif output_gap is not None and output_gap > heartbeat_grace:
132
+ progress_state = "NO_OUTPUT_PROCESS_ACTIVE"
133
+ elif heartbeat_gap is None or heartbeat_gap > heartbeat_grace:
134
+ progress_state = "HEARTBEAT_LOST"
135
+ elif _integer(session.get("resourceWaitMs")) > 0 or session.get("resourceWaitActive") is True:
136
+ progress_state = "RESOURCE_WAIT"
137
+ elif expected_seconds is not None and elapsed_seconds is not None and elapsed_seconds > expected_seconds:
138
+ progress_state = "SLOW_PROGRESSING"
139
+ diagnostic_required = progress_state in {
140
+ "TIMEOUT",
141
+ "HEARTBEAT_LOST",
142
+ "NO_OUTPUT_PROCESS_ACTIVE",
143
+ } or budget_state == "OVER_BUDGET"
144
+ elif progress_state not in {"COMPLETED", "FAILED", "CANCELLED"}:
145
+ diagnostic_required = True
146
+
147
+ return {
148
+ "progressState": progress_state,
149
+ "budgetState": budget_state,
150
+ "diagnosticRequired": diagnostic_required,
151
+ "elapsedSeconds": int(elapsed_seconds) if elapsed_seconds is not None else None,
152
+ "budgetSeconds": budget_seconds,
153
+ "heartbeatGapSeconds": int(heartbeat_gap) if heartbeat_gap is not None else None,
154
+ "outputGapSeconds": int(output_gap) if output_gap is not None else None,
155
+ }
156
+
157
+
158
+ def _failure_class(session: dict[str, Any]) -> str | None:
159
+ status = str(session.get("status") or "").upper()
160
+ reason = str(session.get("reasonCode") or "").upper()
161
+ if status == "OK":
162
+ return None
163
+ if reason.startswith(("LAUNCHER_", "WORKER_", "LAUNCH_SPEC_")):
164
+ return "launcher"
165
+ if any(
166
+ token in reason
167
+ for token in ("ENVIRONMENT", "DOCKER", "PREFLIGHT", "RESOURCE_WAIT")
168
+ ):
169
+ return "environment"
170
+ if reason in {"EXTERNAL_WINDOW_ABORT", "CLIENT_DISCONNECTED"}:
171
+ return "external"
172
+ if status == "FAIL" or reason == "CHILD_EXIT_NONZERO":
173
+ return "test"
174
+ return "unknown"
175
+
176
+
177
+ def _counts(values: Iterable[str]) -> dict[str, int]:
178
+ return dict(sorted(Counter(values).items()))
179
+
180
+
181
+ def _wall_clock_ms(run_sessions: list[dict[str, Any]]) -> int:
182
+ intervals: list[tuple[dt.datetime, dt.datetime]] = []
183
+ fallback = 0
184
+ for session in run_sessions:
185
+ start_raw = session.get("createdAt") or session.get("startedAt")
186
+ end_raw = session.get("endedAt")
187
+ try:
188
+ start = dt.datetime.fromisoformat(
189
+ str(start_raw).replace("Z", "+00:00")
190
+ )
191
+ end = dt.datetime.fromisoformat(str(end_raw).replace("Z", "+00:00"))
192
+ if start.tzinfo is None:
193
+ start = start.astimezone()
194
+ if end.tzinfo is None:
195
+ end = end.astimezone()
196
+ if end < start:
197
+ raise ValueError("negative interval")
198
+ intervals.append((start.astimezone(dt.timezone.utc), end.astimezone(dt.timezone.utc)))
199
+ except (TypeError, ValueError):
200
+ fallback += _integer(session.get("wallClockMs"))
201
+ merged_ms = 0
202
+ current_start: dt.datetime | None = None
203
+ current_end: dt.datetime | None = None
204
+ for start, end in sorted(intervals):
205
+ if current_start is None or current_end is None:
206
+ current_start, current_end = start, end
207
+ continue
208
+ if start <= current_end:
209
+ current_end = max(current_end, end)
210
+ else:
211
+ merged_ms += int((current_end - current_start).total_seconds() * 1000)
212
+ current_start, current_end = start, end
213
+ if current_start is not None and current_end is not None:
214
+ merged_ms += int((current_end - current_start).total_seconds() * 1000)
215
+ return merged_ms + fallback
216
+
217
+
218
+ def _timing_by_stage(
219
+ run_sessions: list[dict[str, Any]],
220
+ ) -> dict[str, dict[str, int]]:
221
+ grouped: dict[str, list[dict[str, Any]]] = {}
222
+ for session in run_sessions:
223
+ stage_timings = session.get("stageTimings")
224
+ if isinstance(stage_timings, list) and stage_timings:
225
+ for item in stage_timings:
226
+ if isinstance(item, dict):
227
+ stage = str(item.get("stage") or "unknown")
228
+ grouped.setdefault(stage, []).append(item)
229
+ continue
230
+ stage = str(
231
+ session.get("stage")
232
+ or session.get("verification")
233
+ or "unknown"
234
+ )
235
+ grouped.setdefault(stage, []).append(session)
236
+ return {
237
+ stage: {
238
+ "wallClockMs": _wall_clock_ms(items),
239
+ "activeTimeMs": sum(_integer(item.get("activeTimeMs")) for item in items),
240
+ "resourceWaitMs": sum(
241
+ _integer(item.get("resourceWaitMs")) for item in items
242
+ ),
243
+ "attempts": len(items),
244
+ }
245
+ for stage, items in sorted(grouped.items())
246
+ }
247
+
248
+
249
+ def build_efficiency_summary(
250
+ *,
251
+ run_sessions: list[dict[str, Any]],
252
+ environment_receipts: list[dict[str, Any]],
253
+ invalidations: list[dict[str, Any]],
254
+ ) -> dict[str, Any]:
255
+ failure_counts = {key: 0 for key in FAILURE_CLASSES}
256
+ progress_states: Counter[str] = Counter()
257
+ budget_states: Counter[str] = Counter()
258
+ slow_stages: Counter[str] = Counter()
259
+ for session in run_sessions:
260
+ classification = _failure_class(session)
261
+ if classification is not None:
262
+ failure_counts[classification] += 1
263
+ progress = str(
264
+ session.get("progressState")
265
+ or classify_progress(session).get("progressState")
266
+ or "INCOMPLETE"
267
+ ).upper()
268
+ budget = str(
269
+ session.get("budgetState")
270
+ or classify_progress(session).get("budgetState")
271
+ or "NO_BUDGET"
272
+ ).upper()
273
+ progress_states[progress] += 1
274
+ budget_states[budget] += 1
275
+ if progress == "SLOW_PROGRESSING":
276
+ slow_stages[str(session.get("stage") or session.get("verification") or "unknown")] += 1
277
+ environment_actions: Counter[str] = Counter()
278
+ for item in environment_receipts:
279
+ action = str(item.get("action") or "").lower()
280
+ if action not in {"prepare", "reuse", "reset", "cleanup"}:
281
+ continue
282
+ if action in {"reset", "cleanup"}:
283
+ evidence = item.get("operationEvidence")
284
+ if not isinstance(evidence, dict) or evidence.get("status") != "OK":
285
+ continue
286
+ environment_actions[action] += 1
287
+ evidence_counts = Counter(
288
+ (
289
+ str(item.get("commandHash")),
290
+ str(item.get("productIdentity")),
291
+ str(item.get("resultDigest")),
292
+ )
293
+ for item in run_sessions
294
+ if str(item.get("commandHash") or "").strip()
295
+ and str(item.get("productIdentity") or "").strip()
296
+ and str(item.get("resultDigest") or "").strip()
297
+ and item.get("testProcessStarted") is True
298
+ )
299
+ product_identities = {
300
+ str(item.get("productIdentity"))
301
+ for item in run_sessions
302
+ if str(item.get("productIdentity") or "").strip()
303
+ }
304
+ return {
305
+ "schemaVersion": SCHEMA_VERSION,
306
+ "timing": {
307
+ "wallClockMs": _wall_clock_ms(run_sessions),
308
+ "activeTimeMs": sum(
309
+ _integer(item.get("activeTimeMs")) for item in run_sessions
310
+ ),
311
+ "resourceWaitMs": sum(
312
+ _integer(item.get("resourceWaitMs")) for item in run_sessions
313
+ ),
314
+ },
315
+ "timingByStage": _timing_by_stage(run_sessions),
316
+ "executionAttempts": len(run_sessions),
317
+ "verificationAttempts": sum(
318
+ 1 for item in run_sessions if item.get("testProcessStarted") is True
319
+ ),
320
+ "launcherAttempts": sum(
321
+ 1 for item in run_sessions if item.get("testProcessStarted") is not True
322
+ ),
323
+ "statusCounts": _counts(
324
+ str(item.get("status") or "UNKNOWN").upper()
325
+ for item in run_sessions
326
+ ),
327
+ "failureClasses": failure_counts,
328
+ "progressStates": dict(sorted(progress_states.items())),
329
+ "budgetStates": dict(sorted(budget_states.items())),
330
+ "slowStages": dict(sorted(slow_stages.items())),
331
+ "invalidationReasons": _counts(
332
+ str(item.get("reasonCode") or "UNKNOWN")
333
+ for item in invalidations
334
+ ),
335
+ "environment": {
336
+ key: environment_actions.get(key, 0)
337
+ for key in ("prepare", "reuse", "reset", "cleanup")
338
+ },
339
+ "productIdentityCount": len(product_identities),
340
+ "repeatedCommandsWithoutNewEvidence": sum(
341
+ max(count - 1, 0) for count in evidence_counts.values()
342
+ ),
343
+ "manualWrapperCount": sum(
344
+ 1
345
+ for item in run_sessions
346
+ if item.get("managedByHarness") is False
347
+ ),
348
+ "notes": [
349
+ "Metrics separate launcher, environment, test, and external failures.",
350
+ "This summary reports facts and does not assign responsibility.",
351
+ ],
352
+ }
353
+
354
+
355
+ def compact_progress_view(
356
+ session: dict[str, Any],
357
+ *,
358
+ historical_durations: list[int | float],
359
+ ) -> dict[str, Any]:
360
+ completed = _integer(session.get("completedItems"))
361
+ planned = _integer(session.get("plannedItems"))
362
+ durations = sorted(
363
+ _integer(value) for value in historical_durations if _integer(value) > 0
364
+ )
365
+ eta: str | dict[str, int]
366
+ if len(durations) < 3:
367
+ eta = "INSUFFICIENT_HISTORY"
368
+ else:
369
+ eta = {
370
+ "lowSeconds": durations[0],
371
+ "typicalSeconds": int(median(durations)),
372
+ "highSeconds": durations[-1],
373
+ }
374
+ classification = classify_progress(
375
+ session,
376
+ historical_durations=historical_durations,
377
+ )
378
+ return {
379
+ "verification": session.get("verification"),
380
+ "stage": session.get("stage"),
381
+ "progress": f"{completed}/{planned}" if planned else str(completed),
382
+ "lastHeartbeatAt": session.get("lastHeartbeatAt"),
383
+ "expectedDurationSeconds": session.get("expectedDurationSeconds"),
384
+ "eta": eta,
385
+ "resourceWait": list(session.get("resourceLocks") or []),
386
+ "status": session.get("status", "RUNNING"),
387
+ "progressState": classification["progressState"],
388
+ "budgetState": classification["budgetState"],
389
+ "diagnosticRequired": classification["diagnosticRequired"],
390
+ "elapsedSeconds": classification["elapsedSeconds"],
391
+ }
392
+
393
+
394
+ def _read_objects(paths: list[Path]) -> list[dict[str, Any]]:
395
+ values: list[dict[str, Any]] = []
396
+ for path in paths:
397
+ try:
398
+ value = json.loads(path.read_text(encoding="utf-8-sig"))
399
+ except (OSError, json.JSONDecodeError):
400
+ continue
401
+ if isinstance(value, dict):
402
+ values.append(value)
403
+ elif isinstance(value, list):
404
+ values.extend(item for item in value if isinstance(item, dict))
405
+ return values
406
+
407
+
408
+ def collect_efficiency_summary(change_dir: Path) -> dict[str, Any]:
409
+ state_root = Path(resolve_state_dir_for_contract(change_dir)).resolve()
410
+ run_sessions = _read_objects(
411
+ sorted((state_root / "runtime" / "run-sessions").glob("*/session.json"))
412
+ )
413
+ environment_receipts = _read_objects(
414
+ sorted((state_root / "runtime" / "environment-receipts").glob("*.json"))
415
+ )
416
+ invalidations = _read_objects(
417
+ sorted((state_root / "runtime" / "invalidations").glob("*.json"))
418
+ )
419
+ return build_efficiency_summary(
420
+ run_sessions=run_sessions,
421
+ environment_receipts=environment_receipts,
422
+ invalidations=invalidations,
423
+ )
424
+
425
+
426
+ def main(argv: list[str] | None = None) -> int:
427
+ parser = argparse.ArgumentParser(prog="harness_efficiency.py")
428
+ parser.add_argument("summary", nargs="?")
429
+ parser.add_argument("--change-dir", required=True)
430
+ parser.add_argument("--out")
431
+ args = parser.parse_args(argv)
432
+ result = collect_efficiency_summary(Path(args.change_dir))
433
+ text = json.dumps(result, ensure_ascii=False, indent=2) + "\n"
434
+ if args.out:
435
+ path = Path(args.out)
436
+ path.parent.mkdir(parents=True, exist_ok=True)
437
+ path.write_text(text, encoding="utf-8", newline="\n")
438
+ print(text, end="")
439
+ return 0
440
+
441
+
442
+ if __name__ == "__main__":
443
+ raise SystemExit(main())