@hunter-harness/workflow-harness 0.2.43 → 0.2.45

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 (274) hide show
  1. package/harness/bundles/general/claude-code/.harness-build.json +1 -1
  2. package/harness/bundles/general/claude-code/contracts/build-profile-v3.schema.json +100 -0
  3. package/harness/bundles/general/claude-code/contracts/fixtures/managed-execution.json +341 -0
  4. package/harness/bundles/general/claude-code/contracts/process-identity.schema.json +132 -0
  5. package/harness/bundles/general/claude-code/contracts/run-session.schema.json +142 -0
  6. package/harness/bundles/general/claude-code/contracts/service-retirement-receipt.schema.json +85 -0
  7. package/harness/bundles/general/claude-code/contracts/service-session.schema.json +147 -0
  8. package/harness/bundles/general/claude-code/harness-archive/SKILL.md +1 -1
  9. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
  10. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  11. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +1 -1
  13. package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
  14. package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
  15. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
  16. package/harness/bundles/general/claude-code/harness-submit/checklist.md +12 -0
  17. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  18. package/harness/bundles/general/claude-code/harness-test/SKILL.md +1 -1
  19. package/harness/bundles/general/claude-code/scripts/harness_archive.py +324 -28
  20. package/harness/bundles/general/claude-code/scripts/harness_change.py +137 -2
  21. package/harness/bundles/general/claude-code/scripts/harness_efficiency.py +153 -0
  22. package/harness/bundles/general/claude-code/scripts/harness_environment.py +55 -25
  23. package/harness/bundles/general/claude-code/scripts/harness_execution_contracts.py +596 -0
  24. package/harness/bundles/general/claude-code/scripts/harness_integration.py +289 -52
  25. package/harness/bundles/general/claude-code/scripts/harness_ledger.py +5 -0
  26. package/harness/bundles/general/claude-code/scripts/harness_orchestration.py +344 -0
  27. package/harness/bundles/general/claude-code/scripts/harness_process.py +1065 -0
  28. package/harness/bundles/general/claude-code/scripts/harness_profile.py +244 -4
  29. package/harness/bundles/general/claude-code/scripts/harness_runtime.py +646 -132
  30. package/harness/bundles/general/claude-code/scripts/harness_service.py +1469 -194
  31. package/harness/bundles/general/claude-code/scripts/harness_test_runner.py +107 -117
  32. package/harness/bundles/general/claude-code/scripts/harness_verification.py +79 -0
  33. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  34. package/harness/bundles/general/codebuddy/contracts/build-profile-v3.schema.json +100 -0
  35. package/harness/bundles/general/codebuddy/contracts/fixtures/managed-execution.json +341 -0
  36. package/harness/bundles/general/codebuddy/contracts/process-identity.schema.json +132 -0
  37. package/harness/bundles/general/codebuddy/contracts/run-session.schema.json +142 -0
  38. package/harness/bundles/general/codebuddy/contracts/service-retirement-receipt.schema.json +85 -0
  39. package/harness/bundles/general/codebuddy/contracts/service-session.schema.json +147 -0
  40. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  41. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  42. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  43. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  44. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
  45. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
  46. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
  47. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
  48. package/harness/bundles/general/codebuddy/harness-submit/checklist.md +12 -0
  49. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  50. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
  51. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +324 -28
  52. package/harness/bundles/general/codebuddy/scripts/harness_change.py +137 -2
  53. package/harness/bundles/general/codebuddy/scripts/harness_efficiency.py +153 -0
  54. package/harness/bundles/general/codebuddy/scripts/harness_environment.py +55 -25
  55. package/harness/bundles/general/codebuddy/scripts/harness_execution_contracts.py +596 -0
  56. package/harness/bundles/general/codebuddy/scripts/harness_integration.py +289 -52
  57. package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +5 -0
  58. package/harness/bundles/general/codebuddy/scripts/harness_orchestration.py +344 -0
  59. package/harness/bundles/general/codebuddy/scripts/harness_process.py +1065 -0
  60. package/harness/bundles/general/codebuddy/scripts/harness_profile.py +244 -4
  61. package/harness/bundles/general/codebuddy/scripts/harness_runtime.py +646 -132
  62. package/harness/bundles/general/codebuddy/scripts/harness_service.py +1469 -194
  63. package/harness/bundles/general/codebuddy/scripts/harness_test_runner.py +107 -117
  64. package/harness/bundles/general/codebuddy/scripts/harness_verification.py +79 -0
  65. package/harness/bundles/general/codex/.harness-build.json +1 -1
  66. package/harness/bundles/general/codex/contracts/build-profile-v3.schema.json +100 -0
  67. package/harness/bundles/general/codex/contracts/fixtures/managed-execution.json +341 -0
  68. package/harness/bundles/general/codex/contracts/process-identity.schema.json +132 -0
  69. package/harness/bundles/general/codex/contracts/run-session.schema.json +142 -0
  70. package/harness/bundles/general/codex/contracts/service-retirement-receipt.schema.json +85 -0
  71. package/harness/bundles/general/codex/contracts/service-session.schema.json +147 -0
  72. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  73. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  74. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  75. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  76. package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
  77. package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
  78. package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
  79. package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
  80. package/harness/bundles/general/codex/harness-submit/checklist.md +12 -0
  81. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  82. package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
  83. package/harness/bundles/general/codex/scripts/harness_archive.py +324 -28
  84. package/harness/bundles/general/codex/scripts/harness_change.py +137 -2
  85. package/harness/bundles/general/codex/scripts/harness_efficiency.py +153 -0
  86. package/harness/bundles/general/codex/scripts/harness_environment.py +55 -25
  87. package/harness/bundles/general/codex/scripts/harness_execution_contracts.py +596 -0
  88. package/harness/bundles/general/codex/scripts/harness_integration.py +289 -52
  89. package/harness/bundles/general/codex/scripts/harness_ledger.py +5 -0
  90. package/harness/bundles/general/codex/scripts/harness_orchestration.py +344 -0
  91. package/harness/bundles/general/codex/scripts/harness_process.py +1065 -0
  92. package/harness/bundles/general/codex/scripts/harness_profile.py +244 -4
  93. package/harness/bundles/general/codex/scripts/harness_runtime.py +646 -132
  94. package/harness/bundles/general/codex/scripts/harness_service.py +1469 -194
  95. package/harness/bundles/general/codex/scripts/harness_test_runner.py +107 -117
  96. package/harness/bundles/general/codex/scripts/harness_verification.py +79 -0
  97. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  98. package/harness/bundles/general/cursor/contracts/build-profile-v3.schema.json +100 -0
  99. package/harness/bundles/general/cursor/contracts/fixtures/managed-execution.json +341 -0
  100. package/harness/bundles/general/cursor/contracts/process-identity.schema.json +132 -0
  101. package/harness/bundles/general/cursor/contracts/run-session.schema.json +142 -0
  102. package/harness/bundles/general/cursor/contracts/service-retirement-receipt.schema.json +85 -0
  103. package/harness/bundles/general/cursor/contracts/service-session.schema.json +147 -0
  104. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  105. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  106. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  107. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  108. package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
  109. package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
  110. package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
  111. package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
  112. package/harness/bundles/general/cursor/harness-submit/checklist.md +12 -0
  113. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  114. package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
  115. package/harness/bundles/general/cursor/scripts/harness_archive.py +324 -28
  116. package/harness/bundles/general/cursor/scripts/harness_change.py +137 -2
  117. package/harness/bundles/general/cursor/scripts/harness_efficiency.py +153 -0
  118. package/harness/bundles/general/cursor/scripts/harness_environment.py +55 -25
  119. package/harness/bundles/general/cursor/scripts/harness_execution_contracts.py +596 -0
  120. package/harness/bundles/general/cursor/scripts/harness_integration.py +289 -52
  121. package/harness/bundles/general/cursor/scripts/harness_ledger.py +5 -0
  122. package/harness/bundles/general/cursor/scripts/harness_orchestration.py +344 -0
  123. package/harness/bundles/general/cursor/scripts/harness_process.py +1065 -0
  124. package/harness/bundles/general/cursor/scripts/harness_profile.py +244 -4
  125. package/harness/bundles/general/cursor/scripts/harness_runtime.py +646 -132
  126. package/harness/bundles/general/cursor/scripts/harness_service.py +1469 -194
  127. package/harness/bundles/general/cursor/scripts/harness_test_runner.py +107 -117
  128. package/harness/bundles/general/cursor/scripts/harness_verification.py +79 -0
  129. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  130. package/harness/bundles/java/claude-code/contracts/build-profile-v3.schema.json +100 -0
  131. package/harness/bundles/java/claude-code/contracts/fixtures/managed-execution.json +341 -0
  132. package/harness/bundles/java/claude-code/contracts/process-identity.schema.json +132 -0
  133. package/harness/bundles/java/claude-code/contracts/run-session.schema.json +142 -0
  134. package/harness/bundles/java/claude-code/contracts/service-retirement-receipt.schema.json +85 -0
  135. package/harness/bundles/java/claude-code/contracts/service-session.schema.json +147 -0
  136. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  137. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  138. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  139. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  140. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  141. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  142. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
  143. package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
  144. package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
  145. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
  146. package/harness/bundles/java/claude-code/harness-submit/checklist.md +12 -0
  147. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  148. package/harness/bundles/java/claude-code/harness-test/SKILL.md +1 -1
  149. package/harness/bundles/java/claude-code/scripts/harness_archive.py +324 -28
  150. package/harness/bundles/java/claude-code/scripts/harness_change.py +137 -2
  151. package/harness/bundles/java/claude-code/scripts/harness_efficiency.py +153 -0
  152. package/harness/bundles/java/claude-code/scripts/harness_environment.py +55 -25
  153. package/harness/bundles/java/claude-code/scripts/harness_execution_contracts.py +596 -0
  154. package/harness/bundles/java/claude-code/scripts/harness_integration.py +289 -52
  155. package/harness/bundles/java/claude-code/scripts/harness_ledger.py +5 -0
  156. package/harness/bundles/java/claude-code/scripts/harness_orchestration.py +344 -0
  157. package/harness/bundles/java/claude-code/scripts/harness_process.py +1065 -0
  158. package/harness/bundles/java/claude-code/scripts/harness_profile.py +244 -4
  159. package/harness/bundles/java/claude-code/scripts/harness_runtime.py +646 -132
  160. package/harness/bundles/java/claude-code/scripts/harness_service.py +1469 -194
  161. package/harness/bundles/java/claude-code/scripts/harness_test_runner.py +107 -117
  162. package/harness/bundles/java/claude-code/scripts/harness_verification.py +79 -0
  163. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  164. package/harness/bundles/java/codebuddy/contracts/build-profile-v3.schema.json +100 -0
  165. package/harness/bundles/java/codebuddy/contracts/fixtures/managed-execution.json +341 -0
  166. package/harness/bundles/java/codebuddy/contracts/process-identity.schema.json +132 -0
  167. package/harness/bundles/java/codebuddy/contracts/run-session.schema.json +142 -0
  168. package/harness/bundles/java/codebuddy/contracts/service-retirement-receipt.schema.json +85 -0
  169. package/harness/bundles/java/codebuddy/contracts/service-session.schema.json +147 -0
  170. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  171. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  172. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  173. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  174. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  175. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  176. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
  177. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
  178. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
  179. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
  180. package/harness/bundles/java/codebuddy/harness-submit/checklist.md +12 -0
  181. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  182. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
  183. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +324 -28
  184. package/harness/bundles/java/codebuddy/scripts/harness_change.py +137 -2
  185. package/harness/bundles/java/codebuddy/scripts/harness_efficiency.py +153 -0
  186. package/harness/bundles/java/codebuddy/scripts/harness_environment.py +55 -25
  187. package/harness/bundles/java/codebuddy/scripts/harness_execution_contracts.py +596 -0
  188. package/harness/bundles/java/codebuddy/scripts/harness_integration.py +289 -52
  189. package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +5 -0
  190. package/harness/bundles/java/codebuddy/scripts/harness_orchestration.py +344 -0
  191. package/harness/bundles/java/codebuddy/scripts/harness_process.py +1065 -0
  192. package/harness/bundles/java/codebuddy/scripts/harness_profile.py +244 -4
  193. package/harness/bundles/java/codebuddy/scripts/harness_runtime.py +646 -132
  194. package/harness/bundles/java/codebuddy/scripts/harness_service.py +1469 -194
  195. package/harness/bundles/java/codebuddy/scripts/harness_test_runner.py +107 -117
  196. package/harness/bundles/java/codebuddy/scripts/harness_verification.py +79 -0
  197. package/harness/bundles/java/codex/.harness-build.json +1 -1
  198. package/harness/bundles/java/codex/contracts/build-profile-v3.schema.json +100 -0
  199. package/harness/bundles/java/codex/contracts/fixtures/managed-execution.json +341 -0
  200. package/harness/bundles/java/codex/contracts/process-identity.schema.json +132 -0
  201. package/harness/bundles/java/codex/contracts/run-session.schema.json +142 -0
  202. package/harness/bundles/java/codex/contracts/service-retirement-receipt.schema.json +85 -0
  203. package/harness/bundles/java/codex/contracts/service-session.schema.json +147 -0
  204. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  205. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  206. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  207. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  208. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  209. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  210. package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
  211. package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
  212. package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
  213. package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
  214. package/harness/bundles/java/codex/harness-submit/checklist.md +12 -0
  215. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  216. package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
  217. package/harness/bundles/java/codex/scripts/harness_archive.py +324 -28
  218. package/harness/bundles/java/codex/scripts/harness_change.py +137 -2
  219. package/harness/bundles/java/codex/scripts/harness_efficiency.py +153 -0
  220. package/harness/bundles/java/codex/scripts/harness_environment.py +55 -25
  221. package/harness/bundles/java/codex/scripts/harness_execution_contracts.py +596 -0
  222. package/harness/bundles/java/codex/scripts/harness_integration.py +289 -52
  223. package/harness/bundles/java/codex/scripts/harness_ledger.py +5 -0
  224. package/harness/bundles/java/codex/scripts/harness_orchestration.py +344 -0
  225. package/harness/bundles/java/codex/scripts/harness_process.py +1065 -0
  226. package/harness/bundles/java/codex/scripts/harness_profile.py +244 -4
  227. package/harness/bundles/java/codex/scripts/harness_runtime.py +646 -132
  228. package/harness/bundles/java/codex/scripts/harness_service.py +1469 -194
  229. package/harness/bundles/java/codex/scripts/harness_test_runner.py +107 -117
  230. package/harness/bundles/java/codex/scripts/harness_verification.py +79 -0
  231. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  232. package/harness/bundles/java/cursor/contracts/build-profile-v3.schema.json +100 -0
  233. package/harness/bundles/java/cursor/contracts/fixtures/managed-execution.json +341 -0
  234. package/harness/bundles/java/cursor/contracts/process-identity.schema.json +132 -0
  235. package/harness/bundles/java/cursor/contracts/run-session.schema.json +142 -0
  236. package/harness/bundles/java/cursor/contracts/service-retirement-receipt.schema.json +85 -0
  237. package/harness/bundles/java/cursor/contracts/service-session.schema.json +147 -0
  238. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  239. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  240. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  241. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  242. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  243. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  244. package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
  245. package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
  246. package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
  247. package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
  248. package/harness/bundles/java/cursor/harness-submit/checklist.md +12 -0
  249. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  250. package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
  251. package/harness/bundles/java/cursor/scripts/harness_archive.py +324 -28
  252. package/harness/bundles/java/cursor/scripts/harness_change.py +137 -2
  253. package/harness/bundles/java/cursor/scripts/harness_efficiency.py +153 -0
  254. package/harness/bundles/java/cursor/scripts/harness_environment.py +55 -25
  255. package/harness/bundles/java/cursor/scripts/harness_execution_contracts.py +596 -0
  256. package/harness/bundles/java/cursor/scripts/harness_integration.py +289 -52
  257. package/harness/bundles/java/cursor/scripts/harness_ledger.py +5 -0
  258. package/harness/bundles/java/cursor/scripts/harness_orchestration.py +344 -0
  259. package/harness/bundles/java/cursor/scripts/harness_process.py +1065 -0
  260. package/harness/bundles/java/cursor/scripts/harness_profile.py +244 -4
  261. package/harness/bundles/java/cursor/scripts/harness_runtime.py +646 -132
  262. package/harness/bundles/java/cursor/scripts/harness_service.py +1469 -194
  263. package/harness/bundles/java/cursor/scripts/harness_test_runner.py +107 -117
  264. package/harness/bundles/java/cursor/scripts/harness_verification.py +79 -0
  265. package/harness/manifests/general/claude-code.json +58 -26
  266. package/harness/manifests/general/codebuddy.json +58 -26
  267. package/harness/manifests/general/codex.json +58 -26
  268. package/harness/manifests/general/cursor.json +58 -26
  269. package/harness/manifests/java/claude-code.json +60 -28
  270. package/harness/manifests/java/codebuddy.json +60 -28
  271. package/harness/manifests/java/codex.json +60 -28
  272. package/harness/manifests/java/cursor.json +60 -28
  273. package/hunter-workflow-family.json +4 -4
  274. package/package.json +1 -1
@@ -36,6 +36,7 @@ if str(SCRIPTS_DIR) not in sys.path:
36
36
  import harness_change # noqa: E402
37
37
  import harness_ledger as hl # noqa: E402
38
38
  import harness_paths # noqa: E402
39
+ import harness_process # noqa: E402
39
40
  import harness_service # noqa: E402
40
41
 
41
42
  if hasattr(sys.stdout, "reconfigure"):
@@ -415,6 +416,10 @@ class LedgerSyncError(IntegrationError):
415
416
  code = "LEDGER_SYNC_PENDING"
416
417
 
417
418
 
419
+ class EvidenceRebindRefusedError(IntegrationError):
420
+ code = "EVIDENCE_REBIND_REFUSED"
421
+
422
+
418
423
  class CleanupRefusedError(IntegrationError):
419
424
  code = "CLEANUP_REFUSED"
420
425
 
@@ -599,22 +604,7 @@ def load_journal(project_root: Path, transaction_id: str) -> dict[str, Any]:
599
604
 
600
605
 
601
606
  def _pid_alive(pid: int) -> bool:
602
- if pid <= 0:
603
- return False
604
- # On Windows, os.kill(pid, 0) can transiently report EINVAL for the
605
- # current low-priority/background process. The current process is
606
- # unambiguously alive, so avoid reclaiming its lock on that platform race.
607
- if pid == os.getpid():
608
- return True
609
- try:
610
- os.kill(pid, 0)
611
- except ProcessLookupError:
612
- return False
613
- except PermissionError:
614
- return True
615
- except OSError:
616
- return False
617
- return True
607
+ return harness_process.is_pid_alive(pid)
618
608
 
619
609
 
620
610
  def _acquire_journal_lock(lock_path: Path, journal_path: Path) -> int:
@@ -727,6 +717,7 @@ class IntegrationTransaction:
727
717
  "schemaVersion": 1,
728
718
  "transactionId": self.transaction_id,
729
719
  "changeName": self.change_id,
720
+ "evidenceChangeName": self.change_id,
730
721
  "runId": self.run_id,
731
722
  "repositoryId": harness_paths.repository_identity(self.project_root),
732
723
  "primaryRoot": str(self.project_root),
@@ -750,12 +741,66 @@ class IntegrationTransaction:
750
741
  "createdAt": now_iso(),
751
742
  }
752
743
 
753
- def _evidence_identity(self) -> dict[str, Any]:
754
- change_dir = (
755
- self.project_root / ".harness" / "changes" / self.change_id
744
+ def _change_roots(self, change_id: str) -> tuple[Path, Path]:
745
+ if re.fullmatch(r"[a-z0-9]+(?:-[a-z0-9]+)*", change_id) is None:
746
+ raise EvidenceRebindRefusedError(
747
+ "evidence change must be a non-empty kebab-case path segment"
748
+ )
749
+ contract_base = (self.project_root / ".harness" / "changes").resolve()
750
+ state_base = (
751
+ self.project_root / ".harness" / "state" / "changes"
756
752
  ).resolve()
753
+ raw_change_dir = contract_base / change_id
754
+ raw_state_dir = state_base / change_id
755
+ change_dir = raw_change_dir.resolve()
756
+ state_dir = raw_state_dir.resolve()
757
+ direct_contract_path = os.path.normcase(str(raw_change_dir.absolute()))
758
+ direct_state_path = os.path.normcase(str(raw_state_dir.absolute()))
759
+ if (
760
+ change_dir.parent != contract_base
761
+ or state_dir.parent != state_base
762
+ or os.path.normcase(str(change_dir)) != direct_contract_path
763
+ or os.path.normcase(str(state_dir)) != direct_state_path
764
+ ):
765
+ raise EvidenceRebindRefusedError(
766
+ "evidence change must remain inside the direct Change roots"
767
+ )
768
+ return change_dir, state_dir
769
+
770
+ def _bound_evidence_change(self, journal: dict[str, Any]) -> str:
771
+ if journal.get("changeName") != self.change_id:
772
+ raise JournalConflictError(
773
+ "transaction Change does not match the journal"
774
+ )
775
+ if "evidenceChangeName" not in journal:
776
+ return self.change_id
777
+ raw_change_id = journal.get("evidenceChangeName")
778
+ if not isinstance(raw_change_id, str) or not raw_change_id:
779
+ raise EvidenceRebindRefusedError(
780
+ "journal evidence Change binding is invalid"
781
+ )
782
+ change_id = raw_change_id
783
+ self._change_roots(change_id)
784
+ if change_id == self.change_id:
785
+ return change_id
786
+ rebind = journal.get("evidenceRebind") or {}
787
+ if (
788
+ rebind.get("status") != "DONE"
789
+ or rebind.get("from") != self.change_id
790
+ or rebind.get("to") != change_id
791
+ or rebind.get("reason")
792
+ != "REMOTE_CONFIRMED_DEFAULT_LEDGER_MISSING"
793
+ or rebind.get("remoteHead") != journal.get("mergeCommit")
794
+ ):
795
+ raise EvidenceRebindRefusedError(
796
+ "journal evidence Change override has no valid recovery receipt"
797
+ )
798
+ return change_id
799
+
800
+ def _evidence_identity(self, change_id: str | None = None) -> dict[str, Any]:
801
+ change_dir, state_dir = self._change_roots(change_id or self.change_id)
757
802
  state_candidates = [
758
- self.project_root / ".harness" / "state" / "changes" / self.change_id,
803
+ state_dir,
759
804
  change_dir,
760
805
  ]
761
806
  events_file = next(
@@ -792,25 +837,23 @@ class IntegrationTransaction:
792
837
  break
793
838
  if artifact_hash:
794
839
  break
795
- for root in state_candidates:
796
- ledger_path = root / "evidence" / "verification-ledger.json"
797
- if not ledger_path.is_file():
798
- continue
840
+ ledger_path = self._ledger_path(change_id or self.change_id)
841
+ if ledger_path is not None:
799
842
  try:
800
843
  ledger = json.loads(ledger_path.read_text(encoding="utf-8-sig"))
801
844
  except (OSError, json.JSONDecodeError):
802
- break
803
- for key in (
804
- "schemaVersion",
805
- "repositoryId",
806
- "changeName",
807
- "baseCommit",
808
- "currentHead",
809
- "diffHash",
810
- "ownershipHash",
811
- ):
812
- ledger_identity[key] = ledger.get(key)
813
- break
845
+ ledger = {}
846
+ if isinstance(ledger, dict):
847
+ for key in (
848
+ "schemaVersion",
849
+ "repositoryId",
850
+ "changeName",
851
+ "baseCommit",
852
+ "currentHead",
853
+ "diffHash",
854
+ "ownershipHash",
855
+ ):
856
+ ledger_identity[key] = ledger.get(key)
814
857
  return {
815
858
  "eventHighWater": {
816
859
  "count": event_count,
@@ -821,16 +864,26 @@ class IntegrationTransaction:
821
864
  "ledgerIdentity": ledger_identity,
822
865
  }
823
866
 
824
- def _ledger_path(self) -> Path | None:
867
+ def _ledger_path(self, change_id: str) -> Path | None:
868
+ change_dir, state_dir = self._change_roots(change_id)
825
869
  candidates = (
826
- self.project_root / ".harness" / "state" / "changes" / self.change_id
827
- / "evidence" / "verification-ledger.json",
828
- self.project_root / ".harness" / "changes" / self.change_id
829
- / "evidence" / "verification-ledger.json",
830
- self.project_root / ".harness" / "state" / "changes" / self.change_id
831
- / "verification-ledger.json",
870
+ state_dir / "evidence" / "verification-ledger.json",
871
+ change_dir / "evidence" / "verification-ledger.json",
872
+ state_dir / "verification-ledger.json",
832
873
  )
833
- return next((path for path in candidates if path.is_file()), None)
874
+ for path in candidates:
875
+ if not path.is_file():
876
+ continue
877
+ resolved = path.resolve()
878
+ if path.is_symlink() or not any(
879
+ resolved.is_relative_to(root)
880
+ for root in (state_dir, change_dir)
881
+ ):
882
+ raise EvidenceRebindRefusedError(
883
+ "verification ledger must remain inside its direct Change root"
884
+ )
885
+ return path
886
+ return None
834
887
 
835
888
  def _finalize_remote_push(
836
889
  self,
@@ -839,7 +892,9 @@ class IntegrationTransaction:
839
892
  merge_commit: str,
840
893
  remote_head: str,
841
894
  ) -> None:
895
+ evidence_change = self._bound_evidence_change(journal)
842
896
  journal.update({
897
+ "evidenceChangeName": evidence_change,
843
898
  "pushedHead": merge_commit,
844
899
  "mergeFinalHash": merge_commit,
845
900
  "ciExpectedHead": merge_commit,
@@ -854,14 +909,14 @@ class IntegrationTransaction:
854
909
  "ledgerSync": {"status": "PENDING", "updatedAt": now_iso()},
855
910
  })
856
911
  self._save(journal)
857
- ledger_path = self._ledger_path()
912
+ ledger_path = self._ledger_path(evidence_change)
858
913
  if ledger_path is None:
859
914
  result = {"ok": False, "code": "LEDGER_MISSING"}
860
915
  else:
861
916
  result = hl.record_integration_hashes(
862
917
  ledger_path,
863
918
  change_dir=(
864
- self.project_root / ".harness" / "changes" / self.change_id
919
+ self.project_root / ".harness" / "changes" / evidence_change
865
920
  ),
866
921
  repository_id=str(journal["repositoryId"]),
867
922
  merge_final_hash=merge_commit,
@@ -881,6 +936,7 @@ class IntegrationTransaction:
881
936
  )
882
937
 
883
938
  def _assert_cleanup_consistency(self, journal: dict[str, Any]) -> None:
939
+ evidence_change = self._bound_evidence_change(journal)
884
940
  push_step = self._step(journal, "push")
885
941
  merge_commit = str(journal.get("mergeCommit") or "")
886
942
  remote_line = self.runner.text(
@@ -909,7 +965,7 @@ class IntegrationTransaction:
909
965
  raise CleanupRefusedError(
910
966
  "remote/journal final hashes are missing or inconsistent"
911
967
  )
912
- ledger_path = self._ledger_path()
968
+ ledger_path = self._ledger_path(evidence_change)
913
969
  if ledger_path is None:
914
970
  raise CleanupRefusedError("verification ledger missing before cleanup")
915
971
  try:
@@ -1344,6 +1400,7 @@ class IntegrationTransaction:
1344
1400
  raise VerifyPlanMissingError(
1345
1401
  "integration verification requires at least one executable command"
1346
1402
  )
1403
+ evidence_change = self._bound_evidence_change(journal)
1347
1404
  intg_root = Path(journal["integrationRoot"]).resolve()
1348
1405
  results: list[dict[str, Any]] = []
1349
1406
  merge_tree = self.runner.text(intg_root, "rev-parse", "--verify", "HEAD^{tree}")
@@ -1355,7 +1412,7 @@ class IntegrationTransaction:
1355
1412
  )
1356
1413
  reused = (
1357
1414
  _reusable_merge_evidence(
1358
- self._ledger_path(),
1415
+ self._ledger_path(evidence_change),
1359
1416
  verification=policy.get("verification"),
1360
1417
  command=command,
1361
1418
  product_tree_hash=merge_tree_hash,
@@ -1509,6 +1566,7 @@ class IntegrationTransaction:
1509
1566
 
1510
1567
  def push(self) -> dict[str, Any]:
1511
1568
  def action(journal: dict[str, Any]) -> None:
1569
+ self._bound_evidence_change(journal)
1512
1570
  verify_step = self._step(journal, "verify")
1513
1571
  verify_results = journal.get("verifyResults")
1514
1572
  if (
@@ -2002,10 +2060,174 @@ class IntegrationTransaction:
2002
2060
 
2003
2061
  # ------------------------------------------------------------ recover
2004
2062
 
2063
+ def _rebind_evidence_change_for_recovery(
2064
+ self,
2065
+ journal: dict[str, Any],
2066
+ evidence_change_id: str,
2067
+ ) -> dict[str, Any]:
2068
+ self._change_roots(evidence_change_id)
2069
+ current_change = self._bound_evidence_change(journal)
2070
+ if current_change == evidence_change_id:
2071
+ return journal
2072
+ if current_change != self.change_id:
2073
+ raise EvidenceRebindRefusedError(
2074
+ "transaction evidence is already bound to another Change"
2075
+ )
2076
+
2077
+ push_step = self._step(journal, "push")
2078
+ ledger_sync = journal.get("ledgerSync") or {}
2079
+ ledger_result = ledger_sync.get("result") or {}
2080
+ merge_commit = str(journal.get("mergeCommit") or "")
2081
+ push_intent = journal.get("pushIntent") or {}
2082
+ if (
2083
+ push_step.get("status") != "FAILED"
2084
+ or ledger_sync.get("status") != "FAILED"
2085
+ or ledger_result.get("code") != "LEDGER_MISSING"
2086
+ or push_intent.get("status") != "REMOTE_CONFIRMED"
2087
+ or push_intent.get("mergeCommit") != merge_commit
2088
+ or push_intent.get("observedRemoteHead") != merge_commit
2089
+ ):
2090
+ raise EvidenceRebindRefusedError(
2091
+ "evidence rebind requires a remote-confirmed push blocked only by "
2092
+ "the default LEDGER_MISSING result"
2093
+ )
2094
+
2095
+ probe = self.runner.remote_probe(
2096
+ self.project_root,
2097
+ "ls-remote",
2098
+ "origin",
2099
+ self.target_branch,
2100
+ )
2101
+ if probe["exitCode"] != 0:
2102
+ raise RemoteProbeFailedError(
2103
+ "cannot confirm the remote target before evidence rebind: "
2104
+ f"{probe['category']}: {probe['redactedStderr']}"
2105
+ )
2106
+ if not merge_commit or probe["stdoutHash"] != merge_commit:
2107
+ raise EvidenceRebindRefusedError(
2108
+ "remote target no longer equals the transaction merge commit"
2109
+ )
2110
+
2111
+ ledger_path = self._ledger_path(evidence_change_id)
2112
+ if ledger_path is None:
2113
+ raise EvidenceRebindRefusedError(
2114
+ "requested evidence Change has no verification ledger"
2115
+ )
2116
+ try:
2117
+ ledger = json.loads(ledger_path.read_text(encoding="utf-8-sig"))
2118
+ except (OSError, json.JSONDecodeError) as exc:
2119
+ raise EvidenceRebindRefusedError(
2120
+ f"requested evidence ledger is unreadable: {exc}"
2121
+ ) from exc
2122
+ missing = hl.validate_ledger_identity(ledger)
2123
+ if missing:
2124
+ raise EvidenceRebindRefusedError(
2125
+ "requested evidence ledger identity is invalid: "
2126
+ + ", ".join(missing)
2127
+ )
2128
+ if ledger.get("changeName") != evidence_change_id:
2129
+ raise EvidenceRebindRefusedError(
2130
+ "requested evidence ledger Change identity does not match"
2131
+ )
2132
+ if ledger.get("repositoryId") != journal.get("repositoryId"):
2133
+ raise EvidenceRebindRefusedError(
2134
+ "requested evidence ledger repository identity does not match"
2135
+ )
2136
+
2137
+ expected_handoff = str(
2138
+ journal.get("remoteTargetHead") or journal.get("base") or ""
2139
+ )
2140
+ handoff_values = [
2141
+ ledger.get("mergeFinalHash"),
2142
+ ledger.get("ciExpectedHead"),
2143
+ ledger.get("remoteHead"),
2144
+ ]
2145
+ handoff_valid = all(
2146
+ isinstance(value, str)
2147
+ and re.fullmatch(r"[0-9a-f]{40}", value) is not None
2148
+ for value in handoff_values
2149
+ )
2150
+ handoff_hashes = set(handoff_values) if handoff_valid else set()
2151
+ if (
2152
+ not handoff_valid
2153
+ or len(handoff_hashes) != 1
2154
+ or next(iter(handoff_hashes), None)
2155
+ not in {expected_handoff, merge_commit}
2156
+ ):
2157
+ raise EvidenceRebindRefusedError(
2158
+ "requested evidence ledger has no matching prior integration handoff"
2159
+ )
2160
+
2161
+ current_head = str(ledger.get("currentHead") or "")
2162
+ feature_head = str(journal.get("featureHead") or "")
2163
+ current_in_feature = self.runner.run(
2164
+ self.project_root,
2165
+ "merge-base",
2166
+ "--is-ancestor",
2167
+ current_head,
2168
+ feature_head,
2169
+ check=False,
2170
+ ).returncode == 0
2171
+ feature_in_merge = self.runner.run(
2172
+ self.project_root,
2173
+ "merge-base",
2174
+ "--is-ancestor",
2175
+ feature_head,
2176
+ merge_commit,
2177
+ check=False,
2178
+ ).returncode == 0
2179
+ if not current_in_feature or not feature_in_merge:
2180
+ raise EvidenceRebindRefusedError(
2181
+ "requested evidence ledger head is not in the integrated feature lineage"
2182
+ )
2183
+
2184
+ previous_identity = journal.get("evidenceIdentity")
2185
+ previous_verification_identity = journal.get("verificationIdentity")
2186
+ target_identity = self._evidence_identity(evidence_change_id)
2187
+ journal["evidenceChangeName"] = evidence_change_id
2188
+ journal["evidenceIdentity"] = target_identity
2189
+ verification_basis = json.dumps(
2190
+ {
2191
+ "mergeCommit": journal.get("mergeCommit"),
2192
+ "results": journal.get("verifyResults"),
2193
+ "evidenceIdentity": target_identity,
2194
+ },
2195
+ ensure_ascii=False,
2196
+ sort_keys=True,
2197
+ )
2198
+ journal["verificationIdentity"] = {
2199
+ "sha256": (
2200
+ "sha256:"
2201
+ + hashlib.sha256(verification_basis.encode("utf-8")).hexdigest()
2202
+ ),
2203
+ "ledgerIdentity": target_identity.get("ledgerIdentity") or {},
2204
+ }
2205
+ journal["evidenceRebind"] = {
2206
+ "status": "DONE",
2207
+ "from": current_change,
2208
+ "to": evidence_change_id,
2209
+ "reason": "REMOTE_CONFIRMED_DEFAULT_LEDGER_MISSING",
2210
+ "remoteHead": merge_commit,
2211
+ "handoffHash": next(iter(handoff_hashes)),
2212
+ "previousEvidenceIdentity": previous_identity,
2213
+ "previousVerificationIdentity": previous_verification_identity,
2214
+ "targetLedgerIdentity": target_identity.get("ledgerIdentity") or {},
2215
+ "updatedAt": now_iso(),
2216
+ }
2217
+ return self._save(journal)
2218
+
2005
2219
  def recover(
2006
- self, verify_commands: Sequence[Sequence[str]] | None = None
2220
+ self,
2221
+ verify_commands: Sequence[Sequence[str]] | None = None,
2222
+ *,
2223
+ evidence_change_id: str | None = None,
2007
2224
  ) -> dict[str, Any]:
2008
2225
  journal = self._load()
2226
+ if evidence_change_id is not None:
2227
+ journal = self._rebind_evidence_change_for_recovery(
2228
+ journal,
2229
+ evidence_change_id,
2230
+ )
2009
2231
  actions: dict[str, Callable[[], dict[str, Any]]] = {
2010
2232
  "preflight": self.preflight,
2011
2233
  "prepare": self.prepare,
@@ -2102,7 +2324,11 @@ def cmd_abandon(args: argparse.Namespace) -> int:
2102
2324
 
2103
2325
 
2104
2326
  def cmd_recover(args: argparse.Namespace) -> int:
2105
- return _emit(_txn_from_args(args).recover())
2327
+ return _emit(
2328
+ _txn_from_args(args).recover(
2329
+ evidence_change_id=getattr(args, "evidence_change", None)
2330
+ )
2331
+ )
2106
2332
 
2107
2333
 
2108
2334
  def cmd_status(args: argparse.Namespace) -> int:
@@ -2138,7 +2364,10 @@ def build_parser() -> argparse.ArgumentParser:
2138
2364
  parser = argparse.ArgumentParser(prog="harness_integration.py")
2139
2365
  sub = parser.add_subparsers(dest="command_name", required=True)
2140
2366
 
2141
- def add(name: str, func: Callable[[argparse.Namespace], int]) -> None:
2367
+ def add(
2368
+ name: str,
2369
+ func: Callable[[argparse.Namespace], int],
2370
+ ) -> argparse.ArgumentParser:
2142
2371
  p = sub.add_parser(name)
2143
2372
  p.add_argument("--change", required=True)
2144
2373
  p.add_argument("--run-id", required=True)
@@ -2146,6 +2375,7 @@ def build_parser() -> argparse.ArgumentParser:
2146
2375
  p.add_argument("--feature-branch", required=True)
2147
2376
  p.add_argument("--temp-root")
2148
2377
  p.set_defaults(func=func)
2378
+ return p
2149
2379
 
2150
2380
  add("preflight", cmd_preflight)
2151
2381
  add("prepare", cmd_prepare)
@@ -2153,7 +2383,14 @@ def build_parser() -> argparse.ArgumentParser:
2153
2383
  add("push", cmd_push)
2154
2384
  add("cleanup", cmd_cleanup)
2155
2385
  add("abandon", cmd_abandon)
2156
- add("recover", cmd_recover)
2386
+ p_recover = add("recover", cmd_recover)
2387
+ p_recover.add_argument(
2388
+ "--evidence-change",
2389
+ help=(
2390
+ "one-time recovery binding after a remote-confirmed "
2391
+ "default LEDGER_MISSING failure"
2392
+ ),
2393
+ )
2157
2394
  add("status", cmd_status)
2158
2395
 
2159
2396
  p_journal = sub.add_parser("journal")
@@ -2233,6 +2233,11 @@ def cmd_record(args: argparse.Namespace) -> int:
2233
2233
  "finishedAt": now_iso(),
2234
2234
  }
2235
2235
  )
2236
+ # A fresh successful execution supersedes the prior target's fixback
2237
+ # invalidation. Carrying these projection-only fields forward would
2238
+ # make every rerecord permanently non-reusable.
2239
+ entry.pop("reusable", None)
2240
+ entry.pop("invalidation", None)
2236
2241
  metrics_raw = getattr(args, "metrics_json", None)
2237
2242
  metrics_file = getattr(args, "metrics_file", None)
2238
2243
  if metrics_file and metrics_raw is not None and str(metrics_raw).strip():