@hunter-harness/workflow-harness 0.2.82 → 0.2.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/harness/bundles/general/claude-code/.harness-build.json +1 -1
  2. package/harness/bundles/general/claude-code/harness-archive/SKILL.md +1 -1
  3. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +1 -1
  4. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  5. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +1 -1
  6. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +1 -1
  7. package/harness/bundles/general/claude-code/harness-pull/SKILL.md +1 -1
  8. package/harness/bundles/general/claude-code/harness-push/SKILL.md +1 -1
  9. package/harness/bundles/general/claude-code/harness-review/SKILL.md +1 -1
  10. package/harness/bundles/general/claude-code/harness-run/SKILL.md +22 -2
  11. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +1 -1
  12. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +1 -1
  13. package/harness/bundles/general/claude-code/harness-test/SKILL.md +1 -1
  14. package/harness/bundles/general/claude-code/scripts/harness_gate.py +78 -3
  15. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  16. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +1 -1
  17. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +1 -1
  18. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  19. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  20. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +1 -1
  21. package/harness/bundles/general/codebuddy/harness-pull/SKILL.md +1 -1
  22. package/harness/bundles/general/codebuddy/harness-push/SKILL.md +1 -1
  23. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +1 -1
  24. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +22 -2
  25. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +1 -1
  26. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +1 -1
  27. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +1 -1
  28. package/harness/bundles/general/codebuddy/scripts/harness_gate.py +78 -3
  29. package/harness/bundles/general/codex/.harness-build.json +1 -1
  30. package/harness/bundles/general/codex/harness-archive/SKILL.md +1 -1
  31. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +1 -1
  32. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +1 -1
  33. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +1 -1
  34. package/harness/bundles/general/codex/harness-plan/SKILL.md +1 -1
  35. package/harness/bundles/general/codex/harness-pull/SKILL.md +1 -1
  36. package/harness/bundles/general/codex/harness-push/SKILL.md +1 -1
  37. package/harness/bundles/general/codex/harness-review/SKILL.md +1 -1
  38. package/harness/bundles/general/codex/harness-run/SKILL.md +22 -2
  39. package/harness/bundles/general/codex/harness-submit/SKILL.md +1 -1
  40. package/harness/bundles/general/codex/harness-sync/SKILL.md +1 -1
  41. package/harness/bundles/general/codex/harness-test/SKILL.md +1 -1
  42. package/harness/bundles/general/codex/scripts/harness_gate.py +78 -3
  43. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  44. package/harness/bundles/general/cursor/harness-archive/SKILL.md +1 -1
  45. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +1 -1
  46. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  47. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +1 -1
  48. package/harness/bundles/general/cursor/harness-plan/SKILL.md +1 -1
  49. package/harness/bundles/general/cursor/harness-pull/SKILL.md +1 -1
  50. package/harness/bundles/general/cursor/harness-push/SKILL.md +1 -1
  51. package/harness/bundles/general/cursor/harness-review/SKILL.md +1 -1
  52. package/harness/bundles/general/cursor/harness-run/SKILL.md +22 -2
  53. package/harness/bundles/general/cursor/harness-submit/SKILL.md +1 -1
  54. package/harness/bundles/general/cursor/harness-sync/SKILL.md +1 -1
  55. package/harness/bundles/general/cursor/harness-test/SKILL.md +1 -1
  56. package/harness/bundles/general/cursor/scripts/harness_gate.py +78 -3
  57. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  58. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +1 -1
  59. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +1 -1
  60. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +1 -1
  61. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +1 -1
  62. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +1 -1
  63. package/harness/bundles/java/claude-code/harness-package/SKILL.md +1 -1
  64. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +1 -1
  65. package/harness/bundles/java/claude-code/harness-pull/SKILL.md +1 -1
  66. package/harness/bundles/java/claude-code/harness-push/SKILL.md +1 -1
  67. package/harness/bundles/java/claude-code/harness-review/SKILL.md +1 -1
  68. package/harness/bundles/java/claude-code/harness-run/SKILL.md +22 -2
  69. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +1 -1
  70. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +1 -1
  71. package/harness/bundles/java/claude-code/harness-test/SKILL.md +1 -1
  72. package/harness/bundles/java/claude-code/scripts/harness_gate.py +78 -3
  73. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  74. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +1 -1
  75. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +1 -1
  76. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +1 -1
  77. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +1 -1
  78. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +1 -1
  79. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +1 -1
  80. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +1 -1
  81. package/harness/bundles/java/codebuddy/harness-pull/SKILL.md +1 -1
  82. package/harness/bundles/java/codebuddy/harness-push/SKILL.md +1 -1
  83. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +1 -1
  84. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +22 -2
  85. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +1 -1
  86. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +1 -1
  87. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +1 -1
  88. package/harness/bundles/java/codebuddy/scripts/harness_gate.py +78 -3
  89. package/harness/bundles/java/codex/.harness-build.json +1 -1
  90. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +1 -1
  91. package/harness/bundles/java/codex/harness-archive/SKILL.md +1 -1
  92. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +1 -1
  93. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +1 -1
  94. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +1 -1
  95. package/harness/bundles/java/codex/harness-package/SKILL.md +1 -1
  96. package/harness/bundles/java/codex/harness-plan/SKILL.md +1 -1
  97. package/harness/bundles/java/codex/harness-pull/SKILL.md +1 -1
  98. package/harness/bundles/java/codex/harness-push/SKILL.md +1 -1
  99. package/harness/bundles/java/codex/harness-review/SKILL.md +1 -1
  100. package/harness/bundles/java/codex/harness-run/SKILL.md +22 -2
  101. package/harness/bundles/java/codex/harness-submit/SKILL.md +1 -1
  102. package/harness/bundles/java/codex/harness-sync/SKILL.md +1 -1
  103. package/harness/bundles/java/codex/harness-test/SKILL.md +1 -1
  104. package/harness/bundles/java/codex/scripts/harness_gate.py +78 -3
  105. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  106. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +1 -1
  107. package/harness/bundles/java/cursor/harness-archive/SKILL.md +1 -1
  108. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +1 -1
  109. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +1 -1
  110. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +1 -1
  111. package/harness/bundles/java/cursor/harness-package/SKILL.md +1 -1
  112. package/harness/bundles/java/cursor/harness-plan/SKILL.md +1 -1
  113. package/harness/bundles/java/cursor/harness-pull/SKILL.md +1 -1
  114. package/harness/bundles/java/cursor/harness-push/SKILL.md +1 -1
  115. package/harness/bundles/java/cursor/harness-review/SKILL.md +1 -1
  116. package/harness/bundles/java/cursor/harness-run/SKILL.md +22 -2
  117. package/harness/bundles/java/cursor/harness-submit/SKILL.md +1 -1
  118. package/harness/bundles/java/cursor/harness-sync/SKILL.md +1 -1
  119. package/harness/bundles/java/cursor/harness-test/SKILL.md +1 -1
  120. package/harness/bundles/java/cursor/scripts/harness_gate.py +78 -3
  121. package/harness/manifests/general/claude-code.json +15 -15
  122. package/harness/manifests/general/codebuddy.json +15 -15
  123. package/harness/manifests/general/codex.json +15 -15
  124. package/harness/manifests/general/cursor.json +15 -15
  125. package/harness/manifests/java/claude-code.json +17 -17
  126. package/harness/manifests/java/codebuddy.json +17 -17
  127. package/harness/manifests/java/codex.json +17 -17
  128. package/harness/manifests/java/cursor.json +17 -17
  129. package/hunter-workflow-family.json +3 -3
  130. package/package.json +1 -1
@@ -2,5 +2,5 @@
2
2
  "schemaVersion": 1,
3
3
  "overlay": "none",
4
4
  "agent": "claude-code",
5
- "coreHash": "611f91f44adcd1d1"
5
+ "coreHash": "d1ddcf707a26d7b6"
6
6
  }
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; 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=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
23
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; 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=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
11
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; 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=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
11
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; 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=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-plan — 需求规划
26
26
 
27
27
  ## Purpose
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; 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=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; 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=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
25
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; 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=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
25
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=claude-code; do not edit -->
26
26
  # harness-run — 需求编码
27
27
 
28
28
  ## Purpose
@@ -92,6 +92,24 @@ disallowed-tools:
92
92
 
93
93
  **Fixback**:入口只用 `launch-review`,后续问题处理通过 `resolve-issue/close` 驱动,不得把修复说明当成新的普通 Run。只读取返回的受影响问题和文件;验证仅失效与 `changedFiles` 相交的目标,其他 Test/Review 证据继续复用。RED 优先;`manual`、`workflow` 或未选用的建议不进入代码批次,使用中文记录处理结论。
94
94
 
95
+ **构建/测试执行入口**:所有构建与测试命令(mvn / gradle / npm test / pytest 等)必须经 `harness_test_runner.py exec` 发起,**禁止**用 `powershell.exe -Command` 直接裸跑:
96
+
97
+ ```text
98
+ python <skills-root>/scripts/harness_test_runner.py exec --project . --timeout-seconds <预估上限> -- <构建命令及参数>
99
+ ```
100
+
101
+ 该入口持有项目级互斥锁并托管进程树。裸跑构建在宿主工具超时后会被推入后台,多个后台构建同时写同一个 `target/`、`build/` 或 `node_modules/.cache`,表现为编译产物被清空、日志文件被占用、"增量编译抖动"——这些都不是代码缺陷,是并发自相残杀,排查成本极高。`--timeout-seconds` 按最慢的一次全量构建估(默认 300 秒偏短),宁可给足也不要让命令被中途掐断。
102
+
103
+ 返回 `TEST_RUN_ALREADY_ACTIVE`(退出码 3)说明**已有构建在跑**:等它结束或用 `lock-status` 查明持有者,**不得**改用裸跑绕开锁,也不得另起一个并行构建。确认持有进程已消失时才用 `lock-reap` 回收。
104
+
105
+ **长阶段租约续期**:`gate begin` 的租约默认 TTL 3600 秒,而 run 阶段常常跑得更久。租约过期不会中断执行,只会让最后的 `gate close` 报 `LEASE_ABSENT`。凡预计超过 1 小时的阶段,每完成一个变更簇就用本阶段**原 run-id** 续租一次(同 run-id 重复 claim 即刷新,不会新开 attempt):
106
+
107
+ ```text
108
+ python <skills-root>/scripts/harness_change.py claim --change <id> --phase run --run-id <本阶段 run-id> --ttl-seconds 3600 --json
109
+ ```
110
+
111
+ 已经报了 `LEASE_ABSENT` 也按同一条命令恢复——错误响应的 `resumeRunId` 就是要用的 run-id;**不要**重跑 `gate begin`,那会新开 attempt 并丢失本轮 capsule。
112
+
95
113
  **执行器边界**:优先使用项目 build profile 和已有测试入口。禁止为了绕过 ESM、路径或参数问题临时生成 `.js`、`require` 脚本;需要文件式 runner 时使用项目已有入口,确需新增时遵循项目模块类型(例如 ESM 使用 `.mjs`)。runner 包装说明写入 `runnerCommand` 元数据,不得拼进账本的规范 `command`。
96
114
 
97
115
  **Foundation Gate**:若 `meta/implementation-checkpoints.json` 中 `foundation-gate` 为 pending,不得开始 plan 中任务 6+;由 `harness_gate.py` 硬阻断。
@@ -123,7 +141,9 @@ disallowed-tools:
123
141
  | **预存变更** | 保留 → baseline 隔离;存在则最终 ≥ 🟡WARN |
124
142
  | **关门/状态** | 10 项关门检查;持久化 run-task-status;仅 run-owned P0 静态-only 导致 WARN;test-owned 待办正常移交 |
125
143
  | **Worktree** | `requested=true` 时代码只写 worktree |
126
- | **PowerShell** | 所有 git/构建经 `powershell.exe -NoProfile -Command` |
144
+ | **构建/测试** | 一律经 `harness_test_runner.py exec`;禁止裸跑 mvn/gradle/npm test;`TEST_RUN_ALREADY_ACTIVE` 表示已有构建在跑,等待而非另起 |
145
+ | **租约** | 阶段超 1 小时按变更簇用原 run-id 续租;`LEASE_ABSENT` 用 `harness_change.py claim` 恢复,不重跑 begin |
146
+ | **PowerShell** | 所有 git 经 `powershell.exe -NoProfile -Command` |
127
147
 
128
148
  ### 陈旧测试安全修复与精确跟踪
129
149
 
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; 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=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
22
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; 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=611f91f44adcd1d1; overlay=none; agent=claude-code; do not edit -->
26
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=claude-code; do not edit -->
27
27
  # harness-test — 测试执行
28
28
 
29
29
  ## Purpose
@@ -1906,6 +1906,31 @@ def _latest_phase_end(
1906
1906
  return None
1907
1907
 
1908
1908
 
1909
+ def _latest_open_run_id(change_dir: Path, phase: str) -> str | None:
1910
+ """Return the newest ``phase.start`` run_id that has no matching ``phase.end``.
1911
+
1912
+ A long phase can outlive its lease TTL; close then reports ``LEASE_ABSENT``
1913
+ with no way back. Resuming needs the *original* run_id, so surface it here
1914
+ instead of making the caller reconstruct it from ``events.ndjson``.
1915
+ """
1916
+ started: list[str] = []
1917
+ ended: set[str] = set()
1918
+ for event in he.load_events(he.events_path(change_dir)):
1919
+ if event.get("phase") != phase:
1920
+ continue
1921
+ run_id = str(event.get("run_id") or "")
1922
+ if not run_id:
1923
+ continue
1924
+ if event.get("type") == "phase.start":
1925
+ started.append(run_id)
1926
+ elif event.get("type") == "phase.end":
1927
+ ended.add(run_id)
1928
+ for run_id in reversed(started):
1929
+ if run_id not in ended:
1930
+ return run_id
1931
+ return None
1932
+
1933
+
1909
1934
  def _terminal_matches_context_session(
1910
1935
  project: Path,
1911
1936
  change_id: str,
@@ -2631,11 +2656,42 @@ def cmd_begin(args: argparse.Namespace) -> int:
2631
2656
  ttl_seconds=int(args.ttl_seconds),
2632
2657
  )
2633
2658
  if not claim.get("ok"):
2659
+ claim_code = str(claim.get("code", "LEASE_CONFLICT"))
2660
+ claim_extra = {
2661
+ k: v for k, v in claim.items() if k not in {"ok", "message", "code"}
2662
+ }
2663
+ holder = claim.get("holder")
2664
+ if claim_code == "LEASE_CONFLICT" and isinstance(holder, dict):
2665
+ holder_phase = str(holder.get("phase") or "")
2666
+ holder_run_id = str(holder.get("runId") or "")
2667
+ # A lease whose own phase already recorded phase.end is leftover state:
2668
+ # only close releases the lease, so any begin-without-close strands it
2669
+ # for the full TTL and blocks the next phase.
2670
+ holder_closed = (
2671
+ bool(holder_phase)
2672
+ and bool(holder_run_id)
2673
+ and _latest_phase_end(change_dir, holder_phase, holder_run_id) is not None
2674
+ )
2675
+ claim_extra["holderPhaseClosed"] = holder_closed
2676
+ if holder_closed:
2677
+ claim_extra["recoveryAction"] = (
2678
+ f"持有租约的 {holder_phase} 阶段(run-id {holder_run_id})已写入 phase.end,"
2679
+ "这是残留租约,释放后重试 begin 是安全的:"
2680
+ "python <skills-root>/scripts/harness_change.py release "
2681
+ f"--change {resolved['changeId']} --phase {holder_phase} "
2682
+ f"--run-id {holder_run_id} --json"
2683
+ )
2684
+ else:
2685
+ claim_extra["recoveryAction"] = (
2686
+ f"{holder_phase or '另一个'} 阶段(run-id {holder_run_id or '未知'})"
2687
+ "仍在进行中且尚未写入 phase.end。先让该阶段正常关门;"
2688
+ "确认其执行进程已不存在时才可释放租约,不要直接 --steal。"
2689
+ )
2634
2690
  return emit_error(
2635
- str(claim.get("code", "LEASE_CONFLICT")),
2691
+ claim_code,
2636
2692
  str(claim.get("message", "lease claim failed")),
2637
2693
  as_json=as_json,
2638
- extra={k: v for k, v in claim.items() if k not in {"ok", "message", "code"}},
2694
+ extra=claim_extra,
2639
2695
  )
2640
2696
 
2641
2697
  guard_result: dict[str, Any] | None = None
@@ -2843,7 +2899,26 @@ def cmd_close(args: argparse.Namespace) -> int:
2843
2899
  as_json=as_json,
2844
2900
  )
2845
2901
  return 0
2846
- return emit_error("LEASE_ABSENT", "no active lease for phase close", as_json=as_json)
2902
+ resume_run_id = explicit_run_id or _latest_open_run_id(change_dir, args.phase)
2903
+ return emit_error(
2904
+ "LEASE_ABSENT",
2905
+ "no active lease for phase close",
2906
+ as_json=as_json,
2907
+ extra={
2908
+ "retryable": True,
2909
+ "phase": args.phase,
2910
+ "changeId": resolved["changeId"],
2911
+ "resumeRunId": resume_run_id,
2912
+ "recoveryAction": (
2913
+ "阶段租约已过期(TTL 由 begin 的 --ttl-seconds 决定,默认 3600 秒)或已被释放。"
2914
+ "用本阶段原 run-id 重新取得租约后原样重试 close:"
2915
+ "python <skills-root>/scripts/harness_change.py claim "
2916
+ f"--change {resolved['changeId']} --phase {args.phase} "
2917
+ f"--run-id {resume_run_id or '<原 run-id>'} --ttl-seconds 3600 --json"
2918
+ "。不要重跑 gate begin——那会新开一次 attempt 并丢失本轮 capsule。"
2919
+ ),
2920
+ },
2921
+ )
2847
2922
  run_id = explicit_run_id or str(current_lease.get("runId") or "")
2848
2923
  if str(current_lease.get("runId")) != run_id or str(current_lease.get("phase")) != args.phase:
2849
2924
  return emit_error(
@@ -2,5 +2,5 @@
2
2
  "schemaVersion": 1,
3
3
  "overlay": "none",
4
4
  "agent": "codebuddy",
5
- "coreHash": "611f91f44adcd1d1"
5
+ "coreHash": "d1ddcf707a26d7b6"
6
6
  }
@@ -3,7 +3,7 @@ name: harness-archive
3
3
  description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档)到 .harness/archive/,含归档元数据。仅当用户显式调用
4
4
  /harness-archive 时使用;不得被其他阶段 skill 自动接续触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-archive — 变更归档
8
8
 
9
9
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-codebase-map
3
3
  description: 分析现有代码库并生成 .harness/codebase/map/
4
4
  下的结构化代码库地图。用于陌生项目理解、重大改造前梳理、harness-sync 提示 map 过期后的人工刷新。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-codebase-map — 代码库地图
8
8
 
9
9
  ## Purpose
@@ -2,7 +2,7 @@
2
2
  name: harness-knowledge-ingest
3
3
  description: 确认归档 ZIP 已上传并由 Hunter Platform 在服务端解包、校验和入库。客户端不再构建或维护本地知识索引。
4
4
  ---
5
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
5
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
6
6
  # harness-knowledge-ingest
7
7
 
8
8
  知识 ingest 完全由 Hunter Platform 负责。归档完成时,客户端生成一个确定性 ZIP;
@@ -2,7 +2,7 @@
2
2
  name: harness-knowledge-query
3
3
  description: 在规划、实现或排查前,通过 hunter-harness CLI 查询远端项目知识库。远端不可用时直接报告不可用,不建立本地索引或离线回退。
4
4
  ---
5
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
5
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
6
6
  # harness-knowledge-query
7
7
 
8
8
  项目知识以 Hunter Platform 的服务端索引为唯一真源。客户端只提交查询并消费结果:
@@ -3,7 +3,7 @@ name: harness-plan
3
3
  description: 将需求转化为设计文档+实施计划+完整测试场景表,必须在编码前完成。仅当用户显式调用 /harness-plan 或明确要求进入
4
4
  Harness 规划阶段时使用;不得因用户描述需求就自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-plan — 需求规划
8
8
 
9
9
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-pull
3
3
  description: 从 Hunter Platform 下拉配置/规则/架构/指令(及显式来源分支的分支文件恢复)。仅当用户显式调用
4
4
  /harness-pull 或明确说'从平台拉取/恢复'时使用;不得自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-pull — 从 Hunter Platform 下拉与恢复
8
8
 
9
9
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-push
3
3
  description: 上传本地配置/规则/架构/指令(及显式归档)到 Hunter Platform。仅当用户显式调用 /harness-push
4
4
  或明确说'上传到平台'时使用;不得因存在本地修改就自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-push — 上传到 Hunter Platform
8
8
 
9
9
  ## Purpose
@@ -4,7 +4,7 @@ description: 6维度代码审查(架构/安全/规范/兼容/测试/性能)
4
4
  .harness/context-index.json)和测试场景表,在隔离上下文运行。仅当用户显式调用 /harness-review 时使用;不得在
5
5
  test 结束后自动接续执行。
6
6
  ---
7
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
7
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
8
8
  # harness-review — 代码审查
9
9
 
10
10
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-run
3
3
  description: 按变更簇执行 TDD 编码循环(RED→GREEN→REFACTOR→编译验证),逐变更簇实现计划中的任务。仅当用户显式调用
4
4
  /harness-run 时使用;不得因用户提到编码/实现就自动触发,也不得被其他阶段 skill 自动接续。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-run — 需求编码
8
8
 
9
9
  ## Purpose
@@ -73,6 +73,24 @@ description: 按变更簇执行 TDD 编码循环(RED→GREEN→REFACTOR→编
73
73
 
74
74
  **Fixback**:入口只用 `launch-review`,后续问题处理通过 `resolve-issue/close` 驱动,不得把修复说明当成新的普通 Run。只读取返回的受影响问题和文件;验证仅失效与 `changedFiles` 相交的目标,其他 Test/Review 证据继续复用。RED 优先;`manual`、`workflow` 或未选用的建议不进入代码批次,使用中文记录处理结论。
75
75
 
76
+ **构建/测试执行入口**:所有构建与测试命令(mvn / gradle / npm test / pytest 等)必须经 `harness_test_runner.py exec` 发起,**禁止**用 `powershell.exe -Command` 直接裸跑:
77
+
78
+ ```text
79
+ python <skills-root>/scripts/harness_test_runner.py exec --project . --timeout-seconds <预估上限> -- <构建命令及参数>
80
+ ```
81
+
82
+ 该入口持有项目级互斥锁并托管进程树。裸跑构建在宿主工具超时后会被推入后台,多个后台构建同时写同一个 `target/`、`build/` 或 `node_modules/.cache`,表现为编译产物被清空、日志文件被占用、"增量编译抖动"——这些都不是代码缺陷,是并发自相残杀,排查成本极高。`--timeout-seconds` 按最慢的一次全量构建估(默认 300 秒偏短),宁可给足也不要让命令被中途掐断。
83
+
84
+ 返回 `TEST_RUN_ALREADY_ACTIVE`(退出码 3)说明**已有构建在跑**:等它结束或用 `lock-status` 查明持有者,**不得**改用裸跑绕开锁,也不得另起一个并行构建。确认持有进程已消失时才用 `lock-reap` 回收。
85
+
86
+ **长阶段租约续期**:`gate begin` 的租约默认 TTL 3600 秒,而 run 阶段常常跑得更久。租约过期不会中断执行,只会让最后的 `gate close` 报 `LEASE_ABSENT`。凡预计超过 1 小时的阶段,每完成一个变更簇就用本阶段**原 run-id** 续租一次(同 run-id 重复 claim 即刷新,不会新开 attempt):
87
+
88
+ ```text
89
+ python <skills-root>/scripts/harness_change.py claim --change <id> --phase run --run-id <本阶段 run-id> --ttl-seconds 3600 --json
90
+ ```
91
+
92
+ 已经报了 `LEASE_ABSENT` 也按同一条命令恢复——错误响应的 `resumeRunId` 就是要用的 run-id;**不要**重跑 `gate begin`,那会新开 attempt 并丢失本轮 capsule。
93
+
76
94
  **执行器边界**:优先使用项目 build profile 和已有测试入口。禁止为了绕过 ESM、路径或参数问题临时生成 `.js`、`require` 脚本;需要文件式 runner 时使用项目已有入口,确需新增时遵循项目模块类型(例如 ESM 使用 `.mjs`)。runner 包装说明写入 `runnerCommand` 元数据,不得拼进账本的规范 `command`。
77
95
 
78
96
  **Foundation Gate**:若 `meta/implementation-checkpoints.json` 中 `foundation-gate` 为 pending,不得开始 plan 中任务 6+;由 `harness_gate.py` 硬阻断。
@@ -104,7 +122,9 @@ description: 按变更簇执行 TDD 编码循环(RED→GREEN→REFACTOR→编
104
122
  | **预存变更** | 保留 → baseline 隔离;存在则最终 ≥ 🟡WARN |
105
123
  | **关门/状态** | 10 项关门检查;持久化 run-task-status;仅 run-owned P0 静态-only 导致 WARN;test-owned 待办正常移交 |
106
124
  | **Worktree** | `requested=true` 时代码只写 worktree |
107
- | **PowerShell** | 所有 git/构建经 `powershell.exe -NoProfile -Command` |
125
+ | **构建/测试** | 一律经 `harness_test_runner.py exec`;禁止裸跑 mvn/gradle/npm test;`TEST_RUN_ALREADY_ACTIVE` 表示已有构建在跑,等待而非另起 |
126
+ | **租约** | 阶段超 1 小时按变更簇用原 run-id 续租;`LEASE_ABSENT` 用 `harness_change.py claim` 恢复,不重跑 begin |
127
+ | **PowerShell** | 所有 git 经 `powershell.exe -NoProfile -Command` |
108
128
 
109
129
  ### 陈旧测试安全修复与精确跟踪
110
130
 
@@ -3,7 +3,7 @@ name: harness-submit
3
3
  description: 最终提交封装:验证→中文 commit→提交/推送;worktree 模式含 --no-ff 合并回主分支。仅当用户显式调用
4
4
  /harness-submit(或 /harness-merge 重入合并段)时使用;用户口头说'提交/commit/push'时必须先确认,不得自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-submit — 最终提交(含 worktree 合并)
8
8
 
9
9
  ## Purpose
@@ -4,7 +4,7 @@ description: Use when the user asks to synchronize, refresh, or validate Harness
4
4
  metadata, adapters, remote knowledge ownership, instruction entrypoints,
5
5
  config origins, or CodeGraph status.
6
6
  ---
7
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
7
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
8
8
  # harness-sync
9
9
 
10
10
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-test
3
3
  description: 测试执行:读取场景表,执行单元测试+API接口测试+数据兼容验证,输出测试报告。仅当用户显式调用 /harness-test
4
4
  时使用;不得在 run 结束后自动接续执行。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=611f91f44adcd1d1; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=d1ddcf707a26d7b6; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-test — 测试执行
8
8
 
9
9
  ## Purpose
@@ -1906,6 +1906,31 @@ def _latest_phase_end(
1906
1906
  return None
1907
1907
 
1908
1908
 
1909
+ def _latest_open_run_id(change_dir: Path, phase: str) -> str | None:
1910
+ """Return the newest ``phase.start`` run_id that has no matching ``phase.end``.
1911
+
1912
+ A long phase can outlive its lease TTL; close then reports ``LEASE_ABSENT``
1913
+ with no way back. Resuming needs the *original* run_id, so surface it here
1914
+ instead of making the caller reconstruct it from ``events.ndjson``.
1915
+ """
1916
+ started: list[str] = []
1917
+ ended: set[str] = set()
1918
+ for event in he.load_events(he.events_path(change_dir)):
1919
+ if event.get("phase") != phase:
1920
+ continue
1921
+ run_id = str(event.get("run_id") or "")
1922
+ if not run_id:
1923
+ continue
1924
+ if event.get("type") == "phase.start":
1925
+ started.append(run_id)
1926
+ elif event.get("type") == "phase.end":
1927
+ ended.add(run_id)
1928
+ for run_id in reversed(started):
1929
+ if run_id not in ended:
1930
+ return run_id
1931
+ return None
1932
+
1933
+
1909
1934
  def _terminal_matches_context_session(
1910
1935
  project: Path,
1911
1936
  change_id: str,
@@ -2631,11 +2656,42 @@ def cmd_begin(args: argparse.Namespace) -> int:
2631
2656
  ttl_seconds=int(args.ttl_seconds),
2632
2657
  )
2633
2658
  if not claim.get("ok"):
2659
+ claim_code = str(claim.get("code", "LEASE_CONFLICT"))
2660
+ claim_extra = {
2661
+ k: v for k, v in claim.items() if k not in {"ok", "message", "code"}
2662
+ }
2663
+ holder = claim.get("holder")
2664
+ if claim_code == "LEASE_CONFLICT" and isinstance(holder, dict):
2665
+ holder_phase = str(holder.get("phase") or "")
2666
+ holder_run_id = str(holder.get("runId") or "")
2667
+ # A lease whose own phase already recorded phase.end is leftover state:
2668
+ # only close releases the lease, so any begin-without-close strands it
2669
+ # for the full TTL and blocks the next phase.
2670
+ holder_closed = (
2671
+ bool(holder_phase)
2672
+ and bool(holder_run_id)
2673
+ and _latest_phase_end(change_dir, holder_phase, holder_run_id) is not None
2674
+ )
2675
+ claim_extra["holderPhaseClosed"] = holder_closed
2676
+ if holder_closed:
2677
+ claim_extra["recoveryAction"] = (
2678
+ f"持有租约的 {holder_phase} 阶段(run-id {holder_run_id})已写入 phase.end,"
2679
+ "这是残留租约,释放后重试 begin 是安全的:"
2680
+ "python <skills-root>/scripts/harness_change.py release "
2681
+ f"--change {resolved['changeId']} --phase {holder_phase} "
2682
+ f"--run-id {holder_run_id} --json"
2683
+ )
2684
+ else:
2685
+ claim_extra["recoveryAction"] = (
2686
+ f"{holder_phase or '另一个'} 阶段(run-id {holder_run_id or '未知'})"
2687
+ "仍在进行中且尚未写入 phase.end。先让该阶段正常关门;"
2688
+ "确认其执行进程已不存在时才可释放租约,不要直接 --steal。"
2689
+ )
2634
2690
  return emit_error(
2635
- str(claim.get("code", "LEASE_CONFLICT")),
2691
+ claim_code,
2636
2692
  str(claim.get("message", "lease claim failed")),
2637
2693
  as_json=as_json,
2638
- extra={k: v for k, v in claim.items() if k not in {"ok", "message", "code"}},
2694
+ extra=claim_extra,
2639
2695
  )
2640
2696
 
2641
2697
  guard_result: dict[str, Any] | None = None
@@ -2843,7 +2899,26 @@ def cmd_close(args: argparse.Namespace) -> int:
2843
2899
  as_json=as_json,
2844
2900
  )
2845
2901
  return 0
2846
- return emit_error("LEASE_ABSENT", "no active lease for phase close", as_json=as_json)
2902
+ resume_run_id = explicit_run_id or _latest_open_run_id(change_dir, args.phase)
2903
+ return emit_error(
2904
+ "LEASE_ABSENT",
2905
+ "no active lease for phase close",
2906
+ as_json=as_json,
2907
+ extra={
2908
+ "retryable": True,
2909
+ "phase": args.phase,
2910
+ "changeId": resolved["changeId"],
2911
+ "resumeRunId": resume_run_id,
2912
+ "recoveryAction": (
2913
+ "阶段租约已过期(TTL 由 begin 的 --ttl-seconds 决定,默认 3600 秒)或已被释放。"
2914
+ "用本阶段原 run-id 重新取得租约后原样重试 close:"
2915
+ "python <skills-root>/scripts/harness_change.py claim "
2916
+ f"--change {resolved['changeId']} --phase {args.phase} "
2917
+ f"--run-id {resume_run_id or '<原 run-id>'} --ttl-seconds 3600 --json"
2918
+ "。不要重跑 gate begin——那会新开一次 attempt 并丢失本轮 capsule。"
2919
+ ),
2920
+ },
2921
+ )
2847
2922
  run_id = explicit_run_id or str(current_lease.get("runId") or "")
2848
2923
  if str(current_lease.get("runId")) != run_id or str(current_lease.get("phase")) != args.phase:
2849
2924
  return emit_error(
@@ -2,5 +2,5 @@
2
2
  "schemaVersion": 1,
3
3
  "overlay": "none",
4
4
  "agent": "codex",
5
- "coreHash": "2676178fa6f219fd"
5
+ "coreHash": "164aae46328cbf6c"
6
6
  }
@@ -3,7 +3,7 @@ name: harness-archive
3
3
  description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档)到 .harness/archive/,含归档元数据。仅当用户显式调用
4
4
  /harness-archive 时使用;不得被其他阶段 skill 自动接续触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=2676178fa6f219fd; overlay=none; agent=codex; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=164aae46328cbf6c; overlay=none; agent=codex; do not edit -->
7
7
  # harness-archive — 变更归档
8
8
 
9
9
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-codebase-map
3
3
  description: 分析现有代码库并生成 .harness/codebase/map/
4
4
  下的结构化代码库地图。用于陌生项目理解、重大改造前梳理、harness-sync 提示 map 过期后的人工刷新。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=2676178fa6f219fd; overlay=none; agent=codex; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=164aae46328cbf6c; overlay=none; agent=codex; do not edit -->
7
7
  # harness-codebase-map — 代码库地图
8
8
 
9
9
  ## Purpose
@@ -2,7 +2,7 @@
2
2
  name: harness-knowledge-ingest
3
3
  description: 确认归档 ZIP 已上传并由 Hunter Platform 在服务端解包、校验和入库。客户端不再构建或维护本地知识索引。
4
4
  ---
5
- <!-- generated by harness_deploy.py; core=2676178fa6f219fd; overlay=none; agent=codex; do not edit -->
5
+ <!-- generated by harness_deploy.py; core=164aae46328cbf6c; overlay=none; agent=codex; do not edit -->
6
6
  # harness-knowledge-ingest
7
7
 
8
8
  知识 ingest 完全由 Hunter Platform 负责。归档完成时,客户端生成一个确定性 ZIP;
@@ -2,7 +2,7 @@
2
2
  name: harness-knowledge-query
3
3
  description: 在规划、实现或排查前,通过 hunter-harness CLI 查询远端项目知识库。远端不可用时直接报告不可用,不建立本地索引或离线回退。
4
4
  ---
5
- <!-- generated by harness_deploy.py; core=2676178fa6f219fd; overlay=none; agent=codex; do not edit -->
5
+ <!-- generated by harness_deploy.py; core=164aae46328cbf6c; overlay=none; agent=codex; do not edit -->
6
6
  # harness-knowledge-query
7
7
 
8
8
  项目知识以 Hunter Platform 的服务端索引为唯一真源。客户端只提交查询并消费结果:
@@ -3,7 +3,7 @@ name: harness-plan
3
3
  description: 将需求转化为设计文档+实施计划+完整测试场景表,必须在编码前完成。仅当用户显式调用 /harness-plan 或明确要求进入
4
4
  Harness 规划阶段时使用;不得因用户描述需求就自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=2676178fa6f219fd; overlay=none; agent=codex; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=164aae46328cbf6c; overlay=none; agent=codex; do not edit -->
7
7
  # harness-plan — 需求规划
8
8
 
9
9
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-pull
3
3
  description: 从 Hunter Platform 下拉配置/规则/架构/指令(及显式来源分支的分支文件恢复)。仅当用户显式调用
4
4
  /harness-pull 或明确说'从平台拉取/恢复'时使用;不得自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=2676178fa6f219fd; overlay=none; agent=codex; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=164aae46328cbf6c; overlay=none; agent=codex; do not edit -->
7
7
  # harness-pull — 从 Hunter Platform 下拉与恢复
8
8
 
9
9
  ## Purpose
@@ -3,7 +3,7 @@ name: harness-push
3
3
  description: 上传本地配置/规则/架构/指令(及显式归档)到 Hunter Platform。仅当用户显式调用 /harness-push
4
4
  或明确说'上传到平台'时使用;不得因存在本地修改就自动触发。
5
5
  ---
6
- <!-- generated by harness_deploy.py; core=2676178fa6f219fd; overlay=none; agent=codex; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=164aae46328cbf6c; overlay=none; agent=codex; do not edit -->
7
7
  # harness-push — 上传到 Hunter Platform
8
8
 
9
9
  ## Purpose