@haiyangbg/buildbeat 1.20.0 → 2.0.0-beta.1

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 (82) hide show
  1. package/CHANGELOG.md +29 -7
  2. package/README.en.md +6 -4
  3. package/README.md +6 -4
  4. package/SKILL.md +33 -2
  5. package/bin/buildbeat-v2.js +6 -0
  6. package/docs/BuildBeat v2/357/274/232AI /345/216/237/347/224/237/350/275/257/344/273/266/344/272/244/344/273/230/346/216/247/345/210/266/345/271/263/351/235/242.md" +2053 -0
  7. package/docs/CAPABILITY-MATRIX.md +4 -4
  8. package/docs/CLI.md +6 -6
  9. package/docs/EXECUTION-PLAN.md +9 -9
  10. package/docs/PHASE4-STABILITY-AUDIT-2026-08-25.md +10 -8
  11. package/docs/PHASE4-V1.20-PILOT-2026-08-25.md +4 -0
  12. package/docs/RELEASING.md +6 -6
  13. package/docs/ROADMAP.md +16 -14
  14. package/docs/V1.21-RELEASE-EVIDENCE-2026-08-25.md +55 -0
  15. package/docs/V2-D2-DECISION-CARD.md +37 -0
  16. package/docs/V2-DECISIONS.md +11 -0
  17. package/docs/V2-ITERATION-01.md +60 -0
  18. package/docs/V2-ITERATION-02.md +32 -0
  19. package/docs/V2-ITERATION-03.md +30 -0
  20. package/docs/V2-ITERATION-04.md +29 -0
  21. package/docs/V2-ITERATION-05.md +20 -0
  22. package/docs/V2-ITERATION-06.md +18 -0
  23. package/docs/V2-ITERATION-07.md +36 -0
  24. package/docs/V2-PLAN.md +333 -0
  25. package/docs/V2-PROPOSAL.md +319 -0
  26. package/docs/WP4.3-RELEASE-EVIDENCE-2026-08-25.md +73 -0
  27. package/docs/v2/M1-ACCEPTANCE-2026-08-28.md +38 -0
  28. package/docs/v2/M2-DOD-2026-08-28.md +34 -0
  29. package/docs/v2/M4-CHICKAI-PILOT-2026-08-28.md +44 -0
  30. package/docs/v2/M4-EXTERNAL-PILOT-2026-08-28.md +46 -0
  31. package/docs/v2/M4-SELFHOST-2026-08-28.md +53 -0
  32. package/docs/v2/RFC-0001-product-definition.md +92 -0
  33. package/docs/v2/RFC-0002-domain-model.md +149 -0
  34. package/docs/v2/RFC-0003-workflow-policy.md +204 -0
  35. package/docs/v2/SPEC-0001-events-v1.md +98 -0
  36. package/docs/v2/guide/01-quickstart.md +92 -0
  37. package/docs/v2/guide/02-workflow-guide.md +42 -0
  38. package/docs/v2/guide/03-policy-guide.md +53 -0
  39. package/docs/v2/guide/04-adapter-guide.md +45 -0
  40. package/docs/v2/guide/05-worker-contract.md +37 -0
  41. package/docs/v2/guide/06-evidence-guide.md +38 -0
  42. package/docs/v2/guide/07-approval-guide.md +34 -0
  43. package/docs/v2/guide/08-migration-v1.md +68 -0
  44. package/docs/v2/guide/09-security-boundaries.md +28 -0
  45. package/docs/v2/guide/10-recovery.md +55 -0
  46. package/docs/v2/guide/README.md +18 -0
  47. package/example/.buildbeat/manifest.json +3 -3
  48. package/example/BUILDBEAT.md +1 -1
  49. package/example/README.md +22 -0
  50. package/lessons.md +8 -0
  51. package/package.json +4 -2
  52. package/src/constants.js +4 -1
  53. package/src/project.js +6 -1
  54. package/src/v2/adapters/mock.js +67 -0
  55. package/src/v2/adapters/shell.js +78 -0
  56. package/src/v2/cli/run.js +494 -0
  57. package/src/v2/domain/event-registry.js +100 -0
  58. package/src/v2/domain/model.js +61 -0
  59. package/src/v2/engine/reducer.js +253 -0
  60. package/src/v2/engine/risk-preset.js +48 -0
  61. package/src/v2/engine/workflow.js +201 -0
  62. package/src/v2/engine/yaml-subset.js +194 -0
  63. package/src/v2/evidence/collector.js +63 -0
  64. package/src/v2/observe/observe-config.js +194 -0
  65. package/src/v2/observe/observe-reducer.js +117 -0
  66. package/src/v2/observe/observe.js +420 -0
  67. package/src/v2/policy/policy.js +302 -0
  68. package/src/v2/presets/observe.yaml +45 -0
  69. package/src/v2/presets/policies/ui-render-gate.yaml +13 -0
  70. package/src/v2/presets/risk/controlled.yaml +39 -0
  71. package/src/v2/presets/risk/fast.yaml +19 -0
  72. package/src/v2/presets/risk/legacy-four-gates.yaml +44 -0
  73. package/src/v2/presets/risk/standard.yaml +28 -0
  74. package/src/v2/presets/software-delivery.yaml +39 -0
  75. package/src/v2/runtime/decisions.js +288 -0
  76. package/src/v2/runtime/metrics.js +140 -0
  77. package/src/v2/runtime/orchestrator.js +754 -0
  78. package/src/v2/runtime/run-record.js +55 -0
  79. package/src/v2/storage/event-ledger.js +154 -0
  80. package/src/v2/workspace/workspace-manager.js +137 -0
  81. package/templates/AGENTS.md +21 -0
  82. package/templates//346/214/207/346/214/245/345/217/260.md +23 -0
@@ -0,0 +1,53 @@
1
+ # M4 Self-host 试点证据:BuildBeat builds BuildBeat
2
+
3
+ > 日期:2026-08-28
4
+ > Run:`RUN-SELF-001`(Work:`WORK-SELF-001`,工件与 run-config 见 [`delivery/work/WORK-SELF-001/`](../../delivery/work/WORK-SELF-001/intent.md))
5
+ > 结论上限:脚本 Worker + 真实 Runner + 真实仓库;验证的是运行时与协议,不是 Agent 智能。**Run 停在 `WAITING_HUMAN`(合并决定),未 merge、未 push,等待项目所有者在 inbox 处置。**
6
+
7
+ ## 1. 流程事实(全部由 Runner 回读)
8
+
9
+ - 基线 `daf9d79`,`standard` 风险预设(plan 接受为 build 前置门);intent/plan 均以 digest 绑定接受(`A-WORK-SELF-001-1/2`)。
10
+ - `build → verify → review` 全部一次通过;candidate `59673e2` 由 Git 回读固定,位于 `run/RUN-SELF-001` 分支(未合并,主分支无此变更)。
11
+ - verify 运行本仓库真实测试(`node --test tests/v2-event-ledger.test.js tests/v2-reducer.test.js`),退出码 0 回读入证据日志。
12
+ - review 只读、fresh 进程、结构化 findings 信封(空 findings)落 Evidence。
13
+ - 事件台账 28 条,`replay` 报告 `chain OK: 28 events verified (digest/prev/seq)`。
14
+ - `allowedPaths` 限定 `delivery/work/WORK-SELF-001`,Worker 未越界。
15
+
16
+ ## 2. 真实仓库特有的验证点
17
+
18
+ - **推送保护实测**:本仓库有真实 remote(origin=GitHub)。在 run worktree 内执行 `git push origin HEAD`:
19
+
20
+ ```text
21
+ git: 'remote-protected' is not a git command.
22
+ fatal: remote helper 'protected' aborted session
23
+ ```
24
+
25
+ 能力级失败(worktree 级 pushurl 覆盖),非提示词拦截;主检出的 remote 配置不受影响。
26
+ - **试点还抓到一个真实缺陷**:YAML 子集解析器把列表项中带冒号的引号标量误判为 map,导致 run-config 无法加载。已修复(引号开头的列表项一律按标量解析)并加永久回归(`tests/v2-workflow.test.js`)——这正是 self-host 试点存在的意义。
27
+
28
+ ## 3. inbox 快照(等待项目所有者)
29
+
30
+ ```text
31
+ RUN-SELF-001 (work WORK-SELF-001) [final-decision] enter-wait-merge
32
+ candidate: 59673e2faa19d3aa67339837f16f0db44d6a29cb
33
+ planDigest: sha256:a0e3e86f…
34
+ reason: terminal step requires a human decision
35
+ ```
36
+
37
+ 处置方式:`node src/v2/cli/run.js approve --repo . --run RUN-SELF-001 --transition enter-wait-merge --config delivery/work/WORK-SELF-001/run-config.yaml`(或 `reject`)。批准仅表示 merge-ready;merge 本身仍是人工外部动作。
38
+
39
+ ## 4. M4 退出指标核验
40
+
41
+ | 指标 | 目标 | 当前 | 依据 |
42
+ |---|---:|---|---|
43
+ | 状态转换可追溯 | 100% | **100%** | 每次转换必有 TRANSITION + POLICY_EVALUATED 事件;`replay` 链校验 28/28 |
44
+ | stale Approval 被复用 | 0 | **0** | reducer + approve 双侧强制;eval `stale-approval` |
45
+ | 超预算继续运行 | 0 | **0** | maxAttempts / 指纹 / 超时全停;`v2-invariants` / eval `no-progress` |
46
+ | 试点 Run 自动到达 `WAITING_HUMAN` | ≥70% | **1/1(100%)** | 仅 self-host 分母;**外部试点 ≥2 未跑,该行整体 `UNVERIFIED` 待 T5(项目所有者点名)** |
47
+ | 证据完整率 | ≥95% | **100%** | `metrics`:5/5 finished steps 携带回读证据 |
48
+ | Reviewer 自行修改代码 | 0 | **0** | 只读强制 + eval `reviewer-readonly` |
49
+
50
+ ## 5. 边界
51
+
52
+ - 本次 accept 与 run 启动由受托会话以 `claude-delegated` 身份执行并如实落账;**合并决定未被代行**,留在 inbox。
53
+ - 外部试点(D6:底座内有测试的单仓项目 + 含 UI 项目)待项目所有者点名与授权后执行,指标回填前 M4 不宣称关闭。
@@ -0,0 +1,92 @@
1
+ # RFC-0001:BuildBeat v2 产品定位
2
+
3
+ > 状态:`FINAL`(2026-08-28 项目所有者定稿,`V2-D3`;M0 随三份 RFC 与 [`SPEC-0001-events-v1.md`](SPEC-0001-events-v1.md) 定稿退出)
4
+ > 日期:2026-08-28
5
+ > 上游:[`V2-PLAN.md`](../V2-PLAN.md)(执行基线,`V2-D0=B`);内核范围:完整内核(`V2-D2=A`,[`V2-DECISIONS.md`](../V2-DECISIONS.md))
6
+ > 需求来源:M-1 试点记录——[`pilot/metrics.md`](../../pilot/metrics.md)(能力矩阵 + 卡点 1–5)、[`pilot/evidence/2026-08-28-m1-runtime-gap.md`](../../pilot/evidence/2026-08-28-m1-runtime-gap.md)(F5/F6)、[`V2-ITERATION-01.md`](../V2-ITERATION-01.md)
7
+
8
+ ---
9
+
10
+ ## 1. 定义
11
+
12
+ > **BuildBeat v2 是一个工件驱动的 AI 交付闭环。确定性内核按 Workflow 与 Policy 推进状态,外部 Agent 作为 Worker 执行计划、构建、验证、修复与审查;一切完成以 Runner 回读的真实证据为准;人只在不可委托的判断点被请求最小决策。协议(工件 + 证据 + 决策)永远人机可读、落在 Git——Runner 是引擎,不是协议存在的前提。**
13
+
14
+ 对外定位词可用"AI 原生交付控制面 / 交付闭环"([`V2-PLAN.md`](../V2-PLAN.md) 裁决 #9、D1);**产品之魂是协议**:厂商 runtime 正在被商品化,协议 + 参考实现才是可防守的位置。
15
+
16
+ MVP 核心承诺:
17
+
18
+ > **给 BuildBeat 一个已批准的目标和计划,它会自动完成 Build–Verify–Fix–Review 循环,并携带完整证据停在合并决定前。**
19
+
20
+ ## 2. 是什么 / 不是什么
21
+
22
+ | 是 | 不是 |
23
+ |---|---|
24
+ | 工件协议(Intent/Spec/Plan/Candidate/Evidence/Review/Decision,Git 中,人机可读) | 一个 AI Coding 工具或模型路由平台 |
25
+ | 厂商中立的确定性内核:状态机 / 事件 / Policy,不解释自然语言 | 某家 Agent runtime 的包装层或竞争性 orchestrator |
26
+ | 可恢复的 Agent Loop 运行时(调度 / 重试 / 预算 / 恢复) | 无人值守的自动合并 / 自动部署系统(MVP 停在合并前) |
27
+ | 证据台账:完成以 Runner 回读为准,自然语言声明不算证据 | 效能考核、遥测或排行榜产品(度量本地只读) |
28
+ | 人类升级机制:最小决策请求 + 精确绑定的 Approval | 多人 RBAC / SSO / Web 后台(MVP 之外) |
29
+
30
+ MVP 明确不做的完整清单以报告 B §19.2 为准(多仓、多 Run 并发、后台 daemon、自动 merge/deploy、远程共享等)。
31
+
32
+ ## 3. 用户
33
+
34
+ 第一阶段:使用 Claude Code / Codex / Cursor 等 AI Coding 工具的个人开发者;一人同时驱动多个 AI Worker、希望把 Build–Verify–Fix–Review 连成自动闭环、但保留合并与发布权的场景。后续扩展(远程 Runner、PR/CI 驱动、多仓)不进入 MVP 承诺。
35
+
36
+ ## 4. Runner 的地位
37
+
38
+ Runner 是**引擎**:调度、重试、恢复、预算、staleness 检测只存在于 Runner。但 Runner 不是协议存在的前提——工件是 markdown/YAML,任何 AI 工具无需安装 BuildBeat 即可消费与产出工件。
39
+
40
+ M-1 的核心教训(卡点 1、卡点 5):协议工件齐备但没有 Runner 时,**人仍是节拍器**——三次真实任务自动激活率 `0/3`,"人记得调用薄脚本"不能兑现自动闭环。因此 v2 的 Runner 不是可选增强,而是自动化承诺的唯一载体。
41
+
42
+ ## 5. 手工模式的地位
43
+
44
+ v1 的"Skill-only 完整等价"拆成两个承诺([`V2-PLAN.md`](../V2-PLAN.md) §5):
45
+
46
+ | 承诺 | v2 处置 |
47
+ |---|---|
48
+ | **协议等价** | **保留**。工件人手可写可读;attended 会话(人开任意 AI 工具推进某一步)产出的工件与 headless run 不可区分;任何工具无需安装即可参与 |
49
+ | **自动化等价** | **取消**。手工模式没有调度 / 重试 / 恢复 / 预算 / stale 检测,不假装有 |
50
+
51
+ ## 6. v1 的地位
52
+
53
+ v1 进入 `v1-maintenance` 维护线,只修安全与严重缺陷;npm `latest` 留 v1,`next` 发 v2 预发布;Beta 前 `latest` 不指向 v2。v1 迁移采用半天手工 runbook(装机量 N=1),`migrate-v1` importer 已裁掉(收尾修正三)。旧概念的保留/转换/删除逐项见 [`RFC-0002`](RFC-0002-domain-model.md) §8。
54
+
55
+ ## 7. 自研面与组装面(逐项自研理由)
56
+
57
+ 原则(收尾修正二):**能由厂商 runtime + 薄脚本组装出来的能力一律不自研**;自研只保留厂商结构性不会做的部分。`V2-D2=A` 选择完整内核,不改变这一原则——它只把 M-1 证实"薄脚本做不到"的部分纳入自研面。每一项标注理由与 M-1 证据:
58
+
59
+ ### 7.1 自研面(完整内核范围)
60
+
61
+ | # | 组件 | 自研理由(= 厂商结构性不做) | M-1 证据 |
62
+ |---|---|---|---|
63
+ | 1 | **Run 登记与状态机**(Run/Step 通用状态、转换裁决) | 厂商的"任务"绑定自家会话与账号体系;没有厂商会为跨工具、跨仓的工件协议维护中立状态机 | 卡点 1、卡点 5:无 Run 登记入口,三次任务全部绕过脚本 |
64
+ | 2 | **事件台账 + reducer + 终态压实**(events.jsonl、state 重建、run-record) | 厂商日志是私有格式、随会话消亡、不落 Git;工具中立、可重放、可审计的交付台账没有厂商会提供 | 卡点 1:attempts/token/费用无统一 ledger;度量表全列 `UNVERIFIED` |
65
+ | 3 | **中断恢复**(checkpoint、resume、恢复点裁决) | 厂商的 session resume 只恢复自家会话上下文,不恢复跨 Worker 的交付状态(该继续 Verify、回 Build 还是废弃候选) | F5 = `RECOVERY_MISSING`:重开只能 fail-closed,需人读现场 |
66
+ | 4 | **Approval 对象与 stale 检测**(transition + candidate + planDigest + evidenceDigest 绑定) | 厂商审批是工具内 UI 动作,不产生持久化、跨工具、绑定 digest 的审批对象,更不会在对象变化时自动失效 | F6 = `APPROVAL_STALE_MISSING`;卡点 3:单阶段生产滚动 P1 正是"审批未绑定 rollout plan"的真实事故形态 |
67
+ | 5 | **Policy/Gate 语义检查器 + 强制等级报告**(四类 Policy、`doctor` 报告实际强制等级) | 厂商各有权限系统,但没人会检查"你声称的规则实际达到哪级强制"并跨工具编译到 hook/CI | 边界节:提示词禁令只算 `ADVISORY`;ChickAI 会话始终持有生产能力,未被机器剥离 |
68
+ | 6 | **多 Workspace 绑定**(一个 Work 绑定多仓 candidate 到同一 Decision) | 厂商 Workspace 即"当前打开的仓";跨 meta 仓 + 代码仓的原子绑定是协议层需求 | 卡点 2、卡点 4:ChickAI 与 AI 底座均为 meta+代码多仓,单仓 loop 无法原子关联 |
69
+ | 7 | **统一 Evidence Contract**(回读制证据、grade L0–L4、manifest digest) | 厂商各自产出日志与测试结果,但"什么算证据、谁回读、怎么分级"的合同必须工具中立 | 能力矩阵"证据来源、digest 与未验证范围"= PARTIAL:事后人工汇总、截图无 digest |
70
+
71
+ ### 7.2 组装面(一律不自研)
72
+
73
+ | 能力 | 组装来源 |
74
+ |---|---|
75
+ | Agent 执行本身(计划/编码/修复/审查) | Claude Code / Codex / Cursor 等,经 Shell Adapter 配置化驱动(裁决 #5,不绑厂商) |
76
+ | 测试 / 构建 / lint | 项目自己的命令,Verify 步只回读退出码与报告 |
77
+ | `SERVER_ENFORCED` 强制 | 分支保护、CI、部署平台(BuildBeat 只报告,不重造) |
78
+ | 工具层 hook(`LOCAL_ENFORCED` 的一部分) | 由 gates 配置**编译生成**厂商 hook(如 Claude Code hooks),不自研 hook 机制 |
79
+ | 隔离原语 | git worktree / branch;BuildBeat 只做其上的锁与 candidate 回读 |
80
+ | 触发入口 | 尽量复用宿主机制(git hook / cron / CI 触发调用 `run start`);自研的是 Run 登记与状态,不是定时器 |
81
+
82
+ ## 8. M0 退出核对(本 RFC 承担的部分)
83
+
84
+ - [x] BuildBeat 是什么 / 不是什么 / 谁使用:§1–3
85
+ - [x] Runner 是否核心:§4(引擎,非协议前提;自动化承诺的唯一载体)
86
+ - [x] 手工模式地位:§5(协议等价保留,自动化等价取消)
87
+ - [x] v1 是否继续演进:§6(维护线,不演进)
88
+ - [x] 自研逐项标注"厂商结构性不做":§7
89
+
90
+ ---
91
+
92
+ _核心名词与旧概念处置见 [`RFC-0002`](RFC-0002-domain-model.md);Workflow/Policy/审批语义见 [`RFC-0003`](RFC-0003-workflow-policy.md);事件格式见 [`SPEC-0001-events-v1.md`](SPEC-0001-events-v1.md)。_
@@ -0,0 +1,149 @@
1
+ # RFC-0002:BuildBeat v2 领域模型
2
+
3
+ > 状态:`FINAL`(2026-08-28 项目所有者定稿,`V2-D3`)
4
+ > 日期:2026-08-28
5
+ > 上游:[`V2-PLAN.md`](../V2-PLAN.md) §3–4;报告 B §6 / §13 / §14(经基线裁决修订)
6
+ > 需求来源:[`pilot/metrics.md`](../../pilot/metrics.md) 卡点 1–5;[`pilot/evidence/2026-08-28-m1-runtime-gap.md`](../../pilot/evidence/2026-08-28-m1-runtime-gap.md)
7
+
8
+ ---
9
+
10
+ ## 1. 十三实体
11
+
12
+ | 实体 | 定义 | 权威存放 |
13
+ |---|---|---|
14
+ | **Project** | 项目配置、仓库、Workflow、Policy 和 Adapter 集合 | Git(`.buildbeat/project.yaml`) |
15
+ | **Work** | 一个要达成的用户级结果,生命周期可跨多个 Run | Git(`delivery/work/<id>/work.yaml`) |
16
+ | **Run** | 对一个 Work 的一次具体执行,可失败、重试或被替代 | Runtime(进行中)→ Git(终态压实为 run-record) |
17
+ | **Workflow** | Step、Transition 和默认执行顺序的声明 | Git(`.buildbeat/workflows/`) |
18
+ | **Step** | 一次可调度执行单元(如 plan、build、verify) | Workflow 定义;执行状态在 Runtime |
19
+ | **Worker** | 具有某种能力的逻辑执行者(如 builder、reviewer) | Git(`.buildbeat/workers/`) |
20
+ | **Adapter** | 将 Worker 映射到 Claude / Codex / Shell 或其他执行环境 | Git(`.buildbeat/adapters/`) |
21
+ | **Artifact** | Worker 产生或消费的版本化工件 | Git(`delivery/work/<id>/`) |
22
+ | **Evidence** | 对某个声明进行证明的机器或人工证据 | Git(manifest)+ Runtime(原始日志) |
23
+ | **Policy** | 判断某次转换或动作是否允许的规则 | Git(`.buildbeat/policies/`) |
24
+ | **Decision** | 人类对精确工件或状态转换作出的决定 | Git(`decisions.jsonl`)+ Event |
25
+ | **Event** | Run 中发生的不可变事实记录 | Runtime(events.jsonl);终态摘要压实进 Git |
26
+ | **Workspace** | 某个 Worker 实际工作的隔离目录、分支或 worktree | Runtime 元数据 + git worktree |
27
+
28
+ **Work 与 Run 分离**:一个 Work 可多次 Run,只有一个最终 accepted candidate。M-1 卡点 2/4 的补充要求:**一个 Work 可显式绑定多个 Workspace**(meta 仓 + 代码仓),全部 candidate 由同一 Run 绑定到同一 Decision;MVP 运行时先只支持单仓执行,但领域模型自 day-1 保留多 Workspace 绑定位,防止后续 schema 破坏性变更。
29
+
30
+ ## 2. 状态模型
31
+
32
+ 内核**阶段无关**:只认下列通用状态,`plan/build/review` 等业务阶段由 Workflow 定义。
33
+
34
+ ```text
35
+ Work: OPEN → COMPLETED | CANCELLED
36
+ Run: CREATED → QUEUED → RUNNING → (WAITING_HUMAN | BLOCKED)*
37
+ → SUCCEEDED | FAILED | CANCELLED | SUPERSEDED
38
+ Step: PENDING → READY → RUNNING → SUCCEEDED | FAILED | SKIPPED | CANCELLED
39
+ ```
40
+
41
+ 规则:
42
+
43
+ - Run 终态(SUCCEEDED/FAILED/CANCELLED/SUPERSEDED)默认不可逆,不能被普通事件重新打开(不变量 11);
44
+ - 状态一律由事件派生(reducer),任何手写状态文件不得成为权威来源(不变量 21);
45
+ - 每次状态转换必须对应一个 Event(不变量 5);
46
+ - Worker 永远不能直接修改 Run 状态,其 `suggestedAction` 只是建议(不变量 2)。
47
+
48
+ ## 3. Gate 统一结果(GateResult)
49
+
50
+ ```text
51
+ PASS / RETRY / ROUTE / WAIT_HUMAN / BLOCK / UNVERIFIED
52
+ ```
53
+
54
+ `UNVERIFIED` 永不隐式当作 `PASS`(不变量 7)。语义与转换规则见 [`RFC-0003`](RFC-0003-workflow-policy.md) §3。
55
+
56
+ ## 4. Evidence Contract
57
+
58
+ 字段(报告 B §13 + 基线追加 `grade`):
59
+
60
+ | 字段 | 含义 |
61
+ |---|---|
62
+ | `kind` | test / build / review / screenshot / deployment 等 |
63
+ | `subject` | 所证明的 Artifact 或 candidate |
64
+ | `producer` | Runner / Worker / 外部系统 / 人 |
65
+ | `command` / `exitCode` | 实际执行命令与退出码(适用时) |
66
+ | `startedAt` / `finishedAt` | 执行时间 |
67
+ | `digest` | 证据内容摘要 |
68
+ | `location` | 本地路径或外部权威引用 |
69
+ | `coverage` | 已覆盖和未覆盖范围 |
70
+ | `status` | passed / failed / unverified |
71
+ | `adapter` | 证据来源 Adapter |
72
+ | `grade` | **L0–L4**,v1 证据分级语义原样保留,Policy 可引用最低门槛(如"标准轨合并最低 L3") |
73
+
74
+ 铁律:**Worker 的自然语言总结永远不能单独作为通过证据**;candidate、工作树、测试结果、截图一律由 Runner 回读(M-1 能力矩阵"证据来源"行 PARTIAL 的直接回应:事后人工汇总、截图无 digest 在 v2 结构上不可能)。
75
+
76
+ ## 5. Approval 合同
77
+
78
+ 人批绑定精确对象:
79
+
80
+ ```yaml
81
+ decision: approved | rejected
82
+ transition: review-to-ready-for-merge
83
+ subject:
84
+ candidate: <commit>
85
+ planDigest: sha256:...
86
+ evidenceDigest: sha256:...
87
+ approvedBy: <human>
88
+ approvedAt: <ISO-8601>
89
+ ```
90
+
91
+ 任一受保护输入变化 → `APPROVAL_STALE`,Run 回到 `WAITING_HUMAN`(不变量 3/4/16)。M-1 卡点 3 的追加要求:涉及部署的 Approval subject 还必须能绑定 image digest、rollout plan 与 rollback floor(字段随 `subject` 扩展,additive)。审批动作同时落 `Decision` 事件与 Git 决策记录。
92
+
93
+ ## 6. 存储双平面与终态压实
94
+
95
+ - **Git 平面**:定义类(Workflow/Policy/Worker/standards)、工件类(Intent/Spec/Plan、accepted candidate 引用、Review 报告、Decision、Evidence manifest、Work 摘要)、以及每个终态 Run 的不可变 `run-record.json`。
96
+ - **Runtime 平面**(`.buildbeat/runtime/`,gitignored):events.jsonl(append-only,唯一权威)、state.json(可丢弃重建的加速快照)、锁、会话、临时日志。
97
+
98
+ **终态压实合同**:Run 进入终态后、允许清理 runtime 前,Runner 必须生成 `delivery/work/<id>/runs/<run-id>/run-record.json`,至少固化:事件区间与 digest、起止时间、attempts/budget、终止原因、base/candidate、Evidence manifest digest、Decision/Approval 引用、未验证范围。压实失败不得宣称已归档,也不得清理其 Event Ledger。
99
+
100
+ **硬约束**(不变量 23):删除整个 runtime 目录只损失进行中的 Run 与未承诺保留的原始日志,不损失任何已接受事实或已压实的终态记录;`state.json` 损坏不影响 events.jsonl。
101
+
102
+ ## 7. 核心名词表(消歧)
103
+
104
+ | 名词 | 唯一含义 | 常见误用(禁止) |
105
+ |---|---|---|
106
+ | **candidate** | Workspace 中由 Git 回读固定的候选 commit | ≠ "最新代码";未固定即无 candidate |
107
+ | **accepted** | 经 Decision 明确接受的工件版本 | ≠ "写完了";无 Decision 不算 accepted |
108
+ | **base / baseline** | Run 开始时校验过的基线 commit | ≠ 分支名 |
109
+ | **oracle** | 冻结的验收判据(如 `ACCEPT_CMD`),必须在基线先失败 | ≠ 事后补写的测试 |
110
+ | **evidence** | 满足 §4 合同、由回读产生的记录 | ≠ Worker 的文字总结 |
111
+ | **ledger** | append-only 的 events.jsonl(唯一运行态权威) | ≠ 任何手写日志 |
112
+ | **run-record** | 终态 Run 压实进 Git 的不可变摘要 | ≠ 进行中状态 |
113
+ | **approval** | 绑定 digest 的持久化审批对象 | ≠ 聊天里的"可以" |
114
+ | **stale** | 受保护输入变化导致审批自动失效 | ≠ 超时过期 |
115
+ | **UNVERIFIED** | 无法安全判断,需升级/补证/暂停 | ≠ 默认通过 |
116
+
117
+ ## 8. v1 概念处置表(保留 / 转换 / 删除)
118
+
119
+ 报告 B §17.1 经基线裁决修订后的最终版:
120
+
121
+ | v1 概念 | 处置 | v2 去向 |
122
+ |---|---|---|
123
+ | Evidence-based completion | 保留 | 升级为 Evidence Contract(§4,含 grade L0–L4) |
124
+ | 独立 reviewer(fresh-context、固定 candidate、只读、closure) | 保留 | 升级为标准 Reviewer Worker(M2 迁入) |
125
+ | fail-closed / `UNVERIFIED` | 保留 | 内核化为 GateResult 语义 |
126
+ | Git 版本化事实 | 保留 | 但不承载运行态(双平面,§6) |
127
+ | `AGENTS.md` | 保留 | 项目规则入口;不再承载状态/调度/handoff |
128
+ | `standards/`(STACK/CODE/REVIEW/DESIGN) | 保留 | Policy 输入工件 |
129
+ | 证据分级 L0–L4 | 保留 | Evidence `grade` 字段 |
130
+ | decisions.md | 转换 | Decision 事件 + `decisions.jsonl` + 导出视图 |
131
+ | 固定 Gate1–Gate4 | 转换 | `legacy-four-gates` 迁移预设(非核心) |
132
+ | 产品/全栈/测试三视角 | 转换 | 可选 Worker Preset(非默认) |
133
+ | `pm/changes/` | 转换 | Work + Artifact |
134
+ | `bus-check.sh` | 转换 | 拆为确定性 Evidence Provider + Policy Check |
135
+ | `verify-status.sh` / `drift-check.sh` / `live-status` | 转换 | Evidence Provider(observe 预设,schema 见 RFC-0003 §8) |
136
+ | 三轨(快/标准/重) | 转换 | 三个 Risk Preset(fast/standard/controlled) |
137
+ | `NOW.md` / 当期看板 / `pm/status/{视角}.md` | 删除 | 状态由事件派生;只提供 `*.generated.md` 只读视图 |
138
+ | Skill-only 完整等价 | 拆分 | 协议等价保留、自动化等价取消(RFC-0001 §5) |
139
+ | CLI 不调用 Agent | 删除 | Kernel 确定性、Runner 可调用外部 Agent |
140
+ | `migrate-v1` importer | 删除 | 半天手工 runbook(收尾修正三,装机量 N=1) |
141
+
142
+ ## 9. M0 退出核对(本 RFC 承担的部分)
143
+
144
+ - [x] 十三实体定义与权威存放无歧义:§1
145
+ - [x] 状态模型与派生规则:§2–3
146
+ - [x] Evidence / Approval 合同:§4–5
147
+ - [x] 存储边界(Artifact vs Runtime):§6(报告 B §27 要求 M0 定案的决策点)
148
+ - [x] 核心名词无歧义:§7
149
+ - [x] 旧概念全部标记保留/转换/删除:§8
@@ -0,0 +1,204 @@
1
+ # RFC-0003:BuildBeat v2 Workflow 与 Policy
2
+
3
+ > 状态:`FINAL`(2026-08-28 项目所有者定稿,`V2-D3`;§8 observe/bands schema 已随定稿冻结)
4
+ > 日期:2026-08-28
5
+ > 上游:[`V2-PLAN.md`](../V2-PLAN.md) §3.2–3.7;报告 B §8–11 / WP1.4–1.5 / WP4.3–4.5
6
+ > 需求来源:[`pilot/metrics.md`](../../pilot/metrics.md) 卡点 3/5、故障矩阵 F1–F6;[`pilot/evidence/2026-08-28-m1-runtime-gap.md`](../../pilot/evidence/2026-08-28-m1-runtime-gap.md)
7
+
8
+ ---
9
+
10
+ ## 1. Workflow 文件模型
11
+
12
+ 内核不写死阶段;Workflow 是 Git 中的 YAML 声明(用户配置 YAML,内部以 JSON Schema 校验,schema 文件 M1 WP1.1 落地)。形状 v1:
13
+
14
+ ```yaml
15
+ kind: workflow
16
+ version: 1
17
+ name: software-delivery
18
+ entry: intent
19
+ steps:
20
+ - id: intent
21
+ worker: planner
22
+ - id: spec
23
+ optional: true # 见 §2 spec 规则
24
+ requiredWhen: ui-delivery
25
+ worker: planner
26
+ - id: build
27
+ worker: builder
28
+ - id: verify
29
+ worker: verifier
30
+ # ...
31
+ transitions:
32
+ - from: verify
33
+ on: failed
34
+ to: fix
35
+ - from: review
36
+ on: findings.maxSeverity >= P1
37
+ to: fix
38
+ - from: review
39
+ on: passed
40
+ to: wait-merge # WAITING_HUMAN 终点
41
+ terminal: [wait-merge]
42
+ policies: # 引用 .buildbeat/policies/ 中的定义
43
+ - ref: default
44
+ - ref: protected-actions
45
+ budgets:
46
+ maxAttempts: { build: 4, fix: 4, review-fix: 2 }
47
+ maxSameFailure: 2
48
+ stepTimeout: project-config
49
+ runBudget: project-config
50
+ ```
51
+
52
+ 约束:`entry` 唯一;`terminal` 至少一个;transition 图不得含无出口的非终态环(M1 loop detection);未知字段拒绝加载(fail-closed)。
53
+
54
+ ## 2. 官方预设 `software-delivery`
55
+
56
+ ```text
57
+ Intent → [Spec] → Plan → Build → Verify ⇄ Fix → Independent Review ⇄ Fix → WAIT_HUMAN(merge)
58
+ ```
59
+
60
+ - **Spec 步默认可选;识别到 UI/视觉/交互交付时强制**,且其 Approval subject 必须包含可渲染入口 + 截图 digest(不变量 22;v1 lessons #3 的 v2 化,经 [`V2-PLAN.md`](../V2-PLAN.md) 裁决 #3)。
61
+ - 各步执行规则照报告 B §8.1:Builder 只写授权 Workspace;Fixer 输入必须含失败命令/退出码/日志摘要/candidate/允许范围,不接受泛化的"再检查一下";Reviewer fresh-context、默认只读、不改代码、产出结构化 findings(不变量 9)。
62
+ - MVP 到 merge 决定即暂停,不自动合并(不变量 20)。
63
+
64
+ ## 3. GateResult 语义
65
+
66
+ ```text
67
+ PASS → 进入下一 Step
68
+ RETRY → 重跑当前 Step 或指定修复 Step(受预算约束)
69
+ ROUTE → 转交另一 Worker
70
+ WAIT_HUMAN → 持久化状态并暂停(产生 HUMAN_REQUESTED 事件)
71
+ BLOCK → 确定性终止当前转换
72
+ UNVERIFIED → 无法安全判断;按 Policy 升级、补证或暂停,绝不隐式当 PASS
73
+ ```
74
+
75
+ ## 4. Policy 四类、算子与强制等级
76
+
77
+ ### 4.1 四类
78
+
79
+ | 类型 | 判断 | 例 |
80
+ |---|---|---|
81
+ | 前置(pre) | Step 能否启动 | Plan 已接受、Workspace 干净、依赖工件齐全、预算充足 |
82
+ | 后置(post) | Step 是否真正完成 | 测试通过、Evidence 齐全且达到最低 grade、candidate 已固定 |
83
+ | 转换(transition) | 下一状态 | Verify 失败→Fix;Review P1→Fix;Review 通过→WAIT_HUMAN |
84
+ | Action | Worker 内部危险动作 | merge / push / deploy / publish / migration / 删远端资源 / 改生产配置 |
85
+
86
+ ### 4.2 求值算子 v1(M1 WP1.5 实现集)
87
+
88
+ ```text
89
+ all / any / not
90
+ evidence.exists # 可带 { kind, minGrade }
91
+ artifact.accepted
92
+ attempts.lt
93
+ budget.remaining
94
+ candidate.clean
95
+ human.approved
96
+ finding.maxSeverity
97
+ ```
98
+
99
+ Policy 文件形状:
100
+
101
+ ```yaml
102
+ kind: policy
103
+ version: 1
104
+ name: merge-evidence-floor
105
+ type: transition
106
+ appliesTo: review-to-ready-for-merge
107
+ enforcement: LOCAL_ENFORCED
108
+ rule:
109
+ all:
110
+ - evidence.exists: { kind: test, minGrade: L3 }
111
+ - human.approved: { transition: review-to-ready-for-merge }
112
+ ```
113
+
114
+ ### 4.3 强制三等级
115
+
116
+ | 等级 | 手段 |
117
+ |---|---|
118
+ | `ADVISORY` | prompt / 规则提示 Worker(M-1 边界节确认:提示词禁令只算这一级) |
119
+ | `LOCAL_ENFORCED` | Runner 关卡、Workspace 写路径限制、git hook、工具层 hook(由 gates 配置编译生成,如 Claude Code hooks) |
120
+ | `SERVER_ENFORCED` | 分支保护、CI、部署平台 |
121
+
122
+ `buildbeat doctor` 报告每条 Policy **实际达到**的强制等级,不宣称未强制的规则已被强制(不变量 18)。Protected Actions 的最可靠实现不是提示词,而是不给 Worker 相应凭据与能力(B WP4.4;M-1 能力矩阵"无生产能力"行 PARTIAL 的回应)。
123
+
124
+ ## 5. Approval 与 stale
125
+
126
+ 对象合同见 [`RFC-0002`](RFC-0002-domain-model.md) §5。流程:
127
+
128
+ ```text
129
+ 转换 Policy 判 WAIT_HUMAN
130
+ → HUMAN_REQUESTED 事件(携带 subject digest + findings 摘要 + 风险声明)
131
+ → 人 approve/reject(CLI 展示当前状态、精确对象、candidate、Evidence、风险、批准后动作)
132
+ → DECISION_RECORDED 事件 + Git 决策记录
133
+ → 受保护输入任一变化 → APPROVAL_STALE 事件 → Run 回 WAITING_HUMAN
134
+ ```
135
+
136
+ 秒批率进 metrics(防止人批退化成盖章)。F6 的关闭以本节 + [`SPEC-0001`](SPEC-0001-events-v1.md) 事件为准,验收在 M2。
137
+
138
+ ## 6. Loop 终止条件与 MVP 默认值
139
+
140
+ 任一条件触发即停(报告 B §10 全表采纳):maxAttempts、连续两次相同失败指纹(step + command + exitCode + 错误摘要 + diff digest)、candidate 无实质变化(无进展)、越 Scope 即 `BLOCK`、预算/超时、Workspace 不干净或锁冲突、证据不完整记 `UNVERIFIED`、Adapter 不支持必要强制能力则降级或阻断、人拒绝即 `CANCELLED`。
141
+
142
+ MVP 默认值:
143
+
144
+ ```text
145
+ build/fix 最大尝试:4
146
+ review 修复轮次:2
147
+ 连续相同失败:2
148
+ 单 Step 超时 / 总 Run 预算:项目配置
149
+ ```
150
+
151
+ ## 7. Risk Preset
152
+
153
+ 三个官方预设 + 一个迁移预设(都是 Preset,不是核心固定 Gate):
154
+
155
+ | Preset | 人批点 |
156
+ |---|---|
157
+ | `fast` | 仅 Merge |
158
+ | `standard` | Plan、Merge |
159
+ | `controlled` | Intent、Plan、Merge、Release |
160
+ | `legacy-four-gates` | v1 四 Gate 完整形态(迁移用) |
161
+
162
+ ## 8. observe 预设与 bands schema(随本 RFC 冻结,实现 M5)
163
+
164
+ 裁决 #6:**接口现在冻结,实现推后**。冻结内容为以下 schema 形状与语义;M5 前不实现,但 M1 起任何内核设计不得与之冲突(尤其:Evidence Provider 产出的记录必须能进入同一 Evidence Contract 与事件台账)。
165
+
166
+ ```yaml
167
+ kind: workflow
168
+ version: 1
169
+ name: observe
170
+ providers: # v1 探测器重组为 Evidence Provider
171
+ - id: drift-check
172
+ command: <项目配置>
173
+ schedule: <cron 或 interval>
174
+ evidence: { kind: drift, subject: <deploy-unit> }
175
+ - id: live-status
176
+ command: <项目配置>
177
+ schedule: <cron 或 interval>
178
+ evidence: { kind: runtime-health, subject: <deploy-unit> }
179
+ bands: # 分层响应;层级固定为三层,阈值可配
180
+ - level: log # 层1:只记录事件
181
+ when: <severity 表达式>
182
+ - level: diagnose # 层2:触发只读诊断 Worker
183
+ when: <severity 表达式>
184
+ - level: intent # 层3:生成 Intent 草稿入队(不自动执行)
185
+ when: <severity 表达式>
186
+ triage: # 人分诊
187
+ actions: [fix_now, schedule, dismiss]
188
+ dismissFeedback: bands # dismiss 回调 bands 阈值
189
+ ```
190
+
191
+ 语义冻结点:
192
+
193
+ 1. Provider 输出必须满足 Evidence Contract(含 `status` / `coverage`;采不到即 `UNVERIFIED`);
194
+ 2. bands 只有 log / diagnose / intent 三层,`intent` 层只产生**草稿**入队,接受后才进入 `software-delivery`,闭环成立;
195
+ 3. dismiss 必须回调 bands 阈值(防止告警疲劳单向累积);
196
+ 4. 以上字段 additive-only 演进,破坏性修改需新 `version`。
197
+
198
+ ## 9. M0 退出核对(本 RFC 承担的部分)
199
+
200
+ - [x] GateResult / 转换顺序 / retry / route / block / unverified:§1、§3、§6
201
+ - [x] Human Approval 与 stale:§5
202
+ - [x] Policy 四类 + 算子 + 强制等级:§4
203
+ - [x] Risk Preset 与 legacy 迁移预设:§7
204
+ - [x] observe 与 bands schema 冻结:§8
@@ -0,0 +1,98 @@
1
+ # SPEC-0001:Event Ledger 格式 v1(冻结)
2
+
3
+ > 状态:**FROZEN**(2026-08-28 项目所有者定稿,`V2-D3`;[`V2-PLAN.md`](../V2-PLAN.md) 裁决 #8:格式 day-1 冻结,此后 additive-only)
4
+ > 日期:2026-08-28
5
+ > 冻结范围:**信封字段、通用规则、损坏处理、reducer 合同、初始事件类型注册表的语义**。文件摆放位置、快照格式、CLI 展示均为非规范内容,可变。
6
+ > 演进规则:一切修改 **additive-only**(新增可选字段、新增事件类型);破坏性变更必须升 `v` 并提供旧版读取器。
7
+ > 需求来源:[`pilot/metrics.md`](../../pilot/metrics.md) 卡点 1(无统一 ledger)、卡点 5(无 Run 登记);F5/F6 见 [`pilot/evidence/2026-08-28-m1-runtime-gap.md`](../../pilot/evidence/2026-08-28-m1-runtime-gap.md)
8
+
9
+ ---
10
+
11
+ ## 1. 载体
12
+
13
+ - 每个 Run 一个 ledger:append-only JSONL,UTF-8,每行一个 JSON 对象,`\n` 结尾;
14
+ - 建议路径 `.buildbeat/runtime/runs/<run-id>/events.jsonl`(非规范);
15
+ - 只允许追加,永不改写或删除已有行;追加必须原子(单次 `O_APPEND` 写入完整行);
16
+ - `state.json` 只是加速快照:可丢弃,必须能从 ledger 完整重建(不变量 12/13)。
17
+
18
+ ## 2. 信封(frozen)
19
+
20
+ ```json
21
+ {
22
+ "v": 1,
23
+ "seq": 42,
24
+ "ts": "2026-08-28T04:12:33.201Z",
25
+ "run": "RUN-001",
26
+ "work": "WORK-001",
27
+ "type": "STEP_FINISHED",
28
+ "actor": { "kind": "kernel", "id": "orchestrator" },
29
+ "data": { },
30
+ "prev": "sha256:…",
31
+ "digest": "sha256:…"
32
+ }
33
+ ```
34
+
35
+ | 字段 | 必填 | 规则 |
36
+ |---|---|---|
37
+ | `v` | 是 | 信封版本,本规格恒为 `1`;读取器遇到未知 `v` 必须拒绝,不得猜测 |
38
+ | `seq` | 是 | 每个 Run ledger 内单调递增整数,自 `1` 起,**无间隙** |
39
+ | `ts` | 是 | ISO-8601 UTC,毫秒精度 |
40
+ | `run` / `work` | 是 | 所属 Run / Work ID |
41
+ | `type` | 是 | UPPER_SNAKE,取自 §4 注册表(注册表 additive 扩展) |
42
+ | `actor` | 是 | `kind ∈ {kernel, worker, human, adapter, provider}` + `id` |
43
+ | `data` | 是 | 类型专属载荷(§4);载荷演进 additive-only,破坏性语义变化必须用新 `type` |
44
+ | `prev` | 是 | 前一行事件的 `digest`;首行取 `"sha256:GENESIS"` |
45
+ | `digest` | 是 | 本行除 `digest` 字段外按规范化 JSON(键排序、无空白)序列化后的 sha256 |
46
+
47
+ 未知**信封**字段:读取器必须忽略(向前兼容);未知 `type`:reducer 必须原样保留并跳过,不得报错丢弃(后写的读取器可能认识)。
48
+
49
+ ## 3. 损坏处理(frozen)
50
+
51
+ 1. 逐行校验 `digest` 与 `prev` 链;
52
+ 2. 首个校验失败行即截断点:其后所有行视为不可信,读取器必须显式报告"ledger 在 seq=N 后损坏",不得静默丢弃;
53
+ 3. 截断后的恢复决策升级给人(`WAIT_HUMAN` 语义),内核不得猜测丢失区间;
54
+ 4. 快照与 ledger 冲突时,**ledger 永远是权威**(不变量 21 的运行态版本)。
55
+
56
+ ## 4. 初始事件类型注册表 v1
57
+
58
+ 语义冻结;`data` 列出的字段为该类型的必填最小集,可 additive 扩展。
59
+
60
+ | type | actor | data 最小集 | 语义 |
61
+ |---|---|---|---|
62
+ | `RUN_CREATED` | kernel | `workflowRef, workflowDigest, base, riskPreset` | Run 登记(卡点 5 的回应:没有本事件的工作不得计入 v2 闭环) |
63
+ | `RUN_STARTED` | kernel | —— | 进入 RUNNING |
64
+ | `WORKSPACE_BOUND` | kernel | `workspaceId, repo, branch, worktreePath, base` | 一个 Run 可多次(多仓绑定,卡点 2/4) |
65
+ | `STEP_STARTED` | kernel | `step, attempt, worker, adapter, workspaceId` | Step 开跑 |
66
+ | `STEP_FINISHED` | kernel | `step, attempt, status ∈ {succeeded,failed,blocked,invalid-output,timeout,crashed}, exitCode?` | Adapter 异常退出也必须落此事件(不变量 15) |
67
+ | `CANDIDATE_PINNED` | kernel | `workspaceId, base, candidate` | candidate 由 Git 回读后固定 |
68
+ | `EVIDENCE_RECORDED` | kernel/provider | `evidenceRef, kind, subject, digest, status, grade` | 指向满足 Evidence Contract 的记录 |
69
+ | `POLICY_EVALUATED` | kernel | `policy, phase ∈ {pre,post,transition,action}, result ∈ GateResult, enforcement, reason` | 每次 Policy 裁决可解释 |
70
+ | `TRANSITION` | kernel | `from, to, cause` | 每次状态转换一条(不变量 5) |
71
+ | `FAILURE_FINGERPRINT` | kernel | `step, command, exitCode, errorDigest, diffDigest` | 无进展/相同失败检测的输入 |
72
+ | `BUDGET_CONSUMED` | kernel | `kind ∈ {attempts,tokens,cost,time}, amount, remaining` | 预算台账(卡点 1:token/费用不再 `UNVERIFIED`) |
73
+ | `HUMAN_REQUESTED` | kernel | `transition, subject{candidate,planDigest,evidenceDigest}, reasons` | 进入 WAITING_HUMAN |
74
+ | `DECISION_RECORDED` | human | `decision ∈ {approved,rejected}, transition, subject, decisionRef` | 同步落 Git 决策记录 |
75
+ | `APPROVAL_STALE` | kernel | `approvalRef, changed ⊆ {candidate,plan,evidence}` | F6 的机器化 |
76
+ | `CHECKPOINT` | kernel | `resumePoint{step,attempt}, workspaceStates[]` | F5 的机器化:恢复只允许从最近 CHECKPOINT 或安全推导点继续 |
77
+ | `RUN_INTERRUPTED` | kernel | `cause` | 尽力而为;崩溃时允许缺失,恢复逻辑不得依赖其存在 |
78
+ | `RUN_TERMINAL` | kernel | `status ∈ {SUCCEEDED,FAILED,CANCELLED,SUPERSEDED}, reason` | 终态默认不可逆(不变量 11) |
79
+ | `RUN_COMPACTED` | kernel | `runRecordRef, runRecordDigest` | 终态压实完成;无此事件不得清理 ledger |
80
+
81
+ ## 5. Reducer 合同(frozen)
82
+
83
+ - 确定性:同一 ledger 任意次 replay 必须得到相同状态(Run/Step 状态、attempts、budgets、当前 candidate、待批请求、evidence coverage);
84
+ - 非法转换在 append 前拒绝(写侧校验),reducer 遇到历史非法序列必须报告而非修补;
85
+ - 恢复流程:读 ledger → 校验链 → replay → 定位最近 `CHECKPOINT` / 安全推导点 → 继续或 `WAIT_HUMAN`。不存在"读会话记忆"这一步(F5 = `RECOVERY_MISSING` 的结构性关闭)。
86
+
87
+ ## 6. 示例(一次 Verify 失败进 Fix)
88
+
89
+ ```json
90
+ {"v":1,"seq":7,"ts":"2026-08-28T04:10:01.000Z","run":"RUN-001","work":"WORK-001","type":"STEP_FINISHED","actor":{"kind":"kernel","id":"orchestrator"},"data":{"step":"verify","attempt":1,"status":"failed","exitCode":1},"prev":"sha256:aa…","digest":"sha256:bb…"}
91
+ {"v":1,"seq":8,"ts":"2026-08-28T04:10:01.050Z","run":"RUN-001","work":"WORK-001","type":"FAILURE_FINGERPRINT","actor":{"kind":"kernel","id":"orchestrator"},"data":{"step":"verify","command":"npm test","exitCode":1,"errorDigest":"sha256:cc…","diffDigest":"sha256:dd…"},"prev":"sha256:bb…","digest":"sha256:ee…"}
92
+ {"v":1,"seq":9,"ts":"2026-08-28T04:10:01.100Z","run":"RUN-001","work":"WORK-001","type":"POLICY_EVALUATED","actor":{"kind":"kernel","id":"orchestrator"},"data":{"policy":"default.verify-failed","phase":"transition","result":"RETRY","enforcement":"LOCAL_ENFORCED","reason":"verify failed, attempts 1/4"},"prev":"sha256:ee…","digest":"sha256:ff…"}
93
+ {"v":1,"seq":10,"ts":"2026-08-28T04:10:01.120Z","run":"RUN-001","work":"WORK-001","type":"TRANSITION","actor":{"kind":"kernel","id":"orchestrator"},"data":{"from":"verify","to":"fix","cause":"policy:default.verify-failed"},"prev":"sha256:ff…","digest":"sha256:gg…"}
94
+ ```
95
+
96
+ ---
97
+
98
+ _M1 WP1.2 按本规格实现 Event Store;`event.schema.json`(WP1.1)以本规格为唯一来源。任何实现与本规格冲突时,先改实现;确需改规格,走 additive 或升 `v`。_