@erzhe/harness-kit 0.1.4 → 0.3.0

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/README.md CHANGED
@@ -18,11 +18,14 @@ Onboard 本仓库到 harness-kit:跑 npx -y @erzhe/harness-kit@latest onboard
18
18
 
19
19
  1. 拉取最新版的 onboard skill
20
20
  2. 扫描你的仓库(读 README、package.json、目录结构…)
21
- 3. 逐块跟你确认着填 `.agents/manifest.yaml`
22
- 4. `sync` / `doctor` / `verify` 直到全绿
23
- 5. 装上 git 钩子(`install-hooks`):之后 pre-commit 自动 sync、pre-push verify 拦漂移,维护不用你记命令
21
+ 3. 盘点已有 `AGENTS.md` / `CLAUDE.md` 及其明确引用的业务文档;原文留在原位置,不按文件夹名搬家
22
+ 4. 先保存逐字节 legacy 快照,再由另一个 Agent 盲审规则是否完整;明确缺口自动修复并复审,只有语义歧义才找人确认
23
+ 5. `sync` / `doctor` / `verify`,补齐真实的 `owns / tests / checks` 影响面
24
+ 6. 自动识别当前客户端和 Git worktree 形态,安装真正会生效的 Agent SessionStart + Stop 门禁,并用一个新会话留下真实 evidence;原生 Git hooks 只在作用域可证明安全时按需安装
24
25
 
25
- 全程走 `npx`,不往机器上装任何全局东西;你一发新版,所有人下次执行就用上了。
26
+ 全程走 `npx`,不全局安装 npm 包;你一发新版,所有人下次执行就用上了。唯一的用户级文件例外是 Codex linked-worktree 的显式安全分发器(见下文),因为当前 Codex 在不同启动环境里可能忽略项目 Hook,也可能与用户 Hook 同时执行。
27
+
28
+ 运行要求:Node.js 18 或更高版本。发布前会用打包后的 CLI 在真实 Node 18 上做 `help / doctor / verify` smoke。
26
29
 
27
30
  ---
28
31
 
@@ -34,14 +37,16 @@ Onboard 本仓库到 harness-kit:跑 npx -y @erzhe/harness-kit@latest onboard
34
37
  CLAUDE.md ← [生成] Claude Code 入口
35
38
  .agents/
36
39
  manifest.yaml ← 你维护的唯一真相源
37
- knowledge/ ← Agent 从代码推不出来的知识(领域、约定、决策)
40
+ knowledge/ ← Harness 自己新增的知识(不强迫搬入已有业务文档)
41
+ reference.md ← [生成] 完整命令、环境、原位置知识路径目录
38
42
  contracts/ ← 对外接口的契约基线
43
+ adoption/legacy/ ← 首次接管前的逐字节入口文件快照
39
44
  playbooks/ ← 可复用的工作流(SKILL.md)
40
45
  routing.md ← [生成] 按改动类型导航:改 UI 看哪、加接口看哪
41
46
  modules.md ← [生成] 模块卡:每个子系统的职责/入口/坑
42
47
  ```
43
48
 
44
- 以后改工程知识 → 编辑 `manifest.yaml` → `harness-kit sync`。别手改生成物。
49
+ 以后改工程结构 → 编辑 `manifest.yaml` → `harness-kit sync`。`sync` 只重生成确定性文件,不会替你声称“知识已经复核”。业务文档仍在原路径更新;Agent 完成语义审查后再运行 `record-context-review` 留证。
45
50
 
46
51
  ---
47
52
 
@@ -49,7 +54,8 @@ Onboard 本仓库到 harness-kit:跑 npx -y @erzhe/harness-kit@latest onboard
49
54
 
50
55
  harness-kit 的长期价值不在首次接入,而在**代码演进时上下文不腐烂**——而且这件事不该靠人记命令:
51
56
 
52
- - **装了钩子就无感**:`install-hooks` 之后,pre-commit 自动重生成入口文件、pre-push `verify`,上下文和代码对不上就红灯拦下。
57
+ - **Agent 钩子是交付闭环**:SessionStart 记住任务起点,Stop 让 Claude Code / Cursor / Codex 在结束前真正跑本次改动对应的检查。`doctor` 会显示 `CONFIGURED / ACTIVE / DEGRADED`,避免“文件装了但客户端没执行”被误报成成功。
58
+ - **Git 钩子是可选增强**:它可能影响 linked worktree 或覆盖第三方工具,因此默认只在单 worktree、默认 hooks 路径、无外来 hook 时安装;冲突时拒绝写入并给出路径,不自动 merge。
53
59
  - **漂移了让 Agent 自愈**:知识过期 / 接口契约变了,把仓库丢给 Agent 说一句 `onboard`,它会照 skill 自动考古、改 manifest/knowledge、有据才 accept 契约,最后**产出一份变更清单**。
54
60
  - **你只做一个动作**:审查那份 diff,批准或打回。生产和更新都交给 Agent,人只 review。
55
61
 
@@ -67,14 +73,66 @@ harness-kit 的长期价值不在首次接入,而在**代码演进时上下文
67
73
  | --- | --- |
68
74
  | `harness-kit onboard` | 打印 onboard skill 给 Agent(配合 npx,永远最新、零安装) |
69
75
  | `harness-kit init` | 铺 `.agents/` 骨架 + 空白 manifest |
70
- | `harness-kit sync` | manifest → 生成 AGENTS.md / CLAUDE.md / routing / modules |
76
+ | `harness-kit sync` | manifest → 事务生成 AGENTS.md / CLAUDE.md / reference / routing / modules;不刷新知识复核 |
77
+ | `harness-kit prepare-adoption` | 在仓外生成私有 blind-audit bundle;包含旧入口、嵌套 AGENTS/CLAUDE 及它们显式引用的文档证据和确定性候选,不改仓内文件 |
78
+ | `harness-kit record-adoption-audit` | 把声明的 pass/fail、理由和审计报告 hash 绑定到一版候选 |
79
+ | `harness-kit sync --adopt-existing --candidate ... --audit ...` | 首次接管:只有 live legacy、候选、manifest 和 pass receipt 逐字节一致才事务写入 |
71
80
  | `harness-kit doctor` | 体检:完整性 / 路径引用 / 漂移 / 新鲜度 / 体量预算 |
72
- | `harness-kit verify` | 门禁:跑不变量 + 契约 + 漂移,列出 GAPS,失败非 0 退出 |
81
+ | `harness-kit verify [--json]` | 门禁:跑不变量 + 契约 + 漂移,列出 GAPS;可输出单个结构化 JSON,失败非 0 退出 |
73
82
  | `harness-kit accept-contract` | 有意变更接口后,记录新的契约指纹为基线 |
74
- | `harness-kit install-hooks` | git 钩子:pre-commit 自动 sync + pre-push verify 拦漂移 |
83
+ | `harness-kit install-hooks` | 可选装原生 Git hooks;共享 worktree、自定义/全局路径或第三方 hook 时安全拒绝 |
84
+ | `harness-kit install-hooks --stop --agents <client>` | 只给实际使用的客户端装生命周期门禁:会话开始记基线,结束前跑 `run-checks` + `verify` |
85
+ | `harness-kit install-hooks --stop --agents codex --allow-user-dispatcher` | Codex linked-worktree fallback:保留已有用户 Hook,安装一个惰性分发器并只登记当前 worktree |
86
+ | `harness-kit plan-checks` | 只看本次改动会影响哪些模块、该跑什么、还有哪些验证缺口 |
87
+ | `harness-kit run-checks` | 真正执行本次改动对应的检查,并保存可追溯证据 |
88
+ | `harness-kit evidence` | 查看最近一次验收状态、检查结果和豁免理由 |
89
+ | `harness-kit record-context-review` | Agent 完成语义审查后,记录某条知识或模块的内容/来源 hash 与理由 |
90
+ | `harness-kit check-loop` | 打印给 Agent 使用的“实现 → 验收 → 修复 → 再验收”指南 |
75
91
 
76
92
  所有命令都支持 `-C <dir>` 指定目标仓库(默认当前目录)。
77
93
 
94
+ 首次接管是一个窄状态机,不靠 Agent 记住长说明:`init` 保存将被接管的旧入口 → `prepare-adoption` 在仓外收集原地 guidance 并生成候选 → 独立 Agent 盲审 → `record-adoption-audit` 绑定报告 → 带 candidate/receipt 的 `sync --adopt-existing` 才能写真实入口。manifest、旧入口、snapshot/index、嵌套入口/显式引用文档、候选文件或审计报告任一变化,旧回执立即失效;裸 `--adopt-existing` 不能接管。回执明确写 `assurance: declared`、`independence: unverified`:它能强制顺序和准确字节,不能在没有外部身份系统时伪装证明“审计者一定独立、语义判断一定正确”。
95
+
96
+ ## 实现之后,怎么保证真的验收了
97
+
98
+ 举四个常见场景:
99
+
100
+ - **修旧 bug**:Agent 改了生产代码,却没补回归测试。关键模块配置为 `test_touch: required` 后,结束时会直接拦住,直到补测试;若测试确实不适用,可对这个覆盖缺口留下有范围、有理由的豁免。
101
+ - **代码已经 commit**:门禁从会话开始时记住基线,所以不会因为 `HEAD` 前进就误判“没有改动”。
102
+ - **客户端 hook 没触发**:手动开始任务时先记下 `git rev-parse HEAD`;若中途已经 commit,用 `run-checks --base <task-start-sha>` 验收。未提供任务起点的手动 `no-change` 不算交付证据。
103
+ - **检查根本没跑**:命令不存在、被标成后台任务/有副作用、Git base 无效或 manifest 写坏,都算 `not-verified`,不会再用“跳过”冒充成功。
104
+
105
+ 项目接入时,由 Agent 根据模块风险提议策略,人来 review:默认只是提醒;公共接口、核心逻辑等关键模块再设为强制。每次结果会落到当前 worktree 的私有 Git 状态里,`harness-kit evidence` 随时可查。只有“没补测试 / 模块暂时没测试 / 必需范围未映射”这三类覆盖缺口可豁免;检查没跑、配置写坏、Git 对比失败等系统问题不能绕过。豁免只对当前代码指纹有效,代码一变就失效。
106
+
107
+ 注意:客户端显示“hook 已安装”不等于它真的执行过。`doctor` / `verify --json` 的 Hook 状态会区分:有效配置齐全但尚无新会话证据是 `CONFIGURED`;当前 hook evidence 两道门都过、并且 SessionStart 绑定的完整有效配置指纹仍与现场完全一致,才是 `ACTIVE`;runner 缺失、配置残缺、配置/override/分发器/登记改变、证据失败或 stale 都是 `DEGRADED`。`evidence` JSON 的 `hookActive` 使用同一配置绑定;交付证据本身仍可能有效,但它不会继续替另一版 Hook 配置背书。Codex linked worktree 必须显式使用 `--allow-user-dispatcher`;Cursor 的部分 headless/cloud surface 仍可能不触发生命周期 hooks,CLI 不会伪造成功。
108
+
109
+ 普通 worktree 的 Agent Hook 只写项目内普通文件:runner 与所选客户端配置会先整组预检,再事务写入,最终路径及父目录都不能是软链接。已有 JSON 的 `hooks` 结构无法安全合并、或 runner 属于第三方时,整组拒绝且不留半套文件;`--force` 也不会覆盖第三方 runner。合法的第三方 hook 数组条目会原样保留,只替换与安装器生成的 runner、Agent、事件和失败兜底完整匹配的 Harness 命令;仅仅在注释里出现 marker 不算我们的 Hook。
110
+
111
+ Codex linked-worktree 是一个受限例外:安装器会从项目 `.codex/hooks.json` 中移除且只移除 Harness 自己的 SessionStart/Stop 命令,保留第三方项目 Hook;然后以 compare-and-swap 方式更新 Codex 的**用户 Hook 源配置**,加入两条精确 managed 入口和版本化、兼容 Node 18 的分发器,最后把当前 worktree 的登记以 `0600` 写进其私有 Git admin dir。这样普通仓库只走项目 Hook,linked worktree 只走用户分发器,不会因为客户端行为变化把同一轮检查跑两次。普通 Codex 的源配置就是当前 `$CODEX_HOME`(未设置时为 `~/.codex`);Orca 的 `$CODEX_HOME` 是每次创建终端时由 `~/.codex` 派生的运行时副本,因此安装器会自动写 `~/.codex` 源配置,并要求新建一次 Orca Agent 会话让它安全同步。Harness 不改 Orca 的生成脚本、当前运行时文件或 Hook 信任记录。其他用户 Hook 条目的语义内容与相对顺序保持不变;未登记仓库静默不执行,登记存在但路径、权限、runner hash 或配置不一致则 fail closed。未知 JSON、同名外来分发器、并发修改都会让安装失败,且登记最后写入,因此不会留下“看似激活”的半套状态。这不是原生 Git hook,也不会影响其他 worktree 的业务文件。
112
+
113
+ `evidence` 不是旧绿灯截图:每次读取都会重新核对当前代码,代码一变就标 `stale` 并返回失败。手动执行时,`run-checks` 只会得到 `runChecksValid`;随后对同一代码运行 `verify`,整体 `valid` 才会变成 true。若会话开始时工作区已经有未提交改动,门禁会把这些既有改动也纳入验收范围,并在 evidence 里列出;它保证不漏,不冒充精确的任务归因。
114
+
115
+ 测试文件按最终工作树状态判断:只有新增或修改才满足 `test_touch`,哪怕先暂存修改、随后又删除,也不会被当成“补过测试”。改动指纹还包含可执行位与 submodule 当前提交/脏状态,避免代码内容没变时误沿用旧证据。自动 checks 最多共享 7 分钟,随后 `verify` 最多 2 分钟,确保在客户端 10 分钟 hook 上限前仍能返回明确的拦截结果;超时本身就是失败。
116
+
117
+ ### 已有业务文档不用搬家
118
+
119
+ `knowledge.path` 不是固定目录规则。它可以指向 `.agents/` 内由 Harness 新建的知识,也可以登记仓库里任何已有相对路径:
120
+
121
+ ```yaml
122
+ knowledge:
123
+ - root: repo
124
+ path: engineering/tribal-notes/api.md # 文件夹名完全由业务仓库决定
125
+ role: api
126
+ authority: derived
127
+ binds: [src/api/router.ts]
128
+ - root: agents # 默认值
129
+ path: knowledge/security-policy.md
130
+ authority: policy
131
+ binds: [src/auth/index.ts]
132
+ ```
133
+
134
+ `root: repo` 只表示“从仓库根解析”,不是把 `docs/`、`knowledge/`、`context/` 三个名字写死;CLI 也不会复制这些文件。`authority: derived` 表示文档应跟代码事实同步,`policy` 表示文档约束代码,`review` 表示两边需要 Agent 做语义核对。三种都必须先分析,再由 Agent 运行 `record-context-review --path ... --reason ...`;命令只保存证据,不会替 Agent 做判断。
135
+
78
136
  ---
79
137
 
80
138
  ## 它解决什么问题
@@ -94,20 +152,16 @@ harness-kit 把这些沉淀进 manifest,再确定性地生成与校验。
94
152
  ## 工作原理
95
153
 
96
154
  ```
97
- .agents/manifest.yaml (你 + Agent 维护的唯一源)
98
-
99
- harness-kit sync (确定性生成,勿手改产物)
100
-
101
- AGENTS.md / CLAUDE.md / .agents/routing.md / .agents/modules.md
102
-
103
- harness-kit verify (门禁:不变量 + 契约 + 漂移)
104
-
105
- exit 0 / 非 0 + 诚实的 GAPS 清单
155
+ .agents/manifest.yaml ──sync──> Agent 入口 / 路由 / 模块图
156
+
157
+ └── 本次 diff ──plan-checks──> 影响模块 + checks + gaps
158
+
159
+ └──run-checks + verify──> evidence / 继续修
106
160
  ```
107
161
 
108
162
  - **不变量**:声明式正则 `enforcement`(确定性、无 LLM),或标 `manual`
109
163
  - **契约**:`snapshot` 打印接口指纹 → CLI 存基线并 diff(协议无关)
110
- - **新鲜度**:知识条目 `binds` 源文件哈希,代码一动就告警
164
+ - **新鲜度**:知识条目可登记任意 repo 内相对路径;`authority` 决定语义责任,Agent 审查后记录内容与 `binds` hash,任何一侧变化都会失效
111
165
  - **GAPS**:打包 / 真网络 / 生产上传等本地验证不了的,显式列出
112
166
 
113
167
  ---
package/SPEC-v0.md CHANGED
@@ -1,12 +1,14 @@
1
- # AI-Harness SPEC v0.2
1
+ # AI-Harness SPEC v0.3
2
2
 
3
3
  > 一套 AI-friendly 的仓库规范。定义"任何仓库要让 Agent 冷启动即可高效工作、且人人构建出一致范式,必须声明什么、怎么声明、怎么防过期"。
4
4
  > 配套 CLI:`ai-harness`(`init` / `sync` / `doctor` / `verify`)。manifest 标签仍为 `ai-harness/v0`(v0 主线)。
5
5
  >
6
- > 设计背景与调研见 `DESIGN.md`。本文件是规范正文。
6
+ > 本文件是随仓库与 npm 包公开分发的规范正文。
7
7
  >
8
- > **v0.2 相比 v0**:在"可执行内核"(生成 + 门禁 + 派生防腐烂)之上,叠加一层从竞品吸收来的**行为协议**——
9
- > Task Brief、按改动类型路由(§8)、模块卡(§9)、验证缺口 GAPS(§5)、知识沉淀触发与 adoption 节奏。
8
+ > **v0.3 相比 v0.2**:补齐真实仓库验证暴露出的安全与可信度边界——严格 spec、事务生成、首次接管快照、原位置知识登记、显式 Agent 复核、结构化 verify、Hook 活性状态、worktree-safe Git hooks,以及 Codex linked-worktree 的受限用户分发器 fallback。
9
+ > manifest 标签仍是唯一受支持的 `ai-harness/v0`;任何未知标签(例如 `ai-harness/v999`)必须 fail closed,不能按“未来版本大概兼容”继续执行。
10
+ >
11
+ > v0.2 引入的 Task Brief、按改动类型路由(§8)、模块卡(§9)、验证缺口 GAPS(§5)、知识沉淀触发与 adoption 节奏继续保留。
10
12
  > 切分原则:**能机器校验的做成数据驱动**(routing/modules/GAPS 都由 manifest 生成并被 `doctor`/`verify` 检查),
11
13
  > **纯 agent 运行时行为的留 prose**(写进生成的 `AGENTS.md` Working agreement)。
12
14
 
@@ -31,12 +33,15 @@
31
33
  CLAUDE.md # [生成] 首行 @AGENTS.md
32
34
  .agents/ # canonical 命名空间(唯一手写源)
33
35
  manifest.yaml # 脊椎(本规范核心,见 §3)
34
- knowledge/ # 手写叙述:domain / conventions / journal
36
+ knowledge/ # Harness 自己新增的叙述;已有业务文档可留在任意 repo 路径
35
37
  domain.md
36
38
  conventions.md
37
39
  journal/0001-*.md # ADR:一决策一文件
38
40
  routing.md # [生成] 按改动类型导航(见 §8)
39
41
  modules.md # [生成] 模块卡(见 §9)
42
+ reference.md # [生成] 完整命令、环境、登记知识路径
43
+ adoption/legacy/ # 首次接管前入口文件的逐字节快照
44
+ adoption/legacy-index.json # 快照 hash / symlink target / 来源索引
40
45
  adoption.md # 手写:挣工具节奏账本(见 §5)
41
46
  contracts/<id>.snapshot # 已接受的契约基线,随仓入库(见 §5)
42
47
  playbooks/ # SKILL.md(可选,复用社区标准)
@@ -72,6 +77,7 @@ capabilities:
72
77
  example?: string # 特别用于 CLI:一个真实调用示例
73
78
  background?: bool # dev server 等长驻进程 = true
74
79
  mutating?: bool # release/publish/deploy 等有副作用 → Agent 须先确认
80
+ bootstrap?: bool # 显式决定是否留在短 AGENTS.md;完整目录始终进 reference.md
75
81
 
76
82
  # ── 3. Environment:跑起来需要的配置(每个可运行仓库都要) ────
77
83
  environment:
@@ -83,7 +89,7 @@ environment:
83
89
  # ── 4. Contracts:对外接口 = 契约(破坏需显式版本升级) ──────
84
90
  # 涵盖:库的 public API、CLI 的命令/flag、前后端 API schema…
85
91
  contracts:
86
- - id: string
92
+ - id: string # 1-128 位安全 ASCII 文件名字符;字母/数字开头,不含路径分隔符
87
93
  kind: public-api | cli-interface | http-api | event | other
88
94
  desc: string
89
95
  breaking_needs?: major | minor # 破坏它至少需要哪级版本变更
@@ -101,16 +107,20 @@ invariants:
101
107
  forbid_import?: [string]
102
108
  require_pattern?:[string]
103
109
  path_glob?: [string] # 限定作用范围
110
+ allow_empty?: bool # true = “匹配 0 文件”是刻意的缺席约束,不报警
104
111
  check?: string # (b) 任意命令,exit 0 = pass
105
112
  manual?: bool # (c) 无法机器验证 → 软约定,计入技术债
106
113
  llm_judge?: bool # 复杂语义可 opt-in 让模型判
107
114
 
108
115
  # ── 6. Knowledge:指向叙述文件;新鲜度"派生",不手写日期 ─────
109
116
  knowledge:
110
- - path: string # .agents/knowledge/... 下的文件/目录
117
+ - path: string # root 内解析的相对文件/目录;不能绝对路径或越界
118
+ root?: agents | repo # 默认 agents;repo 可登记任意现有业务路径,不搬家/复制
111
119
  role: domain | conventions | journal | other
120
+ authority?: derived | policy | review
121
+ # derived: 文档跟随代码;policy: 文档约束代码;review: 双向语义核对
112
122
  binds?: [string] # 它描述的源文件(用于算 drift)
113
- # freshness CLI git 与 binds 的 hash 派生,不要求人肉填 verified 日期
123
+ # authority 一旦声明,必须由 Agent 分析后 record-context-review;sync 不能代替复核
114
124
 
115
125
  # ── 8. Routing:按"改动类型"导航(生成 .agents/routing.md,v0.2) ──
116
126
  # 不列举需求,而是按"改动类型"告诉 Agent:先读哪、入口在哪、别假设什么、最少跑什么验证。
@@ -132,6 +142,28 @@ modules:
132
142
  downstream?: [string]
133
143
  must_know?: [string] # Agent 必须知道
134
144
  pitfalls?: [string] # 常见错误(最高价值的一栏)
145
+ # ── 影响面字段(给"实现 -> 验证"闭环用,见 §10)──
146
+ owns?: [string] # 本模块拥有的生产代码 glob(把 diff 映射到模块)
147
+ tests?: [string] # 覆盖本模块的测试文件 glob(判断改了代码有没有补测)
148
+ checks?: [string] # 本模块变更时要跑的 capability 动词(run-checks 执行,不能是原始命令)
149
+ test_touch?: required | advisory | off
150
+ # 生产代码变化时,是否强制/提醒/不要求同步 touch tests
151
+ playbook?: string # 指向 playbooks 下"如何验收本模块改动"的文档(可选)
152
+ remediation?: string # 自定义 gap 修复提示(覆盖默认建议,可选)
153
+
154
+ # ── 10. Validation:影响面驱动的 checkset / 兜底(可选,见 §10)──
155
+ # schema 只定义形状,不含域分类(不内置 "前端"/"HTTP" 等类型)。
156
+ validation:
157
+ policies?:
158
+ test_touch_default?: required | advisory | off
159
+ # 未在 module 覆盖时默认 advisory;由 onboarding agent 提议、人 review
160
+ required_coverage?: [string] # 命中这些 glob 的改动必须属于某个 owns/tests,否则 blocking
161
+ checksets?: # 命名可复用的 check 组,配合 run-checks --profile <id>
162
+ <id>: { checks: [string] }
163
+ defaults?:
164
+ no_match?: [string] # 改动没命中任何 module.owns 时兜底跑的 checks
165
+ always?: [string] # 任何改动都追加的 checks
166
+ # checksets/defaults 里的 check 同样只能引用已声明且非 background/mutating 的 capability 动词
135
167
 
136
168
  # ── 7. Playbooks:复用 SKILL.md(可选) ──────────────────────
137
169
  playbooks:
@@ -139,19 +171,25 @@ playbooks:
139
171
 
140
172
  # ── 生成映射:canonical → 各工具文件 ─────────────────────────
141
173
  generate:
142
- - to: "AGENTS.md" render: "identity+capabilities+environment+invariants"
174
+ - to: "AGENTS.md" render: "短 bootstrap:identity+精选 capabilities+invariants+索引"
143
175
  - to: "CLAUDE.md" content: "@AGENTS.md"
176
+ - to: ".agents/reference.md" render: "完整 capabilities+environment+knowledge catalog"
144
177
  ```
145
178
 
146
179
  **保留动词说明**:`capabilities` 的保留动词全部**可选**——它是一套"共享词汇表",仓库只声明适用的子集(库通常没有 `run`;前端 `run` 是 dev server 且 `background: true`)。Agent 冷启动时能预期这些词的语义。
147
180
 
181
+ **路径与 glob 说明**:`enforcement.path_glob`、`modules.owns/tests`、`validation.required_coverage` 全部是 include-only 正向 glob;以 `!` 开头的否定 glob 必须报 schema error,不能把底层 matcher 的不同语义当兼容。执行型 glob 最长 4096 字符,并在 manifest 校验期由 matcher 预编译,不能把异常拖到 `verify`。`routing.read/entry` 可以是文件、目录或正向 glob,`doctor` 会展开并在 0 匹配时失败。所有 repo 文件指针必须留在其声明根目录内。
182
+
148
183
  ---
149
184
 
150
185
  ## 4. 生成契约(`sync`)
151
186
 
152
- - `manifest.yaml` + `.agents/**` 是唯一手写源。
153
- - `harness sync` 幂等地渲染出 `generate` 列出的所有工具文件,顶部写 DO-NOT-EDIT 头。
154
- - 生成文件不进人工编辑;要改就改 manifest sync
187
+ - `manifest.yaml` 是生成结构的真相源;`.agents/knowledge/` 及 `root: repo` 登记的业务文档仍是手写语义源。
188
+ - `harness sync` 幂等渲染工具文件,先对**全部目标**做安全 preflight,再写同目录临时文件。缺失目标用 hard-link no-replace 安装;已有普通文件先移到唯一 rollback 位并再次核对 identity/bytes,再 no-replace 安装候选。中途失败尽力恢复;若同时有别的进程写入,优先保留较新的路径和原文件 backup、明确失败,绝不静默覆盖。跨平台 Node 没有“比较 inode 后原子替换”的 CAS,因此普通文件替换存在极短路径空窗;这里承诺的是数据保全的 best-effort 文件事务,不冒充数据库级原子性。已完全一致的普通文件不得无谓重写。
189
+ - 最终路径及其父目录不能跟随 symlink。唯一允许保留的语义 alias 是仓库根的相对 `CLAUDE.md -> AGENTS.md`,且解析后必须精确落在同仓 `AGENTS.md`;其它 symlink、目录、越界父目录全部 fail closed
190
+ - `init` 先统一预检 manifest、domain、conventions、journal/playbooks `.gitkeep` 和 adoption log;非 `--force` 时任一 scaffold 目标已存在就必须零写入拒绝。首次接管已有普通入口文件前,`init` 仅对 Harness 将接管的 managed entry 保存逐字节 legacy snapshot、mode/hash(symlink 保存 link target)。snapshot/index 的父链必须是仓内真实目录,读取使用 no-follow,snapshot 用排他 no-replace 写,index 用绑定旧字节的事务写;索引提交失败时初始化整体失败,已安全落下的 append-only snapshot 原位保留并在错误中给出恢复路径,绝不冒险删除可能被并发改写的 inode。嵌套 `AGENTS.md` / `CLAUDE.md` 及它们递归显式引用的仓内文本文档始终留在原地,不写入仓内 `.agents/adoption/legacy`;`prepare-adoption` 才把这些 guidance 复制到仓外私有 bundle,不按业务目录名猜测(Git 不可用时仍完整扫描,VCS 元数据与 Harness 自身 adoption evidence 除外)。guidance path/type/bytes/hash/mode/link target 纳入 candidate 绑定并在 apply 时重新发现、逐项重验;缺失、二进制、越界或指向仓外的 symlink 引用 fail closed,普通代码/资产链接与 Markdown 图片不当作 guidance。普通 `sync` 必须拒绝覆盖;`prepare-adoption` 不写真实入口。盲审报告经 `record-adoption-audit` 形成 `assurance=declared / independence=unverified` 的 pass/fail receipt;它证明被声明审查的是哪些字节,不证明审计身份或语义质量。只有带精确 candidate+pass receipt 的 `sync --adopt-existing` 才会在同次写入 preflight 里重新核对 live legacy、snapshot/index、guidance、manifest、所有候选字节及报告 hash。任一漂移都拒绝,`--force` 不能绕过。
191
+ - `sync` **只生成确定性文件**,绝不写新鲜度 baseline 或自动“接受”知识。语义复核只能由 Agent 完成分析后显式调用 `record-context-review`。
192
+ - 生成文件不进人工编辑;要改结构就改 manifest 再 sync。已有业务文档不搬入 `.agents/`,仍在原路径维护。
155
193
 
156
194
  ## 5. 校验契约(`doctor` / `verify`)
157
195
 
@@ -162,14 +200,15 @@ generate:
162
200
  4. 生成物**无漂移**(re-render 到内存 vs 磁盘 diff)。
163
201
  5. 新鲜度:`knowledge.binds` 的源文件 hash 变了 → 报 drift;`invariants` 里 `manual:true` 的计入"待补门禁"技术债并给出数量。
164
202
  6. **AGENTS.md 体量预算**:生成的 `AGENTS.md` 超过 ~150 行 / ~700 词告警。渐进式披露——入口只指路,细节放 `.agents/` 按需加载,绝不让 Agent 读不完。
203
+ 7. **Agent Hook 状态**:`CONFIGURED` = 至少一个客户端的有效 SessionStart/Stop 路径完整但尚无当前 Stop 证据;普通 worktree 的有效路径是项目 runner + client config,Codex linked-worktree 还必须包含精确用户入口、版本化分发器和当前 worktree 私有登记。`ACTIVE` = 非手动 session 的当前 `run-checks + verify` evidence 有效,且 SessionStart 绑定的完整有效配置指纹仍与现场完全相同;`DEGRADED` = 任一组成缺失或改变(包括合法的本地 CLI override 改值),或 evidence 失败/stale。`evidence.hookActive` 使用同一配置绑定,不能让旧证据替另一版配置背书;无关的第三方用户 Hook 不进入该指纹。状态是可见告警,不冒充 repo 代码门禁。
165
204
 
166
- `harness-kit verify`(CI 门禁,全确定性)= 所有 `invariants` 的 `enforcement`/`check` + `contracts` 的 `check`/`snapshot` + "生成物无漂移"。任一失败即 fail
205
+ `harness-kit verify`(本地/CI 均可用的确定性门禁)= 所有 `invariants` 的 `enforcement`/`check` + `contracts` 的 `check`/`snapshot` + "生成物无漂移" + 显式 authority 的 context freshness。任一 blocking 项失败即 fail。`--json` 必须只向 stdout 输出一个 `ai-harness/verify-report/v1` 文档,包含 `ok/failures/manifestErrors/context/hooks/gaps/messages`;即使 matcher、contract baseline 或 hook 配置遇到异常,也只能返回这一个结构化失败文档。
167
206
 
168
207
  > **`verify` 不执行任何 `capabilities`**。`capabilities.verify` 只是给人 / agent 看的"如何验证本仓"指针;若真去执行会与自身无限递归。声明为 `mutating` / `background` 的 capability 一律进 GAPS(诚实标注"未在门禁里跑"),不实跑。所以放心声明 `setup: rush install`、`build: go build` 等——`verify` 不会在无网 / 无依赖环境里去跑它们。
169
208
 
170
209
  **契约校验(v0.2,协议无关)**:契约的破坏检测有两条互补路径,CLI **不理解任何协议语义**,只当调度器 + 基线框架:
171
210
  - `check`:仓库自带的破坏检测工具(HTTP → `oasdiff`;gRPC/protobuf → `buf breaking`;库 → `api-extractor`;CLI → 自写脚本),exit 0 = 兼容。CLI 只 `execSync` 看退出码。
172
- - `snapshot`:仓库给一条**打印契约当前指纹到 stdout** 的命令(HTTP 打印 openapi / 抓路由;库打印 API 报告;CLI 打印 `--help`)。CLI 把 stdout 存成基线 `.agents/contracts/<id>.snapshot`,`verify` 时重新打印再 diff:一致=过,**漂移=fail**,无基线=提示先 `accept-contract`。这套 snapshot+baseline 与"生成物漂移检测"同一心智,复用于任何形态。
211
+ - `snapshot`:仓库给一条**打印契约当前指纹到 stdout** 的命令(HTTP 打印 openapi / 抓路由;库打印 API 报告;CLI 打印 `--help`)。CLI 把 stdout 存成基线 `.agents/contracts/<id>.snapshot`,`verify` 时重新打印再 diff:一致=过,**漂移=fail**,无基线=提示先 `accept-contract`。`id` 必须先通过跨平台安全文件名校验,拒绝 Windows device stem,并在 ASCII case-fold 后保持唯一,避免 macOS/Windows 大小写不敏感文件系统让两个契约共用同一 baseline。最终 baseline 只能是 `.agents/contracts/` 的直接普通文件,目录与 symlink 均 fail closed。
173
212
  - 有意变更契约时,显式跑 `harness accept-contract [--id <id>]` 更新基线——**与 `sync` 分开**,杜绝破坏被悄悄盖章。
174
213
 
175
214
  **GAPS 报告(v0.2)**:`verify` 末尾输出一段"这里查不了"的显式清单,把以下三类**从散落的 WARN 收拢成一等公民**:
@@ -183,12 +222,16 @@ GAPS 不计入失败,但会打印数量(`verify: OK (N gap(s))`)。配套*
183
222
  - **Task Brief**:动手前先在对话里声明"改什么/属哪类/碰哪些层/怎么验证",治"上来就全仓 grep + 瞎猜"。
184
223
  - **先路由后编辑**:改代码前先在 `routing.md` 里找到对应改动类型、按它指的文件读,别全仓搜。
185
224
  - **知识沉淀触发 + 反沉淀**:学到"代码里推不出来的"(坑/决策/修复)才沉淀到 `knowledge/`(决策走 journal ADR);一次性噪音、代码里显而易见的,**不要沉淀**。
225
+ - **无损接入**:onboarding 要盘点所有既有 AGENTS/CLAUDE 及其明确引用的 repo 文档,不根据目录名猜“哪些算知识”。先留逐字节 snapshot 和逐规则 preservation ledger,用 `prepare-adoption` 在仓外生成内容寻址候选,再让独立 Agent 只看旧/新证据盲审;清晰缺口自动修复并重新生成/复审,只有相互冲突或无法从代码/测试/本地配置判定的语义才升级给人。真实入口只有在 pass receipt 同时绑定 live legacy、候选、manifest 和报告 hash 时才可接管。
186
226
  - **adoption 节奏**(`.agents/adoption.md`,手写账本):默认用最轻的方案;同一错误漏 3 次以上、或一个软约定用满一周确实值得,才把它升级成 `verify` 的机器门禁。反仪式,"挣来"更重的工具。
187
227
 
188
228
  ## 6. 防腐烂(anti-rot)
189
229
 
190
230
  - **结构地图(暂缓 / 可选)**:核心"该看哪、别假设什么"已由 `modules`(模块卡,§9)+ `routing`(§8)用**高信噪比精选**覆盖。全量代码 dump(repomix `--compress`)不是必做项——它面向"喂给无文件访问的外部 LLM",与 IDE agent 场景 + 渐进式披露原则不对口,且腐烂最快。真需要时**按需生成、不入库**(放 .gitignore),不当 CI/hook 固定产物。见 DESIGN 决策日志(2026-07-03)。
191
- - **新鲜度派生、不手写**:知识条目通过 `binds` 绑定源文件,CLI 存其内容 hash;源文件变化 reliability 下降 drift 告警。**不要求人肉维护 `verified` 日期**(那是 ceremony)。
231
+ - **路径不设命名白名单**:`root: agents` `.agents/` 解析;`root: repo` 从仓库根解析。`docs/`、`knowledge/`、`context/` 只是可能的项目命名,不是 Harness 规则;任意现有相对路径都可登记且保持原位。
232
+ - **新鲜度由 Agent 复核推进,不由 sync 偷偷推进**:`record-context-review --path <exact path> --reason <分析依据>` 或 `--module <name>` 同时保存 context 内容 hash、绑定源 hash、理由、可选 session。之后文档或源任一变化即 stale。hash 证明“复核后没变”,不证明语义正确;命令必须在 Agent 已读代码/测试/本地配置并作出判断之后执行。
233
+ - **authority 是语义方向**:`derived` 要求文档跟代码事实同步;`policy` 要求实现遵守文档;`review` 要求双向核对。三种显式 authority 在首次 record 前都 blocking。未声明 authority 的 v0.2 legacy baseline 只保留 advisory 兼容路径,完成一次显式 review 后同样变成 durable blocking evidence。
234
+ - **review 绑定完整语义输入**:删掉或替换 `binds`、修改 `authority`、知识内容变化、绑定源变化或绑定源缺失,都会让旧 review blocking stale;缺失源不能创建新的 review。这样不能靠缩小绑定范围或沿用旧 hash 把未知状态伪装成 current。
192
235
  - **两档 guardian**:
193
236
  - 便宜档(`doctor`,可每日/每次会话跑,确定性):drift、过期候选、`manual` 技术债。
194
237
  - LLM 档(可选、偶发、须先确认花费):找缺失的知识/ADR、语义审计。
@@ -198,9 +241,56 @@ GAPS 不计入失败,但会打印数量(`verify: OK (N gap(s))`)。配套*
198
241
  | 命令 | 作用 |
199
242
  | --- | --- |
200
243
  | `harness init` | 往当前 repo 注入 `.agents/` 骨架 + 交互式填 manifest 关键字段 |
201
- | `harness sync` | manifest 生成各工具文件(幂等,带 DO-NOT-EDIT 头) |
202
- | `harness doctor` | 开发期体检:完整性 + 漂移 + 新鲜度 + 技术债 |
203
- | `harness verify` | CI 门禁:跑全部可执行 checks,任一失败即 fail |
244
+ | `harness prepare-adoption --out <external-dir>` | 在仓库外生成私有 legacy+candidate 审计 bundle,不修改真实入口 |
245
+ | `harness record-adoption-audit --candidate <dir> --verdict pass\|fail --report <file> --reason <text> [--out]` | 生成内容绑定的声明式审计回执;不证明身份或语义质量 |
246
+ | `harness sync [--adopt-existing --candidate <dir> --audit <receipt>]` | 事务生成工具文件;首次接管要求精确 pass receipt 且应用瞬间重新渲染核对;不刷新 context review |
247
+ | `harness doctor` | 开发期体检:完整性 + 漂移 + 新鲜度 + 技术债 + 影响面 owns 空匹配 / playbook 存在性 |
248
+ | `harness verify [--json]` | 本地/CI 门禁:跑全部可执行 checks,任一失败即 fail;JSON 为单文档稳定协议 |
204
249
  | `harness accept-contract [--id]` | 把当前契约指纹记为已接受基线(有意变更后显式跑,与 sync 分开) |
250
+ | `harness install-hooks [--git] [--stop] [--agents ...] [--allow-shared-git-hooks] [--allow-user-dispatcher]` | 装 Agent hooks;Codex linked-worktree 的用户分发器必须显式允许,原生 Git hooks 默认只在单 worktree/default path/无第三方冲突时写入 |
251
+ | `harness plan-checks [--base] [--profile]` | 算影响面:把 diff 映射到模块、选出该跑的 checks、列出 gap;只算不跑(见 §10) |
252
+ | `harness run-checks [--base] [--profile] [--waive <kind> --where <scope> --reason ...]` | 跑选中的 checks,持久化证据;失败或未解决的 blocking gap → 非零退出 |
253
+ | `harness evidence [--session] [--json]` | 查看当前 worktree 最近一次(或指定 session)的验收证据 |
254
+ | `harness record-context-review (--path <path> | --module <name>) --reason <text> [--session] [--json]` | 记录 Agent 已完成的语义复核,不执行或替代分析 |
255
+ | `harness check-loop` | 打印 harness-check-loop skill:给 agent 的"实现 -> 验证"闭环 |
256
+ | `harness onboard` | 打印 erzhe-harness-init skill:引导 agent 给仓库接入 harness-kit |
205
257
 
206
258
  (未来:`harness map` 生成代码地图、`harness new-adr` 起草决策记录。)
259
+
260
+ ## 10. 实现 -> 验证闭环(v0.2)
261
+
262
+ 在"生成 + 门禁"之上,v0.2 提供一层**确定性弹药**,让 agent 在实现需求 / 修 bug 时能闭环验收。harness-kit **不判断功能对不对**(那是 agent + 测试的活),只做确定性的影响面计算和 capability 执行。
263
+
264
+ **`plan-checks`(只算不跑)**:安全调用 Git(ref 永不拼进 shell),计算 committed + staged + unstaged + untracked 的完整改动。普通 `--base` 使用 merge-base;生命周期门禁使用 SessionStart 保存的 exact commit,因而不会漏掉会话内已 commit 的文件。若 `--repo` 指向 Git worktree 内的子 target,只保留该 target 下的 entries 并去掉路径前缀,模块 glob 与证据都保持 target-relative,兄弟 package 不会混入。Git 失败、base 无效、manifest 无效都 fail closed。随后按 `modules[].owns/tests` 映射模块,选出 `checks`(或 `--profile <checkset>`,再叠加 `validation.defaults`),并输出**诚实的 gap**:
265
+
266
+ | gap kind | 含义 | 严重级 |
267
+ | --- | --- | --- |
268
+ | `no-impact-map` | manifest 没有任何声明 `owns` 的模块 | advisory |
269
+ | `unmapped-file` | 改动文件不属于任何模块 `owns/tests` | advisory |
270
+ | `unmapped-required-file` | `required_coverage` 范围内的改动未映射 | blocking |
271
+ | `module-without-tests` | 命中模块没声明 `tests`(无回归网) | 由 test-touch policy 决定 |
272
+ | `missing-test-touch` | 改了模块生产代码但一个测试都没碰 | 由 test-touch policy 决定 |
273
+ | `no-checks-selected` | 有改动但没解析出任何 check | blocking |
274
+ | `manifest-invalid` / `diff-unavailable` | 无法产生可信计划 | blocking |
275
+ | `selected-check-not-run` | 选中的 check 未执行(未知/有副作用/长驻) | blocking |
276
+ | `manual-base-required` | 手动验收只看到干净工作区,无法覆盖已 commit 的任务 | blocking |
277
+
278
+ 跨模块依赖无法从静态 glob 推断,作为 `notes.propagation-note` 明示,不伪装成已覆盖。每个 gap 带 `suggestion`(下一步怎么补),可被 `modules[].remediation` 覆盖。测试文件本身也会映射模块并触发该模块 checks,但只有生产代码变化才触发 test-touch 判断;多层 Git 状态按 `index < worktree < untracked` 折叠到最终状态,测试删除不算有效 touch。
279
+
280
+ **`run-checks`(跑 + 留证据)**:先校验 manifest,再执行选中的 capability。未知、`background`、`mutating` 不是“跳过也算过”,而是 `not-verified`。状态只有:`no-change`、`verified`、`verified-with-advisories`、`verified-with-waivers`、`not-verified`。没有 lifecycle session 时,隐式 HEAD 得到的 `no-change` 不足以证明已 commit 的任务,命令会报 `manual-base-required`;手动工作流应在任务开始时记录 SHA,并传 `--base <task-start-sha>`。结果按 worktree/target/session 写入 Git admin dir 下的 `harness-kit/validation/`(文件权限 0600,保留 7 天、最多 100 条),`evidence` 可读取;同一 Git worktree 里的多个 harness target 不共享 latest 指针。
281
+
282
+ 只有确属非目标的**覆盖类缺口**可用 `--waive <kind> --where <scope> --reason <why>` 豁免:`missing-test-touch`、`module-without-tests`、`unmapped-required-file`。`unknown-profile`、`no-checks-selected`、manifest/Git 失败、check 未执行等系统与执行问题不可豁免。豁免绑定“当前改动指纹 + kind + scope”,代码一变自动失效;空理由、不匹配或歧义 scope 都失败。改动指纹包含 exact base、排序后的 layer/status/path、当前内容与 Git 可执行位;submodule 还包含当前 commit 与脏状态。
283
+
284
+ **执行保证(SessionStart + Stop)**:`install-hooks --stop` 同时安装两个时刻。SessionStart 记录 exact HEAD;每一次 Stop(包括 `stop_hook_active`)都重跑 `run-checks` + `verify`。Claude Code / Codex 输出 JSON `{"decision":"block","reason":"..."}`;Cursor 输出 JSON `followup_message`。Cursor 的 aborted/error 停止不阻断。共享 runner 固定到安装时的 harness-kit 版本(本地开发可用 `HARNESS_KIT_CMD` 覆盖),避免 `latest` 在同一任务中漂移。
285
+
286
+ 项目级 Agent runner 与客户端配置必须整组预检和事务写入:最终路径和父路径都不得是 symlink 或解析到项目外,未知/损坏的 hooks JSON 结构不得被猜测替换,第三方 runner 即使带 `--force` 也不得覆盖。渲染配置所读取的旧字节必须在同一次写事务的 authorize preflight 中重新匹配;中间发生并发编辑就整组失败并保留较新的内容。合法第三方数组项原位保留,只更新与安装器生成的 runner、agent、event、fallback 完整匹配的 Harness 命令;仅出现 marker 文本、错误事件或含 shell expansion 的 `HARNESS_KIT_CMD` 前缀都不能被当成已安装。合法本地 override 也会改变配置指纹:必须由这版精确配置重新产生 SessionStart/Stop 证据,旧证据只能降级。任一客户端预检失败时,所选整组不写入。
287
+
288
+ Codex CLI 对 linked worktree 的项目级 Hook 行为在不同启动 surface 上不一致:可能忽略,也可能与用户 Hook 同时执行。因此 installer 默认拒绝只写项目 Hook,只有显式 `--agents codex --allow-user-dispatcher` 才能启用 fallback。项目事务必须从 `.codex/hooks.json` 移除安装器能精确识别的 Harness SessionStart/Stop 命令,同时原位保留第三方项目 Hook;linked worktree 的 Harness 生命周期只能有用户分发器这一条有效路径,若状态检查发现项目 Harness 命令仍存在必须 `DEGRADED`。随后 installer 用绑定旧字节的 compare-and-swap 更新 Codex 用户 Hook 源配置的精确 SessionStart/Stop managed group 和版本化、兼容 Node 18 的无依赖分发器,再把不含命令的登记记录以 `0600` 写入当前 `git-dir`,登记必须最后写入。默认源目录是 canonical `$CODEX_HOME`(未设置时 `~/.codex`);当且仅当存在 Orca worktree 标识且 canonical `ORCA_CODEX_HOME` 与 canonical `$CODEX_HOME` 相同,当前目录属于 Orca 生成的运行时,此时源目录必须切换为 canonical `~/.codex`,当前运行时文件、Orca 管理脚本和 Hook trust 状态都不得修改,并必须提示新建 Orca Agent 会话完成镜像。这一环境判断只选择用户 Hook 源,不参与 linked-worktree 判定;linked-worktree 仍必须比较 canonical `git-dir` 与 `git-common-dir`,不能把同样使用 `.git` 文件的 submodule 误判为 linked worktree。分发器只接受当前 worktree 的 canonical root/git-dir、项目内普通 manifest/runner、固定 runner relative path/hash/mode;无登记仓库 silent no-op,登记存在但任一检查失败则 SessionStart 非零、Stop 输出 block。已有用户 Hook 条目的语义内容与相对顺序必须保留;未知 JSON shape、同名外来分发器、软链接、路径越界或并发更新全部 fail closed。
289
+
290
+ 安装成功不等于客户端一定执行:首个真实会话后必须跑 `evidence --json` 并看到 `hookActive: true`。Cursor 的部分 headless/cloud surface 仍可能不触发生命周期 hooks;没有 evidence 就只能报告 GAP,不能声称门禁已生效。
291
+
292
+ **原生 Git hooks 是可选增强,不是 Agent 闭环的前提**:安装前必须用参数化 `git` 调用检查 `git worktree list`、`--git-common-dir`、`--git-dir`、解析后的 hooks 目录,以及 `core.hooksPath` 的 scope/origin。多 worktree 默认拒绝;只有用户显式 `--allow-shared-git-hooks` 才可接受共享范围。custom/global/ambiguous `core.hooksPath` 永远拒绝自动写;已有第三方 `pre-commit`/`pre-push` 永远保留,`--force` 也只能刷新 Harness 自己有 marker 的 hook。组合安装时,Git hook 拒绝不能阻止 worktree-local Agent hooks 安装,但整体退出码必须诚实非零。CLI 不自动 merge 第三方 hook、不修改 CI。
293
+
294
+ `evidence` 每次读取都会从原 resolved base 重算当前指纹;代码变化后旧记录立即变 `stale` 并非零退出。手动 `run-checks` 后只有 `runChecksValid`,独立 `verify` 会在指纹仍匹配时把结果写回;整体 `valid` 必须两道门都通过。证据状态保留 7 天,超过期限不再作为有效 hook 证据;JSON 的 `hookActive` 只表示这条期限内的证据来自生命周期 hook 且 `run-checks + verify` 都通过,不表示持续探测客户端安装状态。若 SessionStart 时工作区已经 dirty,安全边界是“从该 HEAD 到最终工作树的全部改动”(包含既有 dirty 的 superset),不是精确的任务归因;`evidence` 会展示 `initialDirty`。自动 checks 共享 7 分钟总预算,`verify` 的 repo 命令再共享 2 分钟预算,给 10 分钟客户端 hook 留出协议回传时间;超预算必须失败并主动返回 blocking 协议。
295
+
296
+ **Goal 4(Harness Loop)**:仓库接入后持续迭代不足,复用既有闭环——`doctor` 报 owns 空匹配 / playbook 缺失 / 漂移 / 新鲜度,agent 自愈、人只 review(见 erzhe-harness-init skill 第 5 节),不新增命令。