@hunter-harness/workflow-harness 0.2.84 → 0.2.86

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 (226) 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 +11 -4
  3. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
  4. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  5. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  6. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +3 -2
  7. package/harness/bundles/general/claude-code/harness-plan/checklist.md +18 -79
  8. package/harness/bundles/general/claude-code/harness-plan/protocols.md +3 -1
  9. package/harness/bundles/general/claude-code/harness-plan/reference.md +37 -8
  10. package/harness/bundles/general/claude-code/harness-pull/SKILL.md +1 -1
  11. package/harness/bundles/general/claude-code/harness-push/SKILL.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
  13. package/harness/bundles/general/claude-code/harness-run/SKILL.md +6 -4
  14. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
  15. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  16. package/harness/bundles/general/claude-code/harness-test/SKILL.md +1 -1
  17. package/harness/bundles/general/claude-code/scripts/harness_archive.py +58 -25
  18. package/harness/bundles/general/claude-code/scripts/harness_change.py +25 -7
  19. package/harness/bundles/general/claude-code/scripts/harness_context.py +62 -19
  20. package/harness/bundles/general/claude-code/scripts/harness_fixback.py +4 -0
  21. package/harness/bundles/general/claude-code/scripts/harness_gate.py +208 -72
  22. package/harness/bundles/general/claude-code/scripts/harness_ledger.py +43 -0
  23. package/harness/bundles/general/claude-code/scripts/harness_paths.py +60 -0
  24. package/harness/bundles/general/claude-code/scripts/harness_phase.py +24 -6
  25. package/harness/bundles/general/claude-code/scripts/harness_plan_finalize.py +124 -1
  26. package/harness/bundles/general/claude-code/scripts/harness_review.py +25 -4
  27. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  28. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +11 -4
  29. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  30. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  31. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  32. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +3 -2
  33. package/harness/bundles/general/codebuddy/harness-plan/checklist.md +18 -79
  34. package/harness/bundles/general/codebuddy/harness-plan/protocols.md +3 -1
  35. package/harness/bundles/general/codebuddy/harness-plan/reference.md +37 -8
  36. package/harness/bundles/general/codebuddy/harness-pull/SKILL.md +1 -1
  37. package/harness/bundles/general/codebuddy/harness-push/SKILL.md +1 -1
  38. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
  39. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +6 -4
  40. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
  41. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  42. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
  43. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +58 -25
  44. package/harness/bundles/general/codebuddy/scripts/harness_change.py +25 -7
  45. package/harness/bundles/general/codebuddy/scripts/harness_context.py +62 -19
  46. package/harness/bundles/general/codebuddy/scripts/harness_fixback.py +4 -0
  47. package/harness/bundles/general/codebuddy/scripts/harness_gate.py +208 -72
  48. package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +43 -0
  49. package/harness/bundles/general/codebuddy/scripts/harness_paths.py +60 -0
  50. package/harness/bundles/general/codebuddy/scripts/harness_phase.py +24 -6
  51. package/harness/bundles/general/codebuddy/scripts/harness_plan_finalize.py +124 -1
  52. package/harness/bundles/general/codebuddy/scripts/harness_review.py +25 -4
  53. package/harness/bundles/general/codex/.harness-build.json +1 -1
  54. package/harness/bundles/general/codex/harness-archive/SKILL.md +11 -4
  55. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  56. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  57. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  58. package/harness/bundles/general/codex/harness-plan/SKILL.md +3 -2
  59. package/harness/bundles/general/codex/harness-plan/checklist.md +18 -79
  60. package/harness/bundles/general/codex/harness-plan/protocols.md +3 -1
  61. package/harness/bundles/general/codex/harness-plan/reference.md +37 -8
  62. package/harness/bundles/general/codex/harness-pull/SKILL.md +1 -1
  63. package/harness/bundles/general/codex/harness-push/SKILL.md +1 -1
  64. package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
  65. package/harness/bundles/general/codex/harness-run/SKILL.md +6 -4
  66. package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
  67. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  68. package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
  69. package/harness/bundles/general/codex/scripts/harness_archive.py +58 -25
  70. package/harness/bundles/general/codex/scripts/harness_change.py +25 -7
  71. package/harness/bundles/general/codex/scripts/harness_context.py +62 -19
  72. package/harness/bundles/general/codex/scripts/harness_fixback.py +4 -0
  73. package/harness/bundles/general/codex/scripts/harness_gate.py +208 -72
  74. package/harness/bundles/general/codex/scripts/harness_ledger.py +43 -0
  75. package/harness/bundles/general/codex/scripts/harness_paths.py +60 -0
  76. package/harness/bundles/general/codex/scripts/harness_phase.py +24 -6
  77. package/harness/bundles/general/codex/scripts/harness_plan_finalize.py +124 -1
  78. package/harness/bundles/general/codex/scripts/harness_review.py +25 -4
  79. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  80. package/harness/bundles/general/cursor/harness-archive/SKILL.md +11 -4
  81. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  82. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  83. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  84. package/harness/bundles/general/cursor/harness-plan/SKILL.md +3 -2
  85. package/harness/bundles/general/cursor/harness-plan/checklist.md +18 -79
  86. package/harness/bundles/general/cursor/harness-plan/protocols.md +3 -1
  87. package/harness/bundles/general/cursor/harness-plan/reference.md +37 -8
  88. package/harness/bundles/general/cursor/harness-pull/SKILL.md +1 -1
  89. package/harness/bundles/general/cursor/harness-push/SKILL.md +1 -1
  90. package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
  91. package/harness/bundles/general/cursor/harness-run/SKILL.md +6 -4
  92. package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
  93. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  94. package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
  95. package/harness/bundles/general/cursor/scripts/harness_archive.py +58 -25
  96. package/harness/bundles/general/cursor/scripts/harness_change.py +25 -7
  97. package/harness/bundles/general/cursor/scripts/harness_context.py +62 -19
  98. package/harness/bundles/general/cursor/scripts/harness_fixback.py +4 -0
  99. package/harness/bundles/general/cursor/scripts/harness_gate.py +208 -72
  100. package/harness/bundles/general/cursor/scripts/harness_ledger.py +43 -0
  101. package/harness/bundles/general/cursor/scripts/harness_paths.py +60 -0
  102. package/harness/bundles/general/cursor/scripts/harness_phase.py +24 -6
  103. package/harness/bundles/general/cursor/scripts/harness_plan_finalize.py +124 -1
  104. package/harness/bundles/general/cursor/scripts/harness_review.py +25 -4
  105. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  106. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  107. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +11 -4
  108. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  109. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  110. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  111. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  112. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +3 -2
  113. package/harness/bundles/java/claude-code/harness-plan/checklist.md +18 -79
  114. package/harness/bundles/java/claude-code/harness-plan/protocols.md +3 -1
  115. package/harness/bundles/java/claude-code/harness-plan/reference.md +37 -8
  116. package/harness/bundles/java/claude-code/harness-pull/SKILL.md +1 -1
  117. package/harness/bundles/java/claude-code/harness-push/SKILL.md +1 -1
  118. package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
  119. package/harness/bundles/java/claude-code/harness-run/SKILL.md +6 -4
  120. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
  121. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  122. package/harness/bundles/java/claude-code/harness-test/SKILL.md +1 -1
  123. package/harness/bundles/java/claude-code/scripts/harness_archive.py +58 -25
  124. package/harness/bundles/java/claude-code/scripts/harness_change.py +25 -7
  125. package/harness/bundles/java/claude-code/scripts/harness_context.py +62 -19
  126. package/harness/bundles/java/claude-code/scripts/harness_fixback.py +4 -0
  127. package/harness/bundles/java/claude-code/scripts/harness_gate.py +208 -72
  128. package/harness/bundles/java/claude-code/scripts/harness_ledger.py +43 -0
  129. package/harness/bundles/java/claude-code/scripts/harness_paths.py +60 -0
  130. package/harness/bundles/java/claude-code/scripts/harness_phase.py +24 -6
  131. package/harness/bundles/java/claude-code/scripts/harness_plan_finalize.py +124 -1
  132. package/harness/bundles/java/claude-code/scripts/harness_review.py +25 -4
  133. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  134. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  135. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +11 -4
  136. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  137. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  138. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  139. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  140. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +3 -2
  141. package/harness/bundles/java/codebuddy/harness-plan/checklist.md +18 -79
  142. package/harness/bundles/java/codebuddy/harness-plan/protocols.md +3 -1
  143. package/harness/bundles/java/codebuddy/harness-plan/reference.md +37 -8
  144. package/harness/bundles/java/codebuddy/harness-pull/SKILL.md +1 -1
  145. package/harness/bundles/java/codebuddy/harness-push/SKILL.md +1 -1
  146. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
  147. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +6 -4
  148. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
  149. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  150. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
  151. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +58 -25
  152. package/harness/bundles/java/codebuddy/scripts/harness_change.py +25 -7
  153. package/harness/bundles/java/codebuddy/scripts/harness_context.py +62 -19
  154. package/harness/bundles/java/codebuddy/scripts/harness_fixback.py +4 -0
  155. package/harness/bundles/java/codebuddy/scripts/harness_gate.py +208 -72
  156. package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +43 -0
  157. package/harness/bundles/java/codebuddy/scripts/harness_paths.py +60 -0
  158. package/harness/bundles/java/codebuddy/scripts/harness_phase.py +24 -6
  159. package/harness/bundles/java/codebuddy/scripts/harness_plan_finalize.py +124 -1
  160. package/harness/bundles/java/codebuddy/scripts/harness_review.py +25 -4
  161. package/harness/bundles/java/codex/.harness-build.json +1 -1
  162. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  163. package/harness/bundles/java/codex/harness-archive/SKILL.md +11 -4
  164. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  165. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  166. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  167. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  168. package/harness/bundles/java/codex/harness-plan/SKILL.md +3 -2
  169. package/harness/bundles/java/codex/harness-plan/checklist.md +18 -79
  170. package/harness/bundles/java/codex/harness-plan/protocols.md +3 -1
  171. package/harness/bundles/java/codex/harness-plan/reference.md +37 -8
  172. package/harness/bundles/java/codex/harness-pull/SKILL.md +1 -1
  173. package/harness/bundles/java/codex/harness-push/SKILL.md +1 -1
  174. package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
  175. package/harness/bundles/java/codex/harness-run/SKILL.md +6 -4
  176. package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
  177. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  178. package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
  179. package/harness/bundles/java/codex/scripts/harness_archive.py +58 -25
  180. package/harness/bundles/java/codex/scripts/harness_change.py +25 -7
  181. package/harness/bundles/java/codex/scripts/harness_context.py +62 -19
  182. package/harness/bundles/java/codex/scripts/harness_fixback.py +4 -0
  183. package/harness/bundles/java/codex/scripts/harness_gate.py +208 -72
  184. package/harness/bundles/java/codex/scripts/harness_ledger.py +43 -0
  185. package/harness/bundles/java/codex/scripts/harness_paths.py +60 -0
  186. package/harness/bundles/java/codex/scripts/harness_phase.py +24 -6
  187. package/harness/bundles/java/codex/scripts/harness_plan_finalize.py +124 -1
  188. package/harness/bundles/java/codex/scripts/harness_review.py +25 -4
  189. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  190. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  191. package/harness/bundles/java/cursor/harness-archive/SKILL.md +11 -4
  192. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  193. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  194. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  195. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  196. package/harness/bundles/java/cursor/harness-plan/SKILL.md +3 -2
  197. package/harness/bundles/java/cursor/harness-plan/checklist.md +18 -79
  198. package/harness/bundles/java/cursor/harness-plan/protocols.md +3 -1
  199. package/harness/bundles/java/cursor/harness-plan/reference.md +37 -8
  200. package/harness/bundles/java/cursor/harness-pull/SKILL.md +1 -1
  201. package/harness/bundles/java/cursor/harness-push/SKILL.md +1 -1
  202. package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
  203. package/harness/bundles/java/cursor/harness-run/SKILL.md +6 -4
  204. package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
  205. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  206. package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
  207. package/harness/bundles/java/cursor/scripts/harness_archive.py +58 -25
  208. package/harness/bundles/java/cursor/scripts/harness_change.py +25 -7
  209. package/harness/bundles/java/cursor/scripts/harness_context.py +62 -19
  210. package/harness/bundles/java/cursor/scripts/harness_fixback.py +4 -0
  211. package/harness/bundles/java/cursor/scripts/harness_gate.py +208 -72
  212. package/harness/bundles/java/cursor/scripts/harness_ledger.py +43 -0
  213. package/harness/bundles/java/cursor/scripts/harness_paths.py +60 -0
  214. package/harness/bundles/java/cursor/scripts/harness_phase.py +24 -6
  215. package/harness/bundles/java/cursor/scripts/harness_plan_finalize.py +124 -1
  216. package/harness/bundles/java/cursor/scripts/harness_review.py +25 -4
  217. package/harness/manifests/general/claude-code.json +27 -27
  218. package/harness/manifests/general/codebuddy.json +27 -27
  219. package/harness/manifests/general/codex.json +27 -27
  220. package/harness/manifests/general/cursor.json +27 -27
  221. package/harness/manifests/java/claude-code.json +29 -29
  222. package/harness/manifests/java/codebuddy.json +29 -29
  223. package/harness/manifests/java/codex.json +29 -29
  224. package/harness/manifests/java/cursor.json +29 -29
  225. package/hunter-workflow-family.json +4 -4
  226. package/package.json +1 -1
@@ -261,6 +261,127 @@ def scenario_manifest_schema_version(scenarios: list[dict[str, Any]]) -> int:
261
261
  return 1
262
262
 
263
263
 
264
+ # v2 场景键 → 门禁与 ledger 消费的 legacy 键。可执行三元是可选的:缺了只是把
265
+ # manifest 降到 schemaVersion 1(绑不上结构化执行收据),不算缺口。
266
+ _V2_SCENARIO_FIELD_MAP = (
267
+ ("scenario_id", "id"),
268
+ ("priority", "priority"),
269
+ ("required_evidence_kind", "requiredEvidenceKind"),
270
+ ("owner_phase", "ownerPhase"),
271
+ )
272
+ _V2_SCENARIO_OPTIONAL_FIELD_MAP = (
273
+ ("executable_test_id", "executableTestId"),
274
+ ("test_file", "testFile"),
275
+ ("test_title", "testTitle"),
276
+ )
277
+ V2_MANIFEST_UNSUPPORTED = "SCENARIO_MANIFEST_V2_UNSUPPORTED"
278
+
279
+
280
+ def is_v2_scenario_manifest(manifest: Any) -> bool:
281
+ """v2 plan finalize 派生的 scenario_manifest artifact 包装体。
282
+
283
+ 它没有顶层 schemaVersion,场景字段全在 content.scenarios 下且改了名。
284
+ """
285
+ return (
286
+ isinstance(manifest, dict)
287
+ and manifest.get("artifact_type") == "scenario_manifest"
288
+ )
289
+
290
+
291
+ def unpack_v2_scenario_manifest(manifest: Any) -> dict[str, Any] | None:
292
+ """v2 artifact 包装体 → 消费端的 legacy 形状;字段不齐时 fail-closed。
293
+
294
+ 返回 None 表示"这不是 v2 包装体",调用方按 legacy 原样处理。否则返回
295
+ ``{"ok": True, "manifest": {...}}``(已是 legacy 形状,后续判定逻辑对
296
+ v2 与 legacy 完全一致)或 ``{"ok": False, "code": V2_MANIFEST_UNSUPPORTED}``。
297
+
298
+ 这个函数住在 finalizer 里,是因为 legacy manifest 的 schema 本来就由本模块
299
+ 定义(``scenario_manifest_schema_version`` / ``PRIORITY_EVIDENCE_KIND``)。
300
+ 门禁与 ledger 都 import 它,两边不会各推一套解包规则。
301
+
302
+ 为什么必须逐场景校验、不能取键的并集:并集只要有**一条**场景带了
303
+ priority 就算"present",其余缺 priority 的场景会静默落进非必需集,
304
+ ``required_ids`` 随之缩水——那正是把证据门禁悄悄关掉的老路子。
305
+ """
306
+ if not is_v2_scenario_manifest(manifest):
307
+ return None
308
+ content = manifest.get("content")
309
+ raw = content.get("scenarios") if isinstance(content, dict) else None
310
+ if not isinstance(raw, list):
311
+ return {
312
+ "ok": False,
313
+ "code": V2_MANIFEST_UNSUPPORTED,
314
+ "message": "v2 scenario-manifest 的 content.scenarios 必须是数组",
315
+ "missingFields": [legacy for _, legacy in _V2_SCENARIO_FIELD_MAP],
316
+ "artifactType": "scenario_manifest",
317
+ }
318
+ scenarios: list[dict[str, Any]] = []
319
+ missing: set[str] = set()
320
+ for item in raw:
321
+ if not isinstance(item, dict):
322
+ missing.update(legacy for _, legacy in _V2_SCENARIO_FIELD_MAP)
323
+ continue
324
+ mapped: dict[str, Any] = {}
325
+ for source, legacy in _V2_SCENARIO_FIELD_MAP:
326
+ value = item.get(source)
327
+ if not str(value or "").strip():
328
+ missing.add(legacy)
329
+ continue
330
+ mapped[legacy] = value
331
+ for source, legacy in _V2_SCENARIO_OPTIONAL_FIELD_MAP:
332
+ value = item.get(source)
333
+ if str(value or "").strip():
334
+ mapped[legacy] = value
335
+ scenarios.append(mapped)
336
+ if missing:
337
+ return {
338
+ "ok": False,
339
+ "code": V2_MANIFEST_UNSUPPORTED,
340
+ "message": (
341
+ "meta/scenario-manifest.json 是 v2 plan artifact 包装体,"
342
+ "部分场景缺少消费端需要的字段;请在规划阶段补齐后重新发布,"
343
+ "不要手改派生产物"
344
+ ),
345
+ "missingFields": sorted(missing),
346
+ "artifactType": "scenario_manifest",
347
+ }
348
+ return {
349
+ "ok": True,
350
+ "manifest": {
351
+ # 与 legacy 同一条规则判版本,不另立一套。
352
+ "schemaVersion": scenario_manifest_schema_version(scenarios),
353
+ "scenarios": scenarios,
354
+ },
355
+ }
356
+
357
+
358
+ def unpack_v2_implementation_checkpoints(document: Any) -> dict[str, Any] | None:
359
+ """v2 的 implementation_checkpoints artifact 包装体 → 门禁消费的形状。
360
+
361
+ 返回 None 表示"这不是 v2 包装体",调用方按原样处理。
362
+
363
+ v2 的 content 是 ``{tasks, foundation_gate}``,而 ``checkpoint_status`` 找的是
364
+ ``checkpoints: [{id, status}]``——找不到就返回 "missing",``foundation_gate_blocks``
365
+ 随即放行。也就是说 foundation-gate 对**所有 v2 计划**是静默关闭的。信息本身是够
366
+ 的(``foundation_gate`` 就是那个状态),只是形状不同,所以这里解包而不是改文件名
367
+ ——与 scenario-manifest 同一模式。
368
+ """
369
+ if (
370
+ not isinstance(document, dict)
371
+ or document.get("artifact_type") != "implementation_checkpoints"
372
+ ):
373
+ return None
374
+ content = document.get("content")
375
+ content = content if isinstance(content, dict) else {}
376
+ status = str(content.get("foundation_gate") or "").strip() or "pending"
377
+ tasks = content.get("tasks")
378
+ return {
379
+ "schemaVersion": 1,
380
+ "checkpoints": [{"id": "foundation-gate", "status": status, "blocking": True}],
381
+ "tasks": tasks if isinstance(tasks, list) else [],
382
+ }
383
+
384
+
264
385
  def parse_plan_tasks(plan_path: Path) -> list[dict[str, str]]:
265
386
  """C8: parse plan.md task table rows, extracting optional ownerPhase/implementationDoneWhen/verificationPhase columns.
266
387
 
@@ -877,7 +998,9 @@ def _verify_plan_v2(change_dir: Path) -> dict[str, Any] | None:
877
998
  f"plans/{change_dir.name}-plan.md",
878
999
  f"plans/{change_dir.name}-implementation-detail.md",
879
1000
  f"plans/{change_dir.name}-test-scenarios.md",
880
- "meta/gate-policy.json",
1001
+ # v2 发布的是派生视图 meta/plan-profile.json,不是 Python classify 写的
1002
+ # meta/gate-policy.json——后者是 run/test 门禁的权威输入,不能被发布覆盖。
1003
+ "meta/plan-profile.json",
881
1004
  "meta/worktree.json",
882
1005
  }
883
1006
  missing_required = sorted(required - set(ownership_paths))
@@ -194,14 +194,30 @@ def _load_findings(change_dir: Path) -> dict[str, Any] | None:
194
194
 
195
195
 
196
196
  def validate_dispositions(
197
- doc: Any, known_ids: set[str]
197
+ doc: Any, known_ids: set[str], findings_run_id: str | None = None
198
198
  ) -> list[str]:
199
+ """校验处置文档。``findings_run_id`` 给出时,还要求两份 sidecar 同属一轮。
200
+
201
+ runId 以前完全不校验——``write_dispositions`` 直接透传 ``doc.get("runId")``,
202
+ 写 ``None`` 都能落盘,整条 sidecar 的强制力全压在 gate 关门时的一行断言上。
203
+ 而这条断言防的是 fixback 循环里的跨轮重放:sidecar 是 per-change 单文件、不带
204
+ runId 后缀,第二轮 review 关门时磁盘上躺着第一轮那份(finding 全已 FIXED)。
205
+ 在写入端就挡住,比等到关门再拒绝早一整轮。
206
+ """
199
207
  problems: list[str] = []
200
208
  if not isinstance(doc, dict):
201
209
  return ["dispositions document must be an object"]
210
+ run_id = doc.get("runId")
211
+ if not isinstance(run_id, str) or not run_id.strip():
212
+ problems.append("runId is required")
213
+ elif findings_run_id is not None and run_id != findings_run_id:
214
+ problems.append(
215
+ f"runId {run_id} does not match review findings runId {findings_run_id}"
216
+ )
202
217
  dispositions = doc.get("dispositions")
203
218
  if not isinstance(dispositions, list):
204
- return ["dispositions must be a list"]
219
+ problems.append("dispositions must be a list")
220
+ return problems
205
221
  for index, item in enumerate(dispositions):
206
222
  if not isinstance(item, dict):
207
223
  problems.append(f"dispositions[{index}] must be an object")
@@ -226,12 +242,17 @@ def write_dispositions(change_dir: Path, doc: dict[str, Any]) -> dict[str, Any]:
226
242
  f.get("id") for f in (findings_doc or {}).get("findings", [])
227
243
  if isinstance(f, dict)
228
244
  }
229
- problems = validate_dispositions(doc, known_ids)
245
+ findings_run_id = (findings_doc or {}).get("runId")
246
+ problems = validate_dispositions(
247
+ doc,
248
+ known_ids,
249
+ findings_run_id if isinstance(findings_run_id, str) else None,
250
+ )
230
251
  if problems:
231
252
  return {"ok": False, "code": "DISPOSITIONS_INVALID", "problems": problems}
232
253
  payload = {
233
254
  "schemaVersion": 1,
234
- "runId": doc.get("runId"),
255
+ "runId": doc["runId"],
235
256
  "dispositions": doc["dispositions"],
236
257
  }
237
258
  out = dispositions_path(change_dir)
@@ -2,5 +2,5 @@
2
2
  "schemaVersion": 1,
3
3
  "overlay": "java",
4
4
  "agent": "codebuddy",
5
- "coreHash": "c0f4b71956cfc910"
5
+ "coreHash": "0130f72da1a50434"
6
6
  }
@@ -3,7 +3,7 @@ name: harness-apidoc
3
3
  description: 从 Java 后端代码生成结构化前端 API 文档(Controller/VO/ErrorCode)。仅当用户显式调用
4
4
  /harness-apidoc 时使用,不得自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
7
7
  # harness-apidoc — 前端接口文档(Java overlay)
8
8
 
9
9
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-archive
3
3
  description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档)到 .harness/archive/,含归档元数据。仅当用户显式调用
4
4
  /harness-archive 时使用;不得被其他阶段 skill 自动接续触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
7
7
  # harness-archive — 变更归档
8
8
 
9
9
  ## Purpose
@@ -160,9 +160,16 @@ description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档
160
160
  > ⚠️ 行内标注是**申报**,不是绕过:它把"这是设计决策"写进文档本身,可审计、可追溯。
161
161
  > **不要**为了过扫描去删改设计文档的事实内容——那是篡改证据。
162
162
  >
163
- > ⚠️ 已知限制:`hunter-harness-ignore` 在本地扫描器上确认生效;**服务端是否认这条标注尚未验证**
164
- > (归档上传端点只收裸 ZIP,没有独立的豁免申报通道)。若加了标注仍被 422 拒收,
165
- > 剩余动作是在平台侧对该规则/内容加白,本地无法自解。
163
+ > 行内标注**服务端确认生效**:平台归档入口跑的是同一个 `scanSensitiveFiles`,
164
+ > 它直接从文件内容里解析 `hunter-harness-ignore`,命中转为 `overridden`、不再阻断。
165
+ > 上传端点只收裸 ZIP、没有独立申报通道,靠的就是这条写在文档里的标注。
166
+ >
167
+ > ⚠️ 一处已知的服务端滞后:**不带凭据的连接串**(如 `postgres://dbhost:5432/appdb`)
168
+ > 本地预检判 `low`/可豁免,而线上服务端目前仍判 `high`——high 不接受行内标注,
169
+ > 这类设计文档暂时无法上传。平台侧修复已提交(见 hunter-platform
170
+ > `fix(archive): 归档 422 给出可执行出路`),**部署后**两侧一致。在那之前遇到这一条:
171
+ > 等平台部署,不要为了过扫描删掉连接串。带凭据的连接串(`user:pass@host`)两侧都是
172
+ > `high`,必须真正脱敏。
166
173
 
167
174
  ### 二·B、归档补传(上传失败或历史归档缺条目)
168
175
 
@@ -3,7 +3,7 @@ name: harness-codebase-map
3
3
  description: 分析现有代码库并生成 .harness/codebase/map/
4
4
  下的结构化代码库地图。用于陌生项目理解、重大改造前梳理、harness-sync 提示 map 过期后的人工刷新。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
7
7
  # harness-codebase-map — 代码库地图
8
8
 
9
9
  ## Purpose
@@ -2,7 +2,7 @@
2
2
  name: harness-knowledge-ingest
3
3
  description: 确认归档 ZIP 已上传并由 Hunter Platform 在服务端解包、校验和入库。客户端不再构建或维护本地知识索引。
4
4
  ---
5
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
5
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
6
6
  # harness-knowledge-ingest
7
7
 
8
8
  知识 ingest 完全由 Hunter Platform 负责。归档完成时,客户端生成一个确定性 ZIP;
@@ -2,7 +2,7 @@
2
2
  name: harness-knowledge-query
3
3
  description: 在规划、实现或排查前,通过 hunter-harness CLI 查询远端项目知识库。远端不可用时直接报告不可用,不建立本地索引或离线回退。
4
4
  ---
5
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
5
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
6
6
  # harness-knowledge-query
7
7
 
8
8
  项目知识以 Hunter Platform 的服务端索引为唯一真源。客户端只提交查询并消费结果:
@@ -2,7 +2,7 @@
2
2
  name: harness-package
3
3
  description: 增量模块打包:拉取最新→编译验证→mvn package→汇总 jar/war。仅当用户显式调用 /harness-package 时使用,不得自动触发。
4
4
  ---
5
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
5
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
6
6
  # harness-package — 增量模块打包(Java overlay)
7
7
 
8
8
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-plan
3
3
  description: 将需求转化为设计文档+实施计划+完整测试场景表,必须在编码前完成。仅当用户显式调用 /harness-plan 或明确要求进入
4
4
  Harness 规划阶段时使用;不得因用户描述需求就自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
7
7
  # harness-plan — 需求规划
8
8
 
9
9
  ## Purpose
@@ -70,7 +70,7 @@ description: 将需求转化为设计文档+实施计划+完整测试场景表
70
70
  | 0 | git status;脏工作区 → baseline 隔离 + `decision`,不询问。环境体检并入 0.5 的引导命令,不再单独跑 doctor |
71
71
  | 0.5 | 先定英文 `change-name`(kebab-case,`^[a-z0-9]+(-[a-z0-9]+)*$`)与一次性中文展示标题(建议 6~24 个可见字符,保留必要产品名),然后**一条命令完成引导**:<br>`python <skills-root>/scripts/harness_context.py bootstrap-plan --project . --change <cn> --executor <tool> --title "<中文标题>" --json`<br>它按序做完 doctor → 建 change 骨架 → prepare → state capture(首次把当时 HEAD 固定为不可变 `changeBase`)→ classify(落 `meta/gate-policy.json`)→ 生成合规 `plan_<uuid>` run-id 并追加 `phase.start`,返回紧凑摘要:`runId`/`attempt`/`tier`/`defaultPhases`/`conditionalPhases`/`requiredValidations`/`changeBase`/`head`/`executionRoot`。**重跑复用同一 run-id、不重复写 `phase.start`**(换 run-id 会让 finalize 按生命周期身份 fail-closed)。finalizer 必须复用该 `runId`/`attempt` |
72
72
  | 0.5b | 仅在引导失败需要单步排查时用等价分解——**每条的参数都是必填,少一个就是白跑一轮**:<br>`harness_runtime.py doctor --project . --change-dir ".harness/changes/<cn>" --agent <claude-code\|codebuddy\|codex\|cursor> --json`<br>`harness_context.py prepare --project . --change <cn> --phase plan --executor <tool> --title "<中文标题>" --json`<br>`harness_state.py capture --project . --change-dir ".harness/changes/<cn>" --json`<br>`harness_gate.py classify --change <cn> --stage plan --json`<br>`harness_events.py append --change-dir ".harness/changes/<cn>" --phase plan --type phase.start --run-id plan_<uuid> --attempt 1`<br>⚠️ `--change-dir` 一律是 `.harness/changes/<cn>`(状态目录),**不是** prepare 返回的 `executionRoot`(代码执行根,无 worktree 时等于项目根)——填错会把 gate-policy/events 写到项目根 |
73
- | 0.6 | 用引导返回的 `tier`/`defaultPhases`/`requiredValidations` 生成 `plannedPhases`,向用户用中文说明可选阶段;确认后运行 `harness_context.py configure-plan --project . --change <cn> --phases "plan,run,...,archive" --operator <tool> --reason "<中文原因>" --json`。无 Git 或不需要提交时不得加入 `submit`;快速迭代默认 `plan,run,archive`。省略项由脚本写入 `skippedPhases`,不得伪造阶段事件 |
73
+ | 0.6 | 用引导返回的 `tier`/`defaultPhases`/`requiredValidations` 生成 `plannedPhases`,向用户用中文说明可选阶段;确认后运行 `harness_context.py configure-plan --project . --change <cn> --phases "plan,run,...,archive" --operator <tool> --reason "<中文原因>" --json`。无 Git 或不需要提交时不得加入 `submit`;快速迭代默认 `plan,run,archive`。省略项由脚本写入 `skippedPhases`,不得伪造阶段事件。<br>⚠️ 无风险信号时 classify 默认 `standard`(`plan,run,test,submit,archive` + compile/unitTest/unitTestFull),**不再默认 full**。需要 review 阶段与 apiTest 的高风险变更,在计划文档里写「风险等级: full」或用 `classify --tier-override full` 显式升档 |
74
74
  | 1 | 直接执行一次 `npx hunter-harness knowledge query "<用户需求原文>" --limit 10 --json`。这是唯一执行入口,不扫描技能目录、不查找其他脚本;失败记 `issue` 并继续,不建立本地索引或离线回退 |
75
75
  | 2 | 歧义优先检查 + 复杂度分级;先确认会改变实现方向的语义歧义 |
76
76
  | 3 | 按复杂度执行有预算的代码探索;简单修复不得扩散到无关模块 |
@@ -106,6 +106,7 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
106
106
  | 设计审批包 | 一次 blocking user confirmation 含 worktree(读 `harness.json` `defaultWorktree`)。必须同时展示 **in_scope 与 out_of_scope 两个列表**——只展示"做什么"会让范围误判活到发布之后,代价是整份计划 republish |
107
107
  | 引用即追问 | 需求引用了外部设计文档章节(贴段落、指 `### Bn`、说"之前设计的时候如…")时,阶段 2 必须确认该章节是否纳入本次范围,落到 in_scope 或 out_of_scope;引用 ≠ 纳入,也 ≠ 排除 |
108
108
  | 阶段 8 | 二选一且不得混用:**v2** = `hunter-harness plan finalize`(证据包 → 八 target + journal committed + plan-events.ndjson);**legacy** = 六项标准产物先进入 staging,仅 finalizer 校验成功后发布并写唯一 `phase.end`/log,随后 `verify` 确认 start/end、收据完整覆盖六项标准产物、哈希、全部任务表和非空场景清单一致。失败均不得手工补终态 |
109
+ | 选 v2 还是 legacy | **默认 v2**;legacy 已 deprecated,将在 workflow-harness 0.3.0 移除,只用于自然输入不完整(例如缺真实审批记录)的回退。v2 的场景契约已补齐 `priority`/`owner_phase` 与可执行测试三元,派生的 `meta/scenario-manifest.json` 能被 run/test 门禁与 `harness_ledger.py record` 解包消费,证据闭环走得通。P0/P1 场景必须给全可执行三元(要么整组给全、要么整组省略;省略则 manifest 降为 schemaVersion 1,关门绑不上结构化执行收据) |
109
110
  | 发布后改产物 | 用 `harness_plan_finalize.py republish --run-id <全新> --reason "<why>"` 一次完成(新 attempt + 换收据 + 重新派生 manifest)。重跑 `finalize` 会报 `PLAN_FINALIZATION_HASH_CONFLICT`;**绝不手改 `meta/scenario-manifest.json`**(派生物,手改必致 `ARTIFACT_HASH_DRIFT`)→ `reference.md`「发布后修订计划」 |
110
111
  | v2 输入骨架 | 不要猜 `plan-evidence-input.json` 结构:`npx hunter-harness plan evidence-pack --print-template` 给出**一个字不改就能通过 evidence-pack** 的骨架(结构合法;`change_key`/`run_id` 仍须换成真实身份才能 finalize),逐项替换即可。结构不符时命令返回 `PLAN_EVIDENCE_INPUT_INVALID`,带 `field_path` 与 `problems[]`(缺失/多余键、枚举取值)——按 problems 改完重跑;**不得**为找契约去反编译 `dist/bin.js` 或翻 npx 缓存。带不了 `<>` 的占位字段与硬约束清单 → `reference.md` 阶段 8 v2 路径 |
111
112
  | Plan 结束 | **禁止**询问执行模式;只提示 `/harness-run` |
@@ -184,8 +184,8 @@ source: harness-plan
184
184
  □ 已用 decision / issue 事件 note 记录五类输出:风险识别 / 复用机会 / 替代方案 / 推荐方案 / 关键决策
185
185
  □ 已叠加项目架构约束(分层规范、数据模型、接口规范)
186
186
  □ 需求澄清结论已追加到 events.ndjson,阶段结束后执行日志由渲染器生成
187
- 用户问题未超预算:简单修复 0-1 问,普通需求 1-3 问,高风险需求 5-7 问;无必须裁决事项时 0 问
188
- 提问遵循"一次一问、等答再继续";能由 context pack / 阶段3代码探索 / CodeGraph 自答的问题已自答,未打扰用户
187
+ 提问方式与问题预算符合 protocols.md decision-grilling-protocol(预算数值以那份为准,此处不复述)
188
+ 能由 context pack / 阶段3代码探索 / CodeGraph 自答的问题已自答,未打扰用户
189
189
  □ 每个需要用户决策的问题,AI 先给出了推荐答案、理由和取舍,用户仅确认或修正
190
190
  □ 高风险/业务语义决策(范围、权限、安全、支付、迁移、删除、API契约、用户可见行为)已显式等待用户确认
191
191
  ```
@@ -199,97 +199,34 @@ source: harness-plan
199
199
  ```
200
200
  □ 已读取 protocols.md,并按 implementation-planning-protocol 执行
201
201
  □ 输入为阶段4已审核设计文档
202
- 已生成基础任务列表,并用 artifact 事件 note 记录任务拆分摘要
202
+ 已用 artifact 事件 note 记录任务拆分摘要
203
203
  □ 已叠加项目层序依赖(数据/契约→业务层→接口层)
204
204
  □ 已生成 4 维度场景表(单元/接口/数据兼容/集成)
205
205
  □ 每个自动化场景均标注执行层级、预计时长、资源预算、超时、可复用证据;快速反馈不默认扫描全仓库
206
206
  □ 已确定变更名(kebab-case)
207
- □ 产物已写入 .harness/changes/<change-name>/plans/:
208
- - <change-name>-plan.md(简洁任务表)
209
- - <change-name>-implementation-detail.md(自适应详细执行参考)
210
- - <change-name>-test-scenarios.md(测试场景表)
211
207
  □ implementation-detail.md 按复杂度自适应:简单任务不过度展开,复杂任务写清接口/数据/顺序/风险/测试策略
212
208
  □ plan / implementation-detail / test-scenarios 三件套互相引用一致,无 TBD/TODO/空泛占位
213
209
  ```
214
210
 
211
+ > 产物是否齐全、任务表与场景表是否非空、优先级与 ownerPhase 取值是否合法,由 finalizer
212
+ > fail-closed 判定(`PLAN_ARTIFACT_MISSING` / `PLAN_TASKS_EMPTY` / `PLAN_SCENARIOS_EMPTY` /
213
+ > `PLAN_SCENARIO_PRIORITY_INVALID`),此处不重复勾选。上面留下的都是机器判不了的:
214
+ > 层序依赖是否合理、维度是否真被覆盖、详略是否配得上复杂度、三件套是否自洽。
215
+
215
216
  > 不再检查 Superpowers writing-plans 是否安装或调用;阶段 6 是 harness 原生协议,不存在 `docs/superpowers/` 同步分支。
216
217
 
217
218
  ## 阶段 8:结束前产物完整性检查 ⚠️ 强制
218
219
 
219
- > **缺任一文件❌FAIL,不得宣称 plan 完成。**
220
-
221
- > **先认路径再对表**:v2 与 legacy 的完整性口径不同,混用会得出错误结论。
222
-
223
- ### v2 路径(新 change 默认)
224
-
225
- - [ ] 只手写 `meta/plan-evidence-input.json`;`plans/*.md` 由 finalize 派生,**不得**手写后再被覆盖
226
- - [ ] `evidence-pack` 返回 `code:"PLAN_EVIDENCE_PACK_BUILT"`;结构报错按 `field_path`/`problems[]` 修正后重跑
227
- - [ ] `finalize` exit 0 且 `code:"PLAN_FINALIZED"`
228
- - [ ] 八 target 齐全:`plans/` ×4(design / implementation-detail / plan / test-scenarios)+ `meta/` ×4(gate-policy / implementation-checkpoints / scenario-manifest / worktree)
229
- - [ ] `meta/publication-journals/<op>.json` 的 `state === "committed"`
230
- - [ ] `meta/plan-events.ndjson` 含 `artifact_published` 与 `phase_ended` 两类终态事件
231
- - [ ] 以上任一缺失都不得手工补写;回到对应阶段改自然输入后重跑
232
-
233
- | 文件(v2) | 必须存在 | 检查结果 |
234
- |------|:---:|:---:|
235
- | `.harness/changes/<change>/meta/plan-evidence-input.json` | ✅ | □ |
236
- | `.harness/changes/<change>/plans/<change>-design.md` | ✅ | □ |
237
- | `.harness/changes/<change>/plans/<change>-plan.md` | ✅ | □ |
238
- | `.harness/changes/<change>/plans/<change>-implementation-detail.md` | ✅ | □ |
239
- | `.harness/changes/<change>/plans/<change>-test-scenarios.md` | ✅ | □ |
240
- | `.harness/changes/<change>/meta/gate-policy.json` | ✅ | □ |
241
- | `.harness/changes/<change>/meta/worktree.json` | ✅ | □ |
242
- | `.harness/changes/<change>/meta/implementation-checkpoints.json` | ✅ | □ |
243
- | `.harness/changes/<change>/meta/scenario-manifest.json`(非空且计数一致) | ✅ | □ |
244
- | `.harness/changes/<change>/meta/publication-journals/<op>.json`(committed) | ✅ | □ |
245
- | `.harness/changes/<change>/meta/plan-events.ndjson` | ✅ | □ |
246
- | `.harness/changes/<change>/events.ndjson` | ✅ | □ |
247
-
248
- > v2 过渡期**不写** `meta/plan-finalization.json` 与 `logs/execution-log.md`;缺这两项不算失败,不得为凑表手工补。
249
-
250
- ### legacy 路径(自然输入不完整时的回退)
251
-
252
- - [ ] 所有待发布产物先写入 staging,不直接覆盖正式 change 目录
253
- - [ ] 执行 `harness_plan_finalize.py finalize --change-dir ... --staging-dir ... --change ... --run-id <plan-run-id> --attempt <attempt> --json`;身份必须与本次 `phase.start` 完全相同
254
- - [ ] finalizer 返回 `ok=true`、`artifactsHash`、绝对 `receiptPath` 与稳定 `artifactRef=meta/plan-finalization.json`;重复执行返回 `idempotent=true`
255
- - [ ] 紧接着执行 `harness_plan_finalize.py verify --change-dir ... --json`
256
- - [ ] verify 返回 `phaseStartCount=1`、`phaseEndCount=1`、`phaseEndStatus=OK`、`receiptConsistent=true`
257
- - [ ] 收据 `files` 完整包含 design / plan / implementation-detail / test-scenarios / gate-policy / worktree 六项标准产物;不得省略、重复或经 symlink/junction/reparse point 引用
258
- - [ ] verify 的 `taskCount` 等于全部任务表行数,`scenarioCount` 等于 Markdown 中全部唯一场景 ID 数;任一为 0 或不一致即 ❌FAIL
259
- - [ ] finalizer 失败时正式目录无半发布产物、无成功 `phase.end`、无伪造 execution log
260
- - [ ] 禁止在 finalizer 之前手工追加成功 `phase.end`
261
- - [ ] context close 的 `--artifact` 只传 finalizer 原样返回的 `receiptPath` 或 `artifactRef`,不得猜测、拼接或使用 `<plan-finalization>` 占位文本
262
-
263
- | 文件(legacy) | 必须存在 | 检查结果 |
264
- |------|:---:|:---:|
265
- | `.harness/changes/<change>/spec/<change>-design.md` | ✅ | □ |
266
- | `.harness/changes/<change>/plans/<change>-plan.md` | ✅ | □ |
267
- | `.harness/changes/<change>/plans/<change>-implementation-detail.md` | ✅ | □ |
268
- | `.harness/changes/<change>/plans/<change>-test-scenarios.md` | ✅ | □ |
269
- | `.harness/changes/<change>/meta/gate-policy.json` | ✅ | □ |
270
- | `.harness/changes/<change>/meta/worktree.json` | ✅ | □ |
271
- | `.harness/changes/<change>/meta/implementation-checkpoints.json` | ✅ | □ |
272
- | `.harness/changes/<change>/meta/scenario-manifest.json`(非空且计数一致) | ✅ | □ |
273
- | `.harness/changes/<change>/meta/plan-finalization.json`(finalized) | ✅ | □ |
274
- | `.harness/changes/<change>/logs/execution-log.md` | ✅ | □ |
275
- | `.harness/changes/<change>/events.ndjson` | ✅ | □ |
276
-
277
- ### Plan 结束行为检查
220
+ > **先认路径**:v2 与 legacy 的完整性口径不同,混用会得出错误结论。两条路径各自的必需文件清单 `reference.md`「阶段 8」。
278
221
 
279
- ```
280
- □ 未询问 Subagent-Driven / Inline Execution 等执行模式
281
- □ 最终输出只提示了产出物路径和下一步 /harness-run
282
- □ 未将 docs/superpowers/ 列为最终产物路径
283
- ```
222
+ 文件是否齐全、哈希是否一致、身份是否匹配、计数是否对得上——这些 **finalizer 与 verify 已经 fail-closed 判定**,逐条复述不产生新结论,只会把一份事实变成两份。命令失败时按返回的 `code` 查 `reference.md`,不要对着清单猜。
284
223
 
285
- ### Legacy Frontmatter 兼容
224
+ 下面三条不在机器判定范围内,必须自己守:
225
+
226
+ - [ ] **v2**:只手写 `meta/plan-evidence-input.json`。`plans/*.md` 由 finalize 派生,手写的会被渲染覆盖,只是白写
227
+ - [ ] 任何缺失**都不得手工补写**(包括 `phase.end`);回到对应阶段改自然输入/staging 后重跑
228
+ - [ ] v2 过渡期**不写** `meta/plan-finalization.json` 与 `logs/execution-log.md`;缺这两项不算失败,不得为凑表手工补
286
229
 
287
- ```
288
- □ 已确认 plan 文件 frontmatter 存在
289
- □ 如不存在 → 已从路径推断 change-name 和 plan-name
290
- □ 如不存在 → 执行日志中已标记 🟡 legacy-plan
291
- □ 旧 plan 不因 frontmatter 缺失而 FAIL
292
- ```
293
230
 
294
231
  ## 关键原则
295
232
 
@@ -300,7 +237,9 @@ source: harness-plan
300
237
  - 场景表是后续所有步骤的真相源——宁可多花时间打磨,不要草草了事
301
238
  - 如果需求不明确,优先提问而不是猜测后继续设计
302
239
  - 任务拆分粒度按复杂度调整——plan 简表保持可追踪,implementation-detail 按风险和复杂度自适应展开
303
- - **Plan 结束禁止询问执行模式**:Subagent-Driven / Inline Execution 属于 /harness-run 阶段
240
+
241
+ > Plan 的结束行为(禁止询问执行模式、只提示 `/harness-run`)由 `SKILL.md` 的关键规则表定义,
242
+ > 详细规则见 `reference.md`「Plan 结束行为规则」。此处不再复述。
304
243
 
305
244
  ## 事件记录(前置规则)
306
245
 
@@ -128,4 +128,6 @@ description: harness-plan 的原生规划协议。吸收 brainstorming、grill-m
128
128
  - implementation-planning-protocol:plan 简表、implementation-detail、test-scenarios 三件套一致,无占位符
129
129
  ```
130
130
 
131
- 该自检作为 `verification` 事件的 `note` 追加;关键结论分别追加 `decision` / `issue` 事件。渲染器在 `phase.end` 后生成执行日志。
131
+ 自检结论直接展示给用户即可,**不要**再追加一条 `verification` 事件——「协议自检通过」不改变
132
+ 任何结论,只增加监控噪声(roadmap 12 号「事件规则」)。真正影响行为的东西照常留痕:关键决策
133
+ 追加 `decision`,发现的冲突与阻塞追加 `issue`。渲染器在 `phase.end` 后生成执行日志。
@@ -351,7 +351,8 @@ status: approved
351
351
  | `.harness/changes/<change>/plans/<change>-plan.md` | ✅(派生) | ✅ |
352
352
  | `.harness/changes/<change>/plans/<change>-implementation-detail.md` | ✅(派生) | ✅ |
353
353
  | `.harness/changes/<change>/plans/<change>-test-scenarios.md` | ✅(派生) | ✅ |
354
- | `.harness/changes/<change>/meta/gate-policy.json` | | ✅ |
354
+ | `.harness/changes/<change>/meta/gate-policy.json` | ✅(**classify 写,非发布产物**) | ✅ |
355
+ | `.harness/changes/<change>/meta/plan-profile.json` | ✅(派生) | — |
355
356
  | `.harness/changes/<change>/meta/worktree.json` | ✅ | ✅ |
356
357
  | `.harness/changes/<change>/meta/implementation-checkpoints.json` | ✅ | ✅ |
357
358
  | `.harness/changes/<change>/meta/scenario-manifest.json` | ✅ | ✅ |
@@ -363,6 +364,25 @@ status: approved
363
364
 
364
365
  legacy 的 `plan-finalization.json.files` 必须完整列出 design、plan、implementation-detail、test-scenarios、gate-policy、worktree 六项标准输入。`verify` 对缺项、重复项、越界路径以及 symlink/junction/reparse point 一律 fail-closed;不得通过删减收据文件集后重算哈希来绕过完整性检查。
365
366
 
367
+ ### 两套分类模型的边界(别把它们当同一件事)
368
+
369
+ | | Python `tier` | TS `mode` |
370
+ |---|---|---|
371
+ | 取值 | `fast` / `standard` / `full` | `quick` / `standard` / `assurance` |
372
+ | 写到哪 | `meta/gate-policy.json`(`schemaVersion:1`,camelCase) | `meta/plan-profile.json`(artifact 包装体,snake_case) |
373
+ | 谁写 | `harness_gate.py classify`(阶段 0.5 由 bootstrap-plan 调起) | `hunter-harness plan finalize`(阶段 8 发布) |
374
+ | 地位 | **门禁权威**:驱动 `requiredGateDag`、`requiredValidationsByPhase`,run/test 开门读它 | **派生视图**:供展示与下游只读消费,门禁不读 |
375
+ | 输入 | 计划文档的「风险等级」正则 + capabilityGates 信号 | 自然输入里手填的 `risk_signals` |
376
+
377
+ **两者不共用文件名。** v2 发布对 `binding.ownership_paths` 逐个原子覆盖,若派生视图占用 `meta/gate-policy.json`,阶段 8 会把 classify 写的那份换成包装体,之后 `gate begin --phase run` 直接 `POLICY_LOAD_FAILED`——`harness_gate.effective_workflow_policy` 读 `schemaVersion` 拿不到就 raise。
378
+
379
+ **为什么派生视图目前不能当权威**(将来要接通就得先解决这两条):
380
+
381
+ 1. `plan evidence-pack` 对 `risk_signals` **不做任何推断**——不读 git diff、不扫路径、不解析 frontmatter,值完全来自自然输入里手填的那个数组。拿它当门禁权威等于让 agent 自声明低风险来跳门禁。
382
+ 2. 命令里的 `capabilities` 是写死的(`is_git:true, has_remote:true, uses_worktree:false`),用户在阶段 0.6 通过 `configure-plan` 选的阶段计划被完全忽略,`planned_phases` 退化成 mode 的纯函数。
383
+
384
+ `meta/implementation-checkpoints.json` 的情况不同:v2 包装体里的 `content.foundation_gate` 信息是够的,所以门禁在**只读侧**解包(`checkpoint_status` 同时认 `checkpoints[]`、顶层 `foundationGate` 与 v2 包装体三种形状),不改文件名。注意写回路径(`gate checkpoint approve`)仍然操作原始文档——用归一化结构覆盖会破坏 v2 产物的哈希绑定。
385
+
366
386
  ### 阶段 8 v2 路径(结构化证据包流程,新 change 优先)
367
387
 
368
388
  阶段 8 v2 标准三步流(证据包自举,阶段 14 起可用):
@@ -422,13 +442,22 @@ npx hunter-harness plan finalize --input .harness/changes/<cn>/meta/plan-evidenc
422
442
  | `context` | project_id/run_id/branch_name/attempt(复用 plan-run-id 与 attempt) | 0.5 |
423
443
  | `expected_baseline` | 首次发布 `{state:"absent", manifest_hash:null, generation:0}` | 8 |
424
444
 
425
- > ⚠️ **已知缺口:v2 派生的 `meta/scenario-manifest.json` 目前喂不了 run/test 门禁。**
426
- > 它是 artifact 包装体,每条场景只有 `scenario_id/coverage_dimension/execution_level/
427
- > evidence_requirements/risk_level/task_refs/requirement_refs`;而门禁按
428
- > `id/priority/requiredEvidenceKind/ownerPhase/executableTestId/testFile/testTitle`
429
- > 判定哪些场景需要 ledger 证据。缺 `priority` 与 `requiredEvidenceKind` 时"必需场景"会算成空集,
430
- > 所以门禁**明确报 `SCENARIO_MANIFEST_V2_UNSUPPORTED` 并列出 `missingFields`,绝不静默放行**。
431
- > 需要 ledger 证据闭环的变更,在 v2 场景契约补齐这些字段前请走 legacy 路径。
445
+ > **场景契约与门禁的对接**(曾经的已知缺口,现已打通)
446
+ >
447
+ > v2 派生的 `meta/scenario-manifest.json` 是 artifact 包装体,键名与门禁消费的不同。消费端
448
+ > (`harness_gate` 的 C9、`harness_ledger` 的三处)统一调 `harness_plan_finalize.unpack_v2_scenario_manifest`
449
+ > 解成 legacy 形状再判定:`scenario_id→id`、`owner_phase→ownerPhase`、`required_evidence_kind→requiredEvidenceKind`
450
+ > 、可执行三元 `executable_test_id/test_file/test_title→executableTestId/testFile/testTitle`。
451
+ > `required_evidence_kind` `priority` 派生(P0/P1→`ledger`,P2→`advisory`),写在 artifact 里,
452
+ > 消费侧不重推。
453
+ >
454
+ > 因此自然输入的 `scenarios` **必须**带 `priority`(P0/P1/P2)与 `owner_phase`。缺任一项,
455
+ > 门禁**逐场景**校验后报 `SCENARIO_MANIFEST_V2_UNSUPPORTED` 并列出 `missingFields`,绝不静默放行
456
+ > ——逐场景而不是取键的并集:并集只要有一条场景带了 `priority` 就算通过,其余缺字段的会静默
457
+ > 落进非必需集,"必需场景"随之缩水。
458
+ >
459
+ > 可执行三元是**可选**的,但要么整组给全、要么整组省略。ledger 场景全部带齐 → manifest 声明
460
+ > `schemaVersion 2`,关门可绑结构化执行收据;否则降为 1。
432
461
 
433
462
  - **证据包**(`plan-evidence.json`)是命令推导的产物(trusted/publication/context/baseline),不得手改;任何字段变化必须改自然输入后重跑 evidence-pack。
434
463
  - **成功语义**:finalize exit 0 且 `code:"PLAN_FINALIZED"`。落盘事实 = 八 target(plans/*.md ×4 + meta/*.json ×4)+ `meta/publication-journals/<op>.json`(状态 committed)+ `meta/plan-events.ndjson`(artifact_published/phase_ended)。确定性门失败 exit 1 且 `code:"PLAN_FINALIZE_DETERMINISTIC_FAILED"` 附 findings——此时必须回到对应阶段修正规划内容,**不得**手改证据包或 staged 内容绕过。
@@ -3,7 +3,7 @@ name: harness-pull
3
3
  description: 从 Hunter Platform 下拉配置/规则/架构/指令(及显式来源分支的分支文件恢复)。仅当用户显式调用
4
4
  /harness-pull 或明确说'从平台拉取/恢复'时使用;不得自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
7
7
  # harness-pull — 从 Hunter Platform 下拉与恢复
8
8
 
9
9
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-push
3
3
  description: 上传本地配置/规则/架构/指令(及显式归档)到 Hunter Platform。仅当用户显式调用 /harness-push
4
4
  或明确说'上传到平台'时使用;不得因存在本地修改就自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
7
7
  # harness-push — 上传到 Hunter Platform
8
8
 
9
9
  ## Purpose
@@ -4,7 +4,7 @@ description: 6维度代码审查(架构/安全/规范/兼容/测试/性能)
4
4
  .harness/context-index.json)和测试场景表,在隔离上下文运行。仅当用户显式调用 /harness-review 时使用;不得在
5
5
  test 结束后自动接续执行。
6
6
  ---
7
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
7
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
8
8
  # harness-review — 代码审查
9
9
 
10
10
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-run
3
3
  description: 按变更簇执行 TDD 编码循环(RED→GREEN→REFACTOR→编译验证),逐变更簇实现计划中的任务。仅当用户显式调用
4
4
  /harness-run 时使用;不得因用户提到编码/实现就自动触发,也不得被其他阶段 skill 自动接续。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
7
7
  # harness-run — 需求编码
8
8
 
9
9
  ## Purpose
@@ -83,13 +83,15 @@ python <skills-root>/scripts/harness_test_runner.py exec --project . --timeout-s
83
83
 
84
84
  返回 `TEST_RUN_ALREADY_ACTIVE`(退出码 3)说明**已有构建在跑**:等它结束或用 `lock-status` 查明持有者,**不得**改用裸跑绕开锁,也不得另起一个并行构建。确认持有进程已消失时才用 `lock-reap` 回收。
85
85
 
86
- **长阶段租约续期**:`gate begin` 的租约默认 TTL 3600 秒,而 run 阶段常常跑得更久。租约过期不会中断执行,只会让最后的 `gate close` `LEASE_ABSENT`。凡预计超过 1 小时的阶段,每完成一个变更簇就用本阶段**原 run-id** 续租一次(同 run-id 重复 claim 即刷新,不会新开 attempt):
86
+ **长阶段租约**:`gate begin` 的租约默认 TTL 3600 秒,而 run 阶段常常跑得更久。租约过期不会中断执行,**也不再阻断收尾**:`gate close` 发现租约过期而 run-id 仍是本阶段的,会自动用原 run-id 重取并照常关门,只在返回体的 `leaseLapsed` 里记下这个阶段跑过了 TTL。过期本身不说明所有权变了——抢占会重写租约文件把 run-id 换掉,那时报的是 `LEASE_OWNER_MISMATCH`。
87
+
88
+ 因此**不需要**为了长阶段定期续租。确实想让租约始终有效时,用本阶段原 run-id 刷新即可(同 run-id 重复 claim 即刷新,不会新开 attempt):
87
89
 
88
90
  ```text
89
91
  python <skills-root>/scripts/harness_change.py claim --change <id> --phase run --run-id <本阶段 run-id> --ttl-seconds 3600 --json
90
92
  ```
91
93
 
92
- 已经报了 `LEASE_ABSENT` 也按同一条命令恢复——错误响应的 `resumeRunId` 就是要用的 run-id;**不要**重跑 `gate begin`,那会新开 attempt 并丢失本轮 capsule。
94
+ 仍然报 `LEASE_ABSENT` 说明这个阶段**根本没有租约记录**(从未 begin,或已被释放),不是超时;先确认 `gate begin` 真的跑过。报 `LEASE_INVALID` 说明租约文件损坏,无法证明没被抢占,需人工确认无并发后再用上面的命令重取。两种情况都**不要**重跑 `gate begin`——那会新开 attempt 并丢失本轮 capsule。
93
95
 
94
96
  **执行器边界**:优先使用项目 build profile 和已有测试入口。禁止为了绕过 ESM、路径或参数问题临时生成 `.js`、`require` 脚本;需要文件式 runner 时使用项目已有入口,确需新增时遵循项目模块类型(例如 ESM 使用 `.mjs`)。runner 包装说明写入 `runnerCommand` 元数据,不得拼进账本的规范 `command`。
95
97
 
@@ -131,7 +133,7 @@ python <skills-root>/scripts/harness_change.py claim --change <id> --phase run -
131
133
  | **关门/状态** | 10 项关门检查;持久化 run-task-status;仅 run-owned P0 静态-only 导致 WARN;test-owned 待办正常移交 |
132
134
  | **Worktree** | `requested=true` 时代码只写 worktree |
133
135
  | **构建/测试** | 一律经 `harness_test_runner.py exec`;禁止裸跑 mvn/gradle/npm test;`TEST_RUN_ALREADY_ACTIVE` 表示已有构建在跑,等待而非另起 |
134
- | **租约** | 阶段超 1 小时按变更簇用原 run-id 续租;`LEASE_ABSENT` `harness_change.py claim` 恢复,不重跑 begin |
136
+ | **租约** | 阶段超 TTL close 自动用原 run-id 重取,无需续租;`LEASE_ABSENT`(无记录)/`LEASE_INVALID`(文件损坏)才需人工 `harness_change.py claim`,一律不重跑 begin |
135
137
  | **PowerShell** | 所有 git 经 `powershell.exe -NoProfile -Command` |
136
138
 
137
139
  ### 陈旧测试安全修复与精确跟踪
@@ -3,7 +3,7 @@ name: harness-submit
3
3
  description: 最终提交封装:验证→中文 commit→提交/推送;worktree 模式含 --no-ff 合并回主分支。仅当用户显式调用
4
4
  /harness-submit(或 /harness-merge 重入合并段)时使用;用户口头说'提交/commit/push'时必须先确认,不得自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
7
7
  # harness-submit — 最终提交(含 worktree 合并)
8
8
 
9
9
  ## Purpose
@@ -4,7 +4,7 @@ description: Use when the user asks to synchronize, refresh, or validate Harness
4
4
  metadata, adapters, remote knowledge ownership, instruction entrypoints,
5
5
  config origins, or CodeGraph status.
6
6
  ---
7
- <!-- generated by harness_deploy.py; core=c0f4b71956cfc910; overlay=java; agent=codebuddy; do not edit -->
7
+ <!-- generated by harness_deploy.py; core=0130f72da1a50434; overlay=java; agent=codebuddy; do not edit -->
8
8
  # harness-sync
9
9
 
10
10
  ## Purpose