@hunter-harness/workflow-harness 0.2.42 → 0.2.44

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 (334) 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 +156 -1
  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-archive/reference.md +1 -0
  10. package/harness/bundles/general/claude-code/harness-archive/templates/render-summary.mjs +8 -0
  11. package/harness/bundles/general/claude-code/harness-archive/templates/summary-data-template.json +28 -0
  12. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
  13. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  14. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  15. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +1 -1
  16. package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
  17. package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
  18. package/harness/bundles/general/claude-code/harness-run/reference.md +6 -1
  19. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
  20. package/harness/bundles/general/claude-code/harness-submit/checklist.md +12 -0
  21. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  22. package/harness/bundles/general/claude-code/harness-test/SKILL.md +8 -2
  23. package/harness/bundles/general/claude-code/protocols/execution-session-protocol.md +52 -0
  24. package/harness/bundles/general/claude-code/protocols/state-layout-protocol.md +24 -1
  25. package/harness/bundles/general/claude-code/protocols/verification-graph-protocol.md +6 -0
  26. package/harness/bundles/general/claude-code/scripts/harness_archive.py +271 -22
  27. package/harness/bundles/general/claude-code/scripts/harness_change.py +137 -2
  28. package/harness/bundles/general/claude-code/scripts/harness_efficiency.py +443 -0
  29. package/harness/bundles/general/claude-code/scripts/harness_environment.py +760 -46
  30. package/harness/bundles/general/claude-code/scripts/harness_execution_contracts.py +596 -0
  31. package/harness/bundles/general/claude-code/scripts/harness_fixback.py +742 -0
  32. package/harness/bundles/general/claude-code/scripts/harness_integration.py +289 -52
  33. package/harness/bundles/general/claude-code/scripts/harness_ledger.py +5 -0
  34. package/harness/bundles/general/claude-code/scripts/harness_orchestration.py +344 -0
  35. package/harness/bundles/general/claude-code/scripts/harness_process.py +1065 -0
  36. package/harness/bundles/general/claude-code/scripts/harness_profile.py +278 -4
  37. package/harness/bundles/general/claude-code/scripts/harness_runtime.py +1576 -3
  38. package/harness/bundles/general/claude-code/scripts/harness_service.py +1528 -177
  39. package/harness/bundles/general/claude-code/scripts/harness_test_runner.py +224 -146
  40. package/harness/bundles/general/claude-code/scripts/harness_verification.py +487 -8
  41. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  42. package/harness/bundles/general/codebuddy/contracts/build-profile-v3.schema.json +156 -1
  43. package/harness/bundles/general/codebuddy/contracts/fixtures/managed-execution.json +341 -0
  44. package/harness/bundles/general/codebuddy/contracts/process-identity.schema.json +132 -0
  45. package/harness/bundles/general/codebuddy/contracts/run-session.schema.json +142 -0
  46. package/harness/bundles/general/codebuddy/contracts/service-retirement-receipt.schema.json +85 -0
  47. package/harness/bundles/general/codebuddy/contracts/service-session.schema.json +147 -0
  48. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  49. package/harness/bundles/general/codebuddy/harness-archive/reference.md +1 -0
  50. package/harness/bundles/general/codebuddy/harness-archive/templates/render-summary.mjs +8 -0
  51. package/harness/bundles/general/codebuddy/harness-archive/templates/summary-data-template.json +28 -0
  52. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  53. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  54. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  55. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
  56. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
  57. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
  58. package/harness/bundles/general/codebuddy/harness-run/reference.md +6 -1
  59. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
  60. package/harness/bundles/general/codebuddy/harness-submit/checklist.md +12 -0
  61. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  62. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +8 -2
  63. package/harness/bundles/general/codebuddy/protocols/execution-session-protocol.md +52 -0
  64. package/harness/bundles/general/codebuddy/protocols/state-layout-protocol.md +24 -1
  65. package/harness/bundles/general/codebuddy/protocols/verification-graph-protocol.md +6 -0
  66. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +271 -22
  67. package/harness/bundles/general/codebuddy/scripts/harness_change.py +137 -2
  68. package/harness/bundles/general/codebuddy/scripts/harness_efficiency.py +443 -0
  69. package/harness/bundles/general/codebuddy/scripts/harness_environment.py +760 -46
  70. package/harness/bundles/general/codebuddy/scripts/harness_execution_contracts.py +596 -0
  71. package/harness/bundles/general/codebuddy/scripts/harness_fixback.py +742 -0
  72. package/harness/bundles/general/codebuddy/scripts/harness_integration.py +289 -52
  73. package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +5 -0
  74. package/harness/bundles/general/codebuddy/scripts/harness_orchestration.py +344 -0
  75. package/harness/bundles/general/codebuddy/scripts/harness_process.py +1065 -0
  76. package/harness/bundles/general/codebuddy/scripts/harness_profile.py +278 -4
  77. package/harness/bundles/general/codebuddy/scripts/harness_runtime.py +1576 -3
  78. package/harness/bundles/general/codebuddy/scripts/harness_service.py +1528 -177
  79. package/harness/bundles/general/codebuddy/scripts/harness_test_runner.py +224 -146
  80. package/harness/bundles/general/codebuddy/scripts/harness_verification.py +487 -8
  81. package/harness/bundles/general/codex/.harness-build.json +1 -1
  82. package/harness/bundles/general/codex/contracts/build-profile-v3.schema.json +156 -1
  83. package/harness/bundles/general/codex/contracts/fixtures/managed-execution.json +341 -0
  84. package/harness/bundles/general/codex/contracts/process-identity.schema.json +132 -0
  85. package/harness/bundles/general/codex/contracts/run-session.schema.json +142 -0
  86. package/harness/bundles/general/codex/contracts/service-retirement-receipt.schema.json +85 -0
  87. package/harness/bundles/general/codex/contracts/service-session.schema.json +147 -0
  88. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  89. package/harness/bundles/general/codex/harness-archive/reference.md +1 -0
  90. package/harness/bundles/general/codex/harness-archive/templates/render-summary.mjs +8 -0
  91. package/harness/bundles/general/codex/harness-archive/templates/summary-data-template.json +28 -0
  92. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  93. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  94. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  95. package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
  96. package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
  97. package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
  98. package/harness/bundles/general/codex/harness-run/reference.md +6 -1
  99. package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
  100. package/harness/bundles/general/codex/harness-submit/checklist.md +12 -0
  101. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  102. package/harness/bundles/general/codex/harness-test/SKILL.md +8 -2
  103. package/harness/bundles/general/codex/protocols/execution-session-protocol.md +52 -0
  104. package/harness/bundles/general/codex/protocols/state-layout-protocol.md +24 -1
  105. package/harness/bundles/general/codex/protocols/verification-graph-protocol.md +6 -0
  106. package/harness/bundles/general/codex/scripts/harness_archive.py +271 -22
  107. package/harness/bundles/general/codex/scripts/harness_change.py +137 -2
  108. package/harness/bundles/general/codex/scripts/harness_efficiency.py +443 -0
  109. package/harness/bundles/general/codex/scripts/harness_environment.py +760 -46
  110. package/harness/bundles/general/codex/scripts/harness_execution_contracts.py +596 -0
  111. package/harness/bundles/general/codex/scripts/harness_fixback.py +742 -0
  112. package/harness/bundles/general/codex/scripts/harness_integration.py +289 -52
  113. package/harness/bundles/general/codex/scripts/harness_ledger.py +5 -0
  114. package/harness/bundles/general/codex/scripts/harness_orchestration.py +344 -0
  115. package/harness/bundles/general/codex/scripts/harness_process.py +1065 -0
  116. package/harness/bundles/general/codex/scripts/harness_profile.py +278 -4
  117. package/harness/bundles/general/codex/scripts/harness_runtime.py +1576 -3
  118. package/harness/bundles/general/codex/scripts/harness_service.py +1528 -177
  119. package/harness/bundles/general/codex/scripts/harness_test_runner.py +224 -146
  120. package/harness/bundles/general/codex/scripts/harness_verification.py +487 -8
  121. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  122. package/harness/bundles/general/cursor/contracts/build-profile-v3.schema.json +156 -1
  123. package/harness/bundles/general/cursor/contracts/fixtures/managed-execution.json +341 -0
  124. package/harness/bundles/general/cursor/contracts/process-identity.schema.json +132 -0
  125. package/harness/bundles/general/cursor/contracts/run-session.schema.json +142 -0
  126. package/harness/bundles/general/cursor/contracts/service-retirement-receipt.schema.json +85 -0
  127. package/harness/bundles/general/cursor/contracts/service-session.schema.json +147 -0
  128. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  129. package/harness/bundles/general/cursor/harness-archive/reference.md +1 -0
  130. package/harness/bundles/general/cursor/harness-archive/templates/render-summary.mjs +8 -0
  131. package/harness/bundles/general/cursor/harness-archive/templates/summary-data-template.json +28 -0
  132. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  133. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  134. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  135. package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
  136. package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
  137. package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
  138. package/harness/bundles/general/cursor/harness-run/reference.md +6 -1
  139. package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
  140. package/harness/bundles/general/cursor/harness-submit/checklist.md +12 -0
  141. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  142. package/harness/bundles/general/cursor/harness-test/SKILL.md +8 -2
  143. package/harness/bundles/general/cursor/protocols/execution-session-protocol.md +52 -0
  144. package/harness/bundles/general/cursor/protocols/state-layout-protocol.md +24 -1
  145. package/harness/bundles/general/cursor/protocols/verification-graph-protocol.md +6 -0
  146. package/harness/bundles/general/cursor/scripts/harness_archive.py +271 -22
  147. package/harness/bundles/general/cursor/scripts/harness_change.py +137 -2
  148. package/harness/bundles/general/cursor/scripts/harness_efficiency.py +443 -0
  149. package/harness/bundles/general/cursor/scripts/harness_environment.py +760 -46
  150. package/harness/bundles/general/cursor/scripts/harness_execution_contracts.py +596 -0
  151. package/harness/bundles/general/cursor/scripts/harness_fixback.py +742 -0
  152. package/harness/bundles/general/cursor/scripts/harness_integration.py +289 -52
  153. package/harness/bundles/general/cursor/scripts/harness_ledger.py +5 -0
  154. package/harness/bundles/general/cursor/scripts/harness_orchestration.py +344 -0
  155. package/harness/bundles/general/cursor/scripts/harness_process.py +1065 -0
  156. package/harness/bundles/general/cursor/scripts/harness_profile.py +278 -4
  157. package/harness/bundles/general/cursor/scripts/harness_runtime.py +1576 -3
  158. package/harness/bundles/general/cursor/scripts/harness_service.py +1528 -177
  159. package/harness/bundles/general/cursor/scripts/harness_test_runner.py +224 -146
  160. package/harness/bundles/general/cursor/scripts/harness_verification.py +487 -8
  161. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  162. package/harness/bundles/java/claude-code/contracts/build-profile-v3.schema.json +156 -1
  163. package/harness/bundles/java/claude-code/contracts/fixtures/managed-execution.json +341 -0
  164. package/harness/bundles/java/claude-code/contracts/process-identity.schema.json +132 -0
  165. package/harness/bundles/java/claude-code/contracts/run-session.schema.json +142 -0
  166. package/harness/bundles/java/claude-code/contracts/service-retirement-receipt.schema.json +85 -0
  167. package/harness/bundles/java/claude-code/contracts/service-session.schema.json +147 -0
  168. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  169. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  170. package/harness/bundles/java/claude-code/harness-archive/reference.md +1 -0
  171. package/harness/bundles/java/claude-code/harness-archive/templates/render-summary.mjs +8 -0
  172. package/harness/bundles/java/claude-code/harness-archive/templates/summary-data-template.json +28 -0
  173. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  174. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  175. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  176. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  177. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
  178. package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
  179. package/harness/bundles/java/claude-code/harness-run/SKILL.md +1 -1
  180. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
  181. package/harness/bundles/java/claude-code/harness-submit/checklist.md +12 -0
  182. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  183. package/harness/bundles/java/claude-code/harness-test/SKILL.md +8 -2
  184. package/harness/bundles/java/claude-code/protocols/execution-session-protocol.md +52 -0
  185. package/harness/bundles/java/claude-code/protocols/state-layout-protocol.md +24 -1
  186. package/harness/bundles/java/claude-code/protocols/verification-graph-protocol.md +6 -0
  187. package/harness/bundles/java/claude-code/scripts/harness_archive.py +271 -22
  188. package/harness/bundles/java/claude-code/scripts/harness_change.py +137 -2
  189. package/harness/bundles/java/claude-code/scripts/harness_efficiency.py +443 -0
  190. package/harness/bundles/java/claude-code/scripts/harness_environment.py +760 -46
  191. package/harness/bundles/java/claude-code/scripts/harness_execution_contracts.py +596 -0
  192. package/harness/bundles/java/claude-code/scripts/harness_fixback.py +742 -0
  193. package/harness/bundles/java/claude-code/scripts/harness_integration.py +289 -52
  194. package/harness/bundles/java/claude-code/scripts/harness_ledger.py +5 -0
  195. package/harness/bundles/java/claude-code/scripts/harness_orchestration.py +344 -0
  196. package/harness/bundles/java/claude-code/scripts/harness_process.py +1065 -0
  197. package/harness/bundles/java/claude-code/scripts/harness_profile.py +278 -4
  198. package/harness/bundles/java/claude-code/scripts/harness_runtime.py +1576 -3
  199. package/harness/bundles/java/claude-code/scripts/harness_service.py +1528 -177
  200. package/harness/bundles/java/claude-code/scripts/harness_test_runner.py +224 -146
  201. package/harness/bundles/java/claude-code/scripts/harness_verification.py +487 -8
  202. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  203. package/harness/bundles/java/codebuddy/contracts/build-profile-v3.schema.json +156 -1
  204. package/harness/bundles/java/codebuddy/contracts/fixtures/managed-execution.json +341 -0
  205. package/harness/bundles/java/codebuddy/contracts/process-identity.schema.json +132 -0
  206. package/harness/bundles/java/codebuddy/contracts/run-session.schema.json +142 -0
  207. package/harness/bundles/java/codebuddy/contracts/service-retirement-receipt.schema.json +85 -0
  208. package/harness/bundles/java/codebuddy/contracts/service-session.schema.json +147 -0
  209. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  210. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  211. package/harness/bundles/java/codebuddy/harness-archive/reference.md +1 -0
  212. package/harness/bundles/java/codebuddy/harness-archive/templates/render-summary.mjs +8 -0
  213. package/harness/bundles/java/codebuddy/harness-archive/templates/summary-data-template.json +28 -0
  214. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  215. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  216. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  217. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  218. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
  219. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
  220. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +1 -1
  221. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
  222. package/harness/bundles/java/codebuddy/harness-submit/checklist.md +12 -0
  223. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  224. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +8 -2
  225. package/harness/bundles/java/codebuddy/protocols/execution-session-protocol.md +52 -0
  226. package/harness/bundles/java/codebuddy/protocols/state-layout-protocol.md +24 -1
  227. package/harness/bundles/java/codebuddy/protocols/verification-graph-protocol.md +6 -0
  228. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +271 -22
  229. package/harness/bundles/java/codebuddy/scripts/harness_change.py +137 -2
  230. package/harness/bundles/java/codebuddy/scripts/harness_efficiency.py +443 -0
  231. package/harness/bundles/java/codebuddy/scripts/harness_environment.py +760 -46
  232. package/harness/bundles/java/codebuddy/scripts/harness_execution_contracts.py +596 -0
  233. package/harness/bundles/java/codebuddy/scripts/harness_fixback.py +742 -0
  234. package/harness/bundles/java/codebuddy/scripts/harness_integration.py +289 -52
  235. package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +5 -0
  236. package/harness/bundles/java/codebuddy/scripts/harness_orchestration.py +344 -0
  237. package/harness/bundles/java/codebuddy/scripts/harness_process.py +1065 -0
  238. package/harness/bundles/java/codebuddy/scripts/harness_profile.py +278 -4
  239. package/harness/bundles/java/codebuddy/scripts/harness_runtime.py +1576 -3
  240. package/harness/bundles/java/codebuddy/scripts/harness_service.py +1528 -177
  241. package/harness/bundles/java/codebuddy/scripts/harness_test_runner.py +224 -146
  242. package/harness/bundles/java/codebuddy/scripts/harness_verification.py +487 -8
  243. package/harness/bundles/java/codex/.harness-build.json +1 -1
  244. package/harness/bundles/java/codex/contracts/build-profile-v3.schema.json +156 -1
  245. package/harness/bundles/java/codex/contracts/fixtures/managed-execution.json +341 -0
  246. package/harness/bundles/java/codex/contracts/process-identity.schema.json +132 -0
  247. package/harness/bundles/java/codex/contracts/run-session.schema.json +142 -0
  248. package/harness/bundles/java/codex/contracts/service-retirement-receipt.schema.json +85 -0
  249. package/harness/bundles/java/codex/contracts/service-session.schema.json +147 -0
  250. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  251. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  252. package/harness/bundles/java/codex/harness-archive/reference.md +1 -0
  253. package/harness/bundles/java/codex/harness-archive/templates/render-summary.mjs +8 -0
  254. package/harness/bundles/java/codex/harness-archive/templates/summary-data-template.json +28 -0
  255. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  256. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  257. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  258. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  259. package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
  260. package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
  261. package/harness/bundles/java/codex/harness-run/SKILL.md +1 -1
  262. package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
  263. package/harness/bundles/java/codex/harness-submit/checklist.md +12 -0
  264. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  265. package/harness/bundles/java/codex/harness-test/SKILL.md +8 -2
  266. package/harness/bundles/java/codex/protocols/execution-session-protocol.md +52 -0
  267. package/harness/bundles/java/codex/protocols/state-layout-protocol.md +24 -1
  268. package/harness/bundles/java/codex/protocols/verification-graph-protocol.md +6 -0
  269. package/harness/bundles/java/codex/scripts/harness_archive.py +271 -22
  270. package/harness/bundles/java/codex/scripts/harness_change.py +137 -2
  271. package/harness/bundles/java/codex/scripts/harness_efficiency.py +443 -0
  272. package/harness/bundles/java/codex/scripts/harness_environment.py +760 -46
  273. package/harness/bundles/java/codex/scripts/harness_execution_contracts.py +596 -0
  274. package/harness/bundles/java/codex/scripts/harness_fixback.py +742 -0
  275. package/harness/bundles/java/codex/scripts/harness_integration.py +289 -52
  276. package/harness/bundles/java/codex/scripts/harness_ledger.py +5 -0
  277. package/harness/bundles/java/codex/scripts/harness_orchestration.py +344 -0
  278. package/harness/bundles/java/codex/scripts/harness_process.py +1065 -0
  279. package/harness/bundles/java/codex/scripts/harness_profile.py +278 -4
  280. package/harness/bundles/java/codex/scripts/harness_runtime.py +1576 -3
  281. package/harness/bundles/java/codex/scripts/harness_service.py +1528 -177
  282. package/harness/bundles/java/codex/scripts/harness_test_runner.py +224 -146
  283. package/harness/bundles/java/codex/scripts/harness_verification.py +487 -8
  284. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  285. package/harness/bundles/java/cursor/contracts/build-profile-v3.schema.json +156 -1
  286. package/harness/bundles/java/cursor/contracts/fixtures/managed-execution.json +341 -0
  287. package/harness/bundles/java/cursor/contracts/process-identity.schema.json +132 -0
  288. package/harness/bundles/java/cursor/contracts/run-session.schema.json +142 -0
  289. package/harness/bundles/java/cursor/contracts/service-retirement-receipt.schema.json +85 -0
  290. package/harness/bundles/java/cursor/contracts/service-session.schema.json +147 -0
  291. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  292. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  293. package/harness/bundles/java/cursor/harness-archive/reference.md +1 -0
  294. package/harness/bundles/java/cursor/harness-archive/templates/render-summary.mjs +8 -0
  295. package/harness/bundles/java/cursor/harness-archive/templates/summary-data-template.json +28 -0
  296. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  297. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  298. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  299. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  300. package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
  301. package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
  302. package/harness/bundles/java/cursor/harness-run/SKILL.md +1 -1
  303. package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
  304. package/harness/bundles/java/cursor/harness-submit/checklist.md +12 -0
  305. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  306. package/harness/bundles/java/cursor/harness-test/SKILL.md +8 -2
  307. package/harness/bundles/java/cursor/protocols/execution-session-protocol.md +52 -0
  308. package/harness/bundles/java/cursor/protocols/state-layout-protocol.md +24 -1
  309. package/harness/bundles/java/cursor/protocols/verification-graph-protocol.md +6 -0
  310. package/harness/bundles/java/cursor/scripts/harness_archive.py +271 -22
  311. package/harness/bundles/java/cursor/scripts/harness_change.py +137 -2
  312. package/harness/bundles/java/cursor/scripts/harness_efficiency.py +443 -0
  313. package/harness/bundles/java/cursor/scripts/harness_environment.py +760 -46
  314. package/harness/bundles/java/cursor/scripts/harness_execution_contracts.py +596 -0
  315. package/harness/bundles/java/cursor/scripts/harness_fixback.py +742 -0
  316. package/harness/bundles/java/cursor/scripts/harness_integration.py +289 -52
  317. package/harness/bundles/java/cursor/scripts/harness_ledger.py +5 -0
  318. package/harness/bundles/java/cursor/scripts/harness_orchestration.py +344 -0
  319. package/harness/bundles/java/cursor/scripts/harness_process.py +1065 -0
  320. package/harness/bundles/java/cursor/scripts/harness_profile.py +278 -4
  321. package/harness/bundles/java/cursor/scripts/harness_runtime.py +1576 -3
  322. package/harness/bundles/java/cursor/scripts/harness_service.py +1528 -177
  323. package/harness/bundles/java/cursor/scripts/harness_test_runner.py +224 -146
  324. package/harness/bundles/java/cursor/scripts/harness_verification.py +487 -8
  325. package/harness/manifests/general/claude-code.json +76 -31
  326. package/harness/manifests/general/codebuddy.json +76 -31
  327. package/harness/manifests/general/codex.json +76 -31
  328. package/harness/manifests/general/cursor.json +76 -31
  329. package/harness/manifests/java/claude-code.json +77 -32
  330. package/harness/manifests/java/codebuddy.json +77 -32
  331. package/harness/manifests/java/codex.json +77 -32
  332. package/harness/manifests/java/cursor.json +77 -32
  333. package/hunter-workflow-family.json +6 -4
  334. package/package.json +1 -1
@@ -29,6 +29,7 @@ if str(SCRIPT_DIR) not in sys.path:
29
29
  sys.path.insert(0, str(SCRIPT_DIR))
30
30
 
31
31
  import harness_environment as henv
32
+ import harness_process as hprocess
32
33
 
33
34
  DEFAULT_MAX_WORKERS = 2
34
35
  DEFAULT_TIMEOUT_SECONDS = 300.0
@@ -37,7 +38,10 @@ DEFAULT_RESOURCE_MODULES = (
37
38
  "test_harness_integration.py",
38
39
  "test_harness_service.py",
39
40
  )
40
- DEFAULT_DETACHED_SERVICE_MODULES = ("test_harness_service.py",)
41
+ DEFAULT_DETACHED_SERVICE_MODULES = (
42
+ "test_harness_service.py",
43
+ "test_harness_runtime.py",
44
+ )
41
45
  TRUTHY_VALUES = frozenset({"1", "true", "yes", "on"})
42
46
 
43
47
 
@@ -136,35 +140,30 @@ def build_unittest_plan(
136
140
 
137
141
 
138
142
  def _pid_is_running(pid: int) -> bool:
139
- if pid <= 0:
140
- return False
141
- if pid == os.getpid():
142
- return True
143
- if os.name == "nt":
144
- process_query_limited_information = 0x1000
145
- kernel32 = ctypes.windll.kernel32
146
- kernel32.OpenProcess.restype = ctypes.c_void_p
147
- handle = kernel32.OpenProcess(
148
- process_query_limited_information,
149
- False,
150
- pid,
151
- )
152
- if not handle:
153
- return False
154
- try:
155
- exit_code = ctypes.c_uint32()
156
- if not kernel32.GetExitCodeProcess(handle, ctypes.byref(exit_code)):
157
- return False
158
- return int(exit_code.value) == 259
159
- finally:
160
- kernel32.CloseHandle(ctypes.c_void_p(handle))
143
+ return hprocess.is_pid_alive(pid)
144
+
145
+
146
+ def _verify_recorded_owner(owner: Mapping[str, object]) -> bool | None:
147
+ """Verify a legacy lock owner through the canonical process provider."""
148
+
161
149
  try:
162
- os.kill(pid, 0)
163
- except ProcessLookupError:
164
- return False
165
- except PermissionError:
150
+ pid = int(owner.get("pid") or 0)
151
+ except (TypeError, ValueError):
152
+ return None
153
+ observed = hprocess.observe_process_identity(pid)
154
+ decision = hprocess.verify_process_identity(
155
+ {
156
+ "pid": pid,
157
+ "createdAt": owner.get("startedAt"),
158
+ "executable": owner.get("executable"),
159
+ },
160
+ observed,
161
+ )
162
+ if decision.get("ok") is True:
166
163
  return True
167
- return True
164
+ if decision.get("reasonCode") == "IDENTITY_UNVERIFIABLE":
165
+ return None
166
+ return False
168
167
 
169
168
 
170
169
  def classify_test_lock(path: Path) -> dict[str, object]:
@@ -189,16 +188,17 @@ def classify_test_lock(path: Path) -> dict[str, object]:
189
188
  "path": str(path),
190
189
  "token": payload.get("token"),
191
190
  }
192
- if time.time() < float(expires):
193
- return {
194
- "classification": "ACTIVE",
195
- "path": str(path),
196
- "token": payload.get("token"),
197
- "owner": owner,
198
- }
191
+ unexpired = time.time() < float(expires)
199
192
  if not isinstance(owner, dict) or any(
200
193
  not owner.get(field) for field in ("pid", "executable", "startedAt")
201
194
  ):
195
+ if unexpired:
196
+ return {
197
+ "classification": "ACTIVE",
198
+ "path": str(path),
199
+ "token": payload.get("token"),
200
+ "owner": owner,
201
+ }
202
202
  return {
203
203
  "classification": "OWNER_IDENTITY_INCOMPLETE",
204
204
  "path": str(path),
@@ -207,6 +207,13 @@ def classify_test_lock(path: Path) -> dict[str, object]:
207
207
  try:
208
208
  owner_pid = int(owner["pid"])
209
209
  except (TypeError, ValueError):
210
+ if unexpired:
211
+ return {
212
+ "classification": "ACTIVE",
213
+ "path": str(path),
214
+ "token": payload.get("token"),
215
+ "owner": owner,
216
+ }
210
217
  return {
211
218
  "classification": "OWNER_IDENTITY_INCOMPLETE",
212
219
  "path": str(path),
@@ -219,13 +226,14 @@ def classify_test_lock(path: Path) -> dict[str, object]:
219
226
  "token": payload.get("token"),
220
227
  "owner": owner,
221
228
  }
222
- verified = henv.hservice.verify_process_identity(
223
- {
224
- "pid": owner_pid,
225
- "startedAt": owner["startedAt"],
226
- "processIdentity": {"executable": owner["executable"]},
229
+ if unexpired:
230
+ return {
231
+ "classification": "ACTIVE",
232
+ "path": str(path),
233
+ "token": payload.get("token"),
234
+ "owner": owner,
227
235
  }
228
- )
236
+ verified = _verify_recorded_owner(owner)
229
237
  classification = (
230
238
  "OWNER_ACTIVE"
231
239
  if verified is True
@@ -244,7 +252,7 @@ def classify_test_lock(path: Path) -> dict[str, object]:
244
252
 
245
253
 
246
254
  def reap_test_lock(path: Path) -> dict[str, object]:
247
- """Reap only an expired lock whose exact recorded owner is absent."""
255
+ """Reap only a lock whose exact recorded owner is definitely absent."""
248
256
  classification = classify_test_lock(path)
249
257
  reaped = classification.get("classification") == "RECLAIMABLE"
250
258
  if reaped:
@@ -330,9 +338,9 @@ class TestRunLock:
330
338
  )
331
339
  else:
332
340
  now = time.time()
333
- created = henv.hservice.get_process_create_time(os.getpid())
341
+ created = hprocess.get_process_create_time(os.getpid())
334
342
  executable = (
335
- henv.hservice.get_process_executable(os.getpid())
343
+ hprocess.get_process_executable(os.getpid())
336
344
  or str(Path(sys.executable).resolve())
337
345
  )
338
346
  payload = {
@@ -484,6 +492,20 @@ class _WindowsBasicAccountingInformation(ctypes.Structure):
484
492
  ]
485
493
 
486
494
 
495
+ _WINDOWS_JOB_PROCESS_ID_CAPACITY = 4096
496
+
497
+
498
+ class _WindowsJobProcessIdList(ctypes.Structure):
499
+ _fields_ = [
500
+ ("NumberOfAssignedProcesses", ctypes.c_uint32),
501
+ ("NumberOfProcessIdsInList", ctypes.c_uint32),
502
+ (
503
+ "ProcessIdList",
504
+ ctypes.c_size_t * _WINDOWS_JOB_PROCESS_ID_CAPACITY,
505
+ ),
506
+ ]
507
+
508
+
487
509
  class _WindowsKillOnCloseJob:
488
510
  """Best-effort Windows Job Object that kills descendants when closed."""
489
511
 
@@ -491,9 +513,11 @@ class _WindowsKillOnCloseJob:
491
513
  _JOB_OBJECT_LIMIT_BREAKAWAY_OK = 0x00000800
492
514
  _JOB_OBJECT_EXTENDED_LIMIT_INFORMATION_CLASS = 9
493
515
  _JOB_OBJECT_BASIC_ACCOUNTING_INFORMATION_CLASS = 1
516
+ _JOB_OBJECT_BASIC_PROCESS_ID_LIST_CLASS = 3
494
517
 
495
- def __init__(self) -> None:
518
+ def __init__(self, *, allow_breakaway: bool = False) -> None:
496
519
  self.handle: int | None = None
520
+ self.allow_breakaway = allow_breakaway
497
521
 
498
522
  def assign(self, process: subprocess.Popen[object]) -> bool:
499
523
  if os.name != "nt":
@@ -506,7 +530,11 @@ class _WindowsKillOnCloseJob:
506
530
  info = _WindowsExtendedLimitInformation()
507
531
  info.BasicLimitInformation.LimitFlags = (
508
532
  self._JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE
509
- | self._JOB_OBJECT_LIMIT_BREAKAWAY_OK
533
+ | (
534
+ self._JOB_OBJECT_LIMIT_BREAKAWAY_OK
535
+ if self.allow_breakaway
536
+ else 0
537
+ )
510
538
  )
511
539
  configured = kernel32.SetInformationJobObject(
512
540
  ctypes.c_void_p(handle),
@@ -535,26 +563,73 @@ class _WindowsKillOnCloseJob:
535
563
  ctypes.windll.kernel32.CloseHandle(ctypes.c_void_p(self.handle))
536
564
  self.handle = None
537
565
 
538
- def terminate_and_wait(self, timeout_seconds: float = 5.0) -> None:
566
+ def terminate_and_wait(self, timeout_seconds: float = 5.0) -> bool:
539
567
  if self.handle is None:
540
- return
568
+ return True
541
569
  kernel32 = ctypes.windll.kernel32
542
570
  handle = ctypes.c_void_p(self.handle)
543
- kernel32.TerminateJobObject(handle, 1)
544
571
  deadline = time.monotonic() + max(0.0, timeout_seconds)
545
- while time.monotonic() < deadline:
546
- accounting = _WindowsBasicAccountingInformation()
547
- queried = kernel32.QueryInformationJobObject(
548
- handle,
549
- self._JOB_OBJECT_BASIC_ACCOUNTING_INFORMATION_CLASS,
550
- ctypes.byref(accounting),
551
- ctypes.sizeof(accounting),
552
- None,
553
- )
554
- if not queried or accounting.ActiveProcesses == 0:
555
- break
556
- time.sleep(0.02)
557
- self.close()
572
+ process_ids = _WindowsJobProcessIdList()
573
+ process_list_queried = kernel32.QueryInformationJobObject(
574
+ handle,
575
+ self._JOB_OBJECT_BASIC_PROCESS_ID_LIST_CLASS,
576
+ ctypes.byref(process_ids),
577
+ ctypes.sizeof(process_ids),
578
+ None,
579
+ )
580
+ process_list_complete = bool(
581
+ process_list_queried
582
+ and process_ids.NumberOfAssignedProcesses
583
+ == process_ids.NumberOfProcessIdsInList
584
+ )
585
+ kernel32.OpenProcess.restype = ctypes.c_void_p
586
+ process_handles: list[int] = []
587
+ if process_list_complete:
588
+ for index in range(int(process_ids.NumberOfProcessIdsInList)):
589
+ process_handle = kernel32.OpenProcess(
590
+ 0x00100000,
591
+ False,
592
+ int(process_ids.ProcessIdList[index]),
593
+ )
594
+ if process_handle:
595
+ process_handles.append(int(process_handle))
596
+ else:
597
+ process_list_complete = False
598
+ terminated = bool(kernel32.TerminateJobObject(handle, 1))
599
+ handles_signaled = process_list_complete
600
+ try:
601
+ for process_handle in process_handles:
602
+ remaining_ms = max(
603
+ 0,
604
+ int((deadline - time.monotonic()) * 1000),
605
+ )
606
+ if (
607
+ kernel32.WaitForSingleObject(
608
+ ctypes.c_void_p(process_handle),
609
+ remaining_ms,
610
+ )
611
+ != 0
612
+ ):
613
+ handles_signaled = False
614
+ accounting_drained = False
615
+ while time.monotonic() < deadline:
616
+ accounting = _WindowsBasicAccountingInformation()
617
+ queried = kernel32.QueryInformationJobObject(
618
+ handle,
619
+ self._JOB_OBJECT_BASIC_ACCOUNTING_INFORMATION_CLASS,
620
+ ctypes.byref(accounting),
621
+ ctypes.sizeof(accounting),
622
+ None,
623
+ )
624
+ if queried and accounting.ActiveProcesses == 0:
625
+ accounting_drained = True
626
+ break
627
+ time.sleep(0.02)
628
+ finally:
629
+ for process_handle in process_handles:
630
+ kernel32.CloseHandle(ctypes.c_void_p(process_handle))
631
+ self.close()
632
+ return terminated and handles_signaled and accounting_drained
558
633
 
559
634
 
560
635
  class _WindowsProcessEntry(ctypes.Structure):
@@ -709,50 +784,22 @@ def _terminate_process_tree(
709
784
  *,
710
785
  windows_job: _WindowsKillOnCloseJob | None,
711
786
  ) -> None:
787
+ """Legacy seam retained for callers; ownership must be provider-backed."""
788
+
712
789
  if windows_job is not None and windows_job.handle is not None:
713
790
  windows_job.terminate_and_wait()
714
- elif os.name == "nt":
715
- subprocess.run(
716
- ["taskkill", "/PID", str(process.pid), "/T", "/F"],
717
- stdout=subprocess.DEVNULL,
718
- stderr=subprocess.DEVNULL,
719
- check=False,
720
- timeout=10,
721
- creationflags=getattr(subprocess, "CREATE_NO_WINDOW", 0),
722
- )
723
791
  else:
724
- try:
725
- os.killpg(process.pid, signal.SIGTERM)
726
- except ProcessLookupError:
727
- pass
728
- try:
729
- process.wait(timeout=2)
730
- except subprocess.TimeoutExpired:
731
- try:
732
- os.killpg(process.pid, signal.SIGKILL)
733
- except ProcessLookupError:
734
- pass
735
- if process.poll() is None:
736
- process.kill()
737
- try:
738
- process.wait(timeout=5)
739
- except subprocess.TimeoutExpired:
740
- pass
792
+ raise RuntimeError("PROCESS_OWNERSHIP_REQUIRED")
741
793
 
742
794
 
743
795
  def _cleanup_descendants_after_success(
744
796
  process: subprocess.Popen[object],
745
797
  *,
746
798
  windows_job: _WindowsKillOnCloseJob | None,
747
- ) -> None:
799
+ ) -> bool:
748
800
  if windows_job is not None and windows_job.handle is not None:
749
- windows_job.terminate_and_wait()
750
- return
751
- if os.name != "nt":
752
- try:
753
- os.killpg(process.pid, signal.SIGTERM)
754
- except ProcessLookupError:
755
- pass
801
+ return windows_job.terminate_and_wait()
802
+ return False
756
803
 
757
804
 
758
805
  def run_managed_command(
@@ -774,74 +821,84 @@ def run_managed_command(
774
821
  child_env.setdefault("PYTHONUNBUFFERED", "1")
775
822
  lower_process_priority()
776
823
 
777
- popen_kwargs: dict[str, object] = {
778
- "cwd": str(Path(cwd).resolve()),
779
- "env": child_env,
780
- "shell": False,
781
- }
782
824
  output_stream = tempfile.TemporaryFile(mode="w+b") if capture_output else None
783
- if output_stream is not None:
784
- popen_kwargs["stdout"] = output_stream
785
- popen_kwargs["stderr"] = subprocess.STDOUT
786
- if os.name == "nt":
787
- popen_kwargs["creationflags"] = getattr(
788
- subprocess,
789
- "CREATE_NEW_PROCESS_GROUP",
790
- 0,
791
- )
792
- else:
793
- popen_kwargs["start_new_session"] = True
794
-
795
825
  started = time.monotonic()
826
+ spawned = None
827
+ process: subprocess.Popen[object] | None = None
828
+ cleanup_complete = False
796
829
  try:
797
- process = subprocess.Popen(list(argv), **popen_kwargs)
798
- windows_job = (
799
- _WindowsKillOnCloseJob()
800
- if os.name == "nt" and not allow_detached_processes
801
- else None
830
+ spawned = hprocess.spawn_structured_argv(
831
+ list(argv),
832
+ cwd=Path(cwd).resolve(),
833
+ environment=child_env,
834
+ owner_token=f"test-runner:{uuid.uuid4().hex}",
835
+ stdout=output_stream,
836
+ stderr=(subprocess.STDOUT if output_stream is not None else None),
802
837
  )
803
- isolated = bool(windows_job and windows_job.assign(process))
804
- known_windows_descendants: set[int] = set()
805
- windows_snapshot_ok = True
806
- if os.name != "nt":
807
- isolated = True
838
+ process = spawned.process
839
+ isolated = bool(
840
+ isinstance(spawned.ownershipProof, dict)
841
+ and spawned.ownershipProof.get("membersComplete") is True
842
+ )
843
+
844
+ def provider_cleanup() -> bool:
845
+ hprocess.capture_owned_members(spawned)
846
+ result = hprocess.terminate_owned_tree(
847
+ spawned.attestation,
848
+ spawned.ownershipProof,
849
+ {"graceSeconds": 3.0},
850
+ )
851
+ return bool(result.get("cleanupComplete"))
852
+
853
+ def wait_owned_members_gone() -> bool:
854
+ proof = spawned.ownershipProof
855
+ if not isinstance(proof, dict):
856
+ return False
857
+ members = proof.get("members")
858
+ if not isinstance(members, list):
859
+ return False
860
+ pids = {
861
+ int(item["pid"])
862
+ for item in members
863
+ if isinstance(item, dict) and isinstance(item.get("pid"), int)
864
+ }
865
+ deadline = time.monotonic() + 5.0
866
+ while pids and time.monotonic() < deadline:
867
+ pids = {pid for pid in pids if hprocess.is_pid_alive(pid)}
868
+ if pids:
869
+ time.sleep(0.05)
870
+ return not pids
871
+
808
872
  timed_out = False
809
873
  try:
810
874
  deadline = time.monotonic() + max(0.01, float(timeout_seconds))
811
875
  while True:
812
- if os.name == "nt":
813
- windows_snapshot_ok = (
814
- _update_windows_descendants(
815
- process.pid,
816
- known_windows_descendants,
817
- )
818
- and windows_snapshot_ok
819
- )
820
876
  polled = process.poll()
821
877
  if polled is not None:
822
878
  returncode = polled
823
879
  break
824
880
  if time.monotonic() >= deadline:
825
881
  timed_out = True
826
- _terminate_process_tree(process, windows_job=windows_job)
882
+ cleanup_complete = provider_cleanup()
827
883
  returncode = 124
828
884
  break
829
885
  time.sleep(0.05)
830
886
  except KeyboardInterrupt:
831
- _terminate_process_tree(process, windows_job=windows_job)
832
- if os.name == "nt":
833
- _terminate_tracked_windows_descendants(known_windows_descendants)
887
+ cleanup_complete = provider_cleanup()
834
888
  raise
835
889
  if not timed_out:
836
- _cleanup_descendants_after_success(process, windows_job=windows_job)
837
- if os.name == "nt":
838
- _update_windows_descendants(process.pid, known_windows_descendants)
839
- _terminate_tracked_windows_descendants(known_windows_descendants)
840
- isolated = (
841
- windows_snapshot_ok
842
- if allow_detached_processes
843
- else isolated and windows_snapshot_ok
844
- )
890
+ cleanup_complete = provider_cleanup()
891
+ # A named Windows Job remains an owned capability after the leader
892
+ # exits. Closing that provider handle drains any attested children;
893
+ # PID-only or POSIX group fallbacks stay fail-closed.
894
+ if not cleanup_complete and os.name == "nt":
895
+ spawned.close()
896
+ cleanup_complete = wait_owned_members_gone()
897
+ if process.poll() is None:
898
+ try:
899
+ process.wait(timeout=5)
900
+ except subprocess.TimeoutExpired:
901
+ cleanup_complete = False
845
902
  duration = time.monotonic() - started
846
903
  output_tail = ""
847
904
  if output_stream is not None:
@@ -854,10 +911,28 @@ def run_managed_command(
854
911
  returncode=returncode,
855
912
  timed_out=timed_out,
856
913
  duration_seconds=duration,
857
- process_tree_isolated=isolated,
914
+ process_tree_isolated=isolated and cleanup_complete,
858
915
  output_tail=output_tail,
859
916
  )
860
917
  finally:
918
+ if (
919
+ not cleanup_complete
920
+ and process is not None
921
+ and process.poll() is None
922
+ and spawned is not None
923
+ ):
924
+ try:
925
+ hprocess.capture_owned_members(spawned)
926
+ cleanup = hprocess.terminate_owned_tree(
927
+ spawned.attestation,
928
+ spawned.ownershipProof,
929
+ {"graceSeconds": 3.0},
930
+ )
931
+ cleanup_complete = bool(cleanup.get("cleanupComplete"))
932
+ except Exception:
933
+ cleanup_complete = False
934
+ if spawned is not None:
935
+ spawned.close()
861
936
  if output_stream is not None:
862
937
  output_stream.close()
863
938
 
@@ -1320,7 +1395,10 @@ def build_parser() -> argparse.ArgumentParser:
1320
1395
  exec_parser.add_argument(
1321
1396
  "--allow-detached-processes",
1322
1397
  action="store_true",
1323
- help="Use exact Windows PID-lineage tracking instead of a Job Object.",
1398
+ help=(
1399
+ "Permit explicit Windows Job breakaway while retaining ordinary "
1400
+ "descendants and tracking escaped process lineages."
1401
+ ),
1324
1402
  )
1325
1403
  exec_parser.set_defaults(handler=_run_exec)
1326
1404