Skip to content

第 10 章 · 项目模式与合并权限:no-mistakes / direct-PR / local-only

本章目标:掌握三种显式项目交付模式(no-mistakes / direct-PR / local-only)的语义与适用场景,理解 +yolo 合并自治标志与 hard rule 2 的关系,学会为不同风险等级的项目选择合适的交付路径。

10.1 为什么交付方式必须「显式」

第 8 章我们知道了任务的两种形态:ship 改项目、scout 出报告。但 ship 任务改完代码之后,成果以什么方式落地,同样是一个必须事先说清的问题——是走完整验证管线再开 PR?是直接开 PR?还是只在本地合并?

如果这个决策留给临场发挥,就会出现两类事故:低风险改动被迫走重流程拖慢节奏;高风险改动却悄悄绕过了验证直接上线。所以 FirstMate 规定:每个任务在 intake(受理)时就确定交付模式与合并姿态,且模式一旦写进 brief 就不可漂移

架构文档的原话是:

text
Delivery modes are explicit per task:

no-mistakes tasks run the full validation pipeline,
direct-PR tasks open PRs without that pipeline,
local-only tasks stay local until firstmate performs
an approved fast-forward merge.

Each task's mode and yolo merge posture are
firstmate's decision at intake.

10.2 三种项目模式逐一拆解

模式一:no-mistakes(完整验证管线)

这是最重的交付路径。ship 任务跑完完整的验证管线后才允许进入合并流程。它适合核心业务仓库、生产相关代码、CI 纪律要求高的团队仓库。两个值得注意的工程细节:

  • 管线在仓库里留存的验证证据会发布到一个 orphan evidence branch——一个与代码分支完全不共享历史的孤儿分支,因此证据永远不会混进 crew 分支或默认分支;
  • .no-mistakes/ 目录属于本地状态、保持 gitignore,若被误提交会被 CI 拒绝;.no-mistakes.yaml 中设置的 disable_project_settings: true 只从受信任的默认分支副本生效,防止某条被推送的分支在验证期间偷偷启用自己的项目指令。

模式二:direct-PR(直接开 PR)

跳过 no-mistakes 管线,任务完成后直接开出 PR。适合有自己 CI 的开源风格仓库——GitHub/GitLab 的检查机制本身就是一道闸门。日常功能开发、文档改进多走这条路。

模式三:local-only(仅本地落地)

任务留在本地,直到 firstmate 执行一次经过批准的 fast-forward merge 才算落地。它不走远程 PR 路径,因此这类项目始终留在主第一副手身边管理;fleet sync 同步舰队时也会把 local-only 项目视为良性跳过(benign skip)。适合个人实验项目、还没有远程仓库的克隆。

text
三种模式的落地路径对比:

ship 任务完成

   ├─ no-mistakes ──→ 完整验证管线 → 孤儿证据分支留存证据 → PR 路径合并

   ├─ direct-PR ────→ 直接开 PR(依赖仓库自身 CI 把关)

   └─ local-only ───→ 留在本地 → captain 批准后 fast-forward 合并进主本地检出

10.3 模式如何流转:brief 固定,spawn 校验

模式不是一句口头约定。它的流转链路是刻意设计成「防漂移」的:

  1. 每个项目的常设姿态(standing posture)和可选的 +yolo 标志记录在 data/projects.md 注册表里,作为船长的默认决定及其上下文,还包括条件性的 no-mistakes-prod-only 策略;
  2. 受理任务时,firstmate 决定本任务的模式与 yolo 姿态;
  3. 模式被显式传给 bin/fm-brief.sh,模式与姿态两者都被显式传给 bin/fm-spawn.shbin/fm-promote.sh——这几个命令都拒绝猜测自己消费的值;
  4. ship brief 把模式写成一行固定的机器可读记录,spawn 若发现要启动的模式与记录不一致会拒绝启动,保证「给工人的指令」和「记录在案的交付方式」永不分叉。
text
data/projects.md 注册表示意(结构示意,非逐字格式):

project: github.com/captain/payments-core
posture: no-mistakes          ← 常设姿态
merge:   captain-approval     ← 未加 yolo,默认须船长发话

project: github.com/captain/blog
posture: direct-PR
merge:   +yolo                ← 常设合并自治标志

另外有一道「降级告警」保护:如果某次 ship spawn 的实际严谨度低于注册表中登记的水准(例如注册的是 no-mistakes 却试图按更轻的模式交付),系统会打印一条 deviation notice(偏差通知)然后继续——让你知情,但不擅自中断。

bin/fm-project-mode.sh 是注册表的唯一解析器,服务于那些「手头没有具体任务」的机械消费者:fleet sync 对 local-only 的跳过判定、home seeding 的拒绝与 no-mistakes 初始化等。

10.4 Hard Rule 2:没有船长的明确指示绝不合并 PR

第 4 章学过五条硬规则中的第二条:

text
Hard rule 2 — Never merge a PR without the captain's explicit word.

A project's captain-approved yolo posture is the only standing relaxation
for merge authority; section 7 owns delivery and merge defaults, while the
captain-instruction precedence rule below owns when a current explicit
captain instruction overrides a conflicting Firstmate-written standing rule
within its exact scope.

三个层次要分清:

  1. 默认态:合并 PR 必须等船长明确发话("merge it");
  2. 常设放宽:只有船长为某个项目批准的 +yolo 姿态可以常设地放宽合并权限——这是唯一的例外通道;
  3. 指令优先级:AGENTS.md 第 7 节拥有交付与合并的默认值;而当船长当下的明确指示与 firstmate 写下的常设规则冲突时,「当下指示在其确切范围内优先」由专门的 precedence 规则裁定。

也就是说,即使你给项目开了 +yolo,你随时仍可以当场下达相反的明确指示收回这一次的决定权;反过来,没有 +yolo 时,任何「顺手合了」都是违规。

10.5 合并动作的技术保障:fm-pr-merge.sh

真正执行 PR 合并的是 bin/fm-pr-merge.sh,它在调用 forge CLI 之前通过 bin/fm-pr-check.sh 记录 pr= 与可用的 pr_head=。几条硬性约束:

text
fm-pr-merge.sh 的输入与校验:

输入要求:
- 必须是完整规范 URL,拒绝畸形 URL 与 repo override 标志

URL 分派:
- https://github.com/<owner>/<repo>/pull/<n>
    → gh-axi pr merge <n> --repo <owner>/<repo>(默认 --squash,
      保留显式的 merge-method 标志)
- https://<host>/<path>/-/merge_requests/<n>(GitLab MR)
    → glab mr merge <n> -R https://<host>/<path>
      (不加 merge-method 标志,沿用项目自身的合并方式)

更重要的是合并前的实时校验。合并只在这五项条件经一次实时读取确认后才执行:

text
合并前置条件(live read,实时读取,不信缓存元数据):

1. MR 处于 open 状态
2. 可合并(mergeable)
3. 无冲突(conflict-free)
4. blocking discussions 已全部解决
5. 当前 head 上 pipeline 成功

满足后把这次合并绑定到该已验证 head。
记录在案的元数据永远不作为这些条件的依据——
因为一次 rebase 就会让它们过期失效。

这套设计把「船长说了 merge it」翻译成了一组机器可验证的安全前提,避免人肉确认造成的遗漏。

10.6 如何为项目选择模式

给出一张决策参考表:

项目特征推荐模式理由
生产相关、核心业务库no-mistakes完整管线 + 证据留存,出错代价最高
有自身 CI 的常规开发仓库direct-PR平台检查即闸门,流程轻快
个人实验 / 无远程的项目local-only无 PR 路径可用,fast-forward 即可
高频琐碎改动 + 你完全信任任一模式 + +yolo免去每次口头批准

选择时的三条经验法则:

  1. 看出错代价而不是改动频率:改动频繁但出错了很难回滚的(如支付、鉴权),宁可重流程;
  2. CI 成熟度决定 direct-PR 是否安全:仓库本身没有可靠 CI 时,direct-PR 等于裸奔;
  3. +yolo 是渐进授权:先观察一段时间某项目 firstmate 的交付质量,再考虑授予,且随时可以用当面的明确指令覆盖单次行为。

一次典型的人机合并对话是这样的:

text
captain> alright, merge it        # CI 绿了之后,船长发话
firstmate> Aye, captain.
           Verifying PR #42 is still open, mergeable, conflict-free,
           with resolved discussions and a green pipeline at HEAD...
           Merged (squash). Teardown queued for the task worktree.

本章小结

  • 三种交付模式语义分明:no-mistakes 跑完整验证管线、direct-PR 直接开 PR、local-only 留在本地等待批准后的 fast-forward 合并;模式与 yolo 姿态都在 intake 时确定。
  • 模式经 brief 固化为机器可读行,fm-brief.sh / fm-spawn.sh / fm-promote.sh 全部拒绝猜测值;spawn 发现模式不符即拒绝启动,杜绝「指令与记录分叉」。
  • data/projects.md 登记各项目常设姿态与可选 +yolo;严谨度降级时打印 deviation notice 继续;fm-project-mode.sh 是机械消费者的唯一注册表解析器。
  • Hard rule 2 默认要求船长明确发话才可合并;+yolo 是唯一的常设放宽通道,且当下明确指示可在其范围内覆盖常设规则。
  • fm-pr-merge.sh 要求完整规范 URL,按 GitHub/GitLab 分派 CLI,并在实时读取确认 open / mergeable / conflict-free / discussions resolved / pipeline 绿五项后绑定到已验证 head 再合并。

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. 三种项目模式中,哪一种会运行完整验证管线(full validation pipeline)?

2. 关于 hard rule 2(未经船长明确指示绝不合并 PR),正确的说法是?

3. fm-pr-merge.sh 在执行合并前如何对待记录在案的元数据(如 pr=、pr_head=)?

4. local-only 项目的落地方式是什么?

🛠️ 动手实践

  1. 为你手头的三个真实项目分别选定交付模式(no-mistakes / direct-PR / local-only),参照本章 10.3 的示意结构写出各自的注册表条目,并用一句话说明每个选择的理由(对照 10.6 的三条经验法则)。
  2. 阅读 FirstMate 仓库中 bin/fm-brief.shbin/fm-spawn.sh 的头部注释,找出「模式固定行」与「拒绝猜测」的具体实现位置,整理成一份笔记说明这条防漂移链路。
  3. 在一个测试仓库上演练合并决策流:开一个 PR 并等 CI 变绿后对 firstmate 说 "merge it",观察 fm-pr-merge.sh 报告的五项实时校验结果;随后再对比一个带 +yolo 姿态的小项目,体会两种合并权限的差异。