@hunter-harness/workflow-harness 0.4.9 → 0.4.11
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-execute/SKILL.md +5 -3
- package/harness/bundles/general/claude-code/harness-execute/testing-pitfalls-java.md +7 -0
- package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +7 -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 -3
- package/harness/bundles/general/claude-code/harness-plan/checklist.md +1 -0
- package/harness/bundles/general/claude-code/harness-plan/reference.md +8 -0
- 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 +12 -1
- 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/scripts/harness_context.py +71 -8
- package/harness/bundles/general/claude-code/scripts/harness_events.py +29 -19
- package/harness/bundles/general/claude-code/scripts/harness_fixback.py +37 -1
- package/harness/bundles/general/claude-code/scripts/harness_gate.py +124 -10
- package/harness/bundles/general/claude-code/scripts/harness_ledger.py +84 -4
- package/harness/bundles/general/claude-code/scripts/harness_process.py +18 -0
- package/harness/bundles/general/claude-code/scripts/harness_runtime.py +47 -1
- 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-execute/SKILL.md +5 -3
- package/harness/bundles/general/codebuddy/harness-execute/testing-pitfalls-java.md +7 -0
- package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +7 -1
- package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +3 -3
- package/harness/bundles/general/codebuddy/harness-plan/checklist.md +1 -0
- package/harness/bundles/general/codebuddy/harness-plan/reference.md +8 -0
- 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 +12 -1
- 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/scripts/harness_context.py +71 -8
- package/harness/bundles/general/codebuddy/scripts/harness_events.py +29 -19
- package/harness/bundles/general/codebuddy/scripts/harness_fixback.py +37 -1
- package/harness/bundles/general/codebuddy/scripts/harness_gate.py +124 -10
- package/harness/bundles/general/codebuddy/scripts/harness_ledger.py +84 -4
- package/harness/bundles/general/codebuddy/scripts/harness_process.py +18 -0
- package/harness/bundles/general/codebuddy/scripts/harness_runtime.py +47 -1
- 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-execute/SKILL.md +5 -3
- package/harness/bundles/general/codex/harness-execute/testing-pitfalls-java.md +7 -0
- package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +7 -1
- package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-plan/SKILL.md +3 -3
- package/harness/bundles/general/codex/harness-plan/checklist.md +1 -0
- package/harness/bundles/general/codex/harness-plan/reference.md +8 -0
- 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-submit/SKILL.md +1 -1
- package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/codex/scripts/harness_context.py +71 -8
- package/harness/bundles/general/codex/scripts/harness_events.py +29 -19
- package/harness/bundles/general/codex/scripts/harness_fixback.py +37 -1
- package/harness/bundles/general/codex/scripts/harness_gate.py +124 -10
- package/harness/bundles/general/codex/scripts/harness_ledger.py +84 -4
- package/harness/bundles/general/codex/scripts/harness_process.py +18 -0
- package/harness/bundles/general/codex/scripts/harness_runtime.py +47 -1
- 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-execute/SKILL.md +5 -3
- package/harness/bundles/general/cursor/harness-execute/testing-pitfalls-java.md +7 -0
- package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +7 -1
- package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-plan/SKILL.md +3 -3
- package/harness/bundles/general/cursor/harness-plan/checklist.md +1 -0
- package/harness/bundles/general/cursor/harness-plan/reference.md +8 -0
- 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-submit/SKILL.md +1 -1
- package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/cursor/scripts/harness_context.py +71 -8
- package/harness/bundles/general/cursor/scripts/harness_events.py +29 -19
- package/harness/bundles/general/cursor/scripts/harness_fixback.py +37 -1
- package/harness/bundles/general/cursor/scripts/harness_gate.py +124 -10
- package/harness/bundles/general/cursor/scripts/harness_ledger.py +84 -4
- package/harness/bundles/general/cursor/scripts/harness_process.py +18 -0
- package/harness/bundles/general/cursor/scripts/harness_runtime.py +47 -1
- package/harness/bundles/general/pi/.harness-build.json +1 -1
- package/harness/bundles/general/pi/harness-archive/SKILL.md +1 -1
- package/harness/bundles/general/pi/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/general/pi/harness-execute/SKILL.md +5 -3
- package/harness/bundles/general/pi/harness-execute/testing-pitfalls-java.md +7 -0
- package/harness/bundles/general/pi/harness-knowledge-ingest/SKILL.md +7 -1
- package/harness/bundles/general/pi/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/general/pi/harness-plan/SKILL.md +3 -3
- package/harness/bundles/general/pi/harness-plan/checklist.md +1 -0
- package/harness/bundles/general/pi/harness-plan/reference.md +8 -0
- package/harness/bundles/general/pi/harness-pull/SKILL.md +1 -1
- package/harness/bundles/general/pi/harness-push/SKILL.md +1 -1
- package/harness/bundles/general/pi/harness-review/SKILL.md +1 -1
- package/harness/bundles/general/pi/harness-submit/SKILL.md +1 -1
- package/harness/bundles/general/pi/harness-sync/SKILL.md +1 -1
- package/harness/bundles/general/pi/scripts/harness_context.py +71 -8
- package/harness/bundles/general/pi/scripts/harness_events.py +29 -19
- package/harness/bundles/general/pi/scripts/harness_fixback.py +37 -1
- package/harness/bundles/general/pi/scripts/harness_gate.py +124 -10
- package/harness/bundles/general/pi/scripts/harness_ledger.py +84 -4
- package/harness/bundles/general/pi/scripts/harness_process.py +18 -0
- package/harness/bundles/general/pi/scripts/harness_runtime.py +47 -1
- 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-execute/SKILL.md +5 -3
- package/harness/bundles/java/claude-code/harness-execute/testing-pitfalls-java.md +1 -0
- package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +7 -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 -3
- package/harness/bundles/java/claude-code/harness-plan/checklist.md +1 -0
- package/harness/bundles/java/claude-code/harness-plan/reference.md +8 -0
- 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 +12 -1
- 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/scripts/harness_context.py +71 -8
- package/harness/bundles/java/claude-code/scripts/harness_events.py +29 -19
- package/harness/bundles/java/claude-code/scripts/harness_fixback.py +37 -1
- package/harness/bundles/java/claude-code/scripts/harness_gate.py +124 -10
- package/harness/bundles/java/claude-code/scripts/harness_ledger.py +84 -4
- package/harness/bundles/java/claude-code/scripts/harness_process.py +18 -0
- package/harness/bundles/java/claude-code/scripts/harness_runtime.py +47 -1
- 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-execute/SKILL.md +5 -3
- package/harness/bundles/java/codebuddy/harness-execute/testing-pitfalls-java.md +1 -0
- package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +7 -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 -3
- package/harness/bundles/java/codebuddy/harness-plan/checklist.md +1 -0
- package/harness/bundles/java/codebuddy/harness-plan/reference.md +8 -0
- 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 +12 -1
- 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/scripts/harness_context.py +71 -8
- package/harness/bundles/java/codebuddy/scripts/harness_events.py +29 -19
- package/harness/bundles/java/codebuddy/scripts/harness_fixback.py +37 -1
- package/harness/bundles/java/codebuddy/scripts/harness_gate.py +124 -10
- package/harness/bundles/java/codebuddy/scripts/harness_ledger.py +84 -4
- package/harness/bundles/java/codebuddy/scripts/harness_process.py +18 -0
- package/harness/bundles/java/codebuddy/scripts/harness_runtime.py +47 -1
- 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-execute/SKILL.md +5 -3
- package/harness/bundles/java/codex/harness-execute/testing-pitfalls-java.md +1 -0
- package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +7 -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 -3
- package/harness/bundles/java/codex/harness-plan/checklist.md +1 -0
- package/harness/bundles/java/codex/harness-plan/reference.md +8 -0
- 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-submit/SKILL.md +1 -1
- package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/codex/scripts/harness_context.py +71 -8
- package/harness/bundles/java/codex/scripts/harness_events.py +29 -19
- package/harness/bundles/java/codex/scripts/harness_fixback.py +37 -1
- package/harness/bundles/java/codex/scripts/harness_gate.py +124 -10
- package/harness/bundles/java/codex/scripts/harness_ledger.py +84 -4
- package/harness/bundles/java/codex/scripts/harness_process.py +18 -0
- package/harness/bundles/java/codex/scripts/harness_runtime.py +47 -1
- 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-execute/SKILL.md +5 -3
- package/harness/bundles/java/cursor/harness-execute/testing-pitfalls-java.md +1 -0
- package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +7 -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 -3
- package/harness/bundles/java/cursor/harness-plan/checklist.md +1 -0
- package/harness/bundles/java/cursor/harness-plan/reference.md +8 -0
- 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-submit/SKILL.md +1 -1
- package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/cursor/scripts/harness_context.py +71 -8
- package/harness/bundles/java/cursor/scripts/harness_events.py +29 -19
- package/harness/bundles/java/cursor/scripts/harness_fixback.py +37 -1
- package/harness/bundles/java/cursor/scripts/harness_gate.py +124 -10
- package/harness/bundles/java/cursor/scripts/harness_ledger.py +84 -4
- package/harness/bundles/java/cursor/scripts/harness_process.py +18 -0
- package/harness/bundles/java/cursor/scripts/harness_runtime.py +47 -1
- package/harness/bundles/java/pi/.harness-build.json +1 -1
- package/harness/bundles/java/pi/harness-apidoc/SKILL.md +1 -1
- package/harness/bundles/java/pi/harness-archive/SKILL.md +1 -1
- package/harness/bundles/java/pi/harness-codebase-map/SKILL.md +1 -1
- package/harness/bundles/java/pi/harness-execute/SKILL.md +5 -3
- package/harness/bundles/java/pi/harness-execute/testing-pitfalls-java.md +1 -0
- package/harness/bundles/java/pi/harness-knowledge-ingest/SKILL.md +7 -1
- package/harness/bundles/java/pi/harness-knowledge-query/SKILL.md +1 -1
- package/harness/bundles/java/pi/harness-package/SKILL.md +1 -1
- package/harness/bundles/java/pi/harness-plan/SKILL.md +3 -3
- package/harness/bundles/java/pi/harness-plan/checklist.md +1 -0
- package/harness/bundles/java/pi/harness-plan/reference.md +8 -0
- package/harness/bundles/java/pi/harness-pull/SKILL.md +1 -1
- package/harness/bundles/java/pi/harness-push/SKILL.md +1 -1
- package/harness/bundles/java/pi/harness-review/SKILL.md +1 -1
- package/harness/bundles/java/pi/harness-submit/SKILL.md +1 -1
- package/harness/bundles/java/pi/harness-sync/SKILL.md +1 -1
- package/harness/bundles/java/pi/scripts/harness_context.py +71 -8
- package/harness/bundles/java/pi/scripts/harness_events.py +29 -19
- package/harness/bundles/java/pi/scripts/harness_fixback.py +37 -1
- package/harness/bundles/java/pi/scripts/harness_gate.py +124 -10
- package/harness/bundles/java/pi/scripts/harness_ledger.py +84 -4
- package/harness/bundles/java/pi/scripts/harness_process.py +18 -0
- package/harness/bundles/java/pi/scripts/harness_runtime.py +47 -1
- package/harness/manifests/general/claude-code.json +22 -22
- package/harness/manifests/general/codebuddy.json +22 -22
- package/harness/manifests/general/codex.json +22 -22
- package/harness/manifests/general/cursor.json +22 -22
- package/harness/manifests/general/pi.json +22 -22
- package/harness/manifests/java/claude-code.json +24 -24
- package/harness/manifests/java/codebuddy.json +24 -24
- package/harness/manifests/java/codex.json +24 -24
- package/harness/manifests/java/cursor.json +24 -24
- package/harness/manifests/java/pi.json +24 -24
- package/hunter-workflow-family.json +2 -2
- 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=cdc01b6329bacd46; 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=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
|
|
24
24
|
# harness-codebase-map — 代码库地图
|
|
25
25
|
|
|
26
26
|
## Purpose
|
|
@@ -23,7 +23,7 @@ disallowed-tools:
|
|
|
23
23
|
- Bash(node *)
|
|
24
24
|
- Bash(codegraph *)
|
|
25
25
|
---
|
|
26
|
-
<!-- generated by harness_deploy.py; core=
|
|
26
|
+
<!-- generated by harness_deploy.py; core=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
|
|
27
27
|
# harness-execute — 执行(编码 + 验证)
|
|
28
28
|
|
|
29
29
|
> 2026-08 阶段合并:原 `run`(编码)与 `test`(验证)合并为单一 `execute` 阶段;
|
|
@@ -80,13 +80,15 @@ disallowed-tools:
|
|
|
80
80
|
|
|
81
81
|
## Workflow 概要
|
|
82
82
|
|
|
83
|
-
0. 加载上下文:先 `harness_context.py prepare --project . --change <id> --phase execute --executor <tool> --json`(`--project` 必填),再 `harness_context.py begin --project . --change <id> --phase execute --executor <tool> --json` 校验交接,最后运行 **`harness_gate.py begin --phase execute --change <id>`**。旧名 `--phase run` / `--phase test` 仍被接受并归一为 execute。<br>**交接凭证不必手工补**:v2 计划的 `plan finalize` 不写 context 事务,`prepare` 会在检测到 committed 的 `meta/publication-journals/*.json` 时自动补录 `plan → execute` 凭证(凭证带 `bootstrapSource=plan_publication_journal` 留痕)。仍报 `HANDOFF_REQUIRED`/`LEGACY_BOOTSTRAP_REQUIRED` 说明**没有**这份发布证据——回到 plan 阶段确认发布是否真的完成,**不得**自己拼 `classify + configure-plan + close` 造凭证。<br>**Fixback** 不得拼装底层步骤,必须只调用一次 `harness_fixback.py launch-review --project . --change <id> --change-dir <change-dir> --executor <tool> --skills-root <skills-root> --product-identity <当前产品身份> --json`;返回 `FIXBACK_NOTHING_TO_APPLY` 时直接报告并停止。禁止手写 `events.ndjson` / `phase.end`。
|
|
83
|
+
0. 加载上下文:先 `harness_context.py prepare --project . --change <id> --phase execute --executor <tool> --json`(`--project` 必填),再 `harness_context.py begin --project . --change <id> --phase execute --executor <tool> --json` 校验交接,最后运行 **`harness_gate.py begin --phase execute --change <id>`**。旧名 `--phase run` / `--phase test` 仍被接受并归一为 execute。<br>Git Bash 注意:`--note` 等字符串参数**不要以 `/` 开头**(MSYS 会把它当路径改写成 `C:/Program Files/Git/...`);以 `/` 开头时先 `MSYS_NO_PATHCONV=1`。<br>**交接凭证不必手工补**:v2 计划的 `plan finalize` 不写 context 事务,`prepare` 会在检测到 committed 的 `meta/publication-journals/*.json` 时自动补录 `plan → execute` 凭证(凭证带 `bootstrapSource=plan_publication_journal` 留痕)。仍报 `HANDOFF_REQUIRED`/`LEGACY_BOOTSTRAP_REQUIRED` 说明**没有**这份发布证据——回到 plan 阶段确认发布是否真的完成,**不得**自己拼 `classify + configure-plan + close` 造凭证。<br>**Fixback** 不得拼装底层步骤,必须只调用一次 `harness_fixback.py launch-review --project . --change <id> --change-dir <change-dir> --executor <tool> --skills-root <skills-root> --product-identity <当前产品身份> --json`;返回 `FIXBACK_NOTHING_TO_APPLY` 时直接报告并停止。禁止手写 `events.ndjson` / `phase.end`。
|
|
84
|
+
|
|
85
|
+
**Fixback 步骤序列**(0.4.11 起文档化;每步失败都有 recoveryAction):launch-review 启动批次 → 托管 RED 会话(`harness_runtime.py run-start --verification fixback-red --product-identity <批次 baseProductIdentity,缺省自动注入> -- ...`)→ `harness_fixback.py evidence-template` 生成证据 + `register-evidence` 注册 → 修复 → GREEN 会话同法 → 逐 issue `resolve-issue` → `harness_review.py write-dispositions` 处置 → affected 验证会话 + review 收据 → `harness_fixback.py close --change-dir <change-dir> --batch-id <批次> --final-product-identity <身份>`(批次关闭会同步把 fixback-session 置 CLOSED)→ `harness_gate.py close --phase execute`(fixback 回环自动派生回 submit)。Windows 上命令名写 `mvn` 会 WinError 2——0.4.11 起 launcher 自动解析 .cmd/.exe,更早版本请写全路径。
|
|
84
86
|
0.5. **测试基础设施探测**与**命令执行模式 preflight** → `testing-reference.md`「命令执行模式 preflight」;测试基线已由 gate begin 内部建立,不得再次执行 guard begin
|
|
85
87
|
1. **变更簇 TDD** — `protocols.md` `run-tdd-protocol`;批量 RED/GREEN;按需 `change-cluster-review-protocol`
|
|
86
88
|
2. 构建验证 + **仅**通过 `harness_ledger.py record` 写 ledger(禁止 Write/Edit `verification-ledger.json`);profile 缺失或陈旧时先 `harness_preflight.py detect --project . --json`;`record --project . --profile-input <key>` 从同一 target 推导 scope、coverage、规范命令与输入闭包
|
|
87
89
|
3. **验证执行**:单元测试可复用则跳过(`harness_ledger.py can-reuse`);接口测试**强制批量执行器**一次跑完全部场景;数据兼容验证按场景表执行 → `testing-reference.md`
|
|
88
90
|
4. **场景覆盖检查**(场景表映射,禁止用用例数冒充场景数)
|
|
89
|
-
5. **关门检查**(10 项)→ 只执行一次 `harness_gate.py close`;`--to-phase` 可省略——计划后继唯一(排除 fixback 自环)时自动派生并交接(输出含 `derivedToPhase`)。仅 fixback 回环时显式传 `--to-phase execute
|
|
91
|
+
5. **关门检查**(10 项)→ 只执行一次 `harness_gate.py close`;`--to-phase` 可省略——计划后继唯一(排除 fixback 自环)时自动派生并交接(输出含 `derivedToPhase`)。仅 fixback 回环时显式传 `--to-phase execute`;fixback 批次的 execute 关门自动派生 review 的后继(submit),不会错误地再回一轮 review(0.4.11 起)。该命令内部关闭 test guard、写 `phase.end`、释放租约、写 handoff 并补传事件;不得再单独调用 test-guard/context close。失败时按结构化 `recoveryAction` 原样重试,已完成步骤幂等复用。
|
|
90
92
|
|
|
91
93
|
**阶段归属规则**:只用 `ownerPhase=execute` 的任务和场景判定本阶段结果。`ownerPhase=review`/`submit` 的场景按计划留给后续阶段属于正常移交,出现在关门返回值的 `deferred` 里,不阻断 execute。合并前 `ownerPhase=run`/`test` 的旧清单经别名表归一为 execute,在 execute 关门时一并到期。
|
|
92
94
|
|
|
@@ -12,3 +12,10 @@ description: Java/Feign 相关测试踩坑(harness-execute)。API 实测前
|
|
|
12
12
|
**根因模式**:`@FeignClient` 方法上只写了 `@GetMapping("/type")`,漏掉服务端类级前缀(如 `/system/dict-data`)。
|
|
13
13
|
**定位**:对照服务端 controller 完整映射(类级 `@RequestMapping` + 方法级注解),或看服务端访问日志中的实际 404 路径。
|
|
14
14
|
**流程要求**:此类缺陷若在 test 阶段被 API 实测发现,属于"计划外修复"——必须记 decision 事件(含根因与修复文件),并检查同客户端文件的其余方法是否同源错误。
|
|
15
|
+
|
|
16
|
+
## Surefire 插件级 excludedGroups 压过命令行覆盖(静默 0 执行)
|
|
17
|
+
|
|
18
|
+
**症状**:`mvn test -Dgroups=mysql -DexcludedGroups=` 想跑集成测试,结果 `Tests run: 0` + **exit 0**——只看退出码就是假阳性。
|
|
19
|
+
**根因**:pom 在 surefire `<configuration>` 里写死 `<excludedGroups>mysql</excludedGroups>` 时,插件级配置压过命令行属性,空值覆盖不生效。
|
|
20
|
+
**修复**:pom 改用属性占位 `<excludedGroups>${excludedGroups}</excludedGroups>`,命令行空值才能生效。
|
|
21
|
+
**防线**:`harness_ledger.py record` 在命令含 `-Dgroups=`/`-Dtest=` 等选择器且证据显示 `Tests run: 0` 时输出 `ZERO_TESTS_WITH_SELECTOR` 警告(0.4.11 起);看到它不要当噪音跳过。
|
|
@@ -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=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
|
|
12
12
|
# harness-knowledge-ingest
|
|
13
13
|
|
|
14
14
|
知识 ingest 完全由 Hunter Platform 负责。归档完成时,客户端生成一个确定性 ZIP;
|
|
@@ -46,6 +46,12 @@ powershell.exe -Command "npx hunter-harness archive upload --file '<archive.zip>
|
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
4. 检查响应中的包哈希、服务端保存状态和 `knowledge_status`。
|
|
49
|
+
4.5. **查询面回读验证(强制)**:`knowledgeStatus=ready` 只是入库回执,不代表可查。
|
|
50
|
+
执行 `npx hunter-harness knowledge status --json` 确认 `pipeline.results_count`
|
|
51
|
+
符合预期(有候选的归档应 > 0);再用归档中的已知关键词跑一次
|
|
52
|
+
`npx hunter-harness knowledge query "<已知关键词>" --json`,`count=0` 视为
|
|
53
|
+
ingest 未真正完成——报告 `pipeline.jobs` 状态(queued/extracting/failed)
|
|
54
|
+
并停止宣称 ready,不得仅凭上传回执收尾。
|
|
49
55
|
5. 只有服务端确认原 ZIP 已持久保存且知识状态为 ready,才删除本地待上传 ZIP。
|
|
50
56
|
6. 上传或 ingest 失败时保留 ZIP 与失败收据;修复连接后重试同一个 ZIP,不重新拼散文件。
|
|
51
57
|
|
|
@@ -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=cdc01b6329bacd46; 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=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
|
|
25
25
|
# harness-plan — 需求规划
|
|
26
26
|
|
|
27
27
|
## Purpose
|
|
@@ -86,10 +86,10 @@ disallowed-tools:
|
|
|
86
86
|
| 阶段 | 动作 |
|
|
87
87
|
|------|------|
|
|
88
88
|
| 0 | git status;脏工作区 → baseline 隔离 + `decision`,不询问。环境体检并入 0.5 的引导命令,不再单独跑 doctor |
|
|
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` |
|
|
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`。返回里的 `legacyBootstrap: true` 只是「本次引导前还没有任何交接凭证」的标记(首个阶段的正常状态),不是项目结构需要迁移 |
|
|
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
91
|
| 0.6 | 用引导返回的 `tier`/`defaultPhases`/`requiredValidations` 生成 `plannedPhases`,向用户用中文说明可选阶段;确认后运行 `harness_context.py configure-plan --project . --change <cn> --phases "plan,execute,...,archive" --operator <tool> --reason "<中文原因>" --json`。无 Git 或不需要提交时不得加入 `submit`;快速迭代默认 `plan,execute,archive`。省略项由脚本写入 `skippedPhases`,不得伪造阶段事件。<br>⚠️ 无风险信号时 classify 默认 `standard`(`plan,execute,submit,archive` + compile/unitTest/unitTestFull),**不再默认 full**。需要 review 阶段与 apiTest 的高风险变更,在计划文档里写「风险等级: full」或用 `classify --tier-override full` 显式升档 |
|
|
92
|
-
| 1 | 直接执行一次 `npx hunter-harness knowledge query "<用户需求原文>" --limit 10 --json`。这是唯一执行入口,不扫描技能目录、不查找其他脚本;失败记 `issue`
|
|
92
|
+
| 1 | 直接执行一次 `npx hunter-harness knowledge query "<用户需求原文>" --limit 10 --json`。这是唯一执行入口,不扫描技能目录、不查找其他脚本;失败记 `issue` 并继续,不建立本地索引或离线回退。**查询结果(含 0 条)必须落事件**:`harness_events.py append --phase plan --type command --name "knowledge query" --message "count=<n>" --json`(query 回执的 `receipt.index_generation` 反映索引代数;0 条时可先跑 `npx hunter-harness knowledge status --json`(0.4.11+)区分「job 未跑 / 失败 / 结果为空」) |
|
|
93
93
|
| 2 | 歧义优先检查 + 复杂度分级;先确认会改变实现方向的语义歧义 |
|
|
94
94
|
| 3 | 按复杂度执行有预算的代码探索;简单修复不得扩散到无关模块 |
|
|
95
95
|
| 4 | **设计审批包** blocking user confirmation;确认事件早于 approved 设计文档和 `meta/worktree.json` |
|
|
@@ -214,6 +214,7 @@ description: harness-plan 的阶段检查清单和覆盖检查列表。仅在执
|
|
|
214
214
|
|
|
215
215
|
- [ ] **v2**:只手写 `meta/plan-evidence-input.json`。`plans/*.md` 由 finalize 派生,手写的会被渲染覆盖,只是白写
|
|
216
216
|
- [ ] 任何缺失**都不得手工补写**(包括 `phase.end`);回到对应阶段改自然输入/staging 后重跑
|
|
217
|
+
- [ ] **phase.start/end 事件对完整**:plan 不经 gate close,0.4.11 起 `context close`/`handoff` 会自动补齐缺失的 `phase.end`(返回体 `phaseEndPair.code=PHASE_END_AUTO_PAIRED`);发现平台 Run 监控计时不停时先查这对事件,而不是手工写事件
|
|
217
218
|
- [ ] v2 过渡期**不写** `meta/plan-finalization.json` 与 `logs/execution-log.md`;缺这两项不算失败,不得为凑表手工补
|
|
218
219
|
|
|
219
220
|
|
|
@@ -376,6 +376,14 @@ finalize 硬性要求证据包顶层 `adversarial_review` 收据,缺失即 `PL
|
|
|
376
376
|
1. 先完成阶段 7.5 对抗评审,把结论写成草稿 `meta/plan-review-draft.json`:
|
|
377
377
|
`{ "reviewer_identity": "inline:<标识>", "findings": [] }`
|
|
378
378
|
(`review_mode` 缺省 `inline`;`completed_at` 缺省取当前时间;`findings` 为空数组表示无发现)
|
|
379
|
+
|
|
380
|
+
**草稿完整契约**(0.4.11 起可 `plan review-record --print-template` 取合法骨架):
|
|
381
|
+
顶层键集精确为 `reviewer_identity / review_mode? / findings? / completed_at?`;
|
|
382
|
+
`reviewer_identity` 匹配 `^[a-z][a-z0-9_.:-]{0,159}$`。`findings` 元素键集精确为
|
|
383
|
+
`finding_id / category / severity / source_refs / message_zh / suggested_location`,
|
|
384
|
+
其中 `severity ∈ {advisory, blocking}`、`source_refs` 至少一条非空字符串、
|
|
385
|
+
`finding_id` 同上面的 identity 规则。缺键/多键/枚举越界都会在
|
|
386
|
+
`PLAN_REVIEW_RECORD_INPUT_INVALID` 的 `problems[]` 里逐条给出 `field_path`。
|
|
379
387
|
2. 跑 `plan review-record`:CLI 内部重跑 layer1/layer2/layer3 算出权威 `input_hash`,
|
|
380
388
|
代算 `findings_hash`,把完整收据写回证据包顶层 `adversarial_review`(缺省覆盖 `--input`,
|
|
381
389
|
可用 `--output` 写到别处)。stdout 的 `review_required: false` 表示该包未触发评审、收据不会被消费。
|
|
@@ -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=cdc01b6329bacd46; 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=cdc01b6329bacd46; 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=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
|
|
26
26
|
# harness-review — 代码审查
|
|
27
27
|
|
|
28
28
|
## Purpose
|
|
@@ -75,6 +75,17 @@ review 默认优先在独立上下文执行,避免主会话已形成的实现
|
|
|
75
75
|
|
|
76
76
|
无隔离能力、定义损坏、spawn 失败、空返回或只有元数据时,不重试,立即由主会话按同一 6 维度检查清单完成审查。无论是否委派,都必须追加一条结构化 `decision` 事件:`--execution-mode delegated|inline` 标明执行方式;委派时写 `--executor-agent harness-reviewer --decision-reason-code REVIEW_DELEGATED`;回退时只写一个 `--fallback-reason-code REVIEW_INLINE_UNAVAILABLE|REVIEW_INLINE_SPAWN_FAILED|REVIEW_INLINE_INVALID_RESULT`。`decision` 和 `reason` 必须用中文完整说明,禁止把原因码拼进正文。正常主会话评审是可接受结果,不显示成流程故障;`fallbackPolicy=inline-no-retry`。
|
|
77
77
|
|
|
78
|
+
完整示例(委派路径,可直接复制改参):
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
python <skills-root>/scripts/harness_events.py append --change-dir ".harness/changes/<cn>" \
|
|
82
|
+
--phase review --type decision --execution-mode delegated \
|
|
83
|
+
--executor-agent harness-reviewer --decision-reason-code REVIEW_DELEGATED \
|
|
84
|
+
--decision "已使用独立评审完成 6 维度审查" --reason "固定 reviewer 可用,避免主会话实现结论影响审查" --json
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
注意:`decision` 事件**不接受** `--name`/`--status`(那是 verification 的字段);`issue` 事件必须带 `--severity`。
|
|
88
|
+
|
|
78
89
|
项目规模小、风险低或没有 CodeGraph 都不是跳过独立评审的理由。原因码是稳定机器字段,仅用于协议与技术详情;面向用户的事件摘要必须写成「已使用独立评审」或「当前环境没有可用的隔离评审能力,已由主会话完成评审」等中文说明。
|
|
79
90
|
|
|
80
91
|
3. **持久化报告与事实 sidecar(强制,主会话)** — Agent 返回后主会话 Write 到 `reports/review/review-report-*.md`,并调用 `python <skills-root>/scripts/harness_review.py scaffold --change-dir <change-dir> [--run-id <id>]` 生成 findings 写入骨架(runId 缺省从 events.ndjson 最新 review phase.start 推断),补齐每一条发现后经 `harness_review.py write-findings --change-dir <change-dir> --stdin` 落地。每条发现必须填写 `fixbackAction=code|manual|workflow`:只有确实需要修改产品代码的项使用 `code`;人工验收用 `manual`;流程、暂存或工具使用建议用 `workflow`。权威计数来自 `reports/review/review-findings.json`,不是 Markdown。任一写入缺失 → 评审未完整结束,不得关门。
|
|
@@ -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=cdc01b6329bacd46; 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=cdc01b6329bacd46; overlay=none; agent=claude-code; do not edit -->
|
|
23
23
|
# harness-sync
|
|
24
24
|
|
|
25
25
|
## Purpose
|
|
@@ -478,6 +478,55 @@ def _phase_has_ended(event_paths: list[Path], phase: str) -> bool:
|
|
|
478
478
|
)
|
|
479
479
|
|
|
480
480
|
|
|
481
|
+
def _ensure_phase_end_event(
|
|
482
|
+
contract_root: Path,
|
|
483
|
+
*,
|
|
484
|
+
phase: str,
|
|
485
|
+
status: str,
|
|
486
|
+
executor: str,
|
|
487
|
+
) -> dict[str, Any] | None:
|
|
488
|
+
"""补齐 phase.start/end 事件对(P0-2)。
|
|
489
|
+
|
|
490
|
+
平台 Run 计时由 events-sync 上报的 phase.start/end 事件对驱动。不经
|
|
491
|
+
gate close 收尾的阶段(典型:plan 走 finalize + context close)只写
|
|
492
|
+
transitions 收据,phase.end 永远缺席,平台计时永不停——连续两个 change
|
|
493
|
+
复现,属结构性缺口(2026-08-30 sales-insight-agent demo-datasource 实测)。
|
|
494
|
+
close_transition 是所有跨阶段推进的共同通道,在此按事件配对补齐:
|
|
495
|
+
有 start 无 end → 复用 start 的 run_id/attempt 代写 end;已有 end(gate
|
|
496
|
+
close 先行写入)或连 start 都没有 → 不动,返回 None。
|
|
497
|
+
"""
|
|
498
|
+
import harness_events as he
|
|
499
|
+
|
|
500
|
+
events_file = contract_root / "events.ndjson"
|
|
501
|
+
events = _read_ndjson(events_file)
|
|
502
|
+
starts = [
|
|
503
|
+
item
|
|
504
|
+
for item in events
|
|
505
|
+
if hpaths.resolve_phase_name(item.get("phase")) == phase
|
|
506
|
+
and item.get("type") == "phase.start"
|
|
507
|
+
]
|
|
508
|
+
if not starts or any(
|
|
509
|
+
hpaths.resolve_phase_name(item.get("phase")) == phase
|
|
510
|
+
and item.get("type") == "phase.end"
|
|
511
|
+
for item in events
|
|
512
|
+
):
|
|
513
|
+
return None
|
|
514
|
+
start = starts[-1]
|
|
515
|
+
result = he.append_event(
|
|
516
|
+
contract_root,
|
|
517
|
+
phase=phase,
|
|
518
|
+
type_="phase.end",
|
|
519
|
+
run_id=str(start.get("run_id") or f"{phase}_unknown"),
|
|
520
|
+
attempt=int(start.get("attempt") or 1),
|
|
521
|
+
status=status,
|
|
522
|
+
executor_tool=executor,
|
|
523
|
+
note="context close 自动补齐 phase.end(平台计时事件对配对)",
|
|
524
|
+
)
|
|
525
|
+
if not result.get("ok"):
|
|
526
|
+
return {"code": "PHASE_END_PAIR_FAILED", "detail": result}
|
|
527
|
+
return {"code": "PHASE_END_AUTO_PAIRED", "event": result.get("event")}
|
|
528
|
+
|
|
529
|
+
|
|
481
530
|
def _reselect_review_fixback(
|
|
482
531
|
project: Path,
|
|
483
532
|
change: str,
|
|
@@ -1334,6 +1383,12 @@ def close_transition(
|
|
|
1334
1383
|
and latest.get("artifacts") == artifact_entries
|
|
1335
1384
|
and (executor is None or latest.get("executor") == executor)
|
|
1336
1385
|
):
|
|
1386
|
+
paired = _ensure_phase_end_event(
|
|
1387
|
+
contract_root,
|
|
1388
|
+
phase=from_phase,
|
|
1389
|
+
status=status,
|
|
1390
|
+
executor=executor or str(latest.get("executor") or "unknown"),
|
|
1391
|
+
)
|
|
1337
1392
|
return {
|
|
1338
1393
|
"ok": True,
|
|
1339
1394
|
"code": "TRANSITION_ALREADY_CLOSED",
|
|
@@ -1341,6 +1396,7 @@ def close_transition(
|
|
|
1341
1396
|
"receipt": latest,
|
|
1342
1397
|
"path": str(paths["transitions"]),
|
|
1343
1398
|
"invalidation": None,
|
|
1399
|
+
"phaseEndPair": paired,
|
|
1344
1400
|
}
|
|
1345
1401
|
return {"ok": False, "code": "CONTEXT_LEASE_REQUIRED"}
|
|
1346
1402
|
try:
|
|
@@ -1397,6 +1453,12 @@ def close_transition(
|
|
|
1397
1453
|
receipt["receiptHash"] = _payload_hash(receipt)
|
|
1398
1454
|
_append_ndjson(paths["transitions"], receipt)
|
|
1399
1455
|
paths["lease"].unlink(missing_ok=True)
|
|
1456
|
+
paired = _ensure_phase_end_event(
|
|
1457
|
+
contract_root,
|
|
1458
|
+
phase=from_phase,
|
|
1459
|
+
status=status,
|
|
1460
|
+
executor=effective_executor,
|
|
1461
|
+
)
|
|
1400
1462
|
invalidation = None
|
|
1401
1463
|
if to_phase == "execute" and from_phase in {"execute", "review"}:
|
|
1402
1464
|
invalidation = _invalidate_for_fixback(
|
|
@@ -1411,6 +1473,7 @@ def close_transition(
|
|
|
1411
1473
|
"receipt": receipt,
|
|
1412
1474
|
"path": str(paths["transitions"]),
|
|
1413
1475
|
"invalidation": invalidation,
|
|
1476
|
+
"phaseEndPair": paired,
|
|
1414
1477
|
}
|
|
1415
1478
|
|
|
1416
1479
|
|
|
@@ -1898,7 +1961,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1898
1961
|
prepare = sub.add_parser("prepare")
|
|
1899
1962
|
prepare.add_argument("--json", action="store_true")
|
|
1900
1963
|
prepare.add_argument("--project", required=True, type=Path)
|
|
1901
|
-
prepare.add_argument("--change")
|
|
1964
|
+
prepare.add_argument("--change", "--change-dir", dest="change")
|
|
1902
1965
|
prepare.add_argument("--phase", required=True)
|
|
1903
1966
|
prepare.add_argument("--executor", required=True)
|
|
1904
1967
|
prepare.add_argument("--title")
|
|
@@ -1907,7 +1970,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1907
1970
|
bootstrap = sub.add_parser("bootstrap-plan")
|
|
1908
1971
|
bootstrap.add_argument("--json", action="store_true")
|
|
1909
1972
|
bootstrap.add_argument("--project", required=True, type=Path)
|
|
1910
|
-
bootstrap.add_argument("--change", required=True)
|
|
1973
|
+
bootstrap.add_argument("--change", "--change-dir", dest="change", required=True)
|
|
1911
1974
|
bootstrap.add_argument("--executor", required=True)
|
|
1912
1975
|
bootstrap.add_argument("--title")
|
|
1913
1976
|
bootstrap.add_argument("--stage", default="plan", choices=["plan", "post-run"])
|
|
@@ -1915,7 +1978,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1915
1978
|
close = sub.add_parser("close")
|
|
1916
1979
|
close.add_argument("--json", action="store_true")
|
|
1917
1980
|
close.add_argument("--project", required=True, type=Path)
|
|
1918
|
-
close.add_argument("--change", required=True)
|
|
1981
|
+
close.add_argument("--change", "--change-dir", dest="change", required=True)
|
|
1919
1982
|
close.add_argument("--from-phase", required=True)
|
|
1920
1983
|
close.add_argument("--to-phase", required=True)
|
|
1921
1984
|
close.add_argument("--executor", required=True)
|
|
@@ -1924,7 +1987,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1924
1987
|
begin = sub.add_parser("begin")
|
|
1925
1988
|
begin.add_argument("--json", action="store_true")
|
|
1926
1989
|
begin.add_argument("--project", required=True, type=Path)
|
|
1927
|
-
begin.add_argument("--change", required=True)
|
|
1990
|
+
begin.add_argument("--change", "--change-dir", dest="change", required=True)
|
|
1928
1991
|
begin.add_argument("--phase", required=True)
|
|
1929
1992
|
begin.add_argument("--executor", required=True)
|
|
1930
1993
|
handoff = sub.add_parser(
|
|
@@ -1933,7 +1996,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1933
1996
|
)
|
|
1934
1997
|
handoff.add_argument("--json", action="store_true")
|
|
1935
1998
|
handoff.add_argument("--project", required=True, type=Path)
|
|
1936
|
-
handoff.add_argument("--change", required=True)
|
|
1999
|
+
handoff.add_argument("--change", "--change-dir", dest="change", required=True)
|
|
1937
2000
|
handoff.add_argument("--to-phase", required=True)
|
|
1938
2001
|
handoff.add_argument(
|
|
1939
2002
|
"--from-phase",
|
|
@@ -1946,20 +2009,20 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
1946
2009
|
)
|
|
1947
2010
|
renew.add_argument("--json", action="store_true")
|
|
1948
2011
|
renew.add_argument("--project", required=True, type=Path)
|
|
1949
|
-
renew.add_argument("--change", required=True)
|
|
2012
|
+
renew.add_argument("--change", "--change-dir", dest="change", required=True)
|
|
1950
2013
|
renew.add_argument("--executor", required=True)
|
|
1951
2014
|
renew.add_argument("--ttl-seconds", type=int, default=3600)
|
|
1952
2015
|
configure = sub.add_parser("configure-plan")
|
|
1953
2016
|
configure.add_argument("--json", action="store_true")
|
|
1954
2017
|
configure.add_argument("--project", required=True, type=Path)
|
|
1955
|
-
configure.add_argument("--change", required=True)
|
|
2018
|
+
configure.add_argument("--change", "--change-dir", dest="change", required=True)
|
|
1956
2019
|
configure.add_argument("--phases", required=True)
|
|
1957
2020
|
configure.add_argument("--operator", required=True)
|
|
1958
2021
|
configure.add_argument("--reason", required=True)
|
|
1959
2022
|
view = sub.add_parser("view")
|
|
1960
2023
|
view.add_argument("--json", action="store_true")
|
|
1961
2024
|
view.add_argument("--project", required=True, type=Path)
|
|
1962
|
-
view.add_argument("--change", required=True)
|
|
2025
|
+
view.add_argument("--change", "--change-dir", dest="change", required=True)
|
|
1963
2026
|
return parser
|
|
1964
2027
|
|
|
1965
2028
|
|
|
@@ -884,22 +884,32 @@ def build_event(args: argparse.Namespace, existing: list[dict[str, Any]]) -> dic
|
|
|
884
884
|
def validate_append_event(args: argparse.Namespace) -> tuple[str, str] | None:
|
|
885
885
|
"""Validate type-specific append fields before any file is mutated."""
|
|
886
886
|
event_type = str(args.type)
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
887
|
+
missing = [
|
|
888
|
+
f"--{field.replace('_', '-')}"
|
|
889
|
+
for field in _EVENT_REQUIRED_FIELDS.get(event_type, ())
|
|
890
|
+
if getattr(args, field, None) is None
|
|
891
|
+
or (isinstance(getattr(args, field, None), str)
|
|
892
|
+
and not getattr(args, field).strip())
|
|
893
|
+
]
|
|
894
|
+
if missing:
|
|
895
|
+
# 一次性列出全部缺失字段——逐个报错会让调用方每个字段往返一轮(E-3)
|
|
896
|
+
return (
|
|
897
|
+
"EVENT_REQUIRED_FIELD",
|
|
898
|
+
f"EVENT_REQUIRED_FIELD: {event_type} requires " + ", ".join(missing),
|
|
899
|
+
)
|
|
894
900
|
allowed = _EVENT_ALLOWED_FIELDS[event_type]
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
901
|
+
disallowed = [
|
|
902
|
+
f"--{field.replace('_', '-')}"
|
|
903
|
+
for field in OPTIONAL_FIELDS
|
|
904
|
+
if getattr(args, field, None) is not None and field not in allowed
|
|
905
|
+
]
|
|
906
|
+
if disallowed:
|
|
907
|
+
# 一次列出全部不被接受的字段——逐个报错会让调用方每字段往返一轮(R-4)
|
|
908
|
+
return (
|
|
909
|
+
"EVENT_FIELD_NOT_ALLOWED",
|
|
910
|
+
f"EVENT_FIELD_NOT_ALLOWED: {event_type} does not accept "
|
|
911
|
+
+ ", ".join(disallowed),
|
|
912
|
+
)
|
|
903
913
|
for field, length in (("trace_id", 32), ("span_id", 16), ("parent_span_id", 16)):
|
|
904
914
|
value = getattr(args, field, None)
|
|
905
915
|
if value is not None and not re.fullmatch(rf"[0-9a-f]{{{length}}}", str(value)):
|
|
@@ -2146,7 +2156,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2146
2156
|
parents=[common],
|
|
2147
2157
|
help="append one event and auto-render execution-log",
|
|
2148
2158
|
)
|
|
2149
|
-
p_append.add_argument("--change-dir", required=True)
|
|
2159
|
+
p_append.add_argument("--change-dir", "--change", dest="change_dir", required=True)
|
|
2150
2160
|
p_append.add_argument("--phase", required=True)
|
|
2151
2161
|
p_append.add_argument("--type", required=True)
|
|
2152
2162
|
p_append.add_argument("--command", default=None)
|
|
@@ -2200,7 +2210,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2200
2210
|
parents=[common],
|
|
2201
2211
|
help="validate and append many events under one lock (H-15)",
|
|
2202
2212
|
)
|
|
2203
|
-
p_batch.add_argument("--change-dir", required=True)
|
|
2213
|
+
p_batch.add_argument("--change-dir", "--change", dest="change_dir", required=True)
|
|
2204
2214
|
p_batch.add_argument(
|
|
2205
2215
|
"--file",
|
|
2206
2216
|
required=True,
|
|
@@ -2213,7 +2223,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2213
2223
|
parents=[common],
|
|
2214
2224
|
help="re-render execution-log.md from events.ndjson",
|
|
2215
2225
|
)
|
|
2216
|
-
p_render.add_argument("--change-dir", required=True)
|
|
2226
|
+
p_render.add_argument("--change-dir", "--change", dest="change_dir", required=True)
|
|
2217
2227
|
p_render.set_defaults(func=cmd_render)
|
|
2218
2228
|
|
|
2219
2229
|
p_summary = sub.add_parser(
|
|
@@ -2221,7 +2231,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
2221
2231
|
parents=[common],
|
|
2222
2232
|
help="summarize phases/issues from events.ndjson",
|
|
2223
2233
|
)
|
|
2224
|
-
p_summary.add_argument("--change-dir", required=True)
|
|
2234
|
+
p_summary.add_argument("--change-dir", "--change", dest="change_dir", required=True)
|
|
2225
2235
|
p_summary.set_defaults(func=cmd_summary)
|
|
2226
2236
|
|
|
2227
2237
|
return parser
|
|
@@ -75,6 +75,14 @@ def _write_json(path: Path, value: dict[str, Any]) -> None:
|
|
|
75
75
|
temporary.unlink(missing_ok=True)
|
|
76
76
|
|
|
77
77
|
|
|
78
|
+
def _read_json(path: Path) -> Any:
|
|
79
|
+
try:
|
|
80
|
+
value = json.loads(path.read_text(encoding="utf-8-sig"))
|
|
81
|
+
except (OSError, json.JSONDecodeError):
|
|
82
|
+
return None
|
|
83
|
+
return value
|
|
84
|
+
|
|
85
|
+
|
|
78
86
|
def _load(change_dir: Path, batch_id: str) -> dict[str, Any]:
|
|
79
87
|
path = _batch_path(change_dir, batch_id)
|
|
80
88
|
try:
|
|
@@ -1186,7 +1194,21 @@ def evidence_template(
|
|
|
1186
1194
|
"provenance": provenance,
|
|
1187
1195
|
}
|
|
1188
1196
|
target = Path(out) if out else Path("runtime") / f"fixback-{resolved_id}.json"
|
|
1189
|
-
|
|
1197
|
+
if target.is_absolute():
|
|
1198
|
+
path = target
|
|
1199
|
+
else:
|
|
1200
|
+
# F-3:与 ledger --out 同一类坑——相对路径已含 change-dir 前缀时直接拼
|
|
1201
|
+
# change_dir 会产生嵌套幽灵目录(2026-08-31 实测)。前缀命中按 cwd 解析。
|
|
1202
|
+
cwd = Path.cwd().resolve()
|
|
1203
|
+
change_resolved = change_dir.resolve()
|
|
1204
|
+
if _is_within(change_resolved, [cwd]):
|
|
1205
|
+
change_rel = change_resolved.relative_to(cwd)
|
|
1206
|
+
if target.parts[: len(change_rel.parts)] == change_rel.parts:
|
|
1207
|
+
path = cwd / target
|
|
1208
|
+
else:
|
|
1209
|
+
path = change_dir / target
|
|
1210
|
+
else:
|
|
1211
|
+
path = change_dir / target
|
|
1190
1212
|
path = path.resolve()
|
|
1191
1213
|
if not _is_within(path, [change_dir.resolve(), state_root, _project_root(change_dir)]):
|
|
1192
1214
|
return {
|
|
@@ -1708,6 +1730,20 @@ def close_batch(
|
|
|
1708
1730
|
}
|
|
1709
1731
|
)
|
|
1710
1732
|
_write_json(_batch_path(change_dir, batch_id), batch)
|
|
1733
|
+
# F-5:批次关闭会同步把托管会话置为 CLOSED——否则 session 永远 ACTIVE,
|
|
1734
|
+
# 后续 launch-review 被 CONTEXT_PREPARATION_ACTIVE 幂等保护误拦(2026-08-31
|
|
1735
|
+
# demo-datasource 实测)。
|
|
1736
|
+
session_file = _session_path(change_dir)
|
|
1737
|
+
session = _read_json(session_file)
|
|
1738
|
+
if (
|
|
1739
|
+
isinstance(session, dict)
|
|
1740
|
+
and session.get("batchId") == batch_id
|
|
1741
|
+
and session.get("status") == "ACTIVE"
|
|
1742
|
+
):
|
|
1743
|
+
session["status"] = "CLOSED"
|
|
1744
|
+
session["nextStep"] = "done"
|
|
1745
|
+
session["updatedAt"] = closed_at
|
|
1746
|
+
_write_json(session_file, session)
|
|
1711
1747
|
return batch
|
|
1712
1748
|
|
|
1713
1749
|
|