@hunter-harness/workflow-harness 0.2.1 → 0.2.3

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/harness-archive/SKILL.md +1 -1
  3. package/harness/bundles/general/claude-code/harness-archive/reference.md +2 -8
  4. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +2 -1
  5. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  6. package/harness/bundles/general/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  7. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  8. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +2 -1
  9. package/harness/bundles/general/claude-code/harness-review/SKILL.md +5 -1
  10. package/harness/bundles/general/claude-code/harness-run/SKILL.md +1 -1
  11. package/harness/bundles/general/claude-code/harness-run/checklist.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +2 -2
  13. package/harness/bundles/general/claude-code/harness-submit/checklist.md +30 -6
  14. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  15. package/harness/bundles/general/claude-code/harness-test/SKILL.md +2 -2
  16. package/harness/bundles/general/claude-code/harness-test/checklist.md +1 -1
  17. package/harness/bundles/general/claude-code/harness-test/pitfalls.md +16 -0
  18. package/harness/bundles/general/claude-code/harness-test/scripts/runtime-helpers.mjs +216 -0
  19. package/harness/bundles/general/claude-code/protocols/archive-report-protocol.md +1 -1
  20. package/harness/bundles/general/claude-code/protocols/ledger-protocol.md +55 -2
  21. package/harness/bundles/general/claude-code/protocols/report-pipeline-protocol.md +1 -8
  22. package/harness/bundles/general/claude-code/protocols/sensitive-info-protocol.md +13 -0
  23. package/harness/bundles/general/claude-code/protocols/state-layout-protocol.md +24 -0
  24. package/harness/bundles/general/claude-code/scripts/harness_archive.py +31 -14
  25. package/harness/bundles/general/claude-code/scripts/harness_check_gate.py +111 -0
  26. package/harness/bundles/general/claude-code/scripts/harness_deploy.py +179 -4
  27. package/harness/bundles/general/claude-code/scripts/harness_ledger.py +269 -3
  28. package/harness/bundles/general/claude-code/scripts/harness_preflight.py +72 -382
  29. package/harness/bundles/general/claude-code/scripts/harness_profile.py +742 -0
  30. package/harness/bundles/general/claude-code/scripts/harness_service.py +99 -2
  31. package/harness/bundles/general/claude-code/scripts/harness_state.py +179 -0
  32. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  33. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  34. package/harness/bundles/general/codebuddy/harness-archive/reference.md +2 -8
  35. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +2 -1
  36. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  37. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  38. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  39. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +2 -1
  40. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +5 -1
  41. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +1 -1
  42. package/harness/bundles/general/codebuddy/harness-run/checklist.md +1 -1
  43. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +2 -2
  44. package/harness/bundles/general/codebuddy/harness-submit/checklist.md +30 -6
  45. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  46. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +2 -2
  47. package/harness/bundles/general/codebuddy/harness-test/checklist.md +1 -1
  48. package/harness/bundles/general/codebuddy/harness-test/pitfalls.md +16 -0
  49. package/harness/bundles/general/codebuddy/harness-test/scripts/runtime-helpers.mjs +216 -0
  50. package/harness/bundles/general/codebuddy/protocols/archive-report-protocol.md +1 -1
  51. package/harness/bundles/general/codebuddy/protocols/ledger-protocol.md +55 -2
  52. package/harness/bundles/general/codebuddy/protocols/report-pipeline-protocol.md +1 -8
  53. package/harness/bundles/general/codebuddy/protocols/sensitive-info-protocol.md +13 -0
  54. package/harness/bundles/general/codebuddy/protocols/state-layout-protocol.md +24 -0
  55. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +31 -14
  56. package/harness/bundles/general/codebuddy/scripts/harness_check_gate.py +111 -0
  57. package/harness/bundles/general/codebuddy/scripts/harness_deploy.py +179 -4
  58. package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +269 -3
  59. package/harness/bundles/general/codebuddy/scripts/harness_preflight.py +72 -382
  60. package/harness/bundles/general/codebuddy/scripts/harness_profile.py +742 -0
  61. package/harness/bundles/general/codebuddy/scripts/harness_service.py +99 -2
  62. package/harness/bundles/general/codebuddy/scripts/harness_state.py +179 -0
  63. package/harness/bundles/general/codex/.harness-build.json +1 -1
  64. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  65. package/harness/bundles/general/codex/harness-archive/reference.md +2 -8
  66. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +2 -1
  67. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  68. package/harness/bundles/general/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  69. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  70. package/harness/bundles/general/codex/harness-plan/SKILL.md +2 -1
  71. package/harness/bundles/general/codex/harness-review/SKILL.md +5 -1
  72. package/harness/bundles/general/codex/harness-run/SKILL.md +1 -1
  73. package/harness/bundles/general/codex/harness-run/checklist.md +1 -1
  74. package/harness/bundles/general/codex/harness-submit/SKILL.md +2 -2
  75. package/harness/bundles/general/codex/harness-submit/checklist.md +30 -6
  76. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  77. package/harness/bundles/general/codex/harness-test/SKILL.md +2 -2
  78. package/harness/bundles/general/codex/harness-test/checklist.md +1 -1
  79. package/harness/bundles/general/codex/harness-test/pitfalls.md +16 -0
  80. package/harness/bundles/general/codex/harness-test/scripts/runtime-helpers.mjs +216 -0
  81. package/harness/bundles/general/codex/protocols/archive-report-protocol.md +1 -1
  82. package/harness/bundles/general/codex/protocols/ledger-protocol.md +55 -2
  83. package/harness/bundles/general/codex/protocols/report-pipeline-protocol.md +1 -8
  84. package/harness/bundles/general/codex/protocols/sensitive-info-protocol.md +13 -0
  85. package/harness/bundles/general/codex/protocols/state-layout-protocol.md +24 -0
  86. package/harness/bundles/general/codex/scripts/harness_archive.py +31 -14
  87. package/harness/bundles/general/codex/scripts/harness_check_gate.py +111 -0
  88. package/harness/bundles/general/codex/scripts/harness_deploy.py +179 -4
  89. package/harness/bundles/general/codex/scripts/harness_ledger.py +269 -3
  90. package/harness/bundles/general/codex/scripts/harness_preflight.py +72 -382
  91. package/harness/bundles/general/codex/scripts/harness_profile.py +742 -0
  92. package/harness/bundles/general/codex/scripts/harness_service.py +99 -2
  93. package/harness/bundles/general/codex/scripts/harness_state.py +179 -0
  94. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  95. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  96. package/harness/bundles/general/cursor/harness-archive/reference.md +2 -8
  97. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +2 -1
  98. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  99. package/harness/bundles/general/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  100. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  101. package/harness/bundles/general/cursor/harness-plan/SKILL.md +2 -1
  102. package/harness/bundles/general/cursor/harness-review/SKILL.md +5 -1
  103. package/harness/bundles/general/cursor/harness-run/SKILL.md +1 -1
  104. package/harness/bundles/general/cursor/harness-run/checklist.md +1 -1
  105. package/harness/bundles/general/cursor/harness-submit/SKILL.md +2 -2
  106. package/harness/bundles/general/cursor/harness-submit/checklist.md +30 -6
  107. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  108. package/harness/bundles/general/cursor/harness-test/SKILL.md +2 -2
  109. package/harness/bundles/general/cursor/harness-test/checklist.md +1 -1
  110. package/harness/bundles/general/cursor/harness-test/pitfalls.md +16 -0
  111. package/harness/bundles/general/cursor/harness-test/scripts/runtime-helpers.mjs +216 -0
  112. package/harness/bundles/general/cursor/protocols/archive-report-protocol.md +1 -1
  113. package/harness/bundles/general/cursor/protocols/ledger-protocol.md +55 -2
  114. package/harness/bundles/general/cursor/protocols/report-pipeline-protocol.md +1 -8
  115. package/harness/bundles/general/cursor/protocols/sensitive-info-protocol.md +13 -0
  116. package/harness/bundles/general/cursor/protocols/state-layout-protocol.md +24 -0
  117. package/harness/bundles/general/cursor/scripts/harness_archive.py +31 -14
  118. package/harness/bundles/general/cursor/scripts/harness_check_gate.py +111 -0
  119. package/harness/bundles/general/cursor/scripts/harness_deploy.py +179 -4
  120. package/harness/bundles/general/cursor/scripts/harness_ledger.py +269 -3
  121. package/harness/bundles/general/cursor/scripts/harness_preflight.py +72 -382
  122. package/harness/bundles/general/cursor/scripts/harness_profile.py +742 -0
  123. package/harness/bundles/general/cursor/scripts/harness_service.py +99 -2
  124. package/harness/bundles/general/cursor/scripts/harness_state.py +179 -0
  125. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  126. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  127. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  128. package/harness/bundles/java/claude-code/harness-archive/reference.md +2 -8
  129. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +2 -1
  130. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  131. package/harness/bundles/java/claude-code/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  132. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  133. package/harness/bundles/java/claude-code/harness-package/SKILL.md +3 -3
  134. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +2 -1
  135. package/harness/bundles/java/claude-code/harness-review/SKILL.md +5 -1
  136. package/harness/bundles/java/claude-code/harness-run/SKILL.md +4 -4
  137. package/harness/bundles/java/claude-code/harness-run/checklist.md +3 -1
  138. package/harness/bundles/java/claude-code/harness-run/reference.md +6 -0
  139. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +3 -3
  140. package/harness/bundles/java/claude-code/harness-submit/checklist.md +30 -6
  141. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  142. package/harness/bundles/java/claude-code/harness-test/SKILL.md +5 -5
  143. package/harness/bundles/java/claude-code/harness-test/checklist.md +3 -1
  144. package/harness/bundles/java/claude-code/harness-test/pitfalls.md +16 -0
  145. package/harness/bundles/java/claude-code/harness-test/reference.md +2 -0
  146. package/harness/bundles/java/claude-code/harness-test/scripts/runtime-helpers.mjs +216 -0
  147. package/harness/bundles/java/claude-code/protocols/archive-report-protocol.md +1 -1
  148. package/harness/bundles/java/claude-code/protocols/ledger-protocol.md +55 -2
  149. package/harness/bundles/java/claude-code/protocols/report-pipeline-protocol.md +1 -8
  150. package/harness/bundles/java/claude-code/protocols/sensitive-info-protocol.md +13 -0
  151. package/harness/bundles/java/claude-code/protocols/state-layout-protocol.md +24 -0
  152. package/harness/bundles/java/claude-code/scripts/harness_archive.py +31 -14
  153. package/harness/bundles/java/claude-code/scripts/harness_check_gate.py +111 -0
  154. package/harness/bundles/java/claude-code/scripts/harness_deploy.py +179 -4
  155. package/harness/bundles/java/claude-code/scripts/harness_ledger.py +269 -3
  156. package/harness/bundles/java/claude-code/scripts/harness_preflight.py +72 -382
  157. package/harness/bundles/java/claude-code/scripts/harness_profile.py +742 -0
  158. package/harness/bundles/java/claude-code/scripts/harness_service.py +99 -2
  159. package/harness/bundles/java/claude-code/scripts/harness_state.py +179 -0
  160. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  161. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  162. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  163. package/harness/bundles/java/codebuddy/harness-archive/reference.md +2 -8
  164. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +2 -1
  165. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  166. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  167. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  168. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +3 -3
  169. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +2 -1
  170. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +5 -1
  171. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +4 -4
  172. package/harness/bundles/java/codebuddy/harness-run/checklist.md +3 -1
  173. package/harness/bundles/java/codebuddy/harness-run/reference.md +6 -0
  174. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +3 -3
  175. package/harness/bundles/java/codebuddy/harness-submit/checklist.md +30 -6
  176. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  177. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +5 -5
  178. package/harness/bundles/java/codebuddy/harness-test/checklist.md +3 -1
  179. package/harness/bundles/java/codebuddy/harness-test/pitfalls.md +16 -0
  180. package/harness/bundles/java/codebuddy/harness-test/reference.md +2 -0
  181. package/harness/bundles/java/codebuddy/harness-test/scripts/runtime-helpers.mjs +216 -0
  182. package/harness/bundles/java/codebuddy/protocols/archive-report-protocol.md +1 -1
  183. package/harness/bundles/java/codebuddy/protocols/ledger-protocol.md +55 -2
  184. package/harness/bundles/java/codebuddy/protocols/report-pipeline-protocol.md +1 -8
  185. package/harness/bundles/java/codebuddy/protocols/sensitive-info-protocol.md +13 -0
  186. package/harness/bundles/java/codebuddy/protocols/state-layout-protocol.md +24 -0
  187. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +31 -14
  188. package/harness/bundles/java/codebuddy/scripts/harness_check_gate.py +111 -0
  189. package/harness/bundles/java/codebuddy/scripts/harness_deploy.py +179 -4
  190. package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +269 -3
  191. package/harness/bundles/java/codebuddy/scripts/harness_preflight.py +72 -382
  192. package/harness/bundles/java/codebuddy/scripts/harness_profile.py +742 -0
  193. package/harness/bundles/java/codebuddy/scripts/harness_service.py +99 -2
  194. package/harness/bundles/java/codebuddy/scripts/harness_state.py +179 -0
  195. package/harness/bundles/java/codex/.harness-build.json +1 -1
  196. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  197. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  198. package/harness/bundles/java/codex/harness-archive/reference.md +2 -8
  199. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +2 -1
  200. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  201. package/harness/bundles/java/codex/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  202. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  203. package/harness/bundles/java/codex/harness-package/SKILL.md +3 -3
  204. package/harness/bundles/java/codex/harness-plan/SKILL.md +2 -1
  205. package/harness/bundles/java/codex/harness-review/SKILL.md +5 -1
  206. package/harness/bundles/java/codex/harness-run/SKILL.md +4 -4
  207. package/harness/bundles/java/codex/harness-run/checklist.md +3 -1
  208. package/harness/bundles/java/codex/harness-run/reference.md +6 -0
  209. package/harness/bundles/java/codex/harness-submit/SKILL.md +3 -3
  210. package/harness/bundles/java/codex/harness-submit/checklist.md +30 -6
  211. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  212. package/harness/bundles/java/codex/harness-test/SKILL.md +5 -5
  213. package/harness/bundles/java/codex/harness-test/checklist.md +3 -1
  214. package/harness/bundles/java/codex/harness-test/pitfalls.md +16 -0
  215. package/harness/bundles/java/codex/harness-test/reference.md +2 -0
  216. package/harness/bundles/java/codex/harness-test/scripts/runtime-helpers.mjs +216 -0
  217. package/harness/bundles/java/codex/protocols/archive-report-protocol.md +1 -1
  218. package/harness/bundles/java/codex/protocols/ledger-protocol.md +55 -2
  219. package/harness/bundles/java/codex/protocols/report-pipeline-protocol.md +1 -8
  220. package/harness/bundles/java/codex/protocols/sensitive-info-protocol.md +13 -0
  221. package/harness/bundles/java/codex/protocols/state-layout-protocol.md +24 -0
  222. package/harness/bundles/java/codex/scripts/harness_archive.py +31 -14
  223. package/harness/bundles/java/codex/scripts/harness_check_gate.py +111 -0
  224. package/harness/bundles/java/codex/scripts/harness_deploy.py +179 -4
  225. package/harness/bundles/java/codex/scripts/harness_ledger.py +269 -3
  226. package/harness/bundles/java/codex/scripts/harness_preflight.py +72 -382
  227. package/harness/bundles/java/codex/scripts/harness_profile.py +742 -0
  228. package/harness/bundles/java/codex/scripts/harness_service.py +99 -2
  229. package/harness/bundles/java/codex/scripts/harness_state.py +179 -0
  230. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  231. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  232. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  233. package/harness/bundles/java/cursor/harness-archive/reference.md +2 -8
  234. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +2 -1
  235. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  236. package/harness/bundles/java/cursor/harness-knowledge-ingest/scripts/harness_knowledge.py +474 -122
  237. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  238. package/harness/bundles/java/cursor/harness-package/SKILL.md +3 -3
  239. package/harness/bundles/java/cursor/harness-plan/SKILL.md +2 -1
  240. package/harness/bundles/java/cursor/harness-review/SKILL.md +5 -1
  241. package/harness/bundles/java/cursor/harness-run/SKILL.md +4 -4
  242. package/harness/bundles/java/cursor/harness-run/checklist.md +3 -1
  243. package/harness/bundles/java/cursor/harness-run/reference.md +6 -0
  244. package/harness/bundles/java/cursor/harness-submit/SKILL.md +3 -3
  245. package/harness/bundles/java/cursor/harness-submit/checklist.md +30 -6
  246. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  247. package/harness/bundles/java/cursor/harness-test/SKILL.md +5 -5
  248. package/harness/bundles/java/cursor/harness-test/checklist.md +3 -1
  249. package/harness/bundles/java/cursor/harness-test/pitfalls.md +16 -0
  250. package/harness/bundles/java/cursor/harness-test/reference.md +2 -0
  251. package/harness/bundles/java/cursor/harness-test/scripts/runtime-helpers.mjs +216 -0
  252. package/harness/bundles/java/cursor/protocols/archive-report-protocol.md +1 -1
  253. package/harness/bundles/java/cursor/protocols/ledger-protocol.md +55 -2
  254. package/harness/bundles/java/cursor/protocols/report-pipeline-protocol.md +1 -8
  255. package/harness/bundles/java/cursor/protocols/sensitive-info-protocol.md +13 -0
  256. package/harness/bundles/java/cursor/protocols/state-layout-protocol.md +24 -0
  257. package/harness/bundles/java/cursor/scripts/harness_archive.py +31 -14
  258. package/harness/bundles/java/cursor/scripts/harness_check_gate.py +111 -0
  259. package/harness/bundles/java/cursor/scripts/harness_deploy.py +179 -4
  260. package/harness/bundles/java/cursor/scripts/harness_ledger.py +269 -3
  261. package/harness/bundles/java/cursor/scripts/harness_preflight.py +72 -382
  262. package/harness/bundles/java/cursor/scripts/harness_profile.py +742 -0
  263. package/harness/bundles/java/cursor/scripts/harness_service.py +99 -2
  264. package/harness/bundles/java/cursor/scripts/harness_state.py +179 -0
  265. package/harness/manifests/general/claude-code.json +44 -28
  266. package/harness/manifests/general/codebuddy.json +44 -28
  267. package/harness/manifests/general/codex.json +44 -28
  268. package/harness/manifests/general/cursor.json +44 -28
  269. package/harness/manifests/java/claude-code.json +48 -32
  270. package/harness/manifests/java/codebuddy.json +48 -32
  271. package/harness/manifests/java/codex.json +48 -32
  272. package/harness/manifests/java/cursor.json +48 -32
  273. package/hunter-workflow-family.json +2 -2
  274. package/package.json +1 -1
@@ -20,7 +20,7 @@ disallowed-tools:
20
20
  - Bash(awk *)
21
21
  - Bash(curl *)
22
22
  ---
23
- <!-- generated by harness_deploy.py; core=781daf01a900c012; overlay=none; agent=claude-code; do not edit -->
23
+ <!-- generated by harness_deploy.py; core=31546eadb30f5fdf; overlay=none; agent=claude-code; do not edit -->
24
24
  # harness-knowledge-query
25
25
 
26
26
  根据用户的新需求或排查问题,从项目本地 `.harness/knowledge` 中检索历史需求、决策、实现、风险和测试证据,并生成 AI 可读的 context pack。
@@ -20,7 +20,7 @@ disallowed-tools:
20
20
  - Bash(awk *)
21
21
  - Bash(curl *)
22
22
  ---
23
- <!-- generated by harness_deploy.py; core=781daf01a900c012; overlay=none; agent=claude-code; do not edit -->
23
+ <!-- generated by harness_deploy.py; core=31546eadb30f5fdf; overlay=none; agent=claude-code; do not edit -->
24
24
  # harness-plan — 需求规划
25
25
 
26
26
  ## Purpose
@@ -99,6 +99,7 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
99
99
  | 阶段 8 | spec/plan/detail/scenarios/worktree.json/logs/events 缺一不可 → ❌FAIL |
100
100
  | Plan 结束 | **禁止**询问执行模式;只提示 `/harness-run` |
101
101
  | 知识查询 | 0.5 失败不得假装已读历史 |
102
+ | state snapshot | 读取 `state-snapshot.json`(`harness_state.py` / state-layout-protocol §state-snapshot.json)了解 project/worktree root、HEAD/base、profile/rules/map/knowledge 指纹;失效由脚本刷新,**不得仅凭缓存跳过代码探索或验证门禁**(design §3.6) |
102
103
  | 协议 | sensitive-info / evidence-based-reporting / state-layout |
103
104
 
104
105
  产出物表、frontmatter、legacy 兼容、结束输出模板 → `reference.md`
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(curl *)
22
22
  - Bash(codegraph *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=781daf01a900c012; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=31546eadb30f5fdf; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-review — 代码审查
26
26
 
27
27
  ## Purpose
@@ -143,6 +143,10 @@ review 结果默认只作参考,不阻塞 submit/archive;报告措辞遵循
143
143
 
144
144
  git diff/log 命令通过 `powershell.exe -Command "..."` 执行;review-report 中如发现明文 token/密码/密钥,必须列入 RED 问题并在报告中以 `<TOKEN_REDACTED>` 等占位符引用;RED/YELLOW/OK 结论必须基于实际 diff 内容,不得凭印象判断。代码探索必须优先使用 CodeGraph MCP 工具(`mcp__codegraph__codegraph_explore`),不允许通过普通 Bash 调 codegraph 命令(已列入 `disallowed-tools`);MCP 不可用时降级为 Grep/Glob + Read,并在执行日志记录降级原因。遵循 `../protocols/powershell-protocol.md` / `sensitive-info-protocol.md` / `evidence-based-reporting-protocol.md`。
145
145
 
146
+ ### 五、state snapshot 与源码重验
147
+
148
+ review 读取 `state-snapshot.json`(`harness_state.py` / state-layout-protocol §state-snapshot.json)的 code/diff 段确定审查范围;snapshot 失效或代码段变化时**必须重新读取实际变更源码**,不得仅凭缓存快照跳过源码审查(design §3.6)。
149
+
146
150
  ## 交互白名单
147
151
 
148
152
  **无** AskUserQuestion(审查全自动)。委派失败 → 主会话审查 + `decision` 事件。
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(curl *)
22
22
  - Bash(codegraph *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=781daf01a900c012; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=31546eadb30f5fdf; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-run — 需求编码
26
26
 
27
27
  ## Purpose
@@ -54,7 +54,7 @@ description: harness-run 的执行检查清单。仅在编码执行时读取。
54
54
  - [ ] 探测 1:测试目录是否存在(如 Java 的 `src/test/java`)
55
55
  - [ ] 探测 2:构建配置/依赖清单是否包含测试依赖(如 Java 的 `pom.xml` 含 `spring-boot-starter-test`/`junit`/`mockito`)
56
56
  - [ ] 探测 3:是否存在已有测试文件(按技术栈测试命名约定,如 Java 的 `*Test.java`/`*Tests.java`)
57
- - [ ] 探测 4:目标模块测试命令是否可运行(按技术栈,如 Java 的 `mvn test -pl <module> -o -q` 试运行)
57
+ - [ ] 探测 4:目标模块测试基础设施是否可用(按技术栈,如 Java 的 `mvn test-compile -pl <module> -o -q` 验证测试可编译,或测试枚举/秒级 smoke;**禁止完整模块测试**,spec §3.3)
58
58
  - [ ] 四项证据收集完毕 → 写结论:✅ 测试基础设施可用 / 🟡 测试基础设施部分可用 / ❌ 测试基础设施不可用
59
59
  - [ ] 如果 ❌ 不可用 → 记录 TDD 降级原因(必须引用具体证据,如"模块 X 无测试目录(如 Java 的 src/test/java)")
60
60
 
@@ -20,7 +20,7 @@ disallowed-tools:
20
20
  - Bash(awk *)
21
21
  - Bash(curl *)
22
22
  ---
23
- <!-- generated by harness_deploy.py; core=781daf01a900c012; overlay=none; agent=claude-code; do not edit -->
23
+ <!-- generated by harness_deploy.py; core=31546eadb30f5fdf; overlay=none; agent=claude-code; do not edit -->
24
24
  # harness-submit — 最终提交(含 worktree 合并)
25
25
 
26
26
  ## Purpose
@@ -72,7 +72,7 @@ disallowed-tools:
72
72
 
73
73
  0. **启动准备** — 确定变更名;读 ledger + 计算 diffHash + post-test 7 类分类;append `phase.start`
74
74
  1. **合并最新代码** — 主目录:`stash` → `pull --rebase` → `stash pop`;**worktree:N/A**(远端同步在合并段主分支完成)
75
- 2. **最终验证** — ledger 复用优先;**提交前最终门禁**:`harness_ledger.py can-reuse --verification unitTestFull --scope module --project . --profile-input unitTestFull --command <build-profile.json buildCommands.unitTestFull>`(`--profile-input unitTestFull` 从 `build-profile.json` `verificationInputs.unitTestFull` 展开依赖闭包文件集,**禁止用仅含 staged 文件的 `--files` 快捷方式**冒充全量闭包;`<command>` 直接读 `buildCommands.unitTestFull`,不复制示例模块名)。不可复用则执行 `buildCommands.unitTestFull` 模块级全量单元测试,成功后用同一文件集、command、`scope=module` 写回 ledger `unitTestFull` 项。增量 `unitTest` 永远不能冒充 `unitTestFull` 门禁。
75
+ 2. **最终验证** — ledger 复用优先;**提交前最终门禁只调 `can-reuse`**(删除与 coverage 冲突的二次全量门禁):`harness_ledger.py can-reuse --verification unitTestFull --scope module --project . --profile-input unitTestFull --command <resolved commands.unitTestFull.command>`。`--command` **按 profile key resolve**:读 `build-profile.json` 的 `commands.unitTestFull.command`(v2),或 `harness_profile.py resolve --project . --key unitTestFull --json` 取 resolved command,**不复制示例模块名**(文档示例只展示 key)。`--profile-input unitTestFull` 从 `verificationInputs.unitTestFull`(v2 `commands.unitTestFull.inputs` 派生)展开依赖闭包,**禁止用仅含 staged 文件的 `--files` 快捷方式**冒充全量闭包。`reuse=true` 不再执行二次全量测试;仅 `reuse=false` 时执行**同一 resolved verification**(profile `unitTestFull` 命令),成功后用同一文件集、command、`scope=module` 写回 ledger `unitTestFull` 项。增量 `unitTest` 永远不能冒充 `unitTestFull` 门禁。
76
76
  3. **.gitignore + 暂存** ⚠️ — 检查 `.harness/` 在 `.gitignore`;**禁止 `git add -A`**
77
77
  4. **提交方式** — 主目录:AskUserQuestion 三选项(commit+push / 仅本地 / 取消);**worktree:固定仅本地 commit**
78
78
  5. **commit-message.txt** ⚠️ — 展示 staged、diff stat、完整中文 message;用户确认
@@ -89,21 +89,21 @@ powershell.exe -NoProfile -Command "<项目测试命令>"
89
89
 
90
90
  **重跑后必须把结果写回 ledger** 的 `compile`/`unitTest` 项,并更新 `diffHash`/`currentHead`。
91
91
 
92
- **提交前最终门禁**(步骤 2 末尾,commit 前强制,`unitTestFull` 模块级全量):
92
+ **提交前最终门禁**(步骤 2 末尾,commit 前强制,`unitTestFull` 模块级全量)——**只调 `can-reuse`,删除二次全量门禁**:
93
93
 
94
94
  ```powershell
95
95
  python <skills-root>/scripts/harness_ledger.py can-reuse `
96
96
  --change-dir ".harness/changes/<change-name>" `
97
97
  --verification unitTestFull --scope module `
98
98
  --project . --profile-input unitTestFull `
99
- --command "<build-profile.json buildCommands.unitTestFull>" --json
99
+ --command "<resolved commands.unitTestFull.command>" --json
100
100
  ```
101
101
 
102
- - `--profile-input unitTestFull` `build-profile.json` 的 `verificationInputs.unitTestFull` 展开**依赖闭包**文件集,**禁止用仅含 staged 业务文件的 `--files` 快捷方式**冒充全量闭包。
103
- - `--command` 必须直接读取当前项目 `build-profile.json` 的 `buildCommands.unitTestFull`,禁止原样复制示例模块名。
102
+ - `--command` **按 profile key resolve**:读 `build-profile.json` 的 `commands.unitTestFull.command`(v2),或 `python <skills-root>/scripts/harness_profile.py resolve --project . --key unitTestFull --json` 取 resolved command。**禁止原样复制示例模块名**(命令按 profile key resolve,文档示例只展示 key)。
103
+ - `--profile-input unitTestFull` `build-profile.json` 的 `verificationInputs.unitTestFull`(v2 由 `commands.unitTestFull.inputs` 派生)展开**依赖闭包**文件集,**禁止用仅含 staged 业务文件的 `--files` 快捷方式**冒充全量闭包。
104
104
  - 增量 `unitTest`(scope=测试类)永远不能冒充 `unitTestFull` 门禁;ledger 只有 `unitTest` 时返回 `insufficient-evidence`。
105
- - `reuse=false` → 执行 `buildCommands.unitTestFull`(模块级全量单元测试),成功后用**同一文件集、command、`scope=module`** 写回 ledger 的 `unitTestFull` 项,再继续步骤 3。
106
- - profile 缺 `verificationInputs.unitTestFull` / glob 无匹配 / 结果为空 → 返回 `insufficient-evidence`(exit 0),仍须执行全量测试但**不允许缓存复用**,直到 profile 正确配置。
105
+ - `reuse=true` → **不再执行二次全量测试**(删除与 coverage 冲突的二次门禁,spec §3.3);仅 `reuse=false`(can-reuse 明确失败)时执行**同一 resolved verification**(profile `unitTestFull` 命令,模块级全量单元测试),成功后用**同一文件集、command、`scope=module`** 写回 ledger 的 `unitTestFull` 项,再继续步骤 3。
106
+ - profile 缺 `commands.unitTestFull` / `verificationInputs.unitTestFull` / glob 无匹配 / 结果为空 → 返回 `insufficient-evidence`(exit 0),仍须执行全量测试但**不允许缓存复用**,直到 profile 正确配置。
107
107
 
108
108
  **编译/测试成功必须有明确证据**:
109
109
  - 构建命令输出必须包含构建成功证据(如 `BUILD SUCCESS` / `Finished` / exit code 0)
@@ -337,6 +337,21 @@ powershell.exe -Command "git -C '<项目路径>' pull --rebase"
337
337
 
338
338
  pull 输出非 `Already up to date.` → 引入他人提交 → M4 必须重跑验证。
339
339
 
340
+ **CRLF 预检**(pull 后强制):旧 working copy 的 `.gitattributes eol=lf` 文件可能是 CRLF(.gitattributes 后加未重新检出),曾导致 `core_content_hash` 跨工作树不一致 → sync 产生 dirty → M5 失败重跑。检测并修复:
341
+
342
+ ```powershell
343
+ # 1. renormalize 暴露 CRLF 漂移(仅规范化行尾,不改内容语义)
344
+ powershell.exe -Command "git -C '<项目路径>' add --renormalize ."
345
+ # 2. 若 git status --porcelain 非空 → working copy 存在 CRLF 漂移
346
+ powershell.exe -Command "git -C '<项目路径>' status --porcelain"
347
+ # 3. 有漂移 → 弃 staging + 强制 LF 重检(worktree 合并段 M2 在主仓库 main,应 clean,安全)
348
+ powershell.exe -Command "git -C '<项目路径>' reset -q; git -C '<项目路径>' checkout -- ."
349
+ # 4. 重新 renormalize 确认 clean(git status --porcelain 应空)
350
+ powershell.exe -Command "git -C '<项目路径>' add --renormalize .; git status --porcelain"
351
+ ```
352
+
353
+ > cluster 1 的 `core_content_hash` 改用 git blob sha 后,CRLF 不再影响 core hash,但 working copy CRLF 仍可能影响 workflow-data 包内容 hash,预检仍有价值。
354
+
340
355
  ### 步骤 M3:合并 worktree 分支
341
356
 
342
357
  ```powershell
@@ -365,6 +380,15 @@ powershell.exe -Command "git -C '<项目路径>' diff --name-only --diff-filter=
365
380
 
366
381
  重跑后写回 ledger 的 `compile`/`unitTest`,更新 `diffHash`/`currentHead`。
367
382
 
383
+ **写 check-ok marker**(npm run check exit 0 后强制):让 pre-push hook 跳过重复 check。三重校验(marker ts<10min + command + commit tree),任一不满足照跑。marker 写入时记录 `git write-tree`,因此验证后创建 commit 不会仅因 HEAD 前移而使缓存失效。
384
+
385
+ ```powershell
386
+ # npm run check exit 0 后立即写 marker(M5 或 REUSED 后均可)
387
+ powershell.exe -Command "python harness/scripts/harness_check_gate.py --write"
388
+ ```
389
+
390
+ > marker 写入 `.harness/check-ok.marker`(gitignored,本地)。push 时 pre-push hook 比较 `HEAD^{tree}` 与 marker 的 `treeHash`,再校验 ts<10min + command;commit tree 未变化即可跳过,任何内容变化都照跑(安全默认)。
391
+
368
392
  ### 步骤 M6:push 主分支
369
393
 
370
394
  ```powershell
@@ -19,7 +19,7 @@ disallowed-tools:
19
19
  - Bash(awk *)
20
20
  - Bash(curl *)
21
21
  ---
22
- <!-- generated by harness_deploy.py; core=781daf01a900c012; overlay=none; agent=claude-code; do not edit -->
22
+ <!-- generated by harness_deploy.py; core=31546eadb30f5fdf; overlay=none; agent=claude-code; do not edit -->
23
23
  # harness-sync — 元数据同步
24
24
 
25
25
  ## Purpose
@@ -22,7 +22,7 @@ disallowed-tools:
22
22
  - Bash(node *)
23
23
  - Bash(codegraph *)
24
24
  ---
25
- <!-- generated by harness_deploy.py; core=781daf01a900c012; overlay=none; agent=claude-code; do not edit -->
25
+ <!-- generated by harness_deploy.py; core=31546eadb30f5fdf; overlay=none; agent=claude-code; do not edit -->
26
26
  # harness-test — 测试执行
27
27
 
28
28
  ## Purpose
@@ -119,7 +119,7 @@ disallowed-tools:
119
119
 
120
120
  ### 四、单元测试复用 + 写入 ledger
121
121
 
122
- Phase 1 前先读 `.harness/changes/<change-name>/evidence/verification-ledger.json`:run 的 unitTest 满足(diffHash 一致 + module/profile 一致 + scope 一致或更严格 + run 后无行为性修改 + run 跑了全量测试)则复用,否则重跑测试命令(按技术栈,如 `mvn test -pl <module>`)。Phase 1/2 完成后必须写回 ledger `unitTest`/`apiTest` 项。详见 `checklist.md`「单元测试复用」、`../protocols/ledger-protocol.md`。
122
+ Phase 1 前先读 `.harness/changes/<change-name>/evidence/verification-ledger.json`:run 的 unitTest 满足(diffHash 一致 + module/profile 一致 + scope 一致或更严格 + run 后无行为性修改 + run 跑了全量测试)则复用,否则按 **profile key resolve** 执行测试命令(`python <skills-root>/scripts/harness_profile.py resolve --project . --key unitTest|unitTestFull --json`,**不复制示例 `-pl` 命令**)。Phase 1/2 完成后必须写回 ledger:执行增量测试类 `unitTest`(scope=incremental);执行 profile 模块全量命令 → 记 `unitTestFull`(scope=module,可供 submit 复用);接口测试 → 记 `apiTest`。详见 `checklist.md`「单元测试复用」、`../protocols/ledger-protocol.md`。
123
123
 
124
124
  ### 五、命令与请求超时治理
125
125
 
@@ -251,7 +251,7 @@ powershell.exe -NoProfile -Command "try { (Invoke-WebRequest -Uri 'http://127.0.
251
251
  - [ ] Phase 1 前读取 `.harness/changes/<change-name>/evidence/verification-ledger.json`
252
252
  - [ ] 判断是否复用 run 的 unitTest:diffHash 一致 + module/profile 一致 + scope 一致或更严格 + run 后无行为性修改 + run 实际跑了全量测试
253
253
  - [ ] 复用 → 跳过重跑,标记"✅ 复用 harness-run 单元测试结果"
254
- - [ ] 不复用 → 重跑测试命令(按技术栈,如 `mvn test -pl <module>`),结果写回 ledger 的 `unitTest` 项
254
+ - [ ] 不复用 → profile key resolve 重跑测试命令(`harness_profile.py resolve --key unitTest`,不复制示例 `-pl` 命令),结果写回 ledger 的 `unitTest` 项
255
255
 
256
256
  ### 批量执行器(强制单次 PowerShell + 执行器绝对路径执行)
257
257
 
@@ -258,3 +258,19 @@ $cred = $resp.data.accessToken
258
258
  **正确做法**:用 `git diff --binary` 生成 patch 并计算 SHA-256,ledger 只认 `sha256:<hash>` 格式。diffHash 不一致时必须重跑相关测试。
259
259
 
260
260
  > diffHash/ledger 复用规则遵循 `../protocols/ledger-protocol.md`;结果证据要求遵循 `../protocols/evidence-based-reporting-protocol.md`。
261
+
262
+ ## BOM-safe JSON / identifier sanitizer / 凭据扫描 (runtime-helpers.mjs)
263
+
264
+ > 变更簇 5 (spec §3.4):Node runtime helper 集中处理 PS5.1 BOM、非法测试标识符、凭据边界三类返工。源码 `scripts/runtime-helpers.mjs`,测试 `scripts/tests/runtime-helpers.test.mjs`(`node --test`)。
265
+
266
+ | 函数 | 用途 | 规避的坑 |
267
+ |------|------|----------|
268
+ | `readJsonUtf8BomSafe(path)` | 读 credential-cache.json / api-test-results.json,容忍 U+FEFF BOM | PS5.1 `Out-File -Encoding utf8` 写入 BOM 导致 `JSON.parse` 失败 |
269
+ | `writeJsonUtf8NoBom(path, value)` | 原子写 (temp+rename),UTF-8 no BOM,LF,2-space 缩进 | 结果文件被 BOM/换行符污染破坏字节稳定;半写入文件被并发读到 |
270
+ | `sanitizeTestIdentifier({name, pattern, maxLength, prefix})` | change-name → 稳定标识(清洗非法字符 + 超长截断 + 原文名短 hash 防碰撞) | 中文/连字符/超长 change-name 生成非法 identifier 触发服务端 400 |
271
+ | `validateRunnerPayload(payload, {identifierPattern})` | Runner 生成前本地校验 payload schema/必填/identifier/重复 id,返回结构化错误码 | 测试脚本错误(缺字段/非法 id)直到请求服务后才暴露,返工成本高 |
272
+ | `findCredentialValues(text)` | 扫描 profile/Markdown/docs 中的凭据明文值(password/token/secret/Authorization/jdbc password),占位符 `<*_REDACTED>` 与 env 引用 `${ENV}`/`$ENV` 不报 | profile/规则文档误含明文凭据被发布 |
273
+
274
+ **Runner 生成前强制**(spec §3.4 point 3):生成 `api-test-runner.mjs` 前用 `validateRunnerPayload` 校验全部场景;`ok=false` → 修复脚本错误,**不得带错请求服务**。场景 id 用 `sanitizeTestIdentifier` 生成(profile v2 `identifier.pattern/maxLength/prefix` 已声明)。
275
+
276
+ **凭据边界**(spec §3.4 point 4):credential 配置只含 env key(如 `${TEST_TOKEN}`)、cache path、角色,不含值。发布前用 `findCredentialValues` 扫 profile/规则/Markdown,命中即 ❌FAIL。详见 `../protocols/sensitive-info-protocol.md` §6。
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env node
2
+ // runtime-helpers.mjs — BOM-safe JSON I/O + test-identifier sanitizer + runner payload validation + credential scan.
3
+ // 变更簇 5 (spec §3.4): BOM-safe Runner, identifier sanitizer, 凭据边界.
4
+ //
5
+ // 设计目标:
6
+ // - readJsonUtf8BomSafe: 容忍 UTF-8 BOM (U+FEFF), credential-cache.json 等文件可能被 PS5.1 写入 BOM
7
+ // - writeJsonUtf8NoBom: 原子写 (temp+rename), UTF-8 no BOM, LF — 结果/报告文件字节稳定
8
+ // - sanitizeTestIdentifier: 按 pattern/maxLength/prefix 生成稳定标识; 超长截断 + 原文名短 hash 防碰撞
9
+ // - validateRunnerPayload: Runner 生成前本地校验 payload schema/必填/identifier, 测试脚本错误不得请求服务后才发现
10
+ // - findCredentialValues: 扫描 profile/Markdown/docs 中的凭据明文值 (sensitive-info-protocol §1)
11
+ //
12
+ // Node ≥18 ESM, stdlib only. 输出 JSON 内容确定性 (不含 Math.random); 仅临时文件名用 randomBytes.
13
+
14
+ import fs from 'node:fs';
15
+ import path from 'node:path';
16
+ import crypto from 'node:crypto';
17
+
18
+ export const BOM = 0xfeff;
19
+ export const DEFAULT_IDENTIFIER_PATTERN = '^[A-Za-z][A-Za-z0-9_-]*$';
20
+ export const DEFAULT_IDENTIFIER_MAX_LENGTH = 64;
21
+ const HASH_LEN = 8;
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // BOM-safe JSON I/O
25
+ // ---------------------------------------------------------------------------
26
+
27
+ /** Strip a single leading UTF-8 BOM (U+FEFF) from text. No-op if absent. */
28
+ export function stripBom(text) {
29
+ return text.codePointAt(0) === BOM ? text.slice(1) : text;
30
+ }
31
+
32
+ /** Read a JSON file, tolerating a leading UTF-8 BOM. Throws on invalid JSON. */
33
+ export function readJsonUtf8BomSafe(filePath) {
34
+ const raw = fs.readFileSync(filePath, 'utf8');
35
+ return JSON.parse(stripBom(raw));
36
+ }
37
+
38
+ /** Atomically write JSON as UTF-8 (no BOM), LF, 2-space indent, trailing newline.
39
+ * Writes to a temp file then renames — readers never see a half-written file. */
40
+ export function writeJsonUtf8NoBom(filePath, value) {
41
+ const json = JSON.stringify(value, null, 2) + '\n';
42
+ const dir = path.dirname(filePath);
43
+ fs.mkdirSync(dir, { recursive: true });
44
+ const tmp = `${filePath}.${process.pid}.${crypto.randomBytes(6).toString('hex')}.tmp`;
45
+ fs.writeFileSync(tmp, json, 'utf8');
46
+ try {
47
+ fs.renameSync(tmp, filePath);
48
+ } catch (err) {
49
+ try {
50
+ fs.unlinkSync(tmp);
51
+ } catch {
52
+ /* best-effort cleanup */
53
+ }
54
+ throw err;
55
+ }
56
+ }
57
+
58
+ // ---------------------------------------------------------------------------
59
+ // sanitizeTestIdentifier
60
+ // ---------------------------------------------------------------------------
61
+
62
+ /**
63
+ * Sanitize a change/test name into a stable identifier matching the default
64
+ * pattern `^[A-Za-z][A-Za-z0-9_-]*$`.
65
+ *
66
+ * - runs of chars outside [A-Za-z0-9_-] → '_'
67
+ * - prepend `prefix_` when prefix given; ensure leading letter (prepend 'T')
68
+ * - if over maxLength: truncate and append a short sha256 hash of the ORIGINAL
69
+ * name, so two near-identical long names that collide after truncation stay
70
+ * distinct (UT-023). Hash is deterministic — no Math.random.
71
+ *
72
+ * @returns {string} identifier matching the default pattern, length ≤ maxLength.
73
+ */
74
+ export function sanitizeTestIdentifier({
75
+ name,
76
+ pattern = DEFAULT_IDENTIFIER_PATTERN,
77
+ maxLength = DEFAULT_IDENTIFIER_MAX_LENGTH,
78
+ prefix = '',
79
+ }) {
80
+ const raw = String(name ?? '');
81
+ let base = prefix ? `${prefix}_` : '';
82
+ base += raw.replace(/[^A-Za-z0-9_-]+/g, '_');
83
+ // leading letter (pattern ^[A-Za-z]); prepend 'T' if first char is _ or digit
84
+ if (!/^[A-Za-z]/.test(base)) base = `T${base}`;
85
+ if (base.length <= maxLength) return base;
86
+ const hash = crypto.createHash('sha256').update(raw, 'utf8').digest('hex').slice(0, HASH_LEN);
87
+ const reserve = HASH_LEN + 1; // '_' + hash
88
+ const cap = Math.max(1, maxLength - reserve);
89
+ let truncated = base.slice(0, cap).replace(/_+$/, '');
90
+ // if truncation removed the leading letter guarantee, restore it
91
+ if (!/^[A-Za-z]/.test(truncated)) truncated = `T${truncated}`;
92
+ return `${truncated}_${hash}`;
93
+ }
94
+
95
+ /** Compile a pattern safely; returns null if invalid. */
96
+ function safeRegex(pattern) {
97
+ try {
98
+ return new RegExp(`^(?:${pattern})$`);
99
+ } catch {
100
+ return null;
101
+ }
102
+ }
103
+
104
+ /** True if id matches pattern. Invalid pattern → false. */
105
+ export function matchesPattern(id, pattern = DEFAULT_IDENTIFIER_PATTERN) {
106
+ const re = safeRegex(pattern);
107
+ return re ? re.test(String(id)) : false;
108
+ }
109
+
110
+ // ---------------------------------------------------------------------------
111
+ // validateRunnerPayload — Runner 生成前本地校验
112
+ // ---------------------------------------------------------------------------
113
+
114
+ const HTTP_METHODS = /^(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)$/i;
115
+
116
+ /**
117
+ * Validate a runner payload (array of API test scenarios) BEFORE generating or
118
+ * executing the runner. Catches script/schema errors locally so they don't
119
+ * surface only after a service request (spec §3.4 point 3).
120
+ *
121
+ * Scenario required fields: id, method, url. id must match identifierPattern
122
+ * and be unique. method must be a known HTTP method.
123
+ *
124
+ * @returns {{ ok: boolean, errors: Array<{code: string, field: string, message: string}> }}
125
+ */
126
+ export function validateRunnerPayload(payload, opts = {}) {
127
+ const errors = [];
128
+ const pattern = opts.identifierPattern || DEFAULT_IDENTIFIER_PATTERN;
129
+ const re = safeRegex(pattern);
130
+
131
+ if (!Array.isArray(payload)) {
132
+ return {
133
+ ok: false,
134
+ errors: [{ code: 'PAYLOAD_NOT_ARRAY', field: 'payload', message: 'payload must be an array of scenarios' }],
135
+ };
136
+ }
137
+ if (payload.length === 0) {
138
+ errors.push({ code: 'PAYLOAD_EMPTY', field: 'payload', message: 'payload has no scenarios' });
139
+ }
140
+
141
+ const seenIds = new Set();
142
+ payload.forEach((scn, i) => {
143
+ const where = `scenarios[${i}]`;
144
+ if (!scn || typeof scn !== 'object' || Array.isArray(scn)) {
145
+ errors.push({ code: 'SCENARIO_NOT_OBJECT', field: where, message: 'scenario must be an object' });
146
+ return;
147
+ }
148
+ for (const f of ['id', 'method', 'url']) {
149
+ if (scn[f] === undefined || scn[f] === null || scn[f] === '') {
150
+ errors.push({ code: 'MISSING_FIELD', field: `${where}.${f}`, message: `required field '${f}' missing or empty` });
151
+ }
152
+ }
153
+ if (scn.id !== undefined && scn.id !== null && scn.id !== '') {
154
+ const idStr = String(scn.id);
155
+ if (re && !re.test(idStr)) {
156
+ errors.push({ code: 'INVALID_IDENTIFIER', field: `${where}.id`, message: `id '${idStr}' does not match pattern ${pattern}` });
157
+ }
158
+ if (seenIds.has(idStr)) {
159
+ errors.push({ code: 'DUPLICATE_ID', field: `${where}.id`, message: `duplicate id '${idStr}'` });
160
+ } else {
161
+ seenIds.add(idStr);
162
+ }
163
+ }
164
+ if (scn.method !== undefined && scn.method !== null && scn.method !== '') {
165
+ if (!HTTP_METHODS.test(String(scn.method))) {
166
+ errors.push({ code: 'INVALID_METHOD', field: `${where}.method`, message: `unknown HTTP method '${scn.method}'` });
167
+ }
168
+ }
169
+ });
170
+
171
+ return { ok: errors.length === 0, errors };
172
+ }
173
+
174
+ // ---------------------------------------------------------------------------
175
+ // findCredentialValues — 凭据明文扫描 (sensitive-info-protocol §1)
176
+ // ---------------------------------------------------------------------------
177
+
178
+ // 值占位符或 env 引用 (不会被当作凭据明文): <*_REDACTED> / ${ENV} / $ENV
179
+ // 前缀匹配 ${ENV (无需闭合 }) — value 正则在 } 处停止, 仍应识别为 env 引用。
180
+ const SAFE_VALUE = /<\w+_REDACTED>|\$\{[A-Z0-9_]+|\$[A-Z][A-Z0-9_]*\b/;
181
+
182
+ const CRED_PATTERNS = [
183
+ // password / passwd / pwd = 或 : 后跟值 (字段名可带 JSON/YAML 引号)
184
+ { code: 'PASSWORD_VALUE', re: /"?password"?\s*[:=]\s*(['"]?)([^'"\s,;)}\n]+)\1/i, group: 2 },
185
+ // token / access_token / api_key / apikey / secret / accessKey / secretAccessKey
186
+ { code: 'SECRET_VALUE', re: /(?:"?(?:access_token|apikey|api_key|secretAccessKey|accessKey|secret|token)"?)\s*[:=]\s*(['"]?)([^'"\s,;)}\n]+)\1/i, group: 2 },
187
+ // Authorization: Bearer <jwt-ish>
188
+ { code: 'AUTH_HEADER', re: /Authorization\s*:\s*Bearer\s+([A-Za-z0-9_.-]{10,})/i, group: 1 },
189
+ // jdbc url with password=
190
+ { code: 'DB_PASSWORD', re: /jdbc:[^\s?]*[?&]password=([^&\s]+)/i, group: 1 },
191
+ ];
192
+
193
+ /**
194
+ * Scan text for credential VALUES per sensitive-info-protocol §1.
195
+ * Placeholders (`<TOKEN_REDACTED>`) and env refs (`${DB_PASSWORD}` / `$DB_PASSWORD`)
196
+ * are NOT flagged — credential config may carry env keys, not values (spec §3.4 point 4).
197
+ *
198
+ * @returns {Array<{ line: number, code: string, snippet: string }>}
199
+ */
200
+ export function findCredentialValues(text) {
201
+ const findings = [];
202
+ const lines = String(text ?? '').split(/\r?\n/);
203
+ lines.forEach((line, idx) => {
204
+ for (const { code, re, group } of CRED_PATTERNS) {
205
+ const m = line.match(re);
206
+ if (!m) continue;
207
+ const value = m[group] || '';
208
+ if (SAFE_VALUE.test(value)) continue; // placeholder / env ref — safe
209
+ // Redact the captured credential value in the snippet so reports/logs
210
+ // never leak it; field name + line number remain for locating the finding.
211
+ const snippet = (value ? line.replace(value, '<REDACTED>') : line).trim().slice(0, 80);
212
+ findings.push({ line: idx + 1, code, snippet });
213
+ }
214
+ });
215
+ return findings;
216
+ }
@@ -139,7 +139,7 @@ PowerShell HTML renderer 仅作 legacy fallback。该脚本以 UTF-8 with BOM
139
139
 
140
140
  **Python fallback(`harness_archive.py` 内置)**:Node 不可用/超时/exit 非 0/未产出文件时,`harness_archive.py render_final_summary` 自动降级为内置 Python fallback(`render_fallback_html`),渲染含 changeName、finalStatus、`reportPipeline.commands`(command/exitCode)、`verification`(unitTests/apiTests/dbCompatibility)、changedFiles、archiveManifest、knownRisks、manualActions、maintenanceNotes 的确定性 HTML;USER_SKIPPED/BLOCKED_BY_DBA/失败状态可见,所有动态值 HTML 转义。返回结构统一为 `{ok, renderer: node|python-fallback|none, fallbackReason, out_path}`。Node 与 Python fallback **都失败**(`renderer=none, ok=false`)时,finalize 立即恢复原 change 目录并 exit 非 0,**绝不归档无 final-summary.html 的变更**。
141
141
 
142
- 渲染后必须运行 report validatevalidate error 存在时,archive 不得删除原 changes 目录。**缺 final-summary.html 恒为 validate error**(不再有"没有 HTML 但只 warning"的分支)。
142
+ `validate` 是 `harness_archive.py finalize` 的内嵌同进程步骤(不存在独立 `report validate` CLI);validate error 存在时,finalize 恢复原 changes 目录并 exit 非 0,绝不删除原 changes 目录。**缺 final-summary.html 恒为 validate error**(不再有"没有 HTML 但只 warning"的分支)。
143
143
 
144
144
  ## 归档与知识维护解耦(§8)
145
145
 
@@ -182,7 +182,7 @@ verification-ledger 把每次验证(compile / unit test / api test / package
182
182
  ```text
183
183
  harness_ledger.py can-reuse --verification unitTestFull --scope module \
184
184
  --project . --profile-input unitTestFull \
185
- --command "<build-profile.json buildCommands.unitTestFull>" --json
185
+ --command "<resolved build-profile.json commands.unitTestFull.command>" --json
186
186
  ```
187
187
 
188
188
  `build-profile.json` 新增 `verificationInputs.unitTestFull`(glob 列表,相对 project 展开,只保留 project 内文件、去重排序):
@@ -201,7 +201,17 @@ profile key 缺失 / glob 无匹配 / 结果为空 → `insufficient-evidence`
201
201
 
202
202
  必须基于真实 diff 计算 SHA-256,且**必须是 commit-invariant 的**——覆盖本变更集相对 `baseCommit` 的全部内容变更(已提交 + 未提交 + 未跟踪),使 checkpoint commit 前后指纹一致,保证 run→test 复用链不断。
203
203
 
204
- `<baseCommit>` 从 ledger 读取(harness-plan 阶段写入);缺失时用 `git merge-base HEAD <默认分支>` 兜底。推荐命令:
204
+ `<baseCommit>` 从 ledger 读取(harness-plan 阶段写入);缺失时用 `git merge-base HEAD <默认分支>` 兜底。
205
+
206
+ **canonical 命令(cluster 2 起脚本化,推荐)**:
207
+
208
+ ```text
209
+ harness_ledger.py diff-hash --repo <projectRoot> --base <baseCommit> --json
210
+ ```
211
+
212
+ `diff-hash` 用 subprocess 直接捕获 Git bytes,基于**内容变更集**计算 SHA-256:working tree 相对 base 的所有变化文件 + 未跟踪文件,按 repo-relative path 排序、长度 framing(`path-len | path | exists | content-len | content`),独立于 shell/控制台编码/BOM/系统换行,且 **commit-invariant**(checkpoint commit 不改 working tree → 指纹不变,UT-011)。算法版本 `content-changeset-1`,输出 `diffHash`/`algorithmVersion`/`fileCount`/`base`/`head`。
213
+
214
+ > 旧 v1 PowerShell 拼接命令(下方)已废弃:依赖文本编码,且未跟踪文件提交后表示从 framed-content 切换为 diff-format 会破坏 commit-invariance。仅作历史参考。
205
215
 
206
216
  ```powershell
207
217
  powershell.exe -NoProfile -Command "$base = '<baseCommit>'; $patch = '.harness/changes/<change>/runtime/current-diff.patch'; & { git diff $base HEAD --binary; git diff --binary; git ls-files --others --exclude-standard | ForEach-Object { Get-Content -Raw -LiteralPath $_ } } | Out-File -Encoding utf8 $patch; (Get-FileHash $patch -Algorithm SHA256).Hash"
@@ -268,3 +278,46 @@ ledger 的 `status` 与 final-summary 展示状态对应:
268
278
  | postTestClassification=NON_BEHAVIORAL_CLEANUP | 小清理 | 🧹NON_BEHAVIORAL_CLEANUP |
269
279
 
270
280
  **强制规则**:任何阶段若复用了前一阶段结果,final-summary 必须显示 `🔁REUSED`,**不得伪装成重新执行**。
281
+
282
+ ## 九、Ledger v2(cluster 2)
283
+
284
+ `harness_ledger.py` v2 引入确定性 `diff-hash`(§五)、v2 entry 字段、coverage lattice、`package` verification 与结构化错误码。Skill 只调用 `record`/`can-reuse`/`diff-hash`,不再手工判断或解释自由文本。
285
+
286
+ ### 9.1 v2 entry 字段
287
+
288
+ `record` 自动写入:
289
+
290
+ | 字段 | 含义 |
291
+ |------|------|
292
+ | `algorithmVersion` | 固定 `harness-ledger-2`;缺失即 v1 entry |
293
+ | `coverage` | 覆盖层级 `incremental`/`module`/`module-am`/`full`,由 verification+scope 派生或 `--coverage` 显式指定 |
294
+ | `toolchainHash`/`profileHash`/`environmentHash` | 可选;`record --toolchain-hash` 等写入,`can-reuse --toolchain-hash` 等比对(UT-017) |
295
+
296
+ ### 9.2 coverage lattice
297
+
298
+ `COVERAGE_RANK = {incremental:0, module:1, module-am:2, full:3}`。各 verification 最低要求:`unitTest`=0、`unitTestFull`/`compile`/`apiTest`=1、`install`/`package`=2。entry.coverage rank < 要求 → `insufficient-evidence`(code `COVERAGE_INSUFFICIENT`),**禁止增量证据提升为全量门禁**(UT-015/API-005)。
299
+
300
+ ### 9.3 package verification
301
+
302
+ `package` 加入 `VERIFICATIONS`。`record --verification package` 额外记录 `deployArtifact`/`sha256`/`testsExecuted`/`testsReusedFrom`。API-006/007 的 package 生命周期复用编排由 cluster 4 负责,cluster 2 仅提供 record/can-reuse 能力(UT-018)。
303
+
304
+ ### 9.4 结构化错误码
305
+
306
+ `can-reuse` 每个非 reuse 结果携带 `code` 字段,Skill 据 `code` 决策,不解析 `detail` 自由文本:
307
+
308
+ | code | reason | 含义 |
309
+ |------|--------|------|
310
+ | `LEDGER_MISSING`/`VALIDATIONS_MISSING`/`VALIDATION_MISSING` | insufficient-evidence | ledger/条目缺失 |
311
+ | `MISSING_V2_FIELDS` | insufficient-evidence | v1 entry 缺 algorithmVersion/coverage,**一次性保守失效**(COM-002),重记录 v2 后可复用 |
312
+ | `MISSING_FIELDS` | insufficient-evidence | 缺 status/evidence/inputsHash/scope 等基础字段 |
313
+ | `COVERAGE_INSUFFICIENT` | insufficient-evidence | coverage rank 不足 |
314
+ | `SCOPE_INSUFFICIENT` | insufficient-evidence | unitTest scope 不覆盖请求 |
315
+ | `INPUT_FILE_MISSING` | insufficient-evidence | 当前文件集读取失败 |
316
+ | `COMMAND_CHANGED` | rerun | 命令变化 |
317
+ | `TOOLCHAIN_CHANGED`/`PROFILE_CHANGED`/`ENVIRONMENT_CHANGED` | rerun | 对应 hash 变化(UT-017) |
318
+ | `INPUTS_HASH_CHANGED` | rerun | inputsHash 变化 |
319
+ | `REUSED` | reuse | 复用 |
320
+
321
+ ### 9.5 v1→v2 兼容
322
+
323
+ v1 ledger 可读;entry 缺 v2 字段时 `can-reuse` 返回 `MISSING_V2_FIELDS`(insufficient-evidence),**不静默升级证据**。重新 `record`(自动补 v2 字段)后恢复复用。diffHash 算法升级后旧 ledger 一次性失效,不危险复用。
@@ -24,14 +24,7 @@ python <skills-root>/scripts/harness_archive.py replay --archive-dir ".harness/a
24
24
  python <skills-root>/scripts/harness_events.py append --change-dir ".harness/changes/<change-name>" --phase "<phase>" --type <type> [--note "..."]
25
25
  ```
26
26
 
27
- 若项目安装 Hunter-Harness CLIcollect/validate 亦可使用(与 finalize 内嵌步骤等价):
28
-
29
- ```powershell
30
- powershell.exe -NoProfile -Command "npx hunter-harness report collect --change-id '<change-name>' --json"
31
- powershell.exe -NoProfile -Command "npx hunter-harness report validate --change-id '<change-name>' --json"
32
- ```
33
-
34
- CLI 不可用时,agent 仍必须按本协议生成等价的 `summary-data.json` 并执行一致性校验,不得退回手写汇总。
27
+ 归档报告流水线只有两个入口,均由 `harness_archive.py` 提供:`collect`/`render`/`validate` 是 `finalize` 的内嵌同进程步骤,**不再作为独立 CLI 暴露**(不存在 `report collect`/`report validate` 子命令)。`summary-data.json` 只能由 `finalize`(归档时)或 `replay`(回放时)生成;**禁止 agent 临场手写或拼装等价的 `summary-data.json`**。`harness_archive.py` 不可用时归档失败退出,不得退回手写汇总。
35
28
 
36
29
  ## events.ndjson
37
30
 
@@ -90,3 +90,16 @@ spring:
90
90
  - API 测试报告的持久化记录中
91
91
 
92
92
  > 对于 API 测试中获取的 token,在测试执行过程中可临时使用(如 Playwright 请求),但测试报告中必须用 `<TOKEN_REDACTED>` 替换。
93
+
94
+ ## 6. profile / 规则 / Markdown 凭据扫描
95
+
96
+ profile `build-profile.json`、规则文档、Skill Markdown **不得包含凭据明文值**(spec §3.4 凭据边界:配置只含 env key、cache path、角色,不含值)。发布前用 `harness-test/scripts/runtime-helpers.mjs` 的 `findCredentialValues(text)` 扫描:
97
+
98
+ - 命中 `password/token/secret/accessKey/Authorization: Bearer/jdbc password=` 等明文值 → ❌FAIL,必须改为占位符 `<*_REDACTED>` 或 env 引用 `${ENV}` / `$ENV`。
99
+ - 占位符 `<TOKEN_REDACTED>` 与 env 引用 `${TEST_TOKEN}` / `$DB_PASSWORD` 不报(credential 配置允许 env key)。
100
+
101
+ ```js
102
+ import { findCredentialValues } from '<skills-root>/harness-test/scripts/runtime-helpers.mjs';
103
+ const findings = findCredentialValues(fs.readFileSync('build-profile.json', 'utf8'));
104
+ if (findings.length > 0) { /* ❌FAIL: 列出 line/code/snippet,改为 env key 或占位符 */ }
105
+ ```
@@ -98,6 +98,30 @@ description: harness .harness 状态目录分层协议。用于减少根目录
98
98
 
99
99
  后续阶段应优先从该文件读取路径,避免手拼 change-name 导致路径拼写错误。
100
100
 
101
+ ## state-snapshot.json(cluster 3 §3.6)
102
+
103
+ `meta/state-snapshot.json`(由 `harness_state.py` 写入)集中记录 project/worktree root、HEAD/base、profile/rules/map/knowledge/diff 各段指纹与相关文件。plan/run/test/review/submit 读取该快照;失效时由脚本刷新,**不得仅凭缓存跳过代码或验证门禁**。
104
+
105
+ schema:
106
+
107
+ ```json
108
+ {
109
+ "schemaVersion": 1,
110
+ "generatedAt": "<iso>",
111
+ "changeName": "<change-name>",
112
+ "project": {"root": "<abs>"},
113
+ "worktree": {"root": "<abs>"},
114
+ "git": {"base": "<sha>", "head": "<sha>"},
115
+ "segments": {
116
+ "<segment>": {"fingerprint": "sha256:...", "files": ["..."], "capturedAt": "<iso>"}
117
+ }
118
+ }
119
+ ```
120
+
121
+ 各段独立失效:`is_segment_stale(snapshot, segment, current_fingerprint)` 比较单段指纹;段不存在 → stale(需采集)。`refresh_segments(..., segments=["profile"])` 只重采受影响段,其他段保留原 capturedAt/fingerprint(缓存失效只重采受影响段)。
122
+
123
+ segment 的文件集由调用方(各 skill)决定:`capture_snapshot(..., segment_files={"profile": [...], "rules": [...]})`。snapshot 只负责采集 + 比对 + 失效,不负责发现文件。git 段记录 base/head;diff 段指纹由调用方按需用 `harness_ledger.compute_diff_hash` 采集后填入 segment_files。
124
+
101
125
  ## archive 结构
102
126
 
103
127
  archive 后保持同样分层结构,不把 `.bak`、脚本、manifest、HTML 全部放在 archive 根目录。