feat: hard merge gate by default (CI + directory + contract + coordinator + reviews)

- cloud/merge_gate_hard.py (new): pure hard gate; mode resolution is
  env-only (unset/invalid -> hard, fail-closed); five checks plus
  branch protection must be protected; unknown/unprotected block
  even with explicit confirm; no-evidence blocks (fail-closed);
  directory check reuses #209 check_directory_isolation (v0.3 rule);
  blocks codes + merge_gate_blocked audit detail are the track-3
  pushback interface (no pushback state machine in this track).
- cloud/server.py: POST /tasks/{id}/merge uses hard mode by default;
  record/enforce/off only when explicitly set via env (preserving
  #209 semantics); body merge_gate_mode is ignored server-side so
  callers cannot downgrade the gate; every gate block writes a
  merge_gate_blocked audit before returning 409, status unchanged;
  hard-mode body type errors return 400.
- docs/merge-gate-branch-protection.md (new): protection payload
  (PR + strict status checks + no force-push + no deletion +
  enforce_admins), empty required_checks = unconfigured, Pro/public
  prerequisites, 403 causes; states protection is NOT claimed enabled.
- SKILL.md (gate-mechanism wording only): four checks -> five checks;
  body + coordinator + client appendix gate paragraphs updated to
  default hard, merge_gate_blocked audit, payload doc reference.
- tests: 31 new hard-gate tests (pure + endpoint + skill text);
  #209 endpoint tests now set record env explicitly (their intent);
  test_server_merge 200-path calls now carry full hard evidence.
This commit is contained in:
host committed 2026-11-04 20:54:04 +00:00
1 parent f6d721158e
commit 93f2b350ac
7 files changed
+1048 -39

No files matched your search

+33 -23
View File
@@ -524,10 +524,10 @@ tests/ # QA 线程专属,含跨端一致性用例
### 合并门:缺一不可,与主分支保护
- 合并前四项全过:① GitHub Checks 全绿;② 目录归属检查通过
- 合并前五项全过:① GitHub Checks 全绿;② 目录归属检查通过
(只改拥有目录,契约变更经批准除外;检查命令与输出文件清单必须
记入合并记录,见“目录与分支规则”);③ 契约版本是冻结版;
④ 协调员评审通过,且无未解决评审意见。有一项不过就不合并。
④ 协调员评审通过;⑤ 无未解决评审意见。有一项不过就不合并。
- CI 怎么查:用只读方式查,例如本平台的 GET /tasks/{id}/pr/checks。
它是只读诊断,绝不重跑检查、不批准、不合并;还没建 PR 时它会 409
(查无可查),这时先补 PR,不要把它当成 CI 通过。
@@ -536,17 +536,24 @@ tests/ # QA 线程专属,含跨端一致性用例
协调员要在决策记录里写明风险并去开通,不能假装已保护,
不能靠“大家自觉”代替保护。
- 合并门禁(2026-10-30 补,代码在 cloud/merge_gate.py,服务端
POST /tasks/{id}/merge 已接线):保护状态只能由调用方或环境变量
POST /tasks/{id}/merge 已接线;2026-10-31 硬门禁轨加
cloud/merge_gate_hard.py):保护状态只能由调用方或环境变量
CLOUD_BRANCH_PROTECTION 显式声明,代码不去 GitHub 核实、不声称
已保护;状态 unknown 时记风险、不阻断。模式由
CLOUD_MERGE_GATE_MODE 控制,默认 record:未保护时须显式确认
(merge_gate_confirm)才放行,无确认阻断;enforce 模式下未保护
一律阻断,确认也不放行——切 enforce 前必须先由用户决定并开通
保护(升级 Pro、公开仓库、或保持纪律 + 记风险,三者用户侧定,
代码不替选)。显式确认只覆盖保护风险,绝不覆盖目录隔离违规;
目录检查复用 v0.3 的 git diff --name-only 口径,越目录只能靠
契约变更批准文件放行。技能播种仍只复制 SKILL.md,不做整目录复制
(租户已改文件绝不被覆盖,见 cloud/skill_seed.py 的评估结论)。
已保护。模式只由环境变量 CLOUD_MERGE_GATE_MODE 控制,默认
hard:上面五项全查,缺一 409 且任务状态不变,并写
merge_gate_blocked 审计;无证据不放行;unknown 不等于
protected,同样阻断;未保护即使带显式确认也不放行。record /
enforce / off 必须显式设置才生效(过渡/显式降级):record 下
未保护时须显式确认(merge_gate_confirm)才放行,无确认阻断,
无证据调用仍按旧接口放行;enforce 模式下未保护一律阻断,
确认也不放行——切 enforce 前必须先由用户决定并开通保护
(升级 Pro、公开仓库、或保持纪律 + 记风险,三者用户侧定,
代码不替选,操作说明与 payload 见
docs/merge-gate-branch-protection.md)。显式确认只覆盖保护风险,
绝不覆盖目录隔离违规;目录检查复用 v0.3 的 git diff --name-only
口径,越目录只能靠契约变更批准文件放行。技能播种仍只复制
SKILL.md,不做整目录复制(租户已改文件绝不被覆盖,见
cloud/skill_seed.py 的评估结论)。
### 合并方式与合并记录
@@ -828,18 +835,19 @@ G8 的交付物是 v1.1 交接清单终版与下一轮 G0-G6 输入冻结清单
测试证据、已知问题、关联待办或 PRD 项;评审意见逐条处理,
未解决的评审意见不能合并。
- 合并门:GitHub Checks 全绿、目录归属检查通过、契约版本是冻结版、
你评审通过且无未解决评审意见,四项缺一不可。
你评审通过、无未解决评审意见,五项缺一不可。
CI 用只读方式查,例如 GET /tasks/{id}/pr/checks,它绝不重跑检查、
不批准、不合并;无 PR 时它会 409,先补 PR。
- 主分支保护:要求 PR、要求 CI 通过、禁止直接推,这是 GitHub 仓库设置,
不是本平台代码能替你开的。没开保护时记为风险并去开通,不假装已保护。
- 合并门禁:同正文,代码在 cloud/merge_gate.py,模式由
CLOUD_MERGE_GATE_MODE 控制,默认 record:未保护时须显式确认
才放行,无确认阻断;enforce 模式下未保护一律阻断,切 enforce
前须由用户决定并开通保护(升级 Pro、公开仓库、或保持纪律 +
记风险,三者用户侧定)。显式确认只覆盖保护风险,绝不覆盖
目录隔离违规;目录检查复用 v0.3 的 git diff --name-only 口径;
技能播种仍只复制 SKILL.md,不做整目录复制。
- 合并门禁:同正文,代码在 cloud/merge_gate.py 与
cloud/merge_gate_hard.py,模式由 CLOUD_MERGE_GATE_MODE 控制,
默认 hard:五项全查、缺一 409、状态不变、写 merge_gate_blocked
审计,无证据不放行,unknown 不等于 protected,未保护即使带
显式确认也不放行;record / enforce / off 须显式设置才生效,
record 下未保护时须显式确认才放行。显式确认只覆盖保护风险,
绝不覆盖目录隔离违规;目录检查复用 v0.3 的 git diff --name-only
口径;技能播种仍只复制 SKILL.md,不做整目录复制。
- 合并记录:默认 merge commit;记录必须含 PR 号、合并提交 hash、
CI 运行链接、执行人(人或宿主操作,不是你自己合);
合并后删远程分支,删前确认合并提交已在主线。
@@ -1068,9 +1076,11 @@ TODO-UPDATE 要求,缺一项就不发任务)。派生提示词里的精简
- 合并门由协调员判定:Checks 全绿、目录归属通过、契约版本是冻结版、
评审通过且无未解决意见;你不自己合并、不绕过评审推主线。
- 合并门禁:同正文,模式由 CLOUD_MERGE_GATE_MODE 控制,默认
record:未保护时须显式确认才放行;显式确认只覆盖保护风险,
绝不覆盖目录隔离违规;目录检查复用 v0.3 的
git diff --name-only 口径;技能播种仍只复制 SKILL.md,
hard:五项全查、缺一 409、状态不变、写 merge_gate_blocked 审计,
无证据不放行,unknown 不等于 protected,未保护即使带显式确认
也不放行;record 须显式设置才生效,未保护时须显式确认才放行;
显式确认只覆盖保护风险,绝不覆盖目录隔离违规;目录检查复用
v0.3 的 git diff --name-only 口径;技能播种仍只复制 SKILL.md,
不做整目录复制。
- 安全:密钥、口令、token 绝不进代码、commit、命令行、PR 正文;
需要调用 GitHub 时 token 只进子进程环境,不写进示例命令。