@hunter-harness/workflow-harness 0.4.11 → 0.4.13

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 (192) 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-codebase-map/SKILL.md +1 -1
  4. package/harness/bundles/general/claude-code/harness-execute/SKILL.md +1 -1
  5. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  6. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  7. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +1 -1
  8. package/harness/bundles/general/claude-code/harness-pull/SKILL.md +1 -1
  9. package/harness/bundles/general/claude-code/harness-push/SKILL.md +1 -1
  10. package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
  11. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +2 -2
  12. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  13. package/harness/bundles/general/claude-code/scripts/harness_archive.py +18 -11
  14. package/harness/bundles/general/claude-code/scripts/harness_gate.py +69 -1
  15. package/harness/bundles/general/claude-code/scripts/harness_knowledge_candidates.py +58 -12
  16. package/harness/bundles/general/claude-code/scripts/harness_ledger.py +27 -3
  17. package/harness/bundles/general/claude-code/scripts/harness_review.py +16 -2
  18. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  19. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  20. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  21. package/harness/bundles/general/codebuddy/harness-execute/SKILL.md +1 -1
  22. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  23. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  24. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
  25. package/harness/bundles/general/codebuddy/harness-pull/SKILL.md +1 -1
  26. package/harness/bundles/general/codebuddy/harness-push/SKILL.md +1 -1
  27. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
  28. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +2 -2
  29. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  30. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +18 -11
  31. package/harness/bundles/general/codebuddy/scripts/harness_gate.py +69 -1
  32. package/harness/bundles/general/codebuddy/scripts/harness_knowledge_candidates.py +58 -12
  33. package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +27 -3
  34. package/harness/bundles/general/codebuddy/scripts/harness_review.py +16 -2
  35. package/harness/bundles/general/codex/.harness-build.json +1 -1
  36. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  37. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  38. package/harness/bundles/general/codex/harness-execute/SKILL.md +1 -1
  39. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  40. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  41. package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
  42. package/harness/bundles/general/codex/harness-pull/SKILL.md +1 -1
  43. package/harness/bundles/general/codex/harness-push/SKILL.md +1 -1
  44. package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
  45. package/harness/bundles/general/codex/harness-submit/SKILL.md +2 -2
  46. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  47. package/harness/bundles/general/codex/scripts/harness_archive.py +18 -11
  48. package/harness/bundles/general/codex/scripts/harness_gate.py +69 -1
  49. package/harness/bundles/general/codex/scripts/harness_knowledge_candidates.py +58 -12
  50. package/harness/bundles/general/codex/scripts/harness_ledger.py +27 -3
  51. package/harness/bundles/general/codex/scripts/harness_review.py +16 -2
  52. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  53. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  54. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  55. package/harness/bundles/general/cursor/harness-execute/SKILL.md +1 -1
  56. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  57. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  58. package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
  59. package/harness/bundles/general/cursor/harness-pull/SKILL.md +1 -1
  60. package/harness/bundles/general/cursor/harness-push/SKILL.md +1 -1
  61. package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
  62. package/harness/bundles/general/cursor/harness-submit/SKILL.md +2 -2
  63. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  64. package/harness/bundles/general/cursor/scripts/harness_archive.py +18 -11
  65. package/harness/bundles/general/cursor/scripts/harness_gate.py +69 -1
  66. package/harness/bundles/general/cursor/scripts/harness_knowledge_candidates.py +58 -12
  67. package/harness/bundles/general/cursor/scripts/harness_ledger.py +27 -3
  68. package/harness/bundles/general/cursor/scripts/harness_review.py +16 -2
  69. package/harness/bundles/general/pi/.harness-build.json +1 -1
  70. package/harness/bundles/general/pi/harness-archive/SKILL.md +1 -1
  71. package/harness/bundles/general/pi/harness-codebase-map/SKILL.md +1 -1
  72. package/harness/bundles/general/pi/harness-execute/SKILL.md +1 -1
  73. package/harness/bundles/general/pi/harness-knowledge-ingest/SKILL.md +1 -1
  74. package/harness/bundles/general/pi/harness-knowledge-query/SKILL.md +1 -1
  75. package/harness/bundles/general/pi/harness-plan/SKILL.md +1 -1
  76. package/harness/bundles/general/pi/harness-pull/SKILL.md +1 -1
  77. package/harness/bundles/general/pi/harness-push/SKILL.md +1 -1
  78. package/harness/bundles/general/pi/harness-review/SKILL.md +1 -1
  79. package/harness/bundles/general/pi/harness-submit/SKILL.md +2 -2
  80. package/harness/bundles/general/pi/harness-sync/SKILL.md +1 -1
  81. package/harness/bundles/general/pi/scripts/harness_archive.py +18 -11
  82. package/harness/bundles/general/pi/scripts/harness_gate.py +69 -1
  83. package/harness/bundles/general/pi/scripts/harness_knowledge_candidates.py +58 -12
  84. package/harness/bundles/general/pi/scripts/harness_ledger.py +27 -3
  85. package/harness/bundles/general/pi/scripts/harness_review.py +16 -2
  86. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  87. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  88. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  89. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  90. package/harness/bundles/java/claude-code/harness-execute/SKILL.md +1 -1
  91. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  92. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  93. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  94. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
  95. package/harness/bundles/java/claude-code/harness-pull/SKILL.md +1 -1
  96. package/harness/bundles/java/claude-code/harness-push/SKILL.md +1 -1
  97. package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
  98. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +2 -2
  99. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  100. package/harness/bundles/java/claude-code/scripts/harness_archive.py +18 -11
  101. package/harness/bundles/java/claude-code/scripts/harness_gate.py +69 -1
  102. package/harness/bundles/java/claude-code/scripts/harness_knowledge_candidates.py +58 -12
  103. package/harness/bundles/java/claude-code/scripts/harness_ledger.py +27 -3
  104. package/harness/bundles/java/claude-code/scripts/harness_review.py +16 -2
  105. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  106. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  107. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  108. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  109. package/harness/bundles/java/codebuddy/harness-execute/SKILL.md +1 -1
  110. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  111. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  112. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  113. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
  114. package/harness/bundles/java/codebuddy/harness-pull/SKILL.md +1 -1
  115. package/harness/bundles/java/codebuddy/harness-push/SKILL.md +1 -1
  116. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
  117. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +2 -2
  118. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  119. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +18 -11
  120. package/harness/bundles/java/codebuddy/scripts/harness_gate.py +69 -1
  121. package/harness/bundles/java/codebuddy/scripts/harness_knowledge_candidates.py +58 -12
  122. package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +27 -3
  123. package/harness/bundles/java/codebuddy/scripts/harness_review.py +16 -2
  124. package/harness/bundles/java/codex/.harness-build.json +1 -1
  125. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  126. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  127. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  128. package/harness/bundles/java/codex/harness-execute/SKILL.md +1 -1
  129. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  130. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  131. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  132. package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
  133. package/harness/bundles/java/codex/harness-pull/SKILL.md +1 -1
  134. package/harness/bundles/java/codex/harness-push/SKILL.md +1 -1
  135. package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
  136. package/harness/bundles/java/codex/harness-submit/SKILL.md +2 -2
  137. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  138. package/harness/bundles/java/codex/scripts/harness_archive.py +18 -11
  139. package/harness/bundles/java/codex/scripts/harness_gate.py +69 -1
  140. package/harness/bundles/java/codex/scripts/harness_knowledge_candidates.py +58 -12
  141. package/harness/bundles/java/codex/scripts/harness_ledger.py +27 -3
  142. package/harness/bundles/java/codex/scripts/harness_review.py +16 -2
  143. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  144. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  145. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  146. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  147. package/harness/bundles/java/cursor/harness-execute/SKILL.md +1 -1
  148. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  149. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  150. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  151. package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
  152. package/harness/bundles/java/cursor/harness-pull/SKILL.md +1 -1
  153. package/harness/bundles/java/cursor/harness-push/SKILL.md +1 -1
  154. package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
  155. package/harness/bundles/java/cursor/harness-submit/SKILL.md +2 -2
  156. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  157. package/harness/bundles/java/cursor/scripts/harness_archive.py +18 -11
  158. package/harness/bundles/java/cursor/scripts/harness_gate.py +69 -1
  159. package/harness/bundles/java/cursor/scripts/harness_knowledge_candidates.py +58 -12
  160. package/harness/bundles/java/cursor/scripts/harness_ledger.py +27 -3
  161. package/harness/bundles/java/cursor/scripts/harness_review.py +16 -2
  162. package/harness/bundles/java/pi/.harness-build.json +1 -1
  163. package/harness/bundles/java/pi/harness-apidoc/SKILL.md +1 -1
  164. package/harness/bundles/java/pi/harness-archive/SKILL.md +1 -1
  165. package/harness/bundles/java/pi/harness-codebase-map/SKILL.md +1 -1
  166. package/harness/bundles/java/pi/harness-execute/SKILL.md +1 -1
  167. package/harness/bundles/java/pi/harness-knowledge-ingest/SKILL.md +1 -1
  168. package/harness/bundles/java/pi/harness-knowledge-query/SKILL.md +1 -1
  169. package/harness/bundles/java/pi/harness-package/SKILL.md +1 -1
  170. package/harness/bundles/java/pi/harness-plan/SKILL.md +1 -1
  171. package/harness/bundles/java/pi/harness-pull/SKILL.md +1 -1
  172. package/harness/bundles/java/pi/harness-push/SKILL.md +1 -1
  173. package/harness/bundles/java/pi/harness-review/SKILL.md +1 -1
  174. package/harness/bundles/java/pi/harness-submit/SKILL.md +2 -2
  175. package/harness/bundles/java/pi/harness-sync/SKILL.md +1 -1
  176. package/harness/bundles/java/pi/scripts/harness_archive.py +18 -11
  177. package/harness/bundles/java/pi/scripts/harness_gate.py +69 -1
  178. package/harness/bundles/java/pi/scripts/harness_knowledge_candidates.py +58 -12
  179. package/harness/bundles/java/pi/scripts/harness_ledger.py +27 -3
  180. package/harness/bundles/java/pi/scripts/harness_review.py +16 -2
  181. package/harness/manifests/general/claude-code.json +17 -17
  182. package/harness/manifests/general/codebuddy.json +17 -17
  183. package/harness/manifests/general/codex.json +17 -17
  184. package/harness/manifests/general/cursor.json +17 -17
  185. package/harness/manifests/general/pi.json +17 -17
  186. package/harness/manifests/java/claude-code.json +19 -19
  187. package/harness/manifests/java/codebuddy.json +19 -19
  188. package/harness/manifests/java/codex.json +19 -19
  189. package/harness/manifests/java/cursor.json +19 -19
  190. package/harness/manifests/java/pi.json +19 -19
  191. package/hunter-workflow-family.json +2 -2
  192. package/package.json +1 -1
@@ -2,5 +2,5 @@
2
2
  "schemaVersion": 1,
3
3
  "overlay": "none",
4
4
  "agent": "claude-code",
5
- "coreHash": "cdc01b6329bacd46"
5
+ "coreHash": "dbe8841e3e01b1c7"
6
6
  }
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-archive — 变更归档
26
26
 
27
27
  ## Purpose
@@ -20,7 +20,7 @@ disallowed-tools:
20
20
  - Bash(awk *)
21
21
  - Bash(curl *)
22
22
  ---
23
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
23
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
24
24
  # harness-codebase-map — 代码库地图
25
25
 
26
26
  ## Purpose
@@ -23,7 +23,7 @@ disallowed-tools:
23
23
  - Bash(node *)
24
24
  - Bash(codegraph *)
25
25
  ---
26
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
26
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
27
27
  # harness-execute — 执行(编码 + 验证)
28
28
 
29
29
  > 2026-08 阶段合并:原 `run`(编码)与 `test`(验证)合并为单一 `execute` 阶段;
@@ -8,7 +8,7 @@ disallowed-tools:
8
8
  - Bash(git *)
9
9
  - Bash(curl *)
10
10
  ---
11
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
11
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
12
12
  # harness-knowledge-ingest
13
13
 
14
14
  知识 ingest 完全由 Hunter Platform 负责。归档完成时,客户端生成一个确定性 ZIP;
@@ -8,7 +8,7 @@ disallowed-tools:
8
8
  - Bash(git *)
9
9
  - Bash(curl *)
10
10
  ---
11
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
11
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
12
12
  # harness-knowledge-query
13
13
 
14
14
  项目知识以 Hunter Platform 的服务端索引为唯一真源。客户端只提交查询并消费结果:
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-plan — 需求规划
26
26
 
27
27
  ## Purpose
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-pull — 从 Hunter Platform 下拉与恢复
26
26
 
27
27
  ## Purpose
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-push — 上传到 Hunter Platform
26
26
 
27
27
  ## Purpose
@@ -22,7 +22,7 @@ disallowed-tools:
22
22
  - Bash(curl *)
23
23
  - Bash(codegraph *)
24
24
  ---
25
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
25
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
26
26
  # harness-review — 代码审查
27
27
 
28
28
  ## Purpose
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-submit — 最终提交(含 worktree 合并)
26
26
 
27
27
  ## Purpose
@@ -83,7 +83,7 @@ worktree 合并前必须运行 `harness_change.py integration-lock acquire --run
83
83
  4. **提交方式** — 主目录:blocking user confirmation 三选项(commit+push / 仅本地 / 取消);**worktree:固定仅本地 commit**
84
84
  5. **commit-message.txt** ⚠️ — 展示 staged、diff stat、完整中文 message;用户确认
85
85
  6. **commit / push** — `git commit -F`;主目录按选项 push(push 前 fetch 检查远端);无 upstream 时允许仅本地 commit。commit 后立即重新运行 `harness_archive.py certify-local`:若验证输入未变化,脚本把候选从提交前身份安全重绑定到最终 commit,不得重跑测试或手工复制账本;**worktree:只 commit,记录 local hash**
86
- 7. **收尾** — `harness_gate.py close --phase submit --status ... --to-phase <实际计划后继>`;通常后继为 Archive,但不得显示“等待 merge”或固定写死。主目录停止并提示真实下一阶段;worktree 才接续下方同一 Submit 内的合并流程。
86
+ 7. **收尾** — `harness_gate.py close --phase submit --status ... --to-phase <实际计划后继>`;通常后继为 Archive,但不得显示“等待 merge”或固定写死。主目录停止并提示真实下一阶段;worktree 才接续下方同一 Submit 内的合并流程。`--json` 的 stdout 只含 JSON;关门摘要横幅在 stderr——管道给 `jq` 时**不要** `2>&1` 合并(stderr 不缓冲会先写,合并后横幅会混进 JSON 流)。
87
87
 
88
88
  详细步骤见 `checklist.md`。
89
89
 
@@ -19,7 +19,7 @@ disallowed-tools:
19
19
  - Bash(awk *)
20
20
  - Bash(curl *)
21
21
  ---
22
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
22
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=claude-code; do not edit -->
23
23
  # harness-sync
24
24
 
25
25
  ## Purpose
@@ -3010,8 +3010,12 @@ def check_status(
3010
3010
  if archive_intent == "record-only"
3011
3011
  else str(ci_gate.get("code") or "PRODUCT_CANDIDATE_NOT_VERIFIED")
3012
3012
  ),
3013
- "message": str(
3014
- ci_gate.get("message") or "product candidate not verified"
3013
+ "message": (
3014
+ # A-2:record-only 豁免阻断,但原文透传授权要求会误读成阻断指引
3015
+ "record-only 归档不要求发布授权,本项仅记录:"
3016
+ + str(ci_gate.get("message") or "product candidate not verified")
3017
+ if archive_intent == "record-only"
3018
+ else str(ci_gate.get("message") or "product candidate not verified")
3015
3019
  ),
3016
3020
  }
3017
3021
  if archive_intent == "record-only":
@@ -3104,15 +3108,18 @@ def check_status(
3104
3108
  code = str(issue.get("code") or "REPORT_ADEQUACY_FAILED")
3105
3109
  if any(item.get("code") == code for item in blockers):
3106
3110
  continue
3107
- blockers.append(
3108
- {
3109
- "code": code,
3110
- "message": adequacy_messages_zh.get(
3111
- code,
3112
- str(issue.get("message") or "归档报告不完整"),
3113
- ),
3114
- }
3115
- )
3111
+ blocker: dict[str, Any] = {
3112
+ "code": code,
3113
+ "message": adequacy_messages_zh.get(
3114
+ code,
3115
+ str(issue.get("message") or "归档报告不完整"),
3116
+ ),
3117
+ }
3118
+ # A-3:出路必须随阻断项下发(对齐 SKILL 二·A 表),不再让使用者翻文档
3119
+ next_action = issue.get("nextAction")
3120
+ if isinstance(next_action, str) and next_action.strip():
3121
+ blocker["recoveryAction"] = next_action.strip()
3122
+ blockers.append(blocker)
3116
3123
  for issue in report_adequacy.get("issues") or []:
3117
3124
  if not isinstance(issue, dict) or issue.get("severity") != "warning":
3118
3125
  continue
@@ -2085,6 +2085,52 @@ def _terminal_matches_context_session(
2085
2085
  )
2086
2086
 
2087
2087
 
2088
+ def _repair_handoff_missing_lease(
2089
+ project: Path,
2090
+ change_id: str,
2091
+ args: argparse.Namespace,
2092
+ *,
2093
+ status: str,
2094
+ handoff: dict[str, Any],
2095
+ ) -> dict[str, Any] | None:
2096
+ """S-1:交接因 context 租约缺失失败时自愈一次。
2097
+
2098
+ 阶段租约仍持有但 context 租约已被消费/缺失时,close_transition 只能报
2099
+ CONTEXT_LEASE_REQUIRED——原样重跑永远撞同一错误(2026-08-31 submit 实测,
2100
+ recoveryAction 声称“会重试”但重试无自愈能力)。这里补齐缺口:
2101
+ prepare_context 幂等重建本阶段 context 租约后重试一次交接,与
2102
+ `harness_context.py handoff` 命令同源(同 prepare→close 顺序)。
2103
+ """
2104
+ if handoff.get("code") != "CONTEXT_LEASE_REQUIRED":
2105
+ return None
2106
+ executor = getattr(args, "executor", None)
2107
+ if not executor:
2108
+ view = hctx.context_view(project, change_id)
2109
+ current = view.get("current") if isinstance(view, dict) else None
2110
+ executor = (
2111
+ str(current.get("executor"))
2112
+ if isinstance(current, dict) and current.get("executor")
2113
+ else None
2114
+ )
2115
+ if not executor:
2116
+ return None
2117
+ try:
2118
+ prepared = hctx.prepare_context(
2119
+ project,
2120
+ change=change_id,
2121
+ phase=args.phase,
2122
+ executor=executor,
2123
+ )
2124
+ except Exception:
2125
+ return None
2126
+ if not prepared.get("ok"):
2127
+ return None
2128
+ repaired = _close_context_handoff(project, change_id, args, status=status)
2129
+ if isinstance(repaired, dict):
2130
+ repaired = {**repaired, "leaseRepaired": True}
2131
+ return repaired
2132
+
2133
+
2088
2134
  def _close_context_handoff(
2089
2135
  project: Path,
2090
2136
  change_id: str,
@@ -3154,6 +3200,14 @@ def _resume_closed_phase(
3154
3200
  status=close_status,
3155
3201
  )
3156
3202
  monitor = _sync_after_phase_close(project, change_dir)
3203
+ if isinstance(handoff, dict) and not handoff.get("ok"):
3204
+ # S-1:续跑路径同样的自愈
3205
+ repaired = _repair_handoff_missing_lease(
3206
+ project, change_id, args,
3207
+ status=close_status, handoff=handoff,
3208
+ )
3209
+ if repaired is not None:
3210
+ handoff = repaired
3157
3211
  if isinstance(handoff, dict) and not handoff.get("ok"):
3158
3212
  return emit_error(
3159
3213
  "PHASE_HANDOFF_PENDING",
@@ -3737,6 +3791,15 @@ def cmd_close(args: argparse.Namespace) -> int:
3737
3791
  status=close_status,
3738
3792
  )
3739
3793
  platform_monitor = _sync_after_phase_close(project, change_dir)
3794
+ if isinstance(context_handoff, dict) and not context_handoff.get("ok"):
3795
+ # S-1:context 租约缺失时自愈一次(prepare 幂等重建 + 重试交接),
3796
+ # 修复前“原样重跑”永远撞同一个 CONTEXT_LEASE_REQUIRED
3797
+ repaired = _repair_handoff_missing_lease(
3798
+ project, str(resolved["changeId"]), args,
3799
+ status=close_status, handoff=context_handoff,
3800
+ )
3801
+ if repaired is not None:
3802
+ context_handoff = repaired
3740
3803
  if isinstance(context_handoff, dict) and not context_handoff.get("ok"):
3741
3804
  record_gate_blocked(
3742
3805
  change_dir,
@@ -3759,7 +3822,12 @@ def cmd_close(args: argparse.Namespace) -> int:
3759
3822
  "platformMonitor": platform_monitor,
3760
3823
  "recoveryAction": (
3761
3824
  "租约仍持有,无需重新 claim——原样重跑同一 close 命令即可幂等续跑"
3762
- "(phase.end 已落会跳过,handoff 会重试)"
3825
+ "(phase.end 已落会跳过,handoff 会重试;context 租约缺失时会自动"
3826
+ "补建)。仍失败时用一条命令补齐交接:"
3827
+ "harness_context.py handoff --project . "
3828
+ f"--change {resolved['changeId']} --to-phase "
3829
+ f"{getattr(args, 'to_phase', None) or '<后继阶段>'} "
3830
+ "--executor <tool> --json"
3763
3831
  ),
3764
3832
  },
3765
3833
  )
@@ -30,6 +30,8 @@ from __future__ import annotations
30
30
 
31
31
  import hashlib
32
32
  import json
33
+ import re
34
+ import sys
33
35
  from typing import Any
34
36
 
35
37
  SCHEMA_VERSION = 1
@@ -44,6 +46,44 @@ _DISPOSITION_ENTRY_TYPES = {
44
46
  "DEFERRED": "risk",
45
47
  }
46
48
  _SEVERITY_CONFIDENCE = {"RED": 0.95, "YELLOW": 0.85}
49
+
50
+
51
+ def _valid_source_path(path: Any) -> str | None:
52
+ """source_ref 的结构校验(与服务端 ARCHIVE_CANDIDATE_SOURCE_UNBOUND 同规则)。
53
+
54
+ 合法形态:`relative/path/to/file.ext`(调用方再附 `#L<line>`)。
55
+ 拒绝:目录引用(尾部斜杠)、空路径段、`.`/`..` 段、绝对路径、盘符、
56
+ 反斜杠。返回规范化路径;不合法返回 None——调用方必须跳过该候选,
57
+ 不得生成「目录 + 行号」的伪来源(2026-08-31 demo-datasource 实测:
58
+ `quality/#L1` 一条不合法 ref 挡掉整份 42 条候选的包)。
59
+ """
60
+ if not isinstance(path, str):
61
+ return None
62
+ raw = path.strip()
63
+ if not raw:
64
+ return None
65
+ if "\\" in raw: # 反斜杠路径不合法(服务端拒绝,不做静默转换)
66
+ return None
67
+ if raw.startswith("/") or re.match(r"^[A-Za-z]:", raw):
68
+ return None
69
+ if raw.endswith("/"): # 目录引用——尾部斜杠形成空路径段
70
+ return None
71
+ segments = raw.split("/")
72
+ if any(segment in ("", ".", "..") for segment in segments):
73
+ return None
74
+ return raw
75
+
76
+
77
+ def _bound_source_refs(path: Any, line: Any, archive_id: str) -> list[str] | None:
78
+ """构造可绑定文件来源;path 缺失时回退 archive 级来源,非法时返回 None。"""
79
+ if not path or not isinstance(path, str) or not path.strip():
80
+ return [f"archive:{archive_id}"]
81
+ valid = _valid_source_path(path)
82
+ if valid is None:
83
+ return None
84
+ if isinstance(line, int) and line > 0:
85
+ return [f"{valid}#L{line}"]
86
+ return [valid]
47
87
  _KNOWN_RISK_CONFIDENCE = 0.85
48
88
 
49
89
  # decisions[](来自 change 的 evidence/decisions.json,经 summary.decisions 传入)
@@ -141,12 +181,16 @@ def _finding_candidate(
141
181
  disposition,
142
182
  )
143
183
  source_ref = f"archive:{archive_id}#{finding_id}" if finding_id else f"archive:{archive_id}"
144
- if path and location != path:
145
- source_refs = [f"{path}#L{line}"]
146
- elif path:
147
- source_refs = [path]
148
- else:
149
- source_refs = [f"archive:{archive_id}"]
184
+ source_refs = _bound_source_refs(path, line, archive_id)
185
+ if source_refs is None:
186
+ # 目录/非法路径——跳过整条候选,不生成伪来源(服务端会拒绝整包);
187
+ # 跳过必须可见,否则「少了一条候选」无从追溯
188
+ print(
189
+ "[harness-knowledge-candidates] 跳过候选:source_refs 非法"
190
+ f"(path={path!r},finding={finding_id or title!r})",
191
+ file=sys.stderr,
192
+ )
193
+ return None
150
194
 
151
195
  return {
152
196
  "schema_version": SCHEMA_VERSION,
@@ -266,12 +310,14 @@ def _decision_candidate(
266
310
  segments[-2] if len(segments) >= 2 else "",
267
311
  entry_type,
268
312
  )
269
- if path and location != path:
270
- source_refs = [f"{path}#L{line}"]
271
- elif path:
272
- source_refs = [path]
273
- else:
274
- source_refs = [f"archive:{archive_id}"]
313
+ source_refs = _bound_source_refs(path, line, archive_id)
314
+ if source_refs is None:
315
+ print(
316
+ "[harness-knowledge-candidates] 跳过候选:source_refs 非法"
317
+ f"(path={path!r})",
318
+ file=sys.stderr,
319
+ )
320
+ return None
275
321
 
276
322
  return {
277
323
  "schema_version": SCHEMA_VERSION,
@@ -2565,6 +2565,20 @@ def cmd_can_reuse(args: argparse.Namespace) -> int:
2565
2565
  return 0
2566
2566
 
2567
2567
 
2568
+ def _profile_input_missing_warning(
2569
+ verification: str, target: Any, profile_input: str | None
2570
+ ) -> str | None:
2571
+ """S-4:profile 声明了 target 却没带 --profile-input 时提前预警。"""
2572
+ if profile_input or not isinstance(target, dict):
2573
+ return None
2574
+ return (
2575
+ "PROFILE_INPUT_MISSING: 未传 --profile-input,本条记录缺少 profile 推导的"
2576
+ " scope/coverage/inputsHash 身份字段,can-reuse 将无法复用。建议重跑:"
2577
+ f"record --verification {verification} --profile-input <key> --project . "
2578
+ "(key 见 build-profile.json verificationInputs)"
2579
+ )
2580
+
2581
+
2568
2582
  def cmd_record(args: argparse.Namespace) -> int:
2569
2583
  as_json = bool(args.json)
2570
2584
  verbose = bool(getattr(args, "verbose", False))
@@ -2612,6 +2626,11 @@ def cmd_record(args: argparse.Namespace) -> int:
2612
2626
  "verificationGraph.targets",
2613
2627
  as_json=as_json,
2614
2628
  )
2629
+ # S-4:profile 声明了 target 却没带 --profile-input,条目缺身份字段,
2630
+ # can-reuse 事后才报 MISSING_FIELDS——只能重跑一遍(2026-08-31 实测)。
2631
+ profile_input_missing_warn = _profile_input_missing_warning(
2632
+ verification, target, profile_input
2633
+ )
2615
2634
  if profile_input:
2616
2635
  resolved_files, err = expand_profile_input_files(project_root, profile_input)
2617
2636
  if err:
@@ -3068,9 +3087,14 @@ def cmd_record(args: argparse.Namespace) -> int:
3068
3087
  zero_warn = _zero_tests_with_selector_warning(
3069
3088
  str(args.command), args.evidence, project_root
3070
3089
  )
3071
- if zero_warn is not None:
3072
- payload["warnings"] = [zero_warn]
3073
- print(f"[harness-ledger] WARNING {zero_warn}", file=sys.stderr)
3090
+ record_warnings = [
3091
+ warning for warning in (zero_warn, profile_input_missing_warn)
3092
+ if warning is not None
3093
+ ]
3094
+ if record_warnings:
3095
+ payload["warnings"] = record_warnings
3096
+ for warning in record_warnings:
3097
+ print(f"[harness-ledger] WARNING {warning}", file=sys.stderr)
3074
3098
  emit_compact_or_verbose(
3075
3099
  payload, as_json=as_json, verbose=verbose,
3076
3100
  compact_fn=_compact_record_payload,
@@ -176,10 +176,24 @@ def write_findings(change_dir: Path, doc: dict[str, Any]) -> dict[str, Any]:
176
176
  "changeName": doc.get("changeName") or Path(change_dir).name,
177
177
  "findings": assigned,
178
178
  }
179
+ # 目录路径的 finding 下游产不出可绑定的知识候选(source_refs 会拒整包),
180
+ # 写入时提前可见——demo-datasource 的 quality/#L1 就是这么漏出去的
181
+ directory_paths = [
182
+ str(f.get("path"))
183
+ for f in assigned
184
+ if isinstance(f.get("path"), str) and f["path"].rstrip().endswith("/")
185
+ ]
179
186
  out = findings_path(change_dir)
180
187
  _write_json_atomic(out, payload)
181
- return {"ok": True, "code": "FINDINGS_WRITTEN", "path": str(out),
182
- "count": len(assigned)}
188
+ result = {"ok": True, "code": "FINDINGS_WRITTEN", "path": str(out),
189
+ "count": len(assigned)}
190
+ if directory_paths:
191
+ result["warnings"] = [
192
+ "以下 finding 的 path 是目录而非文件,知识候选生成时会整条跳过"
193
+ "(source_refs 无法绑定文件):" + "; ".join(directory_paths) +
194
+ "。请改为具体文件路径后重新写入"
195
+ ]
196
+ return result
183
197
 
184
198
 
185
199
  def _load_findings(change_dir: Path) -> dict[str, Any] | None:
@@ -2,5 +2,5 @@
2
2
  "schemaVersion": 1,
3
3
  "overlay": "none",
4
4
  "agent": "codebuddy",
5
- "coreHash": "cdc01b6329bacd46"
5
+ "coreHash": "dbe8841e3e01b1c7"
6
6
  }
@@ -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=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-archive — 变更归档
8
8
 
9
9
  ## Purpose
@@ -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=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-codebase-map — 代码库地图
8
8
 
9
9
  ## Purpose
@@ -4,7 +4,7 @@ description: 执行阶段:按变更簇执行 TDD
4
4
  编码循环(RED→GREEN→REFACTOR→编译验证),随后完成单元/接口/数据兼容验证并输出测试报告。仅当用户显式调用
5
5
  /harness-execute 时使用;不得因用户提到编码/实现/测试就自动触发,也不得被其他阶段 skill 自动接续。
6
6
  ---
7
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
7
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=codebuddy; do not edit -->
8
8
  # harness-execute — 执行(编码 + 验证)
9
9
 
10
10
  > 2026-08 阶段合并:原 `run`(编码)与 `test`(验证)合并为单一 `execute` 阶段;
@@ -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=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
5
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; 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=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
5
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=codebuddy; do not edit -->
6
6
  # harness-knowledge-query
7
7
 
8
8
  项目知识以 Hunter Platform 的服务端索引为唯一真源。客户端只提交查询并消费结果:
@@ -3,7 +3,7 @@ name: harness-plan
3
3
  description: 将需求转化为设计文档+实施计划+完整测试场景表,必须在编码前完成。仅当用户显式调用 /harness-plan 或明确要求进入
4
4
  Harness 规划阶段时使用;不得因用户描述需求就自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-plan — 需求规划
8
8
 
9
9
  ## Purpose
@@ -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=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; 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=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; 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=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
7
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=codebuddy; do not edit -->
8
8
  # harness-review — 代码审查
9
9
 
10
10
  ## Purpose
@@ -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=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-submit — 最终提交(含 worktree 合并)
8
8
 
9
9
  ## Purpose
@@ -65,7 +65,7 @@ worktree 合并前必须运行 `harness_change.py integration-lock acquire --run
65
65
  4. **提交方式** — 主目录:blocking user confirmation 三选项(commit+push / 仅本地 / 取消);**worktree:固定仅本地 commit**
66
66
  5. **commit-message.txt** ⚠️ — 展示 staged、diff stat、完整中文 message;用户确认
67
67
  6. **commit / push** — `git commit -F`;主目录按选项 push(push 前 fetch 检查远端);无 upstream 时允许仅本地 commit。commit 后立即重新运行 `harness_archive.py certify-local`:若验证输入未变化,脚本把候选从提交前身份安全重绑定到最终 commit,不得重跑测试或手工复制账本;**worktree:只 commit,记录 local hash**
68
- 7. **收尾** — `harness_gate.py close --phase submit --status ... --to-phase <实际计划后继>`;通常后继为 Archive,但不得显示“等待 merge”或固定写死。主目录停止并提示真实下一阶段;worktree 才接续下方同一 Submit 内的合并流程。
68
+ 7. **收尾** — `harness_gate.py close --phase submit --status ... --to-phase <实际计划后继>`;通常后继为 Archive,但不得显示“等待 merge”或固定写死。主目录停止并提示真实下一阶段;worktree 才接续下方同一 Submit 内的合并流程。`--json` 的 stdout 只含 JSON;关门摘要横幅在 stderr——管道给 `jq` 时**不要** `2>&1` 合并(stderr 不缓冲会先写,合并后横幅会混进 JSON 流)。
69
69
 
70
70
  详细步骤见 `checklist.md`。
71
71
 
@@ -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=cdc01b6329bacd46; overlay=none; agent=codebuddy; do not edit -->
7
+ <!-- generated by harness_deploy.py; core=dbe8841e3e01b1c7; overlay=none; agent=codebuddy; do not edit -->
8
8
  # harness-sync
9
9
 
10
10
  ## Purpose
@@ -3010,8 +3010,12 @@ def check_status(
3010
3010
  if archive_intent == "record-only"
3011
3011
  else str(ci_gate.get("code") or "PRODUCT_CANDIDATE_NOT_VERIFIED")
3012
3012
  ),
3013
- "message": str(
3014
- ci_gate.get("message") or "product candidate not verified"
3013
+ "message": (
3014
+ # A-2:record-only 豁免阻断,但原文透传授权要求会误读成阻断指引
3015
+ "record-only 归档不要求发布授权,本项仅记录:"
3016
+ + str(ci_gate.get("message") or "product candidate not verified")
3017
+ if archive_intent == "record-only"
3018
+ else str(ci_gate.get("message") or "product candidate not verified")
3015
3019
  ),
3016
3020
  }
3017
3021
  if archive_intent == "record-only":
@@ -3104,15 +3108,18 @@ def check_status(
3104
3108
  code = str(issue.get("code") or "REPORT_ADEQUACY_FAILED")
3105
3109
  if any(item.get("code") == code for item in blockers):
3106
3110
  continue
3107
- blockers.append(
3108
- {
3109
- "code": code,
3110
- "message": adequacy_messages_zh.get(
3111
- code,
3112
- str(issue.get("message") or "归档报告不完整"),
3113
- ),
3114
- }
3115
- )
3111
+ blocker: dict[str, Any] = {
3112
+ "code": code,
3113
+ "message": adequacy_messages_zh.get(
3114
+ code,
3115
+ str(issue.get("message") or "归档报告不完整"),
3116
+ ),
3117
+ }
3118
+ # A-3:出路必须随阻断项下发(对齐 SKILL 二·A 表),不再让使用者翻文档
3119
+ next_action = issue.get("nextAction")
3120
+ if isinstance(next_action, str) and next_action.strip():
3121
+ blocker["recoveryAction"] = next_action.strip()
3122
+ blockers.append(blocker)
3116
3123
  for issue in report_adequacy.get("issues") or []:
3117
3124
  if not isinstance(issue, dict) or issue.get("severity") != "warning":
3118
3125
  continue