@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.
- package/harness/bundles/general/claude-code/.harness-build.json +1 -1
- package/harness/bundles/general/claude-code/harness-archive/SKILL.md +11 -4
- package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-plan/SKILL.md +3 -2
- package/harness/bundles/general/claude-code/harness-plan/checklist.md +18 -79
- package/harness/bundles/general/claude-code/harness-plan/protocols.md +3 -1
- package/harness/bundles/general/claude-code/harness-plan/reference.md +37 -8
- package/harness/bundles/general/claude-code/harness-pull/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-push/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-run/SKILL.md +6 -4
- package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/claude-code/scripts/harness_archive.py +58 -25
- package/harness/bundles/general/claude-code/scripts/harness_change.py +25 -7
- package/harness/bundles/general/claude-code/scripts/harness_context.py +62 -19
- package/harness/bundles/general/claude-code/scripts/harness_fixback.py +4 -0
- package/harness/bundles/general/claude-code/scripts/harness_gate.py +208 -72
- package/harness/bundles/general/claude-code/scripts/harness_ledger.py +43 -0
- package/harness/bundles/general/claude-code/scripts/harness_paths.py +60 -0
- package/harness/bundles/general/claude-code/scripts/harness_phase.py +24 -6
- package/harness/bundles/general/claude-code/scripts/harness_plan_finalize.py +124 -1
- package/harness/bundles/general/claude-code/scripts/harness_review.py +25 -4
- package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +11 -4
- package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +3 -2
- package/harness/bundles/general/codebuddy/harness-plan/checklist.md +18 -79
- package/harness/bundles/general/codebuddy/harness-plan/protocols.md +3 -1
- package/harness/bundles/general/codebuddy/harness-plan/reference.md +37 -8
- package/harness/bundles/general/codebuddy/harness-pull/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-push/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-run/SKILL.md +6 -4
- package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/scripts/harness_archive.py +58 -25
- package/harness/bundles/general/codebuddy/scripts/harness_change.py +25 -7
- package/harness/bundles/general/codebuddy/scripts/harness_context.py +62 -19
- package/harness/bundles/general/codebuddy/scripts/harness_fixback.py +4 -0
- package/harness/bundles/general/codebuddy/scripts/harness_gate.py +208 -72
- package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +43 -0
- package/harness/bundles/general/codebuddy/scripts/harness_paths.py +60 -0
- package/harness/bundles/general/codebuddy/scripts/harness_phase.py +24 -6
- package/harness/bundles/general/codebuddy/scripts/harness_plan_finalize.py +124 -1
- package/harness/bundles/general/codebuddy/scripts/harness_review.py +25 -4
- package/harness/bundles/general/codex/.harness-build.json +1 -1
- package/harness/bundles/general/codex/harness-archive/SKILL.md +11 -4
- package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-plan/SKILL.md +3 -2
- package/harness/bundles/general/codex/harness-plan/checklist.md +18 -79
- package/harness/bundles/general/codex/harness-plan/protocols.md +3 -1
- package/harness/bundles/general/codex/harness-plan/reference.md +37 -8
- package/harness/bundles/general/codex/harness-pull/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-push/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-run/SKILL.md +6 -4
- package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/codex/scripts/harness_archive.py +58 -25
- package/harness/bundles/general/codex/scripts/harness_change.py +25 -7
- package/harness/bundles/general/codex/scripts/harness_context.py +62 -19
- package/harness/bundles/general/codex/scripts/harness_fixback.py +4 -0
- package/harness/bundles/general/codex/scripts/harness_gate.py +208 -72
- package/harness/bundles/general/codex/scripts/harness_ledger.py +43 -0
- package/harness/bundles/general/codex/scripts/harness_paths.py +60 -0
- package/harness/bundles/general/codex/scripts/harness_phase.py +24 -6
- package/harness/bundles/general/codex/scripts/harness_plan_finalize.py +124 -1
- package/harness/bundles/general/codex/scripts/harness_review.py +25 -4
- package/harness/bundles/general/cursor/.harness-build.json +1 -1
- package/harness/bundles/general/cursor/harness-archive/SKILL.md +11 -4
- package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-plan/SKILL.md +3 -2
- package/harness/bundles/general/cursor/harness-plan/checklist.md +18 -79
- package/harness/bundles/general/cursor/harness-plan/protocols.md +3 -1
- package/harness/bundles/general/cursor/harness-plan/reference.md +37 -8
- package/harness/bundles/general/cursor/harness-pull/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-push/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-run/SKILL.md +6 -4
- package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
- package/harness/bundles/general/cursor/scripts/harness_archive.py +58 -25
- package/harness/bundles/general/cursor/scripts/harness_change.py +25 -7
- package/harness/bundles/general/cursor/scripts/harness_context.py +62 -19
- package/harness/bundles/general/cursor/scripts/harness_fixback.py +4 -0
- package/harness/bundles/general/cursor/scripts/harness_gate.py +208 -72
- package/harness/bundles/general/cursor/scripts/harness_ledger.py +43 -0
- package/harness/bundles/general/cursor/scripts/harness_paths.py +60 -0
- package/harness/bundles/general/cursor/scripts/harness_phase.py +24 -6
- package/harness/bundles/general/cursor/scripts/harness_plan_finalize.py +124 -1
- package/harness/bundles/general/cursor/scripts/harness_review.py +25 -4
- package/harness/bundles/java/claude-code/.harness-build.json +1 -1
- package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-archive/SKILL.md +11 -4
- package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-plan/SKILL.md +3 -2
- package/harness/bundles/java/claude-code/harness-plan/checklist.md +18 -79
- package/harness/bundles/java/claude-code/harness-plan/protocols.md +3 -1
- package/harness/bundles/java/claude-code/harness-plan/reference.md +37 -8
- package/harness/bundles/java/claude-code/harness-pull/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-push/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-run/SKILL.md +6 -4
- package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/claude-code/scripts/harness_archive.py +58 -25
- package/harness/bundles/java/claude-code/scripts/harness_change.py +25 -7
- package/harness/bundles/java/claude-code/scripts/harness_context.py +62 -19
- package/harness/bundles/java/claude-code/scripts/harness_fixback.py +4 -0
- package/harness/bundles/java/claude-code/scripts/harness_gate.py +208 -72
- package/harness/bundles/java/claude-code/scripts/harness_ledger.py +43 -0
- package/harness/bundles/java/claude-code/scripts/harness_paths.py +60 -0
- package/harness/bundles/java/claude-code/scripts/harness_phase.py +24 -6
- package/harness/bundles/java/claude-code/scripts/harness_plan_finalize.py +124 -1
- package/harness/bundles/java/claude-code/scripts/harness_review.py +25 -4
- package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
- package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +11 -4
- package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +3 -2
- package/harness/bundles/java/codebuddy/harness-plan/checklist.md +18 -79
- package/harness/bundles/java/codebuddy/harness-plan/protocols.md +3 -1
- package/harness/bundles/java/codebuddy/harness-plan/reference.md +37 -8
- package/harness/bundles/java/codebuddy/harness-pull/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-push/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-run/SKILL.md +6 -4
- package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/codebuddy/scripts/harness_archive.py +58 -25
- package/harness/bundles/java/codebuddy/scripts/harness_change.py +25 -7
- package/harness/bundles/java/codebuddy/scripts/harness_context.py +62 -19
- package/harness/bundles/java/codebuddy/scripts/harness_fixback.py +4 -0
- package/harness/bundles/java/codebuddy/scripts/harness_gate.py +208 -72
- package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +43 -0
- package/harness/bundles/java/codebuddy/scripts/harness_paths.py +60 -0
- package/harness/bundles/java/codebuddy/scripts/harness_phase.py +24 -6
- package/harness/bundles/java/codebuddy/scripts/harness_plan_finalize.py +124 -1
- package/harness/bundles/java/codebuddy/scripts/harness_review.py +25 -4
- package/harness/bundles/java/codex/.harness-build.json +1 -1
- package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-archive/SKILL.md +11 -4
- package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-plan/SKILL.md +3 -2
- package/harness/bundles/java/codex/harness-plan/checklist.md +18 -79
- package/harness/bundles/java/codex/harness-plan/protocols.md +3 -1
- package/harness/bundles/java/codex/harness-plan/reference.md +37 -8
- package/harness/bundles/java/codex/harness-pull/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-push/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-run/SKILL.md +6 -4
- package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/codex/scripts/harness_archive.py +58 -25
- package/harness/bundles/java/codex/scripts/harness_change.py +25 -7
- package/harness/bundles/java/codex/scripts/harness_context.py +62 -19
- package/harness/bundles/java/codex/scripts/harness_fixback.py +4 -0
- package/harness/bundles/java/codex/scripts/harness_gate.py +208 -72
- package/harness/bundles/java/codex/scripts/harness_ledger.py +43 -0
- package/harness/bundles/java/codex/scripts/harness_paths.py +60 -0
- package/harness/bundles/java/codex/scripts/harness_phase.py +24 -6
- package/harness/bundles/java/codex/scripts/harness_plan_finalize.py +124 -1
- package/harness/bundles/java/codex/scripts/harness_review.py +25 -4
- package/harness/bundles/java/cursor/.harness-build.json +1 -1
- package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-archive/SKILL.md +11 -4
- package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-plan/SKILL.md +3 -2
- package/harness/bundles/java/cursor/harness-plan/checklist.md +18 -79
- package/harness/bundles/java/cursor/harness-plan/protocols.md +3 -1
- package/harness/bundles/java/cursor/harness-plan/reference.md +37 -8
- package/harness/bundles/java/cursor/harness-pull/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-push/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-run/SKILL.md +6 -4
- package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
- package/harness/bundles/java/cursor/scripts/harness_archive.py +58 -25
- package/harness/bundles/java/cursor/scripts/harness_change.py +25 -7
- package/harness/bundles/java/cursor/scripts/harness_context.py +62 -19
- package/harness/bundles/java/cursor/scripts/harness_fixback.py +4 -0
- package/harness/bundles/java/cursor/scripts/harness_gate.py +208 -72
- package/harness/bundles/java/cursor/scripts/harness_ledger.py +43 -0
- package/harness/bundles/java/cursor/scripts/harness_paths.py +60 -0
- package/harness/bundles/java/cursor/scripts/harness_phase.py +24 -6
- package/harness/bundles/java/cursor/scripts/harness_plan_finalize.py +124 -1
- package/harness/bundles/java/cursor/scripts/harness_review.py +25 -4
- package/harness/manifests/general/claude-code.json +27 -27
- package/harness/manifests/general/codebuddy.json +27 -27
- package/harness/manifests/general/codex.json +27 -27
- package/harness/manifests/general/cursor.json +27 -27
- package/harness/manifests/java/claude-code.json +29 -29
- package/harness/manifests/java/codebuddy.json +29 -29
- package/harness/manifests/java/codex.json +29 -29
- package/harness/manifests/java/cursor.json +29 -29
- package/hunter-workflow-family.json +4 -4
- package/package.json +1 -1
|
@@ -21,7 +21,7 @@ disallowed-tools:
|
|
|
21
21
|
- Bash(awk *)
|
|
22
22
|
- Bash(curl *)
|
|
23
23
|
---
|
|
24
|
-
<!-- generated by harness_deploy.py; core=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-archive — 变更归档
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -178,9 +178,16 @@ disallowed-tools:
|
|
|
178
178
|
> ⚠️ 行内标注是**申报**,不是绕过:它把"这是设计决策"写进文档本身,可审计、可追溯。
|
|
179
179
|
> **不要**为了过扫描去删改设计文档的事实内容——那是篡改证据。
|
|
180
180
|
>
|
|
181
|
-
>
|
|
182
|
-
>
|
|
183
|
-
>
|
|
181
|
+
> ✅ 行内标注**服务端确认生效**:平台归档入口跑的是同一个 `scanSensitiveFiles`,
|
|
182
|
+
> 它直接从文件内容里解析 `hunter-harness-ignore`,命中转为 `overridden`、不再阻断。
|
|
183
|
+
> 上传端点只收裸 ZIP、没有独立申报通道,靠的就是这条写在文档里的标注。
|
|
184
|
+
>
|
|
185
|
+
> ⚠️ 一处已知的服务端滞后:**不带凭据的连接串**(如 `postgres://dbhost:5432/appdb`)
|
|
186
|
+
> 本地预检判 `low`/可豁免,而线上服务端目前仍判 `high`——high 不接受行内标注,
|
|
187
|
+
> 这类设计文档暂时无法上传。平台侧修复已提交(见 hunter-platform
|
|
188
|
+
> `fix(archive): 归档 422 给出可执行出路`),**部署后**两侧一致。在那之前遇到这一条:
|
|
189
|
+
> 等平台部署,不要为了过扫描删掉连接串。带凭据的连接串(`user:pass@host`)两侧都是
|
|
190
|
+
> `high`,必须真正脱敏。
|
|
184
191
|
|
|
185
192
|
### 二·B、归档补传(上传失败或历史归档缺条目)
|
|
186
193
|
|
|
@@ -20,7 +20,7 @@ disallowed-tools:
|
|
|
20
20
|
- Bash(awk *)
|
|
21
21
|
- Bash(curl *)
|
|
22
22
|
---
|
|
23
|
-
<!-- generated by harness_deploy.py; core=
|
|
23
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; overlay=none; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-codebase-map — 代码库地图
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -8,7 +8,7 @@ disallowed-tools:
|
|
|
8
8
|
- Bash(git *)
|
|
9
9
|
- Bash(curl *)
|
|
10
10
|
---
|
|
11
|
-
<!-- generated by harness_deploy.py; core=
|
|
11
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; 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=
|
|
11
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; 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=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-plan — 需求规划
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -88,7 +88,7 @@ disallowed-tools:
|
|
|
88
88
|
| 0 | git status;脏工作区 → baseline 隔离 + `decision`,不询问。环境体检并入 0.5 的引导命令,不再单独跑 doctor |
|
|
89
89
|
| 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` |
|
|
90
90
|
| 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 写到项目根 |
|
|
91
|
-
| 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
|
|
91
|
+
| 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` 显式升档 |
|
|
92
92
|
| 1 | 直接执行一次 `npx hunter-harness knowledge query "<用户需求原文>" --limit 10 --json`。这是唯一执行入口,不扫描技能目录、不查找其他脚本;失败记 `issue` 并继续,不建立本地索引或离线回退 |
|
|
93
93
|
| 2 | 歧义优先检查 + 复杂度分级;先确认会改变实现方向的语义歧义 |
|
|
94
94
|
| 3 | 按复杂度执行有预算的代码探索;简单修复不得扩散到无关模块 |
|
|
@@ -124,6 +124,7 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
|
|
|
124
124
|
| 设计审批包 | 一次 blocking user confirmation 含 worktree(读 `harness.json` `defaultWorktree`)。必须同时展示 **in_scope 与 out_of_scope 两个列表**——只展示"做什么"会让范围误判活到发布之后,代价是整份计划 republish |
|
|
125
125
|
| 引用即追问 | 需求引用了外部设计文档章节(贴段落、指 `### Bn`、说"之前设计的时候如…")时,阶段 2 必须确认该章节是否纳入本次范围,落到 in_scope 或 out_of_scope;引用 ≠ 纳入,也 ≠ 排除 |
|
|
126
126
|
| 阶段 8 | 二选一且不得混用:**v2** = `hunter-harness plan finalize`(证据包 → 八 target + journal committed + plan-events.ndjson);**legacy** = 六项标准产物先进入 staging,仅 finalizer 校验成功后发布并写唯一 `phase.end`/log,随后 `verify` 确认 start/end、收据完整覆盖六项标准产物、哈希、全部任务表和非空场景清单一致。失败均不得手工补终态 |
|
|
127
|
+
| 选 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,关门绑不上结构化执行收据) |
|
|
127
128
|
| 发布后改产物 | 用 `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`「发布后修订计划」 |
|
|
128
129
|
| 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 路径 |
|
|
129
130
|
| Plan 结束 | **禁止**询问执行模式;只提示 `/harness-run` |
|
|
@@ -184,8 +184,8 @@ source: harness-plan
|
|
|
184
184
|
□ 已用 decision / issue 事件 note 记录五类输出:风险识别 / 复用机会 / 替代方案 / 推荐方案 / 关键决策
|
|
185
185
|
□ 已叠加项目架构约束(分层规范、数据模型、接口规范)
|
|
186
186
|
□ 需求澄清结论已追加到 events.ndjson,阶段结束后执行日志由渲染器生成
|
|
187
|
-
□
|
|
188
|
-
□
|
|
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
|
-
□
|
|
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
|
-
>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
>
|
|
426
|
-
>
|
|
427
|
-
>
|
|
428
|
-
> `
|
|
429
|
-
>
|
|
430
|
-
>
|
|
431
|
-
>
|
|
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 内容绕过。
|
|
@@ -21,7 +21,7 @@ disallowed-tools:
|
|
|
21
21
|
- Bash(awk *)
|
|
22
22
|
- Bash(curl *)
|
|
23
23
|
---
|
|
24
|
-
<!-- generated by harness_deploy.py; core=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; 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=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; 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=
|
|
25
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; overlay=none; agent=claude-code; do not edit -->
|
|
26
26
|
# harness-review — 代码审查
|
|
27
27
|
|
|
28
28
|
## Purpose
|
|
@@ -22,7 +22,7 @@ disallowed-tools:
|
|
|
22
22
|
- Bash(curl *)
|
|
23
23
|
- Bash(codegraph *)
|
|
24
24
|
---
|
|
25
|
-
<!-- generated by harness_deploy.py; core=
|
|
25
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; overlay=none; agent=claude-code; do not edit -->
|
|
26
26
|
# harness-run — 需求编码
|
|
27
27
|
|
|
28
28
|
## Purpose
|
|
@@ -102,13 +102,15 @@ python <skills-root>/scripts/harness_test_runner.py exec --project . --timeout-s
|
|
|
102
102
|
|
|
103
103
|
返回 `TEST_RUN_ALREADY_ACTIVE`(退出码 3)说明**已有构建在跑**:等它结束或用 `lock-status` 查明持有者,**不得**改用裸跑绕开锁,也不得另起一个并行构建。确认持有进程已消失时才用 `lock-reap` 回收。
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
**长阶段租约**:`gate begin` 的租约默认 TTL 3600 秒,而 run 阶段常常跑得更久。租约过期不会中断执行,**也不再阻断收尾**:`gate close` 发现租约过期而 run-id 仍是本阶段的,会自动用原 run-id 重取并照常关门,只在返回体的 `leaseLapsed` 里记下这个阶段跑过了 TTL。过期本身不说明所有权变了——抢占会重写租约文件把 run-id 换掉,那时报的是 `LEASE_OWNER_MISMATCH`。
|
|
106
|
+
|
|
107
|
+
因此**不需要**为了长阶段定期续租。确实想让租约始终有效时,用本阶段原 run-id 刷新即可(同 run-id 重复 claim 即刷新,不会新开 attempt):
|
|
106
108
|
|
|
107
109
|
```text
|
|
108
110
|
python <skills-root>/scripts/harness_change.py claim --change <id> --phase run --run-id <本阶段 run-id> --ttl-seconds 3600 --json
|
|
109
111
|
```
|
|
110
112
|
|
|
111
|
-
|
|
113
|
+
仍然报 `LEASE_ABSENT` 说明这个阶段**根本没有租约记录**(从未 begin,或已被释放),不是超时;先确认 `gate begin` 真的跑过。报 `LEASE_INVALID` 说明租约文件损坏,无法证明没被抢占,需人工确认无并发后再用上面的命令重取。两种情况都**不要**重跑 `gate begin`——那会新开 attempt 并丢失本轮 capsule。
|
|
112
114
|
|
|
113
115
|
**执行器边界**:优先使用项目 build profile 和已有测试入口。禁止为了绕过 ESM、路径或参数问题临时生成 `.js`、`require` 脚本;需要文件式 runner 时使用项目已有入口,确需新增时遵循项目模块类型(例如 ESM 使用 `.mjs`)。runner 包装说明写入 `runnerCommand` 元数据,不得拼进账本的规范 `command`。
|
|
114
116
|
|
|
@@ -142,7 +144,7 @@ python <skills-root>/scripts/harness_change.py claim --change <id> --phase run -
|
|
|
142
144
|
| **关门/状态** | 10 项关门检查;持久化 run-task-status;仅 run-owned P0 静态-only 导致 WARN;test-owned 待办正常移交 |
|
|
143
145
|
| **Worktree** | `requested=true` 时代码只写 worktree |
|
|
144
146
|
| **构建/测试** | 一律经 `harness_test_runner.py exec`;禁止裸跑 mvn/gradle/npm test;`TEST_RUN_ALREADY_ACTIVE` 表示已有构建在跑,等待而非另起 |
|
|
145
|
-
| **租约** | 阶段超
|
|
147
|
+
| **租约** | 阶段超 TTL 由 close 自动用原 run-id 重取,无需续租;`LEASE_ABSENT`(无记录)/`LEASE_INVALID`(文件损坏)才需人工 `harness_change.py claim`,一律不重跑 begin |
|
|
146
148
|
| **PowerShell** | 所有 git 经 `powershell.exe -NoProfile -Command` |
|
|
147
149
|
|
|
148
150
|
### 陈旧测试安全修复与精确跟踪
|
|
@@ -21,7 +21,7 @@ disallowed-tools:
|
|
|
21
21
|
- Bash(awk *)
|
|
22
22
|
- Bash(curl *)
|
|
23
23
|
---
|
|
24
|
-
<!-- generated by harness_deploy.py; core=
|
|
24
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-submit — 最终提交(含 worktree 合并)
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -19,7 +19,7 @@ disallowed-tools:
|
|
|
19
19
|
- Bash(awk *)
|
|
20
20
|
- Bash(curl *)
|
|
21
21
|
---
|
|
22
|
-
<!-- generated by harness_deploy.py; core=
|
|
22
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; overlay=none; agent=claude-code; do not edit -->
|
|
23
23
|
# harness-sync
|
|
24
24
|
|
|
25
25
|
## Purpose
|
|
@@ -23,7 +23,7 @@ disallowed-tools:
|
|
|
23
23
|
- Bash(node *)
|
|
24
24
|
- Bash(codegraph *)
|
|
25
25
|
---
|
|
26
|
-
<!-- generated by harness_deploy.py; core=
|
|
26
|
+
<!-- generated by harness_deploy.py; core=76790449b05e0e2e; overlay=none; agent=claude-code; do not edit -->
|
|
27
27
|
# harness-test — 测试执行
|
|
28
28
|
|
|
29
29
|
## Purpose
|
|
@@ -2599,23 +2599,12 @@ def check_status(
|
|
|
2599
2599
|
}
|
|
2600
2600
|
)
|
|
2601
2601
|
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
warnings.append({
|
|
2609
|
-
"code": "PUBLICATION_CONTENT_SCAN_FLAGGED",
|
|
2610
|
-
"message": str(content_scan.get("nextAction") or ""),
|
|
2611
|
-
})
|
|
2612
|
-
elif not content_scan.get("ok"):
|
|
2613
|
-
warnings.append({
|
|
2614
|
-
"code": str(
|
|
2615
|
-
content_scan.get("reasonCode") or "PUBLICATION_CONTENT_SCAN_UNAVAILABLE"
|
|
2616
|
-
),
|
|
2617
|
-
"message": str(content_scan.get("message") or ""),
|
|
2618
|
-
})
|
|
2602
|
+
checks["publication_content_scan"] = {
|
|
2603
|
+
"ok": True,
|
|
2604
|
+
"scan_performed": False,
|
|
2605
|
+
"findings": [],
|
|
2606
|
+
"message": "上传归档链路已停用内容敏感扫描;保留路径、凭据与 ZIP 安全校验。",
|
|
2607
|
+
}
|
|
2619
2608
|
|
|
2620
2609
|
sensitive_gate = validate_sensitive_evidence_publication_gate(
|
|
2621
2610
|
change_dir,
|
|
@@ -9408,6 +9397,9 @@ def resolve_hunter_cli_command(project_root: Path) -> list[str]:
|
|
|
9408
9397
|
"""Command prefix that runs the hunter-harness CLI, cheapest route first."""
|
|
9409
9398
|
node = shutil.which("node")
|
|
9410
9399
|
if node:
|
|
9400
|
+
current_entry = os.environ.get("HUNTER_HARNESS_CLI_ENTRY", "").strip()
|
|
9401
|
+
if current_entry and Path(current_entry).is_file():
|
|
9402
|
+
return [node, str(Path(current_entry).resolve())]
|
|
9411
9403
|
entry = _installed_cli_entry(project_root)
|
|
9412
9404
|
if entry is not None:
|
|
9413
9405
|
return [node, str(entry)]
|
|
@@ -9774,6 +9766,7 @@ def auto_push_archive_core(
|
|
|
9774
9766
|
change_key: str | None = None,
|
|
9775
9767
|
extra_entries: dict[str, tuple[str, str, bytes]] | None = None,
|
|
9776
9768
|
reuse_retained_package: bool = False,
|
|
9769
|
+
prepared_package: dict[str, Any] | None = None,
|
|
9777
9770
|
) -> dict[str, Any]:
|
|
9778
9771
|
"""Build and upload one deterministic core ZIP after finalize.
|
|
9779
9772
|
|
|
@@ -9786,11 +9779,13 @@ def auto_push_archive_core(
|
|
|
9786
9779
|
"""
|
|
9787
9780
|
project_root = project_root.resolve()
|
|
9788
9781
|
effective_change_key = change_key or archive_dir.name
|
|
9789
|
-
package =
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
9782
|
+
package = prepared_package
|
|
9783
|
+
if package is None:
|
|
9784
|
+
package = (
|
|
9785
|
+
load_retained_package(project_root, effective_change_key)
|
|
9786
|
+
if reuse_retained_package
|
|
9787
|
+
else None
|
|
9788
|
+
)
|
|
9794
9789
|
if package is None:
|
|
9795
9790
|
try:
|
|
9796
9791
|
package = build_archive_package(
|
|
@@ -10637,6 +10632,28 @@ def resolve_archive_dir_for_change(
|
|
|
10637
10632
|
return archive_root / matches[-1], matches
|
|
10638
10633
|
|
|
10639
10634
|
|
|
10635
|
+
def resolve_latest_unpublished_archive(project_root: Path) -> tuple[str | None, list[str]]:
|
|
10636
|
+
"""Choose the newest sealed archive without a durable local receipt."""
|
|
10637
|
+
archive_root = project_root / ".harness" / "archive"
|
|
10638
|
+
if not archive_root.is_dir():
|
|
10639
|
+
return None, []
|
|
10640
|
+
candidates: list[tuple[str, str]] = []
|
|
10641
|
+
for entry in archive_root.iterdir():
|
|
10642
|
+
if not entry.is_dir():
|
|
10643
|
+
continue
|
|
10644
|
+
change = entry.name
|
|
10645
|
+
try:
|
|
10646
|
+
summary = read_json(entry / "reports" / "final" / "summary-data.json")
|
|
10647
|
+
if isinstance(summary, dict) and isinstance(summary.get("changeName"), str):
|
|
10648
|
+
change = str(summary["changeName"]).strip() or change
|
|
10649
|
+
except (OSError, ValueError, json.JSONDecodeError):
|
|
10650
|
+
pass
|
|
10651
|
+
if read_durable_archive_receipt(project_root, change) is None:
|
|
10652
|
+
candidates.append((entry.name, change))
|
|
10653
|
+
candidates.sort(reverse=True)
|
|
10654
|
+
return (candidates[0][1] if candidates else None), [item[1] for item in candidates]
|
|
10655
|
+
|
|
10656
|
+
|
|
10640
10657
|
def _republish_knowledge_entry(archive_dir: Path) -> dict[str, tuple[str, str, bytes]]:
|
|
10641
10658
|
"""Knowledge candidates for archives sealed before the candidates step.
|
|
10642
10659
|
|
|
@@ -10707,12 +10724,26 @@ def cmd_republish(
|
|
|
10707
10724
|
"changeKey": change_key,
|
|
10708
10725
|
"dryRun": dry_run,
|
|
10709
10726
|
}
|
|
10727
|
+
root = resolve_republish_project_root(project_root, archive_dir)
|
|
10728
|
+
if change_key == "latest":
|
|
10729
|
+
selected, available = resolve_latest_unpublished_archive(root)
|
|
10730
|
+
if selected is None:
|
|
10731
|
+
payload.update({
|
|
10732
|
+
"ok": True,
|
|
10733
|
+
"reasonCode": "ARCHIVE_NO_UNPUBLISHED_ARCHIVE",
|
|
10734
|
+
"noChanges": True,
|
|
10735
|
+
"availableChanges": available,
|
|
10736
|
+
"projectRoot": str(root)
|
|
10737
|
+
})
|
|
10738
|
+
return 0, payload
|
|
10739
|
+
change_key = selected
|
|
10740
|
+
payload["changeKey"] = change_key
|
|
10741
|
+
payload["selectedChange"] = selected
|
|
10710
10742
|
if re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]{0,159}", change_key) is None:
|
|
10711
10743
|
payload["error"] = "change key must be a portable path segment"
|
|
10712
10744
|
payload["reasonCode"] = "ARCHIVE_CHANGE_KEY_INVALID"
|
|
10713
10745
|
return 2, payload
|
|
10714
10746
|
|
|
10715
|
-
root = resolve_republish_project_root(project_root, archive_dir)
|
|
10716
10747
|
payload["projectRoot"] = str(root)
|
|
10717
10748
|
matches: list[str] = []
|
|
10718
10749
|
if archive_dir is None:
|
|
@@ -10821,7 +10852,7 @@ def cmd_republish(
|
|
|
10821
10852
|
# distinct name; it must never be mistaken for a pending upload.
|
|
10822
10853
|
preview_path = (
|
|
10823
10854
|
root / ".harness" / "state" / "local" / "archive-packages"
|
|
10824
|
-
/ f"{change_key}.preview.zip"
|
|
10855
|
+
/ f"{change_key}{'.preview.zip' if dry_run else '.zip'}"
|
|
10825
10856
|
)
|
|
10826
10857
|
try:
|
|
10827
10858
|
package = build_archive_package(
|
|
@@ -10837,7 +10868,8 @@ def cmd_republish(
|
|
|
10837
10868
|
return 1, payload
|
|
10838
10869
|
finally:
|
|
10839
10870
|
try:
|
|
10840
|
-
|
|
10871
|
+
if dry_run:
|
|
10872
|
+
preview_path.unlink(missing_ok=True)
|
|
10841
10873
|
except OSError:
|
|
10842
10874
|
pass
|
|
10843
10875
|
|
|
@@ -10907,6 +10939,7 @@ def cmd_republish(
|
|
|
10907
10939
|
archive_dir,
|
|
10908
10940
|
change_key=change_key,
|
|
10909
10941
|
extra_entries=extra_entries,
|
|
10942
|
+
prepared_package=package,
|
|
10910
10943
|
)
|
|
10911
10944
|
payload["push"] = result
|
|
10912
10945
|
payload["ok"] = bool(result.get("ok"))
|
|
@@ -564,18 +564,36 @@ def _lease_expired(lease: dict[str, Any]) -> bool:
|
|
|
564
564
|
return dt.datetime.now().astimezone() >= exp_dt
|
|
565
565
|
|
|
566
566
|
|
|
567
|
-
def
|
|
568
|
-
"""
|
|
567
|
+
def inspect_lease_state(project_root: Path, change_id: str) -> dict[str, Any]:
|
|
568
|
+
"""Read the lease without mutating it, keeping the three failure modes apart.
|
|
569
|
+
|
|
570
|
+
``inspect_lease`` collapses absent / expired / corrupt into ``None``, so a
|
|
571
|
+
caller cannot tell "nobody ever held this" from "the phase outlived its
|
|
572
|
+
TTL". Those need different answers: an expired lease still carries the
|
|
573
|
+
runId that proves who owns the phase, a corrupt one proves nothing, and an
|
|
574
|
+
absent one may just mean the phase already closed.
|
|
575
|
+
|
|
576
|
+
state is one of ``active`` | ``expired`` | ``absent`` | ``corrupt``. The
|
|
577
|
+
lease dict is returned for ``active`` and ``expired``; ``None`` otherwise.
|
|
578
|
+
"""
|
|
569
579
|
path = _lease_path(project_root, change_id)
|
|
570
580
|
if not path.is_file():
|
|
571
|
-
return None
|
|
581
|
+
return {"state": "absent", "lease": None}
|
|
572
582
|
try:
|
|
573
583
|
lease = _read_json(path)
|
|
574
584
|
except (OSError, json.JSONDecodeError):
|
|
575
|
-
return None
|
|
576
|
-
if not isinstance(lease, dict)
|
|
577
|
-
return None
|
|
578
|
-
|
|
585
|
+
return {"state": "corrupt", "lease": None}
|
|
586
|
+
if not isinstance(lease, dict):
|
|
587
|
+
return {"state": "corrupt", "lease": None}
|
|
588
|
+
if _lease_expired(lease):
|
|
589
|
+
return {"state": "expired", "lease": lease}
|
|
590
|
+
return {"state": "active", "lease": lease}
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
def inspect_lease(project_root: Path, change_id: str) -> dict[str, Any] | None:
|
|
594
|
+
"""Return the current non-expired lease without mutating it."""
|
|
595
|
+
state = inspect_lease_state(project_root, change_id)
|
|
596
|
+
return state["lease"] if state["state"] == "active" else None
|
|
579
597
|
|
|
580
598
|
|
|
581
599
|
def _claim_lease_locked(
|