@hunter-harness/workflow-harness 0.2.85 → 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 +1 -1
- 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_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 +1 -1
- 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_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 +1 -1
- 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_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 +1 -1
- 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_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 +1 -1
- 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_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 +1 -1
- 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_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 +1 -1
- 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_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 +1 -1
- 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_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 +26 -26
- package/harness/manifests/general/codebuddy.json +26 -26
- package/harness/manifests/general/codex.json +26 -26
- package/harness/manifests/general/cursor.json +26 -26
- package/harness/manifests/java/claude-code.json +28 -28
- package/harness/manifests/java/codebuddy.json +28 -28
- package/harness/manifests/java/codex.json +28 -28
- package/harness/manifests/java/cursor.json +28 -28
- 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
|
|
@@ -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
|
|
@@ -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(
|
|
@@ -21,6 +21,7 @@ if str(SCRIPTS_DIR) not in sys.path:
|
|
|
21
21
|
sys.path.insert(0, str(SCRIPTS_DIR))
|
|
22
22
|
|
|
23
23
|
import harness_ledger as hl # noqa: E402
|
|
24
|
+
import harness_paths as hpaths # noqa: E402
|
|
24
25
|
|
|
25
26
|
|
|
26
27
|
PHASE_GRAPH = {
|
|
@@ -31,17 +32,8 @@ PHASE_GRAPH = {
|
|
|
31
32
|
"submit": (),
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
"run",
|
|
37
|
-
"test",
|
|
38
|
-
"review",
|
|
39
|
-
"package",
|
|
40
|
-
"apidoc",
|
|
41
|
-
"submit",
|
|
42
|
-
"merge",
|
|
43
|
-
"archive",
|
|
44
|
-
)
|
|
35
|
+
# 唯一权威清单在 harness_paths(叶子模块,harness_phase 引的是同一个对象)。
|
|
36
|
+
WORKFLOW_PHASES = hpaths.WORKFLOW_PHASES
|
|
45
37
|
|
|
46
38
|
DISPLAY_TITLE_MAX_LENGTH = 80
|
|
47
39
|
|
|
@@ -270,13 +262,24 @@ def _contract(project: Path, change: str) -> tuple[Path, dict[str, Any], Path]:
|
|
|
270
262
|
|
|
271
263
|
|
|
272
264
|
def _phase_plan(contract_root: Path) -> tuple[list[str] | None, str]:
|
|
265
|
+
"""读出阶段计划;无法采信时说明原因,而不是悄悄退成 legacy。
|
|
266
|
+
|
|
267
|
+
以前这里遇到未知阶段名一律返回 (None, "legacy"):阶段计划整个失效,
|
|
268
|
+
`_allowed_next_phases` 退回硬编码的 PHASE_GRAPH,而调用方看不出发生过这件事。
|
|
269
|
+
未知阶段名不是假想问题——阶段清单少一个 merge 时,worktree 变更的
|
|
270
|
+
plannedPhases 就会带着 merge 走到这里。
|
|
271
|
+
|
|
272
|
+
未知名先过 LEGACY_PHASE_ALIASES 读时映射(阶段改名后历史 change 靠它继续可读),
|
|
273
|
+
仍然解析不了才降级,并把原因与具体阶段名带在 source 里。
|
|
274
|
+
"""
|
|
273
275
|
policy_path = contract_root / "meta" / "gate-policy.json"
|
|
274
276
|
if not policy_path.is_file():
|
|
275
277
|
return None, "legacy"
|
|
276
278
|
try:
|
|
277
279
|
policy = _read_json(policy_path)
|
|
278
280
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
279
|
-
return None, "legacy"
|
|
281
|
+
return None, "legacy:policy-unreadable"
|
|
282
|
+
unknown: list[str] = []
|
|
280
283
|
for field, source in (
|
|
281
284
|
("plannedPhases", "change"),
|
|
282
285
|
("defaultPhases", "policy-default"),
|
|
@@ -285,12 +288,17 @@ def _phase_plan(contract_root: Path) -> tuple[list[str] | None, str]:
|
|
|
285
288
|
if not isinstance(raw, list):
|
|
286
289
|
continue
|
|
287
290
|
phases = [str(item).strip() for item in raw if str(item).strip()]
|
|
288
|
-
if (
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
291
|
+
if not phases or len(phases) != len(set(phases)):
|
|
292
|
+
continue
|
|
293
|
+
resolved = [hpaths.resolve_phase_name(item) for item in phases]
|
|
294
|
+
missing = [item for item, hit in zip(phases, resolved) if hit is None]
|
|
295
|
+
if missing:
|
|
296
|
+
unknown.extend(missing)
|
|
297
|
+
continue
|
|
298
|
+
# 映射后可能出现重复(两个旧名合并成同一个新阶段),保序去重。
|
|
299
|
+
return list(dict.fromkeys(str(item) for item in resolved)), source
|
|
300
|
+
if unknown:
|
|
301
|
+
return None, "legacy:unknown-phases=" + ",".join(dict.fromkeys(unknown))
|
|
294
302
|
return None, "legacy"
|
|
295
303
|
|
|
296
304
|
|
|
@@ -405,6 +413,7 @@ def _paths(state_root: Path) -> dict[str, Path]:
|
|
|
405
413
|
"begins": runtime / "transition-begins.ndjson",
|
|
406
414
|
"current": runtime / "current-context.json",
|
|
407
415
|
"lease": runtime / "context-lease.json",
|
|
416
|
+
"adoptions": runtime / "context-adoptions.ndjson",
|
|
408
417
|
}
|
|
409
418
|
|
|
410
419
|
|
|
@@ -604,8 +613,14 @@ def _claim_prepared_context(
|
|
|
604
613
|
)
|
|
605
614
|
except (OSError, ValueError, json.JSONDecodeError):
|
|
606
615
|
return {"ok": False, "code": "CONTEXT_CURRENT_INVALID"}
|
|
616
|
+
# 跨阶段推进必须有 receipt 证明它合法;同一个阶段换执行者不需要。
|
|
617
|
+
# 以前两者都要 receipt,于是上一阶段崩溃没能正常 close 时,接手的工具
|
|
618
|
+
# 连"继续把这个阶段干完"都做不到。并发保护不受影响:租约未过期而
|
|
619
|
+
# owner 不同,上面 CONTEXT_LEASE_HELD 已经拦下了,能走到这里只剩
|
|
620
|
+
# 「租约已过期」和「租约已被上一阶段 close 删除」两种情况。
|
|
621
|
+
adoption: dict[str, Any] | None = None
|
|
607
622
|
if recovery is None and isinstance(current, dict) and (
|
|
608
|
-
current.get("
|
|
623
|
+
current.get("phase") != phase
|
|
609
624
|
):
|
|
610
625
|
valid_receipt = (
|
|
611
626
|
isinstance(latest, dict)
|
|
@@ -621,6 +636,19 @@ def _claim_prepared_context(
|
|
|
621
636
|
"toExecutor": executor,
|
|
622
637
|
"toPhase": phase,
|
|
623
638
|
}
|
|
639
|
+
executor_changed = (
|
|
640
|
+
isinstance(current, dict) and current.get("executor") != executor
|
|
641
|
+
)
|
|
642
|
+
if recovery is not None or executor_changed:
|
|
643
|
+
adoption = {
|
|
644
|
+
"previousExecutor": (
|
|
645
|
+
current.get("executor") if isinstance(current, dict) else None
|
|
646
|
+
),
|
|
647
|
+
"newExecutor": executor,
|
|
648
|
+
"reason": (
|
|
649
|
+
"lease_expired" if recovery is not None else "same_phase_handoff"
|
|
650
|
+
),
|
|
651
|
+
}
|
|
624
652
|
|
|
625
653
|
try:
|
|
626
654
|
execution_root = _execution_root(project, contract_root, state_root)
|
|
@@ -657,6 +685,20 @@ def _claim_prepared_context(
|
|
|
657
685
|
current_context["preparationId"] = preparation_id
|
|
658
686
|
_write_json_atomic(paths["lease"], lease)
|
|
659
687
|
_write_json_atomic(paths["current"], current_context)
|
|
688
|
+
if adoption is not None:
|
|
689
|
+
# 接管必须留痕。过期租约本来就允许任何执行者顶替,但以前只在返回体
|
|
690
|
+
# 里挂一个 recovery,退出进程就没了——事后查"这个阶段是谁接手的"
|
|
691
|
+
# 无据可依。收据形状照 harness_archive.adopt_existing_range。
|
|
692
|
+
adoption = {
|
|
693
|
+
"schemaVersion": 1,
|
|
694
|
+
"changeName": change,
|
|
695
|
+
"phase": phase,
|
|
696
|
+
**adoption,
|
|
697
|
+
"previousOwner": recovery.get("previousOwner") if recovery else None,
|
|
698
|
+
"expiredAt": recovery.get("expiredAt") if recovery else None,
|
|
699
|
+
"adoptedAt": now.isoformat(),
|
|
700
|
+
}
|
|
701
|
+
_append_ndjson(paths["adoptions"], adoption)
|
|
660
702
|
return {
|
|
661
703
|
"ok": True,
|
|
662
704
|
"lease": lease,
|
|
@@ -664,6 +706,7 @@ def _claim_prepared_context(
|
|
|
664
706
|
"transitions": transitions,
|
|
665
707
|
"latestTransition": latest,
|
|
666
708
|
"recovery": recovery,
|
|
709
|
+
"adoption": adoption,
|
|
667
710
|
"executionRoot": str(execution_root),
|
|
668
711
|
}
|
|
669
712
|
|
|
@@ -405,6 +405,10 @@ def _default_gate_begin(**kwargs: Any) -> dict[str, Any]:
|
|
|
405
405
|
str(kwargs["run_id"]),
|
|
406
406
|
"--note",
|
|
407
407
|
"开始处理评审中确认需要修改的代码问题。",
|
|
408
|
+
# 显式标记这一轮是 review fixback。以前靠 gate 嗅探 note 里有没有
|
|
409
|
+
# "fixback" 字样——而上面这条 note 一个都没有,于是 fixback 的 run 事件
|
|
410
|
+
# 从来没被打上 trigger/from_phase。
|
|
411
|
+
"--fixback",
|
|
408
412
|
]
|
|
409
413
|
for option, key in (
|
|
410
414
|
("--executor-tool", "executor_tool"),
|