@hunter-harness/workflow-harness 0.2.48 → 0.2.50

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 +9 -1
  3. package/harness/bundles/general/claude-code/harness-codebase-map/SKILL.md +6 -1
  4. package/harness/bundles/general/claude-code/harness-knowledge-ingest/SKILL.md +21 -4
  5. package/harness/bundles/general/claude-code/harness-knowledge-query/SKILL.md +17 -6
  6. package/harness/bundles/general/claude-code/harness-plan/SKILL.md +6 -1
  7. package/harness/bundles/general/claude-code/harness-review/SKILL.md +6 -1
  8. package/harness/bundles/general/claude-code/harness-run/SKILL.md +7 -2
  9. package/harness/bundles/general/claude-code/harness-submit/SKILL.md +6 -1
  10. package/harness/bundles/general/claude-code/harness-sync/SKILL.md +6 -1
  11. package/harness/bundles/general/claude-code/harness-test/SKILL.md +6 -1
  12. package/harness/bundles/general/claude-code/scripts/harness_archive.py +31 -1
  13. package/harness/bundles/general/claude-code/scripts/harness_events_sync.py +90 -12
  14. package/harness/bundles/general/claude-code/scripts/harness_gate.py +17 -0
  15. package/harness/bundles/general/codebuddy/.harness-build.json +1 -1
  16. package/harness/bundles/general/codebuddy/harness-archive/SKILL.md +9 -1
  17. package/harness/bundles/general/codebuddy/harness-codebase-map/SKILL.md +6 -1
  18. package/harness/bundles/general/codebuddy/harness-knowledge-ingest/SKILL.md +21 -4
  19. package/harness/bundles/general/codebuddy/harness-knowledge-query/SKILL.md +17 -6
  20. package/harness/bundles/general/codebuddy/harness-plan/SKILL.md +6 -1
  21. package/harness/bundles/general/codebuddy/harness-review/SKILL.md +6 -1
  22. package/harness/bundles/general/codebuddy/harness-run/SKILL.md +7 -2
  23. package/harness/bundles/general/codebuddy/harness-submit/SKILL.md +6 -1
  24. package/harness/bundles/general/codebuddy/harness-sync/SKILL.md +6 -1
  25. package/harness/bundles/general/codebuddy/harness-test/SKILL.md +6 -1
  26. package/harness/bundles/general/codebuddy/scripts/harness_archive.py +31 -1
  27. package/harness/bundles/general/codebuddy/scripts/harness_events_sync.py +90 -12
  28. package/harness/bundles/general/codebuddy/scripts/harness_gate.py +17 -0
  29. package/harness/bundles/general/codex/.harness-build.json +1 -1
  30. package/harness/bundles/general/codex/harness-archive/SKILL.md +9 -1
  31. package/harness/bundles/general/codex/harness-codebase-map/SKILL.md +6 -1
  32. package/harness/bundles/general/codex/harness-knowledge-ingest/SKILL.md +21 -4
  33. package/harness/bundles/general/codex/harness-knowledge-query/SKILL.md +17 -6
  34. package/harness/bundles/general/codex/harness-plan/SKILL.md +6 -1
  35. package/harness/bundles/general/codex/harness-review/SKILL.md +6 -1
  36. package/harness/bundles/general/codex/harness-run/SKILL.md +7 -2
  37. package/harness/bundles/general/codex/harness-submit/SKILL.md +6 -1
  38. package/harness/bundles/general/codex/harness-sync/SKILL.md +6 -1
  39. package/harness/bundles/general/codex/harness-test/SKILL.md +6 -1
  40. package/harness/bundles/general/codex/scripts/harness_archive.py +31 -1
  41. package/harness/bundles/general/codex/scripts/harness_events_sync.py +90 -12
  42. package/harness/bundles/general/codex/scripts/harness_gate.py +17 -0
  43. package/harness/bundles/general/cursor/.harness-build.json +1 -1
  44. package/harness/bundles/general/cursor/harness-archive/SKILL.md +9 -1
  45. package/harness/bundles/general/cursor/harness-codebase-map/SKILL.md +6 -1
  46. package/harness/bundles/general/cursor/harness-knowledge-ingest/SKILL.md +21 -4
  47. package/harness/bundles/general/cursor/harness-knowledge-query/SKILL.md +17 -6
  48. package/harness/bundles/general/cursor/harness-plan/SKILL.md +6 -1
  49. package/harness/bundles/general/cursor/harness-review/SKILL.md +6 -1
  50. package/harness/bundles/general/cursor/harness-run/SKILL.md +7 -2
  51. package/harness/bundles/general/cursor/harness-submit/SKILL.md +6 -1
  52. package/harness/bundles/general/cursor/harness-sync/SKILL.md +6 -1
  53. package/harness/bundles/general/cursor/harness-test/SKILL.md +6 -1
  54. package/harness/bundles/general/cursor/scripts/harness_archive.py +31 -1
  55. package/harness/bundles/general/cursor/scripts/harness_events_sync.py +90 -12
  56. package/harness/bundles/general/cursor/scripts/harness_gate.py +17 -0
  57. package/harness/bundles/java/claude-code/.harness-build.json +1 -1
  58. package/harness/bundles/java/claude-code/harness-apidoc/SKILL.md +6 -1
  59. package/harness/bundles/java/claude-code/harness-archive/SKILL.md +9 -1
  60. package/harness/bundles/java/claude-code/harness-codebase-map/SKILL.md +6 -1
  61. package/harness/bundles/java/claude-code/harness-knowledge-ingest/SKILL.md +21 -4
  62. package/harness/bundles/java/claude-code/harness-knowledge-query/SKILL.md +17 -6
  63. package/harness/bundles/java/claude-code/harness-package/SKILL.md +6 -1
  64. package/harness/bundles/java/claude-code/harness-plan/SKILL.md +6 -1
  65. package/harness/bundles/java/claude-code/harness-review/SKILL.md +6 -1
  66. package/harness/bundles/java/claude-code/harness-run/SKILL.md +7 -2
  67. package/harness/bundles/java/claude-code/harness-submit/SKILL.md +6 -1
  68. package/harness/bundles/java/claude-code/harness-sync/SKILL.md +6 -1
  69. package/harness/bundles/java/claude-code/harness-test/SKILL.md +6 -1
  70. package/harness/bundles/java/claude-code/scripts/harness_archive.py +31 -1
  71. package/harness/bundles/java/claude-code/scripts/harness_events_sync.py +90 -12
  72. package/harness/bundles/java/claude-code/scripts/harness_gate.py +17 -0
  73. package/harness/bundles/java/codebuddy/.harness-build.json +1 -1
  74. package/harness/bundles/java/codebuddy/harness-apidoc/SKILL.md +6 -1
  75. package/harness/bundles/java/codebuddy/harness-archive/SKILL.md +9 -1
  76. package/harness/bundles/java/codebuddy/harness-codebase-map/SKILL.md +6 -1
  77. package/harness/bundles/java/codebuddy/harness-knowledge-ingest/SKILL.md +21 -4
  78. package/harness/bundles/java/codebuddy/harness-knowledge-query/SKILL.md +17 -6
  79. package/harness/bundles/java/codebuddy/harness-package/SKILL.md +6 -1
  80. package/harness/bundles/java/codebuddy/harness-plan/SKILL.md +6 -1
  81. package/harness/bundles/java/codebuddy/harness-review/SKILL.md +6 -1
  82. package/harness/bundles/java/codebuddy/harness-run/SKILL.md +7 -2
  83. package/harness/bundles/java/codebuddy/harness-submit/SKILL.md +6 -1
  84. package/harness/bundles/java/codebuddy/harness-sync/SKILL.md +6 -1
  85. package/harness/bundles/java/codebuddy/harness-test/SKILL.md +6 -1
  86. package/harness/bundles/java/codebuddy/scripts/harness_archive.py +31 -1
  87. package/harness/bundles/java/codebuddy/scripts/harness_events_sync.py +90 -12
  88. package/harness/bundles/java/codebuddy/scripts/harness_gate.py +17 -0
  89. package/harness/bundles/java/codex/.harness-build.json +1 -1
  90. package/harness/bundles/java/codex/harness-apidoc/SKILL.md +6 -1
  91. package/harness/bundles/java/codex/harness-archive/SKILL.md +9 -1
  92. package/harness/bundles/java/codex/harness-codebase-map/SKILL.md +6 -1
  93. package/harness/bundles/java/codex/harness-knowledge-ingest/SKILL.md +21 -4
  94. package/harness/bundles/java/codex/harness-knowledge-query/SKILL.md +17 -6
  95. package/harness/bundles/java/codex/harness-package/SKILL.md +6 -1
  96. package/harness/bundles/java/codex/harness-plan/SKILL.md +6 -1
  97. package/harness/bundles/java/codex/harness-review/SKILL.md +6 -1
  98. package/harness/bundles/java/codex/harness-run/SKILL.md +7 -2
  99. package/harness/bundles/java/codex/harness-submit/SKILL.md +6 -1
  100. package/harness/bundles/java/codex/harness-sync/SKILL.md +6 -1
  101. package/harness/bundles/java/codex/harness-test/SKILL.md +6 -1
  102. package/harness/bundles/java/codex/scripts/harness_archive.py +31 -1
  103. package/harness/bundles/java/codex/scripts/harness_events_sync.py +90 -12
  104. package/harness/bundles/java/codex/scripts/harness_gate.py +17 -0
  105. package/harness/bundles/java/cursor/.harness-build.json +1 -1
  106. package/harness/bundles/java/cursor/harness-apidoc/SKILL.md +6 -1
  107. package/harness/bundles/java/cursor/harness-archive/SKILL.md +9 -1
  108. package/harness/bundles/java/cursor/harness-codebase-map/SKILL.md +6 -1
  109. package/harness/bundles/java/cursor/harness-knowledge-ingest/SKILL.md +21 -4
  110. package/harness/bundles/java/cursor/harness-knowledge-query/SKILL.md +17 -6
  111. package/harness/bundles/java/cursor/harness-package/SKILL.md +6 -1
  112. package/harness/bundles/java/cursor/harness-plan/SKILL.md +6 -1
  113. package/harness/bundles/java/cursor/harness-review/SKILL.md +6 -1
  114. package/harness/bundles/java/cursor/harness-run/SKILL.md +7 -2
  115. package/harness/bundles/java/cursor/harness-submit/SKILL.md +6 -1
  116. package/harness/bundles/java/cursor/harness-sync/SKILL.md +6 -1
  117. package/harness/bundles/java/cursor/harness-test/SKILL.md +6 -1
  118. package/harness/bundles/java/cursor/scripts/harness_archive.py +31 -1
  119. package/harness/bundles/java/cursor/scripts/harness_events_sync.py +90 -12
  120. package/harness/bundles/java/cursor/scripts/harness_gate.py +17 -0
  121. package/harness/manifests/general/claude-code.json +16 -16
  122. package/harness/manifests/general/codebuddy.json +16 -16
  123. package/harness/manifests/general/codex.json +16 -16
  124. package/harness/manifests/general/cursor.json +16 -16
  125. package/harness/manifests/java/claude-code.json +18 -18
  126. package/harness/manifests/java/codebuddy.json +18 -18
  127. package/harness/manifests/java/codex.json +18 -18
  128. package/harness/manifests/java/cursor.json +18 -18
  129. package/hunter-workflow-family.json +4 -4
  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": "0c6cb544b7c0aef7"
5
+ "coreHash": "6b900d319d6b6d77"
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=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-archive — 变更归档
26
26
 
27
27
  ## Purpose
@@ -119,6 +119,9 @@ disallowed-tools:
119
119
  1. 运行 `python <skills-root>/scripts/harness_archive.py status --change-dir ".harness/changes/<change-name>" --intent release-candidate --json` 前置检查。无 CI 项目若已有完整全量 ledger,先运行 `certify-local`;若用户明确只封存事实,则 status/finalize 均使用 `--intent record-only`。
120
120
  2. `meta/archive-meta.md` **由 `harness_archive.py finalize` 自动生成**(与 summary-data `finalStatus` 同源);**禁止 agent 手写**该文件,手写视为数据丢失。维护者结论写入 events(decision/issue)即可,finalize 会汇总到 summary / archive-meta。
121
121
  3. 运行 `python <skills-root>/scripts/harness_archive.py finalize --change-dir ".harness/changes/<change-name>" --archive-root ".harness/archive" --intent <release-candidate|record-only> --json`;读 JSON(cleanup、事件、移动、collect、render、validate、manifest 比对、archive-meta)。finalize 内部负责且仅负责一次 `phase.start` / `phase.end`,调用者不得重复追加。**finalize 不再同步执行知识维护**(§8.2):它写一个 `pending` maintenance-outbox 项即返回,`knowledgeMaintenance=QUEUED`;写 outbox 失败时 `NOT_QUEUED`(warning,不回滚 archive,总状态 CONDITIONAL)。后续由 `harness-sync` / `harness_knowledge.py maintain` 异步推进 outbox。**finalize 失败或 validate 报错时不删除原目录**。
122
+ - **平台钩子(best-effort,不阻断归档)**:
123
+ 1. **归档推送(C1)**:有远程凭据时自动 `hunter-harness push` 上传核心+可选辅助档(spec/plans/summary-data/knowledge + `reports/review/*`、`reports/test/*`、`meta/archive-meta.md`、`meta/change-context.json`)。
124
+ 2. **监控终态(C3)**:auto-push 之后自动 `events-sync`,用归档前 change 路径派生的 `run_id` + 原 `change_key` 上报;平台依据 `phase.end`/`archive` 将 run 置为 succeeded/failed(含 `ended_at`)。失败只记 warning。
122
125
 
123
126
  - **Read `reference.md`** — finalize 输出字段、archive-meta 格式、CONDITIONAL_OK 规则
124
127
  - **Read `templates/summary-data-template.json`** — summary-data 数据结构
@@ -135,6 +138,11 @@ disallowed-tools:
135
138
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
136
139
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
137
140
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
141
+
142
+ ## 生成内容语言约定
143
+
144
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
145
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
138
146
  > 片段:p0-trust
139
147
 
140
148
  ## 关键规则(硬门禁速查)
@@ -20,7 +20,7 @@ disallowed-tools:
20
20
  - Bash(awk *)
21
21
  - Bash(curl *)
22
22
  ---
23
- <!-- generated by harness_deploy.py; core=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
23
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
24
24
  # harness-codebase-map — 代码库地图
25
25
 
26
26
  ## Purpose
@@ -73,6 +73,11 @@ disallowed-tools:
73
73
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
74
74
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
75
75
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
76
+
77
+ ## 生成内容语言约定
78
+
79
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
80
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
76
81
  > 片段:p0-trust · map 额外:文件存在/行数/hash 为证据
77
82
 
78
83
  ## 关键规则
@@ -20,12 +20,21 @@ disallowed-tools:
20
20
  - Bash(awk *)
21
21
  - Bash(curl *)
22
22
  ---
23
- <!-- generated by harness_deploy.py; core=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
23
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
24
24
  # harness-knowledge-ingest
25
25
 
26
- 从 `.harness/archive/**/reports/final/summary-data.json` 抽取项目知识,生成并维护本地 `.harness/knowledge/` 索引。
26
+ 从 `.harness/archive/**/reports/final/summary-data.json` **本地抽取**知识条目,产物随归档 push 上传;**裁决与投影以平台为准**(远程优先)。本地 SQLite / Agent judge 仅作离线或未连接平台时的回退。
27
27
 
28
- 当前实现是本地、离线、无 LLM、无外部服务的 SQLite FTS MVP,已经支持基础生命周期:`candidate`、`stale`、`active`、`superseded`、`conflicted`。按新需求查询历史由独立的 `harness-knowledge-query` 负责。
28
+ > 语言约定:知识条目的 title / summary / body 及一切生成文档优先使用中文(标识符与字段名保持原文)。详见 [[../shared/p0-trust.md|p0-trust]] 的"生成内容语言约定"。
29
+
30
+ ## 远程优先模式(平台连接后)
31
+
32
+ 1. **本地职责**:抽取 candidate 条目 JSON,写入 `.harness/knowledge/entries/**`(及可选本地 index)。
33
+ 2. **上传**:条目随 `hunter-harness push` / 归档 finalize 的 auto-push 上传(见归档分级清单:核心含 `knowledge/entries/active|candidate`)。
34
+ 3. **平台职责**:服务端 ingest 后自动裁决 status(promote→active 等启发式),并投影到语义知识库;`deprecate` 粘性不被后续 push 覆盖。
35
+ 4. **本地 judge / SQLite**:无平台凭据或离线时仍可用;已连接平台时**不要**把本地裁决当作多人共享真源。
36
+
37
+ 未连接平台时,行为退回本地离线 MVP:`candidate` / `stale` / `active` / `superseded` / `conflicted` + SQLite FTS。按新需求查询历史由独立的 `harness-knowledge-query` 负责(默认远程语义搜索,本地索引离线回退)。
29
38
 
30
39
  ## Triggers
31
40
 
@@ -45,13 +54,16 @@ disallowed-tools:
45
54
  - `.harness/knowledge/index.json`
46
55
  - `.harness/codebase/map-summary.md`(如存在)
47
56
  - design.md
57
+ - (可选)`.harness/credentials.local.yaml` — 已连接平台时走远程裁决
48
58
 
49
59
  ## Purpose
50
60
 
51
61
  解决两个问题:
52
62
 
53
63
  1. **整理知识库内容**:把归档里的 `businessGoal`、`changedFiles`、`maintenanceNotes`、`knownRisks`、`manualActions`、`verification`、`reviewSummary` 抽成知识条目。
54
- 2. **维护知识生命周期**:检查索引是否过期,保留 active 条目;高置信 candidate 由 `autoPromote` 自动提升;其余 candidate/conflicted 由 **Agent judge** 闭环裁决,不再默认输出人工待办清单。
64
+ 2. **维护知识生命周期**:
65
+ - **远程优先**:平台 ingest 后裁决并投影;本地只需保证条目 JSON 可上传。
66
+ - **离线回退**:检查索引是否过期,保留 active;高置信 candidate 由 `autoPromote` 自动提升;其余由 **Agent judge** 闭环裁决。
55
67
 
56
68
  ## Outputs
57
69
 
@@ -251,6 +263,11 @@ powershell.exe -Command "python '<skill-dir>\scripts\harness_knowledge.py' sync
251
263
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
252
264
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
253
265
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
266
+
267
+ ## 生成内容语言约定
268
+
269
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
270
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
254
271
  > 片段:p0-trust · ingest/sync 须绑定 `upToDate`/产物路径证据
255
272
 
256
273
  ## Output Format
@@ -20,14 +20,18 @@ disallowed-tools:
20
20
  - Bash(awk *)
21
21
  - Bash(curl *)
22
22
  ---
23
- <!-- generated by harness_deploy.py; core=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
23
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
24
24
  # harness-knowledge-query
25
25
 
26
26
  并行 change 中查询必须传 `--change <change-id>`;成功后以该 change 的 `meta/knowledge-context.json` 为稳定指针。全局 `context-packs/latest.json` 仅向后兼容,不得用于判断多个 active change 的上下文归属。
27
27
 
28
- 根据用户的新需求或排查问题,从项目本地 `.harness/knowledge` 中检索历史需求、决策、实现、风险和测试证据,并生成 AI 可读的 context pack。
28
+ 根据用户的新需求或排查问题检索历史需求、决策、实现、风险和测试证据,并生成 AI 可读的 context pack。
29
29
 
30
- skill 只负责查询和使用知识。整理、同步和 promote 条目由 `harness-knowledge-ingest` 负责。
30
+ ## 远程优先 / 离线回退
31
+
32
+ 1. **默认(已 `hunter-harness connect`)**:优先查询平台语义知识库(与 ingest 上传 + 服务端裁决结果一致);多机/多人共享同一裁决结果。
33
+ 2. **离线回退**:无凭据、网络失败或平台不可用时,回退到本地 `.harness/knowledge`(SQLite FTS / 条目文件)。
34
+ 3. 此 skill 只负责查询和使用知识。整理与上传由 `harness-knowledge-ingest` + push/归档负责;**不要**在已连接平台时把本地 promote 当作共享真源。
31
35
 
32
36
  ## Triggers
33
37
 
@@ -42,9 +46,9 @@ disallowed-tools:
42
46
 
43
47
  ## Automatic Use
44
48
 
45
- 当用户提出新功能、改造、排查、设计方案、继续历史任务,且项目存在 `.harness/archive` `.harness/knowledge` 时,AI 应主动运行本 skill,不需要等用户提醒。
49
+ 当用户提出新功能、改造、排查、设计方案、继续历史任务,且项目存在平台连接或 `.harness/archive` / `.harness/knowledge` 时,AI 应主动运行本 skill,不需要等用户提醒。
46
50
 
47
- 不在 query 前单独执行 sync。`query` 命令内部执行一次 ensure-current:建立一次当前快照,索引新鲜时无操作,过期或缺失时只构建一次,然后在同一调用内完成查询。
51
+ 不在 query 前单独执行 sync。`query` 命令内部执行一次 ensure-current:建立一次当前快照,索引新鲜时无操作,过期或缺失时只构建一次,然后在同一调用内完成查询(离线路径)。
48
52
 
49
53
  ## Commands
50
54
 
@@ -56,6 +60,8 @@ disallowed-tools:
56
60
  powershell.exe -Command "python '<ingest-skill-dir>\scripts\harness_knowledge.py' query --project '<project-root>' --query '<用户需求原文>'"
57
61
  ```
58
62
 
63
+ 已连接平台时,优先使用平台语义搜索(CLI/`hunter-harness` 知识查询路径,若可用);上述本地命令作为离线回退。
64
+
59
65
  ### Query with metadata filters
60
66
 
61
67
  ```powershell
@@ -65,7 +71,7 @@ powershell.exe -Command "python '<ingest-skill-dir>\scripts\harness_knowledge.py
65
71
  可重复使用:
66
72
 
67
73
  - `--file <path>`:只返回关联到指定文件的知识。
68
- - `--status active|candidate|stale|superseded|conflicted`:按生命周期过滤。
74
+ - `--status active|candidate|stale|superseded|conflicted`:按生命周期过滤(远程路径通常已排除 deprecated)。
69
75
  - `--type requirement|decision|implementation|risk|test-evidence|pitfall|api-contract`:按知识类型过滤。
70
76
  - `--limit <n>`:限制返回数量。
71
77
 
@@ -128,6 +134,11 @@ powershell.exe -Command "python '<ingest-skill-dir>\scripts\harness_knowledge.py
128
134
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
129
135
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
130
136
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
137
+
138
+ ## 生成内容语言约定
139
+
140
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
141
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
131
142
  > 片段:p0-trust · query 成功须含 `contextPack`/`planInput.kind` 与 `latest.json` 写入
132
143
 
133
144
  ## Output Format
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-plan — 需求规划
26
26
 
27
27
  ## Purpose
@@ -101,6 +101,11 @@ change-name 范围变更 → 提示重命名或记 🟡WARN(→ `reference.md`
101
101
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
102
102
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
103
103
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
104
+
105
+ ## 生成内容语言约定
106
+
107
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
108
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
104
109
  > 片段:p0-trust
105
110
 
106
111
  ## 关键规则
@@ -22,7 +22,7 @@ disallowed-tools:
22
22
  - Bash(curl *)
23
23
  - Bash(codegraph *)
24
24
  ---
25
- <!-- generated by harness_deploy.py; core=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
25
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
26
26
  # harness-review — 代码审查
27
27
 
28
28
  ## Purpose
@@ -125,6 +125,11 @@ review:
125
125
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
126
126
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
127
127
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
128
+
129
+ ## 生成内容语言约定
130
+
131
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
132
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
128
133
  > 片段:p0-trust
129
134
 
130
135
  ## 关键规则(硬门禁速查)
@@ -22,7 +22,7 @@ disallowed-tools:
22
22
  - Bash(curl *)
23
23
  - Bash(codegraph *)
24
24
  ---
25
- <!-- generated by harness_deploy.py; core=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
25
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
26
26
  # harness-run — 需求编码
27
27
 
28
28
  ## Purpose
@@ -78,7 +78,7 @@ disallowed-tools:
78
78
 
79
79
  ## Workflow 概要
80
80
 
81
- 0. 加载上下文:先 `harness_context.py prepare --phase run --executor <tool> [--change <id>] --json`,以返回的唯一 change/executionRoot/transition receipt 为准(多 active 缺参 → `ACTIVE_CHANGE_AMBIGUOUS`,禁止按 mtime 猜测);再 **`harness_context.py begin --phase run --change <id> --executor <tool> --json`** 校验 Plan artifact/hash/HEAD,读 spec/plan/detail/scenarios/ledger/run-task-status/worktree;`--fixback` 读 fixback → **`harness_gate.py begin --phase run --change <id>`**(claim + phase.start + identity;禁止手工 Write `events.ndjson` / 手工 `phase.end`)
81
+ 0. 加载上下文:先 `harness_context.py prepare --phase run --executor <tool> [--change <id>] --json`,以返回的唯一 change/executionRoot/transition receipt 为准(多 active 缺参 → `ACTIVE_CHANGE_AMBIGUOUS`,禁止按 mtime 猜测);再 **`harness_context.py begin --phase run --change <id> --executor <tool> --json`** 校验 Plan artifact/hash/HEAD,读 spec/plan/detail/scenarios/ledger/run-task-status/worktree;`--fixback` 读 fixback → **`harness_gate.py begin --phase run --change <id>`**(claim + phase.start + identity;禁止手工 Write `events.ndjson` / 手工 `phase.end`)。**C3 钩子**:`harness_gate.py begin` 在已连接平台时会 best-effort 调用 events-sync(注册 run / `running`);失败只告警,不阻断 begin。
82
82
  0.5. **测试基础设施探测**(先写 `CHECKING`,四项证据齐备后再结论)→ `reference.md` Step 0.5;进入 TDD 前执行 `harness_test_guard.py begin --project . --change-dir ".harness/changes/<cn>" --json`
83
83
  1. **变更簇 TDD** — `protocols.md` `run-tdd-protocol`;批量 RED/GREEN;按需 `change-cluster-review-protocol`(高风险 + reviewer 预检可用)
84
84
  2. 构建验证 + **仅**通过 `harness_ledger.py record` 写 ledger(禁止 Write/Edit `verification-ledger.json`);`diff-hash --change-dir` 纳入 ignored tests → `reference.md` Step 2c
@@ -94,6 +94,11 @@ disallowed-tools:
94
94
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
95
95
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
96
96
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
97
+
98
+ ## 生成内容语言约定
99
+
100
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
101
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
97
102
  > 片段:p0-trust
98
103
 
99
104
  ## 关键规则(硬门禁速查)
@@ -21,7 +21,7 @@ disallowed-tools:
21
21
  - Bash(awk *)
22
22
  - Bash(curl *)
23
23
  ---
24
- <!-- generated by harness_deploy.py; core=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
24
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
25
25
  # harness-submit — 最终提交(含 worktree 合并)
26
26
 
27
27
  ## Purpose
@@ -112,6 +112,11 @@ M7. **ledger + 收尾** — 经 `harness_ledger.py record` 写入 `mergeFinalHas
112
112
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
113
113
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
114
114
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
115
+
116
+ ## 生成内容语言约定
117
+
118
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
119
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
115
120
  > 片段:p0-trust
116
121
 
117
122
  ## 关键规则(硬门禁速查)
@@ -19,7 +19,7 @@ disallowed-tools:
19
19
  - Bash(awk *)
20
20
  - Bash(curl *)
21
21
  ---
22
- <!-- generated by harness_deploy.py; core=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
22
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
23
23
  # harness-sync
24
24
 
25
25
  ## Purpose
@@ -71,6 +71,11 @@ JSON 报告回显到对话。
71
71
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
72
72
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
73
73
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
74
+
75
+ ## 生成内容语言约定
76
+
77
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
78
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
74
79
  > 片段:p0-trust
75
80
 
76
81
  ## 执行日志
@@ -23,7 +23,7 @@ disallowed-tools:
23
23
  - Bash(node *)
24
24
  - Bash(codegraph *)
25
25
  ---
26
- <!-- generated by harness_deploy.py; core=0c6cb544b7c0aef7; overlay=none; agent=claude-code; do not edit -->
26
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=claude-code; do not edit -->
27
27
  # harness-test — 测试执行
28
28
 
29
29
  ## Purpose
@@ -142,6 +142,11 @@ Runner 强制同项目单实例、低调度优先级、逐命令超时、正常
142
142
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
143
143
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
144
144
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
145
+
146
+ ## 生成内容语言约定
147
+
148
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
149
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
145
150
  > 片段:p0-trust
146
151
 
147
152
  ## 关键规则(硬门禁速查)
@@ -70,6 +70,7 @@ if str(SCRIPTS_DIR) not in sys.path:
70
70
  sys.path.insert(0, str(SCRIPTS_DIR))
71
71
 
72
72
  import harness_events as he # noqa: E402
73
+ import harness_events_sync as hes # noqa: E402
73
74
  import harness_efficiency as heff # noqa: E402
74
75
  import harness_gate as hgate # noqa: E402
75
76
  import harness_ledger as hl # noqa: E402
@@ -8284,6 +8285,9 @@ def cmd_finalize(
8284
8285
 
8285
8286
  # Publish only after every validator passes. The archive path is never used
8286
8287
  # as mutable staging, so a failed attempt cannot poison the next retry.
8288
+ # Capture monitoring run_id from the live change path before it is deleted
8289
+ # so archive finalize can report terminal status on the same platform run.
8290
+ monitoring_run_id = hes.run_id_for(original_change_dir)
8287
8291
  try:
8288
8292
  archive_root.mkdir(parents=True, exist_ok=True)
8289
8293
  shutil.move(str(operation_temp_dir), str(archive_dir))
@@ -8368,6 +8372,23 @@ def cmd_finalize(
8368
8372
  if push_result.get("warning"):
8369
8373
  warnings.append(str(push_result["warning"]))
8370
8374
 
8375
+ # C3: best-effort terminal events-sync so platform run ends (succeeded/failed).
8376
+ # Use the pre-delete change-path run_id + original change_key for continuity.
8377
+ try:
8378
+ monitor = hes.auto_events_sync(
8379
+ project_root,
8380
+ archive_dir,
8381
+ run_id=monitoring_run_id,
8382
+ change_key=change_name,
8383
+ )
8384
+ payload["steps"]["platform_events_sync"] = monitor
8385
+ if monitor.get("warning"):
8386
+ warnings.append(str(monitor["warning"]))
8387
+ except Exception as exc: # noqa: BLE001 — never roll back archive
8388
+ warn = f"events-sync terminal hook failed: {exc}"
8389
+ warnings.append(warn)
8390
+ payload["steps"]["platform_events_sync"] = {"ok": False, "warning": warn}
8391
+
8371
8392
  payload["ok"] = True
8372
8393
  payload["finalStatus"] = "OK"
8373
8394
  payload["warnings"] = warnings
@@ -8387,7 +8408,7 @@ def _remote_credentials_configured(project_root: Path) -> bool:
8387
8408
 
8388
8409
 
8389
8410
  def collect_archive_core_paths(project_root: Path, archive_dir: Path) -> list[str]:
8390
- """Relative paths for the P4 core four push set."""
8411
+ """Relative paths for the archive push allowlist (core + optional supporting)."""
8391
8412
  root = project_root.resolve()
8392
8413
  archive = archive_dir.resolve()
8393
8414
  paths: list[str] = []
@@ -8403,6 +8424,15 @@ def collect_archive_core_paths(project_root: Path, archive_dir: Path) -> list[st
8403
8424
  for path in sorted(base.rglob("*")):
8404
8425
  if path.is_file():
8405
8426
  paths.append(path.relative_to(root).as_posix())
8427
+ # C1 optional supporting files.
8428
+ for folder in (("reports", "review"), ("reports", "test")):
8429
+ base = archive.joinpath(*folder)
8430
+ if base.is_dir():
8431
+ for path in sorted(base.rglob("*")):
8432
+ if path.is_file():
8433
+ paths.append(path.relative_to(root).as_posix())
8434
+ add_if_exists(archive / "meta" / "archive-meta.md")
8435
+ add_if_exists(archive / "meta" / "change-context.json")
8406
8436
  knowledge = root / ".harness" / "knowledge" / "entries"
8407
8437
  for status in ("active", "candidate"):
8408
8438
  folder = knowledge / status
@@ -119,12 +119,19 @@ def post_json(endpoint: dict[str, str], path: str, body: dict[str, Any]) -> dict
119
119
  return json.loads(response.read().decode("utf-8"))
120
120
 
121
121
 
122
- def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False) -> dict[str, Any]:
122
+ def sync_change(
123
+ project: Path,
124
+ change_dir: Path,
125
+ *,
126
+ heartbeat_only: bool = False,
127
+ run_id: str | None = None,
128
+ change_key: str | None = None,
129
+ ) -> dict[str, Any]:
123
130
  endpoint = load_endpoint(project)
124
131
  if endpoint is None:
125
132
  return {"ok": True, "skipped": True, "reason": "remote credentials not configured"}
126
- change_key = change_dir.name
127
- rid = run_id_for(change_dir)
133
+ resolved_key = change_key or change_dir.name
134
+ rid = run_id or run_id_for(change_dir)
128
135
  project_id = endpoint["project_id"]
129
136
 
130
137
  # Always heartbeat so the console can separate connection vs run status.
@@ -138,20 +145,26 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
138
145
  {
139
146
  "protocol_version": "hunter-progress-sync/v1",
140
147
  "run_id": rid,
141
- "change_key": change_key,
148
+ "change_key": resolved_key,
142
149
  "client_time": client_time,
143
- "title": change_key,
150
+ "title": resolved_key,
144
151
  },
145
152
  )
146
153
  except (urllib.error.URLError, TimeoutError, OSError, json.JSONDecodeError) as exc:
147
154
  return {"ok": False, "error": f"heartbeat failed: {exc}", "run_id": rid}
148
155
 
149
156
  if heartbeat_only:
150
- return {"ok": True, "heartbeat": True, "run_id": rid}
157
+ return {"ok": True, "heartbeat": True, "run_id": rid, "change_key": resolved_key}
151
158
 
152
159
  events_file = change_dir / "events.ndjson"
153
160
  if not events_file.is_file():
154
- return {"ok": True, "run_id": rid, "uploaded": 0, "reason": "no events.ndjson"}
161
+ return {
162
+ "ok": True,
163
+ "run_id": rid,
164
+ "change_key": resolved_key,
165
+ "uploaded": 0,
166
+ "reason": "no events.ndjson",
167
+ }
155
168
 
156
169
  lines = events_file.read_text(encoding="utf-8").splitlines()
157
170
  acked = load_cursor(change_dir)
@@ -167,7 +180,7 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
167
180
  continue
168
181
  if not isinstance(event, dict):
169
182
  continue
170
- event_id = str(event.get("id") or f"{change_key}:{acked + offset}")
183
+ event_id = str(event.get("id") or f"{resolved_key}:{acked + offset}")
171
184
  payload = sanitize(event)
172
185
  batch.append(
173
186
  {
@@ -181,7 +194,13 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
181
194
  )
182
195
  if not batch:
183
196
  save_cursor(change_dir, len(lines))
184
- return {"ok": True, "run_id": rid, "uploaded": 0, "acked_lines": len(lines)}
197
+ return {
198
+ "ok": True,
199
+ "run_id": rid,
200
+ "change_key": resolved_key,
201
+ "uploaded": 0,
202
+ "acked_lines": len(lines),
203
+ }
185
204
 
186
205
  # Drop None phase keys for strict schema.
187
206
  for item in batch:
@@ -195,8 +214,8 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
195
214
  {
196
215
  "protocol_version": "hunter-progress-sync/v1",
197
216
  "run_id": rid,
198
- "change_key": change_key,
199
- "title": change_key,
217
+ "change_key": resolved_key,
218
+ "title": resolved_key,
200
219
  "events": batch,
201
220
  },
202
221
  )
@@ -222,6 +241,7 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
222
241
  return {
223
242
  "ok": accepted == len(batch),
224
243
  "run_id": rid,
244
+ "change_key": resolved_key,
225
245
  "uploaded": accepted,
226
246
  "batch_size": len(batch),
227
247
  "acked_lines": acked_lines,
@@ -229,10 +249,62 @@ def sync_change(project: Path, change_dir: Path, *, heartbeat_only: bool = False
229
249
  }
230
250
 
231
251
 
252
+ def auto_events_sync(
253
+ project_root: Path,
254
+ change_dir: Path,
255
+ *,
256
+ heartbeat_only: bool = False,
257
+ run_id: str | None = None,
258
+ change_key: str | None = None,
259
+ ) -> dict[str, Any]:
260
+ """Best-effort platform events sync (same style as auto_push_archive_core).
261
+
262
+ Failures become warnings so the caller never rolls back the main workflow.
263
+ """
264
+ project_root = project_root.resolve()
265
+ change_dir = change_dir.resolve()
266
+ if load_endpoint(project_root) is None:
267
+ return {"skipped": True, "reason": "no remote credentials"}
268
+ try:
269
+ result = sync_change(
270
+ project_root,
271
+ change_dir,
272
+ heartbeat_only=heartbeat_only,
273
+ run_id=run_id,
274
+ change_key=change_key,
275
+ )
276
+ except Exception as exc: # noqa: BLE001 — best-effort never blocks caller
277
+ return {
278
+ "skipped": False,
279
+ "ok": False,
280
+ "warning": f"events-sync deferred: {exc}",
281
+ }
282
+ if result.get("skipped"):
283
+ return {"skipped": True, "reason": result.get("reason") or "skipped"}
284
+ if result.get("ok"):
285
+ return {"skipped": False, "ok": True, **{
286
+ key: result[key]
287
+ for key in ("run_id", "change_key", "uploaded", "acked_lines", "heartbeat")
288
+ if key in result
289
+ }}
290
+ return {
291
+ "skipped": False,
292
+ "ok": False,
293
+ "warning": str(result.get("error") or "events-sync failed"),
294
+ **{
295
+ key: result[key]
296
+ for key in ("run_id", "change_key")
297
+ if key in result
298
+ },
299
+ }
300
+
301
+
232
302
  def main(argv: list[str] | None = None) -> int:
233
303
  parser = argparse.ArgumentParser(description="Sync events.ndjson to platform Run monitoring")
234
304
  parser.add_argument("--project", default=".", help="Project root")
235
305
  parser.add_argument("--change-dir", help="Specific change directory")
306
+ parser.add_argument("--run-id", help="Override stable run_id (archive finalize continuity)")
307
+ parser.add_argument("--change-key", help="Override change_key sent to the platform")
236
308
  parser.add_argument("--heartbeat-only", action="store_true")
237
309
  parser.add_argument("--json", action="store_true")
238
310
  args = parser.parse_args(argv)
@@ -243,7 +315,13 @@ def main(argv: list[str] | None = None) -> int:
243
315
  root = project / ".harness" / "changes"
244
316
  changes = sorted(path for path in root.glob("*") if path.is_dir()) if root.is_dir() else []
245
317
  results = [
246
- sync_change(project, change_dir, heartbeat_only=args.heartbeat_only)
318
+ sync_change(
319
+ project,
320
+ change_dir,
321
+ heartbeat_only=args.heartbeat_only,
322
+ run_id=args.run_id,
323
+ change_key=args.change_key,
324
+ )
247
325
  for change_dir in changes
248
326
  ]
249
327
  ok = all(item.get("ok") for item in results) if results else True
@@ -31,6 +31,7 @@ if str(SCRIPTS_DIR) not in sys.path:
31
31
 
32
32
  import harness_change as hc # noqa: E402
33
33
  import harness_events as he # noqa: E402
34
+ import harness_events_sync as hes # noqa: E402
34
35
  import harness_ledger as hl # noqa: E402
35
36
  import harness_paths as hp # noqa: E402
36
37
  import harness_plan_finalize as hpf # noqa: E402
@@ -2213,6 +2214,22 @@ def cmd_begin(args: argparse.Namespace) -> int:
2213
2214
  "gateSeverityMode": severity_mode,
2214
2215
  "gateWarnings": gate_warnings,
2215
2216
  }
2217
+ # C3: best-effort start platform run monitoring (register + running via heartbeat/events).
2218
+ try:
2219
+ monitor = hes.auto_events_sync(project, change_dir)
2220
+ payload["platformMonitor"] = monitor
2221
+ if monitor.get("warning"):
2222
+ warnings_msg = str(monitor["warning"])
2223
+ gate_warnings.append({
2224
+ "code": "PLATFORM_EVENTS_SYNC_WARN",
2225
+ "message": warnings_msg,
2226
+ })
2227
+ payload["gateWarnings"] = gate_warnings
2228
+ except Exception as exc: # noqa: BLE001 — never block phase begin
2229
+ payload["platformMonitor"] = {
2230
+ "ok": False,
2231
+ "warning": f"events-sync hook failed: {exc}",
2232
+ }
2216
2233
  emit(payload, as_json=as_json)
2217
2234
  return 0
2218
2235
 
@@ -2,5 +2,5 @@
2
2
  "schemaVersion": 1,
3
3
  "overlay": "none",
4
4
  "agent": "codebuddy",
5
- "coreHash": "0c6cb544b7c0aef7"
5
+ "coreHash": "6b900d319d6b6d77"
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=0c6cb544b7c0aef7; overlay=none; agent=codebuddy; do not edit -->
6
+ <!-- generated by harness_deploy.py; core=6b900d319d6b6d77; overlay=none; agent=codebuddy; do not edit -->
7
7
  # harness-archive — 变更归档
8
8
 
9
9
  ## Purpose
@@ -101,6 +101,9 @@ description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档
101
101
  1. 运行 `python <skills-root>/scripts/harness_archive.py status --change-dir ".harness/changes/<change-name>" --intent release-candidate --json` 前置检查。无 CI 项目若已有完整全量 ledger,先运行 `certify-local`;若用户明确只封存事实,则 status/finalize 均使用 `--intent record-only`。
102
102
  2. `meta/archive-meta.md` **由 `harness_archive.py finalize` 自动生成**(与 summary-data `finalStatus` 同源);**禁止 agent 手写**该文件,手写视为数据丢失。维护者结论写入 events(decision/issue)即可,finalize 会汇总到 summary / archive-meta。
103
103
  3. 运行 `python <skills-root>/scripts/harness_archive.py finalize --change-dir ".harness/changes/<change-name>" --archive-root ".harness/archive" --intent <release-candidate|record-only> --json`;读 JSON(cleanup、事件、移动、collect、render、validate、manifest 比对、archive-meta)。finalize 内部负责且仅负责一次 `phase.start` / `phase.end`,调用者不得重复追加。**finalize 不再同步执行知识维护**(§8.2):它写一个 `pending` maintenance-outbox 项即返回,`knowledgeMaintenance=QUEUED`;写 outbox 失败时 `NOT_QUEUED`(warning,不回滚 archive,总状态 CONDITIONAL)。后续由 `harness-sync` / `harness_knowledge.py maintain` 异步推进 outbox。**finalize 失败或 validate 报错时不删除原目录**。
104
+ - **平台钩子(best-effort,不阻断归档)**:
105
+ 1. **归档推送(C1)**:有远程凭据时自动 `hunter-harness push` 上传核心+可选辅助档(spec/plans/summary-data/knowledge + `reports/review/*`、`reports/test/*`、`meta/archive-meta.md`、`meta/change-context.json`)。
106
+ 2. **监控终态(C3)**:auto-push 之后自动 `events-sync`,用归档前 change 路径派生的 `run_id` + 原 `change_key` 上报;平台依据 `phase.end`/`archive` 将 run 置为 succeeded/failed(含 `ended_at`)。失败只记 warning。
104
107
 
105
108
  - **Read `reference.md`** — finalize 输出字段、archive-meta 格式、CONDITIONAL_OK 规则
106
109
  - **Read `templates/summary-data-template.json`** — summary-data 数据结构
@@ -117,6 +120,11 @@ description: 归档所有变更产出(计划/测试报告/审查/SQL/API文档
117
120
  - 命令结果不得靠猜测;普通 Bash 被拒 → 立即改用等价 PowerShell 重试一次
118
121
  - 仅 PowerShell 成功且有明确证据(构建/git/测试输出、文件存在、exit 0)时可标 ✅OK;否则 ❌FAIL 或 🟡WARN
119
122
  - 禁止把 hook 拒绝、静态验证、无输出、用户跳过说成成功 → 详见 [[../protocols/powershell-protocol.md|powershell-protocol]]、[[../protocols/evidence-based-reporting-protocol.md|evidence-based-reporting-protocol]]
123
+
124
+ ## 生成内容语言约定
125
+
126
+ - sync/ingest 等生成的文档、规则、知识条目、架构说明一律**优先使用中文**撰写(标识符、命令、代码、API 字段名保持原文)
127
+ - 面向平台展示的标题/摘要/正文默认中文;仅当用户明确要求或目标系统强制时才用英文
120
128
  > 片段:p0-trust
121
129
 
122
130
  ## 关键规则(硬门禁速查)