@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,220 @@
1
+ #!/usr/bin/env python3
2
+ """Migration head single-source consistency check (Wave-2 H-7).
3
+
4
+ Canonical file (default ``.harness/config/migration-head.json``)::
5
+
6
+ {
7
+ "schemaVersion": 1,
8
+ "head": "005_example",
9
+ "sources": [
10
+ {"path": "backend/app/config.py", "pattern": "EXPECTED_ALEMBIC_HEAD\\s*=\\s*[\\\"']([^\\\"']+)[\\\"']"},
11
+ {"path": "integration/manifest.json", "jsonPointer": "/migrationHead"}
12
+ ]
13
+ }
14
+
15
+ Each source must resolve to the same ``head`` value. This harness repo may not
16
+ ship alembic; consumer projects declare the canonical file and run::
17
+
18
+ python harness_migration_head.py check --project . --json
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ import argparse
24
+ import json
25
+ import re
26
+ import sys
27
+ from pathlib import Path
28
+ from typing import Any
29
+
30
+ DEFAULT_REL = ".harness/config/migration-head.json"
31
+
32
+
33
+ def emit_json(payload: dict[str, Any], *, as_json: bool) -> None:
34
+ if as_json:
35
+ sys.stdout.write(json.dumps(payload, ensure_ascii=False, indent=2) + "\n")
36
+ else:
37
+ code = payload.get("code") or ("OK" if payload.get("ok") else "FAIL")
38
+ sys.stdout.write(f"{code}\n")
39
+
40
+
41
+ def emit_error(code: str, message: str, *, as_json: bool, extra: dict[str, Any] | None = None) -> int:
42
+ payload: dict[str, Any] = {"ok": False, "code": code, "message": message}
43
+ if extra:
44
+ payload.update(extra)
45
+ stream = sys.stdout if as_json else sys.stderr
46
+ if as_json:
47
+ stream.write(json.dumps(payload, ensure_ascii=False, indent=2) + "\n")
48
+ else:
49
+ stream.write(f"{code}: {message}\n")
50
+ return 1
51
+
52
+
53
+ def _read_json_pointer(data: Any, pointer: str) -> Any:
54
+ if not pointer.startswith("/"):
55
+ raise ValueError(f"jsonPointer must start with /: {pointer}")
56
+ cur = data
57
+ for part in pointer.lstrip("/").split("/"):
58
+ part = part.replace("~1", "/").replace("~0", "~")
59
+ if isinstance(cur, dict) and part in cur:
60
+ cur = cur[part]
61
+ else:
62
+ raise KeyError(pointer)
63
+ return cur
64
+
65
+
66
+ def _extract_source(project: Path, source: dict[str, Any]) -> str:
67
+ rel = str(source.get("path") or "").strip().replace("\\", "/")
68
+ if not rel or rel.startswith("/") or ".." in rel.split("/"):
69
+ raise ValueError(f"invalid source path: {rel}")
70
+ target = (project / rel).resolve()
71
+ try:
72
+ target.relative_to(project.resolve())
73
+ except ValueError as exc:
74
+ raise ValueError(f"source escapes project: {rel}") from exc
75
+ if not target.is_file():
76
+ raise FileNotFoundError(rel)
77
+ text = target.read_text(encoding="utf-8-sig")
78
+ if "jsonPointer" in source and source["jsonPointer"]:
79
+ data = json.loads(text)
80
+ value = _read_json_pointer(data, str(source["jsonPointer"]))
81
+ if value is None or (isinstance(value, str) and not value.strip()):
82
+ raise ValueError(f"empty value at {source['jsonPointer']} in {rel}")
83
+ return str(value).strip()
84
+ pattern = str(source.get("pattern") or "").strip()
85
+ if not pattern:
86
+ raise ValueError(f"source {rel} requires pattern or jsonPointer")
87
+ match = re.search(pattern, text, flags=re.MULTILINE)
88
+ if not match:
89
+ raise ValueError(f"pattern did not match in {rel}")
90
+ return str(match.group(1) if match.lastindex else match.group(0)).strip()
91
+
92
+
93
+ def check_migration_head(
94
+ project: Path,
95
+ *,
96
+ config_rel: str = DEFAULT_REL,
97
+ ) -> dict[str, Any]:
98
+ project = project.resolve()
99
+ config_path = (project / config_rel).resolve()
100
+ try:
101
+ config_path.relative_to(project)
102
+ except ValueError:
103
+ return {
104
+ "ok": False,
105
+ "code": "MIGRATION_HEAD_CONFIG_ESCAPE",
106
+ "message": f"config path escapes project: {config_rel}",
107
+ }
108
+ if not config_path.is_file():
109
+ return {
110
+ "ok": False,
111
+ "code": "MIGRATION_HEAD_MISSING",
112
+ "message": f"canonical migration-head file missing: {config_rel}",
113
+ "configPath": str(config_path),
114
+ }
115
+ try:
116
+ data = json.loads(config_path.read_text(encoding="utf-8-sig"))
117
+ except (OSError, json.JSONDecodeError) as exc:
118
+ return {
119
+ "ok": False,
120
+ "code": "MIGRATION_HEAD_UNREADABLE",
121
+ "message": str(exc),
122
+ "configPath": str(config_path),
123
+ }
124
+ if not isinstance(data, dict) or data.get("schemaVersion") != 1:
125
+ return {
126
+ "ok": False,
127
+ "code": "MIGRATION_HEAD_SCHEMA_INVALID",
128
+ "message": "migration-head.json must be schemaVersion 1 object",
129
+ "configPath": str(config_path),
130
+ }
131
+ head = str(data.get("head") or "").strip()
132
+ sources = data.get("sources")
133
+ if not head:
134
+ return {
135
+ "ok": False,
136
+ "code": "MIGRATION_HEAD_EMPTY",
137
+ "message": "head must be a non-empty string",
138
+ "configPath": str(config_path),
139
+ }
140
+ if not isinstance(sources, list) or not sources:
141
+ return {
142
+ "ok": False,
143
+ "code": "MIGRATION_HEAD_SOURCES_EMPTY",
144
+ "message": "sources must be a non-empty array",
145
+ "configPath": str(config_path),
146
+ }
147
+
148
+ observed: list[dict[str, Any]] = []
149
+ drifts: list[dict[str, Any]] = []
150
+ for index, source in enumerate(sources):
151
+ if not isinstance(source, dict):
152
+ return {
153
+ "ok": False,
154
+ "code": "MIGRATION_HEAD_SOURCE_INVALID",
155
+ "message": f"sources[{index}] must be an object",
156
+ }
157
+ try:
158
+ value = _extract_source(project, source)
159
+ except (OSError, ValueError, KeyError, json.JSONDecodeError) as exc:
160
+ return {
161
+ "ok": False,
162
+ "code": "MIGRATION_HEAD_SOURCE_UNREADABLE",
163
+ "message": str(exc),
164
+ "index": index,
165
+ "path": source.get("path"),
166
+ }
167
+ item = {"path": source.get("path"), "value": value}
168
+ observed.append(item)
169
+ if value != head:
170
+ drifts.append({**item, "expected": head})
171
+
172
+ if drifts:
173
+ return {
174
+ "ok": False,
175
+ "code": "MIGRATION_HEAD_DRIFT",
176
+ "message": "one or more sources disagree with canonical head",
177
+ "head": head,
178
+ "drifts": drifts,
179
+ "observed": observed,
180
+ "configPath": str(config_path),
181
+ }
182
+ return {
183
+ "ok": True,
184
+ "code": "MIGRATION_HEAD_OK",
185
+ "head": head,
186
+ "observed": observed,
187
+ "configPath": str(config_path),
188
+ "sourceCount": len(observed),
189
+ }
190
+
191
+
192
+ def build_parser() -> argparse.ArgumentParser:
193
+ parser = argparse.ArgumentParser(prog="harness_migration_head.py")
194
+ sub = parser.add_subparsers(dest="command", required=True)
195
+ check = sub.add_parser("check", help="verify sources match canonical head")
196
+ check.add_argument("--project", required=True)
197
+ check.add_argument("--config", default=DEFAULT_REL)
198
+ check.add_argument("--json", action="store_true")
199
+ return parser
200
+
201
+
202
+ def main(argv: list[str] | None = None) -> int:
203
+ args = build_parser().parse_args(argv)
204
+ as_json = bool(getattr(args, "json", False))
205
+ if args.command == "check":
206
+ result = check_migration_head(Path(args.project), config_rel=str(args.config))
207
+ if not result.get("ok"):
208
+ return emit_error(
209
+ str(result.get("code") or "MIGRATION_HEAD_FAIL"),
210
+ str(result.get("message") or "check failed"),
211
+ as_json=as_json,
212
+ extra={k: v for k, v in result.items() if k not in {"ok", "code", "message"}},
213
+ )
214
+ emit_json(result, as_json=as_json)
215
+ return 0
216
+ return emit_error("UNKNOWN_COMMAND", f"unknown command: {args.command}", as_json=as_json)
217
+
218
+
219
+ if __name__ == "__main__":
220
+ raise SystemExit(main())
@@ -0,0 +1,344 @@
1
+ #!/usr/bin/env python3
2
+ """Compose environment, identity, verification, and progress decisions.
3
+
4
+ The planner is deliberately side-effect free. It consumes already-produced
5
+ receipts and declarations; provider operations and managed test execution stay
6
+ in their existing lifecycle modules.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import datetime as dt
13
+ import fnmatch
14
+ import json
15
+ import sys
16
+ from collections import Counter
17
+ from pathlib import Path
18
+ from typing import Any
19
+
20
+ try:
21
+ import harness_efficiency
22
+ import harness_verification
23
+ except ImportError: # pragma: no cover - supports direct source loading
24
+ SCRIPTS_DIR = Path(__file__).resolve().parent
25
+ if str(SCRIPTS_DIR) not in sys.path:
26
+ sys.path.insert(0, str(SCRIPTS_DIR))
27
+ import harness_efficiency
28
+ import harness_verification
29
+
30
+
31
+ SCHEMA_VERSION = 1
32
+ VALID_ENVIRONMENT_MODES = {"change-session", "ephemeral"}
33
+
34
+
35
+ def _timestamp(value: Any) -> dt.datetime | None:
36
+ if isinstance(value, dt.datetime):
37
+ parsed = value
38
+ elif value:
39
+ try:
40
+ parsed = dt.datetime.fromisoformat(str(value).replace("Z", "+00:00"))
41
+ except (TypeError, ValueError):
42
+ return None
43
+ else:
44
+ return None
45
+ if parsed.tzinfo is None:
46
+ parsed = parsed.replace(tzinfo=dt.timezone.utc)
47
+ return parsed.astimezone(dt.timezone.utc)
48
+
49
+
50
+ def _targets(raw: Any) -> list[dict[str, Any]]:
51
+ if isinstance(raw, dict):
52
+ return [
53
+ {**dict(value), "id": str(value.get("id") or key)}
54
+ for key, value in sorted(raw.items())
55
+ if isinstance(value, dict)
56
+ ]
57
+ if isinstance(raw, list):
58
+ return [
59
+ dict(value)
60
+ for value in raw
61
+ if isinstance(value, dict) and str(value.get("id") or "").strip()
62
+ ]
63
+ return []
64
+
65
+
66
+ def _record(reason_code: str, explanation: str, *, target_id: str = "", path: str = "") -> dict[str, Any]:
67
+ result = {
68
+ "reasonCode": reason_code,
69
+ "explanation": explanation,
70
+ }
71
+ if target_id:
72
+ result["targetId"] = target_id
73
+ if path:
74
+ result["path"] = path
75
+ return result
76
+
77
+
78
+ def build_invalidation_records(payload: dict[str, Any]) -> list[dict[str, Any]]:
79
+ changed = sorted(
80
+ {str(path).replace("\\", "/") for path in payload.get("changedFiles", []) if str(path).strip()}
81
+ )
82
+ records: list[dict[str, Any]] = []
83
+ targets = _targets(payload.get("targets", []))
84
+ for target in sorted(targets, key=lambda item: str(item.get("id") or "")):
85
+ target_id = str(target.get("id") or "")
86
+ patterns = [str(pattern) for pattern in target.get("inputs", [])]
87
+ for path in changed:
88
+ if any(fnmatch.fnmatch(path, pattern) for pattern in patterns):
89
+ records.append(
90
+ _record(
91
+ "PRODUCT_INPUT_CHANGED",
92
+ f"Changed path {path} matches verification input for {target_id}.",
93
+ target_id=target_id,
94
+ path=path,
95
+ )
96
+ )
97
+
98
+ product_identity = str(payload.get("productIdentity") or "").strip()
99
+ frozen_identity = str(payload.get("frozenIdentity") or "").strip()
100
+ for target in sorted(targets, key=lambda item: str(item.get("id") or "")):
101
+ if target.get("requiresFrozenIdentity") is True and product_identity and frozen_identity and product_identity != frozen_identity:
102
+ records.append(
103
+ _record(
104
+ "FROZEN_IDENTITY_DRIFT",
105
+ "Current product identity differs from the frozen identity required by the target.",
106
+ target_id=str(target.get("id") or ""),
107
+ )
108
+ )
109
+ graph_identity = str(payload.get("verificationGraphIdentity") or "").strip()
110
+ previous_graph = str(payload.get("previousVerificationGraphIdentity") or "").strip()
111
+ if graph_identity and previous_graph and graph_identity != previous_graph:
112
+ records.append(
113
+ _record(
114
+ "VERIFICATION_GRAPH_CHANGED",
115
+ "The declared verification graph identity changed since the previous plan.",
116
+ )
117
+ )
118
+ environment = payload.get("environment")
119
+ environment_hash = str(environment.get("environmentHash") or "").strip() if isinstance(environment, dict) else ""
120
+ previous_environment = str(payload.get("previousEnvironmentIdentity") or "").strip()
121
+ if environment_hash and previous_environment and environment_hash != previous_environment:
122
+ records.append(
123
+ _record(
124
+ "ENVIRONMENT_IDENTITY_CHANGED",
125
+ "The current environment identity differs from the previous environment session.",
126
+ )
127
+ )
128
+ return sorted(
129
+ records,
130
+ key=lambda item: (
131
+ str(item.get("reasonCode") or ""),
132
+ str(item.get("targetId") or ""),
133
+ str(item.get("path") or ""),
134
+ ),
135
+ )
136
+
137
+
138
+ def validate_environment_contract(payload: dict[str, Any]) -> dict[str, Any]:
139
+ environment = payload.get("environment")
140
+ if not isinstance(environment, dict) or environment.get("required") is False:
141
+ return {
142
+ "ok": True,
143
+ "decision": "NOT_REQUIRED",
144
+ "reasonCode": "ENVIRONMENT_NOT_REQUIRED",
145
+ "explanation": "This orchestration payload does not require a managed environment session.",
146
+ }
147
+ mode = str(environment.get("mode") or "").strip()
148
+ if mode not in VALID_ENVIRONMENT_MODES:
149
+ return {
150
+ "ok": False,
151
+ "decision": "BLOCKED",
152
+ "reasonCode": "ENVIRONMENT_SESSION_MODE_INVALID",
153
+ "explanation": "Environment mode must be change-session or ephemeral.",
154
+ }
155
+ lease = environment.get("lease")
156
+ if not isinstance(lease, dict):
157
+ return {
158
+ "ok": False,
159
+ "decision": "BLOCKED",
160
+ "reasonCode": "ENVIRONMENT_LEASE_REQUIRED",
161
+ "explanation": "A typed active environment lease is required before verification.",
162
+ "mode": mode,
163
+ }
164
+ change_id = str(payload.get("changeId") or "").strip()
165
+ expected_hash = str(environment.get("environmentHash") or "").strip()
166
+ expected_content = str(environment.get("contentFingerprint") or "").strip()
167
+ if lease.get("status") != "ACTIVE":
168
+ return {
169
+ "ok": False,
170
+ "decision": "BLOCKED",
171
+ "reasonCode": "ENVIRONMENT_LEASE_INACTIVE",
172
+ "explanation": "The environment lease is not active.",
173
+ "mode": mode,
174
+ }
175
+ if str(lease.get("changeId") or "") != change_id:
176
+ return {
177
+ "ok": False,
178
+ "decision": "BLOCKED",
179
+ "reasonCode": "ENVIRONMENT_LEASE_CROSS_CHANGE",
180
+ "explanation": "The environment lease is owned by a different change.",
181
+ "mode": mode,
182
+ }
183
+ if str(lease.get("mode") or mode) != mode:
184
+ return {
185
+ "ok": False,
186
+ "decision": "BLOCKED",
187
+ "reasonCode": "ENVIRONMENT_SESSION_MODE_MISMATCH",
188
+ "explanation": "The lease mode does not match the requested session mode.",
189
+ "mode": mode,
190
+ }
191
+ if expected_hash and str(lease.get("environmentHash") or "") != expected_hash:
192
+ return {
193
+ "ok": False,
194
+ "decision": "BLOCKED",
195
+ "reasonCode": "ENVIRONMENT_IDENTITY_MISMATCH",
196
+ "explanation": "The active lease environment identity does not match the requested identity.",
197
+ "mode": mode,
198
+ }
199
+ if expected_content and str(lease.get("contentFingerprint") or "") != expected_content:
200
+ return {
201
+ "ok": False,
202
+ "decision": "BLOCKED",
203
+ "reasonCode": "ENVIRONMENT_CONTENT_IDENTITY_MISMATCH",
204
+ "explanation": "The active lease content fingerprint does not match the typed receipt.",
205
+ "mode": mode,
206
+ }
207
+ expires_at = _timestamp(lease.get("expiresAt"))
208
+ if expires_at is None or expires_at <= dt.datetime.now(dt.timezone.utc):
209
+ return {
210
+ "ok": False,
211
+ "decision": "RESET_REQUIRED",
212
+ "reasonCode": "ENVIRONMENT_LEASE_EXPIRED",
213
+ "explanation": "The environment lease has expired and must be reacquired before verification.",
214
+ "mode": mode,
215
+ }
216
+ if lease.get("ownerVerified") is not True:
217
+ return {
218
+ "ok": False,
219
+ "decision": "BLOCKED",
220
+ "reasonCode": "ENVIRONMENT_OWNER_UNVERIFIED",
221
+ "explanation": "The recorded lease owner cannot be verified for this execution.",
222
+ "mode": mode,
223
+ }
224
+ required = {
225
+ str(item).strip()
226
+ for item in environment.get("requiredFields", [])
227
+ if str(item).strip()
228
+ }
229
+ resolved = environment.get("resolvedFields")
230
+ resolved = resolved if isinstance(resolved, dict) else {}
231
+ missing = sorted(field for field in required if not str(resolved.get(field) or "").strip())
232
+ if missing:
233
+ return {
234
+ "ok": False,
235
+ "decision": "BLOCKED",
236
+ "reasonCode": "VERIFICATION_ENVIRONMENT_INCOMPLETE",
237
+ "explanation": "Required dynamic environment identities are missing from the receipt.",
238
+ "missing": missing,
239
+ "mode": mode,
240
+ }
241
+ decision = "REUSE_ELIGIBLE" if environment.get("reuseEligible") is True else "READY"
242
+ reason = "ENVIRONMENT_REUSE_ELIGIBLE" if decision == "REUSE_ELIGIBLE" else "ENVIRONMENT_READY"
243
+ return {
244
+ "ok": True,
245
+ "decision": decision,
246
+ "reasonCode": reason,
247
+ "explanation": (
248
+ "The active environment lease and typed content identity are valid for reuse."
249
+ if decision == "REUSE_ELIGIBLE"
250
+ else "The active environment lease, owner, TTL, content identity, and required fields are valid."
251
+ ),
252
+ "mode": mode,
253
+ "environmentHash": expected_hash,
254
+ "contentFingerprint": expected_content,
255
+ }
256
+
257
+
258
+ def _budget_state(payload: dict[str, Any]) -> dict[str, Any]:
259
+ budget = payload.get("budget")
260
+ if not isinstance(budget, dict):
261
+ return {"state": "NO_BUDGET", "maxDurationSeconds": None}
262
+ raw = budget.get("maxDurationSeconds") or budget.get("budgetSeconds")
263
+ try:
264
+ seconds = float(raw)
265
+ except (TypeError, ValueError):
266
+ seconds = 0
267
+ if seconds <= 0:
268
+ return {"state": "NO_BUDGET", "maxDurationSeconds": None}
269
+ return {
270
+ "state": str(budget.get("state") or "WITHIN_BUDGET").upper(),
271
+ "maxDurationSeconds": int(seconds),
272
+ }
273
+
274
+
275
+ def build_orchestration_plan(payload: dict[str, Any]) -> dict[str, Any]:
276
+ if not isinstance(payload, dict):
277
+ return {"ok": False, "code": "ORCHESTRATION_PAYLOAD_INVALID"}
278
+ targets = _targets(payload.get("targets", []))
279
+ if not targets:
280
+ return {"ok": False, "code": "VERIFICATION_TARGETS_REQUIRED"}
281
+ selection = harness_verification.select_verifications(payload)
282
+ selected = selection.get("selected") if isinstance(selection, dict) else []
283
+ schedule_payload = dict(payload)
284
+ schedule_payload["targets"] = selected if selected else targets
285
+ verification = harness_verification.schedule_verifications(schedule_payload)
286
+ environment = validate_environment_contract(payload)
287
+ invalidations = build_invalidation_records(payload)
288
+ progress_sessions = payload.get("progressSessions")
289
+ progress = []
290
+ if isinstance(progress_sessions, list):
291
+ progress = [
292
+ harness_efficiency.classify_progress(item)
293
+ for item in progress_sessions
294
+ if isinstance(item, dict)
295
+ ]
296
+ decision_counts = dict(
297
+ sorted(Counter(item.get("decision") for item in verification.get("plan", [])).items())
298
+ )
299
+ ok = bool(verification.get("ok")) and bool(environment.get("ok"))
300
+ return {
301
+ "schemaVersion": SCHEMA_VERSION,
302
+ "ok": ok,
303
+ "code": "ORCHESTRATION_PLAN_READY" if ok else "ORCHESTRATION_PLAN_BLOCKED",
304
+ "changeId": str(payload.get("changeId") or ""),
305
+ "productIdentity": str(payload.get("productIdentity") or ""),
306
+ "frozenIdentity": str(payload.get("frozenIdentity") or ""),
307
+ "selection": selection,
308
+ "invalidations": invalidations,
309
+ "environment": environment,
310
+ "verification": verification,
311
+ "decisionCounts": decision_counts,
312
+ "budget": _budget_state(payload),
313
+ "progress": progress,
314
+ }
315
+
316
+
317
+ def main(argv: list[str] | None = None) -> int:
318
+ parser = argparse.ArgumentParser(prog="harness_orchestration.py")
319
+ sub = parser.add_subparsers(dest="command", required=True)
320
+ plan = sub.add_parser("plan")
321
+ plan.add_argument("--input", required=True)
322
+ plan.add_argument("--out")
323
+ plan.add_argument("--json", action="store_true")
324
+ args = parser.parse_args(argv)
325
+ if args.command != "plan":
326
+ return 2
327
+ try:
328
+ payload = json.loads(Path(args.input).read_text(encoding="utf-8-sig"))
329
+ except (OSError, json.JSONDecodeError) as exc:
330
+ result = {"ok": False, "code": "ORCHESTRATION_INPUT_INVALID", "error": str(exc)}
331
+ print(json.dumps(result, ensure_ascii=False, indent=2))
332
+ return 1
333
+ result = build_orchestration_plan(payload)
334
+ text = json.dumps(result, ensure_ascii=False, indent=2, sort_keys=True) + "\n"
335
+ if args.out:
336
+ output = Path(args.out)
337
+ output.parent.mkdir(parents=True, exist_ok=True)
338
+ output.write_text(text, encoding="utf-8", newline="\n")
339
+ print(text, end="")
340
+ return 0 if result.get("ok") else 1
341
+
342
+
343
+ if __name__ == "__main__":
344
+ raise SystemExit(main())