@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,92 @@
1
+ # 快速开始(5 分钟)
2
+
3
+ 目标:在一个真实 Git 仓库里,让 v2 Runner 驱动 Build→Verify→Review 自动跑完,**停在合并决定**,由你带着证据拍板。
4
+
5
+ ## 0. 安装
6
+
7
+ ```bash
8
+ npm install -g @haiyangbg/buildbeat@next
9
+ ```
10
+
11
+ Beta 期 `latest` 仍指向 v1;v2 CLI 是独立入口 `buildbeat-v2`(源码检出等价于 `node src/v2/cli/run.js`)。要求 Node ≥ 20,零运行时依赖。
12
+
13
+ ## 1. 准备工作项(Git 面)
14
+
15
+ 在目标仓库建工作项目录并写下意图与计划(它们的 digest 会绑进批准对象):
16
+
17
+ ```bash
18
+ mkdir -p delivery/work/WORK-DEMO-1
19
+ printf "# 意图\n修复 X。\n" > delivery/work/WORK-DEMO-1/intent.md
20
+ printf "# 计划\n1. 改 A;2. 测 B。\n" > delivery/work/WORK-DEMO-1/plan.md
21
+ ```
22
+
23
+ ## 2. 写 run 配置
24
+
25
+ `delivery/work/WORK-DEMO-1/run-config.yaml`(路径相对本文件解析;YAML 为严格子集,无行内 `{}`/`[]`、无锚点):
26
+
27
+ ```yaml
28
+ repo: ../../..
29
+ work: WORK-DEMO-1
30
+ run: RUN-DEMO-1
31
+ workflow: <buildbeat安装目录>/src/v2/presets/software-delivery.yaml
32
+ riskPreset: standard
33
+ entry: build
34
+ allowedPaths:
35
+ - src
36
+ - tests
37
+ workers:
38
+ builder:
39
+ command: codex
40
+ args:
41
+ - exec
42
+ - -s
43
+ - workspace-write
44
+ - 按 delivery/work/WORK-DEMO-1/plan.md 实施,改动后 git commit
45
+ verifier:
46
+ command: bash
47
+ args:
48
+ - -lc
49
+ - npm test
50
+ reviewer:
51
+ command: codex
52
+ args:
53
+ - exec
54
+ - -s
55
+ - read-only
56
+ - 只读审查本分支相对 base 的改动,把 JSON 信封写入 $BUILDBEAT_OUTPUT
57
+ ```
58
+
59
+ Worker 是任意 CLI(codex / claude / 脚本),见 [Adapter 指南](04-adapter-guide.md) 与 [Worker 合同](05-worker-contract.md)。
60
+
61
+ ## 3. 起 Run,停在人批
62
+
63
+ ```bash
64
+ buildbeat-v2 start --config delivery/work/WORK-DEMO-1/run-config.yaml
65
+ ```
66
+
67
+ Runner 会:开隔离 worktree(分支 `run/RUN-DEMO-1`,push 已被物理封禁)→ builder 产出提交并固定 candidate → verifier 真实跑测试(退出码回读为证据)→ reviewer 只读出结构化 findings → 到达 `WAITING_HUMAN`。`standard` 预设下 build 前还要求 plan 是已接受工件:
68
+
69
+ ```bash
70
+ buildbeat-v2 accept --repo . --work WORK-DEMO-1 --artifact plan --by <你的名字>
71
+ ```
72
+
73
+ ## 4. 看证据、拍板
74
+
75
+ ```bash
76
+ buildbeat-v2 inbox --repo .
77
+ buildbeat-v2 status --repo . --run RUN-DEMO-1
78
+ buildbeat-v2 approve --repo . --run RUN-DEMO-1 --transition enter-wait-merge --by <你的名字> --config delivery/work/WORK-DEMO-1/run-config.yaml
79
+ ```
80
+
81
+ 批准即 merge-ready;合并/推送/发布永远是你的动作,Runner 不代劳。被 findings 阻断时会自动路由 fix→verify 重走,超预算或指纹重复则停下交还给你([Approval 指南](07-approval-guide.md)、[Recovery](10-recovery.md))。
82
+
83
+ ## 5. observe:让系统盯生产(v0)
84
+
85
+ ```bash
86
+ cp <buildbeat>/src/v2/presets/observe.yaml .buildbeat/observe.yaml # 改成项目真实探针
87
+ buildbeat-v2 observe run --config .buildbeat/observe.yaml # 一次=一个周期;周期化交给 cron
88
+ buildbeat-v2 observe status --repo .
89
+ buildbeat-v2 observe triage --repo . --intent delivery/observe/intents/INTENT-<fp>.md --action fix_now --by <你>
90
+ ```
91
+
92
+ 探针失败/采不到 → 证据 `failed`/`unverified` → bands 分层(记录→只读诊断→Intent 草稿入队)。草稿**绝不自动执行**;`dismiss` 会回调阈值,同指纹在严重度升级前不再打扰。详见 [Evidence 指南](06-evidence-guide.md) §observe。
@@ -0,0 +1,42 @@
1
+ # Workflow 编写指南
2
+
3
+ 权威:[`RFC-0003 §2`](../RFC-0003-workflow-policy.md);实现:`src/v2/engine/workflow.js`。官方预设 [`software-delivery.yaml`](../../../src/v2/presets/software-delivery.yaml) 是最好的范本。
4
+
5
+ ## 形状
6
+
7
+ ```yaml
8
+ kind: workflow
9
+ version: 1
10
+ name: software-delivery
11
+ entry: intent
12
+ steps:
13
+ - id: build
14
+ worker: builder
15
+ - id: review
16
+ worker: reviewer
17
+ readonly: true
18
+ - id: wait-merge
19
+ transitions:
20
+ - from: verify
21
+ on: failed
22
+ to: fix
23
+ terminal:
24
+ - wait-merge
25
+ ```
26
+
27
+ ## 规则(加载期 fail-closed 校验)
28
+
29
+ 1. **步序即默认边**:`steps` 的书写顺序定义 happy path——每步 `succeeded` 默认走向下一步;不想进默认链的步(如 `fix`)放在末尾、只经显式转换进入。
30
+ 2. **显式转换**:`transitions` 的 `on` 取 worker 结果(`succeeded` / `failed` / `findings-blocking`);显式边优先于默认边。
31
+ 3. **`readonly: true`**:该步 Worker 的任何工作树写入都会让步骤按失败处理并落账——Reviewer 不改代码是不变量 9,靠 Runner 的前后快照比对强制,不靠 prompt 自觉。
32
+ 4. **`optional` / `requiredWhen`**:可选步默认跳过;`requiredWhen: ui-delivery` 在 UI 交付时强制(配合 [ui-render-gate](03-policy-guide.md) 与不变量 22)。
33
+ 5. **`terminal`**:列出的步是出口。加载器做**无出口环检测**——verify⇄fix 这类环必须存在能到 terminal 的路径,否则拒绝加载。
34
+ 6. **无 worker 的步**(如 `wait-merge`)是纯等待/决定点,Runner 在这里产生 `HUMAN_REQUESTED` 或按 `stopAt` 停下。
35
+
36
+ ## 与 run 配置的关系
37
+
38
+ run 配置里 `entry` 可覆盖 workflow 的 `entry`(例如从 `build` 起步、跳过 intent/plan 步——digest 仍会绑进批准对象);`stopAt` 指定停点。workflow 文件整体做 sha256 → `RUN_CREATED.workflowDigest`,事后可证明当时跑的是哪份流程。
39
+
40
+ ## 修改纪律
41
+
42
+ 预设是产品的一部分:改 `software-delivery.yaml` 前先想清是不是项目差异——项目差异用自己的 workflow 文件(run 配置 `workflow:` 指过去),不改官方预设。schema additive-only,破坏性改法升 `version`。
@@ -0,0 +1,53 @@
1
+ # Policy 指南
2
+
3
+ 权威:[`RFC-0003 §4`](../RFC-0003-workflow-policy.md);实现:`src/v2/policy/policy.js`。范本:risk 预设内嵌策略(`src/v2/presets/risk/*.yaml`)与 [`ui-render-gate.yaml`](../../../src/v2/presets/policies/ui-render-gate.yaml)。
4
+
5
+ ## 一条 Policy 的形状
6
+
7
+ ```yaml
8
+ kind: policy
9
+ version: 1
10
+ name: merge-evidence-floor
11
+ type: transition # pre | post | transition | action
12
+ appliesTo: enter-wait-merge # pre/post 填步 id;transition 填 enter-<步>
13
+ enforcement: LOCAL_ENFORCED # ADVISORY | LOCAL_ENFORCED | SERVER_ENFORCED
14
+ rule:
15
+ all:
16
+ - evidence.exists:
17
+ kind: command
18
+ minGrade: L2
19
+ - finding.maxSeverity:
20
+ atMost: P2
21
+ ```
22
+
23
+ ## 8 个算子与三值逻辑
24
+
25
+ | 算子 | 含义 |
26
+ |---|---|
27
+ | `all` / `any` / `not` | 组合子 |
28
+ | `evidence.exists: {kind, minGrade}` | 存在指定种类、等级达标的证据 |
29
+ | `artifact.accepted: {artifact}` | 工件(plan/intent/spec)已被 digest 绑定地接受 |
30
+ | `attempts.lt: {step, max}` | 某步尝试次数未超上限 |
31
+ | `budget.remaining: {kind}` | 预算仍有余量 |
32
+ | `candidate.clean` | 存在已固定且干净的 candidate |
33
+ | `human.approved: {transition}` | 存在未 stale 的对应批准 |
34
+ | `finding.maxSeverity: {atMost}` | 未解决 findings 严重度不超过阈值 |
35
+
36
+ 求值是**三值**的:`PASS` / `FAIL` / `UNVERIFIED`。取不到数据(证据缺失、无 candidate)永远是 `UNVERIFIED` 而不是通过——`UNVERIFIED` 在任何门上都不会被当作 `PASS`(GateResult 六值见 RFC-0003 §3.3)。
37
+
38
+ **候选作用域**:待批对象带 candidate 时,`evidence.exists` 与 `finding.maxSeverity` 只统计该 candidate 的证据——被新一轮修复取代的旧 review findings 不会挡住已修好的候选(2026-08-28 真实事故的永久回归在 `tests/` 与 `evals/`)。
39
+
40
+ ## 四类挂点
41
+
42
+ - `pre`:步开始前(如 `plan-accepted` 挡在 build 前);
43
+ - `post`:步结束后;
44
+ - `transition`:状态转换瞬间(如 merge 决定盖章那一刻 re-check——批准命令会在盖章前重读实况,门不过则拒绝落章);
45
+ - `action`:保护动作前(配合 [安全边界](09-security-boundaries.md))。
46
+
47
+ ## 强制等级
48
+
49
+ `ADVISORY` 只提示 Worker;`LOCAL_ENFORCED` 由 Runner/Workspace 物理执行(本地能保证的都用它);`SERVER_ENFORCED` 声明该门在服务端(分支保护/CI/部署平台)——Runner 落账但不能替服务端保证。诚实标注:本地挡不住的不要标 LOCAL。
50
+
51
+ ## 接入
52
+
53
+ run 配置 `policies:` 列表引用文件路径;risk 预设(`fast`/`standard`/`controlled`/`legacy-four-gates`)自带一组策略与停点,`riskPreset:` 一行即可启用,再叠加项目自定义策略。
@@ -0,0 +1,45 @@
1
+ # Adapter 指南
2
+
3
+ 权威:[`RFC-0002 §Adapter`](../RFC-0002-domain-model.md);实现:`src/v2/adapters/shell.js`(生产用)、`src/v2/adapters/mock.js`(测试用)。裁决 #5:厂商中立——不绑定任何 Agent 供应商。
4
+
5
+ ## Shell Adapter:一切 CLI 皆 Worker
6
+
7
+ run 配置的 `workers.<角色>` 就是一份 Shell Adapter 配置:
8
+
9
+ ```yaml
10
+ workers:
11
+ builder:
12
+ command: codex
13
+ args:
14
+ - exec
15
+ - -s
16
+ - workspace-write
17
+ - <prompt 或脚本参数>
18
+ timeoutMs: 900000
19
+ ```
20
+
21
+ - 执行目录 = 该步的隔离 worktree(不是主检出);
22
+ - `args` 支持模板:`{workspace}` `{step}` `{worker}`;
23
+ - 已实证的 Worker:`codex exec`(M4 四个真实试点)、任意 bash 脚本;`claude -p` 同构可换。
24
+
25
+ ## env 白名单(默认,能力移除的一部分)
26
+
27
+ Worker 子进程默认**只**拿到 `PATH HOME LANG LC_ALL TMPDIR TERM USER SHELL`——宿主 shell 里的云凭据、token 环境变量物理到不了 Worker。`inheritEnv: true` 可显式打开(doctor 会把它标为仅 ADVISORY 隔离);单个变量可用 `env:` 白名单式注入。
28
+
29
+ ## 输入输出
30
+
31
+ - 输入:`BUILDBEAT_INPUT` 环境变量携带 JSON(step/worker/candidate/失败摘要等,按角色见 [Worker 合同](05-worker-contract.md));
32
+ - 输出:需要结构化结果的步(reviewer 等)从 `BUILDBEAT_OUTPUT` 指向的路径写 JSON 信封;codex 用 `-o` 落最后消息再由包装脚本转写也可以;
33
+ - 纯命令步(verifier 跑测试)不需要信封——退出码与日志由 Runner 回读为证据。
34
+
35
+ ## 结果语义
36
+
37
+ Adapter 只报告事实:exitCode / signal / timedOut / spawnError / stdout / stderr / 起止时间。写事件的是 Orchestrator,Adapter 永不触碰内核状态。超时、崩溃、无法启动分别落 `timeout` / `crashed` / 失败路径,都有端到端测试(`tests/v2-invariants.test.js`)。
38
+
39
+ ## Mock Adapter
40
+
41
+ `createMockAdapter(script)`:按步给定 `"succeed"`/`"fail"` 或 `{behavior, envelope}` 序列,用于测试与 evals;行为卡见 [`evals/`](../../../evals/README.md)。
42
+
43
+ ## 何时写专用 Adapter
44
+
45
+ 只有当 Shell 表达不了(需要流式交互、会话保持)才写专用 Adapter;按 M3 裁决,先用 Shell 接一切,等真实试点证明不够再说。
@@ -0,0 +1,37 @@
1
+ # Worker 合同
2
+
3
+ 权威:[`RFC-0003 §5`](../RFC-0003-workflow-policy.md)(报告 B §8.1)。Worker 是可替换的执行者;合同的另一半永远由 Runner 物理保证,不依赖 Worker 自觉。
4
+
5
+ ## 通用合同
6
+
7
+ - **输入**:环境变量 `BUILDBEAT_INPUT`(JSON):step、worker、run/work id、candidate(如已固定)、允许范围;
8
+ - **输出**:需要结构化结论的步把 JSON 信封写到 `BUILDBEAT_OUTPUT` 指向的文件:
9
+
10
+ ```json
11
+ {"status": "succeeded", "findings": []}
12
+ ```
13
+
14
+ - `status`: `succeeded` | `failed` | `blocked`;
15
+ - `findings[]`: `{severity: "P1|P2|P3", title, detail?}`——`P1/P2` 会触发 `findings-blocking` 路由进 fix;
16
+ - 信封外多裹一层 markdown 代码栏(```json … ```)可容忍,其余任何格式=`invalid-output`,按失败处理;
17
+ - **Worker 说的不算证据**:Runner 只相信自己回读的事实(退出码、日志、git 状态);见 [Evidence 指南](06-evidence-guide.md)。
18
+
19
+ ## 各角色纪律
20
+
21
+ | 角色 | 写权限 | 合同要点 |
22
+ |---|---|---|
23
+ | planner | 工作项目录 | 产出 intent/plan 草稿;接受与否是人的 digest 绑定动作 |
24
+ | builder | 隔离 worktree(`allowedPaths` 内) | 改动必须落成 git 提交;越界写入 = Run BLOCK,不固定 candidate |
25
+ | verifier | 只跑命令 | 跑真实测试;退出码就是结论,不写信封 |
26
+ | fixer | 同 builder | 输入必含失败命令/退出码/日志摘要/candidate/允许范围;不接受泛化的"再检查一下" |
27
+ | reviewer | **无**(`readonly: true`) | fresh-context 只读;产出结构化 findings;任何工作树写入由快照比对捕获并按失败落账(不变量 9) |
28
+
29
+ ## 失败与预算
30
+
31
+ 同一步失败会带着**失败指纹**(命令+退出码+错误摘要+diff digest)重试;连续同指纹或超 `maxAttemptsPerStep`/预算即停,转人工。Worker 不需要(也不能)自己决定"再试一次"。
32
+
33
+ ## 实践提示
34
+
35
+ - prompt 里明确引用 `delivery/work/<id>/plan.md`,让 Worker 的目标与被批准的 digest 是同一份文件;
36
+ - builder 的提交动作可以由包装脚本机械执行(M4 试点即如此:codex 只改文件,`git commit` 在包装层);
37
+ - reviewer 的 prompt 要求"只输出信封 JSON",并用 `-o`/重定向落到 `$BUILDBEAT_OUTPUT`。
@@ -0,0 +1,38 @@
1
+ # Evidence 指南
2
+
3
+ 权威:[`RFC-0002 §4`](../RFC-0002-domain-model.md);实现:`src/v2/evidence/collector.js`、`src/v2/observe/`。核心:**证据是 Runner 回读到的事实,不是 Worker 的自述**。
4
+
5
+ ## 证据记录的形状
6
+
7
+ 每条证据进事件台账(`EVIDENCE_RECORDED`)并含:`kind`(command/screenshot/drift/runtime-health/diagnosis/…)、`subject`(候选 SHA 或部署单元)、`digest`(原始日志的 sha256,runtime 可删、digest 永续)、`status`、`grade`、producer、起止时间。原始日志落 runtime 面 `.buildbeat/runtime/`;台账与压实记录只引用 digest。
8
+
9
+ ## 状态:三值,fail-closed
10
+
11
+ | status | 含义 |
12
+ |---|---|
13
+ | `passed` | 命令零退出、未超时、未被信号杀死 |
14
+ | `failed` | 非零退出 / 超时 / 信号 |
15
+ | `unverified` | **采不到**:无法启动、数据缺失。永远不是"没问题" |
16
+
17
+ `unverified` 不会被任何门当作通过([Policy 指南](03-policy-guide.md) 三值逻辑)。这是 v1 fail-closed 文化的内核化。
18
+
19
+ ## 等级 L0–L4
20
+
21
+ `L0` 自述 → `L1` 静态检查 → `L2` 本地真实执行(命令回读默认档)→ `L3` 部署后验证 → `L4` 生产实测。门用 `minGrade` 提要求(如 merge 底线 L2;生产切换收口要 L4)。
22
+
23
+ ## 候选作用域
24
+
25
+ 证据以 `subject` 绑定候选:merge 门只统计当前 candidate 的证据,旧候选/旧 review 轮次的记录不混入(真实事故回归,见 evals `fix-loop`)。
26
+
27
+ ## observe:把生产也纳入证据面(v0)
28
+
29
+ [`RFC-0003 §8`](../RFC-0003-workflow-policy.md) 冻结、M5 实现(`src/v2/observe/`):
30
+
31
+ - **Provider**(drift-check / live-status 等项目探针)按同一 Evidence Contract 产出记录,进独立 observe 台账(同一链校验机制,`.buildbeat/runtime/observe/`);探针挂了=`unverified`(severity 默认 warn),绝不静默;
32
+ - **bands 三层**(阈值可配,层级固定):`log` 只落账 → `diagnose` 触发只读诊断命令、产出 `diagnosis` 证据 → `intent` 把 Intent **草稿**写进 Git 面 `delivery/observe/intents/`(绝不自动执行);
33
+ - **人分诊**:`observe triage --action fix_now|schedule|dismiss`。`fix_now` 之后由人把它带进 software-delivery Run,闭环成立;`dismiss` 回调 bands——同指纹在严重度升级前不再入队(防告警疲劳);分诊终态写在草稿文件里,删 runtime 不丢(不变量 23);
34
+ - **调度 v0 边界**:`schedule` 字段解析落账但不内置调度器;周期运行=宿主 cron 反复调 `observe run`。
35
+
36
+ ## 完整率
37
+
38
+ `buildbeat-v2 metrics` 输出证据完整率(有证据的步/应有证据的步);M4/M5 退出线 ≥95%,试点实测 100%。
@@ -0,0 +1,34 @@
1
+ # Human Approval 指南
2
+
3
+ 权威:[`RFC-0003 §5`](../RFC-0003-workflow-policy.md);实现:`src/v2/runtime/decisions.js`。原则:**人批的是一个 digest 绑定的对象,不是一句"可以了"**。
4
+
5
+ ## 批准绑定什么
6
+
7
+ 一次批准 = `transition + candidate + planDigest + evidenceDigest` 四元组。其中任何一项事后变化,批准自动 `APPROVAL_STALE`,Run 回到 `WAITING_HUMAN`——旧章不能盖新对象(stale 复用 0 是退出指标,试点实测 0)。
8
+
9
+ ## 日常操作
10
+
11
+ ```bash
12
+ buildbeat-v2 inbox --repo . # 所有等人的 Run:transition、candidate、digest、理由
13
+ buildbeat-v2 status --repo . --run RUN-X # 单个 Run 的完整派生视图(步、证据、findings)
14
+ buildbeat-v2 approve --repo . --run RUN-X --transition enter-wait-merge --by <名字> --config <run-config>
15
+ buildbeat-v2 reject --repo . --run RUN-X --reason "<为什么>" --by <名字>
16
+ buildbeat-v2 accept --repo . --work WORK-X --artifact plan --by <名字> # 工件接受(digest 绑定)
17
+ ```
18
+
19
+ 决定落 Git 面 `delivery/work/<id>/decisions.jsonl`,事件台账同步记 `DECISION_RECORDED`。
20
+
21
+ ## approve 的安全语义(都有测试)
22
+
23
+ 1. **transition 必须匹配**当前待批项;
24
+ 2. **盖章前重读实况**:待批快照与实况不一致(候选又动了、计划改了)→ 拒绝并要求刷新,不落章;
25
+ 3. **transition 门在盖章瞬间 re-check**:merge-evidence-floor / ui-render-gate 等此刻不 PASS → 拒绝;
26
+ 4. 终局决定(final-decision 类待批)批准即 `RUN_TERMINAL SUCCEEDED` + 压实 run-record 进 Git 面。
27
+
28
+ ## 批准 ≠ 执行
29
+
30
+ merge 批准只表示 **merge-ready**:真正的合并、push、发布是你在 Runner 之外的动作(保护动作见 [安全边界](09-security-boundaries.md))。同理 observe 草稿的 `fix_now` 只是接受,Run 由人发起。
31
+
32
+ ## 人批点由 Risk Preset 决定
33
+
34
+ `fast` 仅 Merge;`standard` Plan+Merge;`controlled` Intent+Plan+Merge+Release;`legacy-four-gates` 为 v1 四 Gate 完整形态(迁移期用,见 [迁移指南](08-migration-v1.md))。待批项强制携带 findings 摘要与理由——防"秒批"退化;人批等待时长进 `metrics`。
@@ -0,0 +1,68 @@
1
+ # v1 → v2 迁移指南(半天手工 runbook)
2
+
3
+ 按收尾修正三:装机量 N=1,**不做 importer 工具**,半天人工走完。三条铁律全程有效:
4
+
5
+ 1. **不猜旧状态有效性**——v1 看板/状态文件里没有证据支撑的行,一律当"待人工确认",不自动翻译成 v2 状态;
6
+ 2. **单向迁移**——v1 只冻结不删除,历史归档可查;
7
+ 3. **禁止双写**——切换日之后新工作只进 v2,任何"两边都记一下"都是回退。
8
+
9
+ ## 前提(约 30 分钟)
10
+
11
+ - [ ] 安装 v2 beta(`npm i -g @haiyangbg/buildbeat@next`),`buildbeat-v2` 可用;
12
+ - [ ] 读完 [快速开始](01-quickstart.md) 与 [Approval 指南](07-approval-guide.md);
13
+ - [ ] 目标仓库工作树干净、基线已提交。
14
+
15
+ ## 第 1 步:只读分析 v1(约 1 小时)
16
+
17
+ 盘点现有 v1 资产,只读不改:
18
+
19
+ - 看板/状态文件(`pm/status/*.md` 或等价物):列出**声称在途**的工作项;
20
+ - 提案与决策台账(`pm/changes/`、`pm/decisions.md`):找出已批准未完成的事项;
21
+ - 契约(`contracts/*.md`)与探测器(`drift-check.sh` / `live-status.sh`):记录现状与调用方式。
22
+
23
+ 产出一张三栏清单:`确认在途 / 疑似过期 / 已完成未归档`。判断依据只认证据(提交、部署记录、生产事实),不认状态文件自述。
24
+
25
+ ## 第 2 步:生成 v2 Work 草稿(约 1 小时)
26
+
27
+ 只为"确认在途"的事项建 v2 工作项:
28
+
29
+ ```bash
30
+ mkdir -p delivery/work/WORK-<名字>
31
+ # intent.md:这件事为什么存在(从 v1 提案摘录+核对)
32
+ # plan.md:接下来真实要做的步骤(不是 v1 计划的搬运——过期部分当场砍掉)
33
+ ```
34
+
35
+ "疑似过期"的行**不迁移**,在清单上标注理由留档;"已完成未归档"的补归档到 v1 历史区。
36
+
37
+ ## 第 3 步:人工确认当前活动 Work(约 30 分钟)
38
+
39
+ 项目所有者逐项过草稿清单,拍板哪些 Work 开(accept intent/plan 即 digest 绑定确认)。没被拍板的草稿删掉或留在未接受状态——**未接受的草稿不产生任何义务**。
40
+
41
+ ## 第 4 步:冻结旧看板(约 15 分钟)
42
+
43
+ 在 v1 看板/状态文件顶部加冻结声明(日期 + "新工作见 delivery/,本文件停止更新"),提交。不删除、不再写入。
44
+
45
+ ## 第 5 步:探测器重挂到 observe(约 30 分钟,可选先行)
46
+
47
+ 把 drift-check/live-status 挂为 observe Provider([Evidence 指南 §observe](06-evidence-guide.md)):
48
+
49
+ ```bash
50
+ cp <buildbeat>/src/v2/presets/observe.yaml .buildbeat/observe.yaml # 改 command/subject
51
+ buildbeat-v2 observe run --config .buildbeat/observe.yaml # 跑一个周期验证
52
+ ```
53
+
54
+ v1 脚本本体不用改——它们的权威边界(各查什么、不证什么)原样保留。
55
+
56
+ ## 第 6 步:真实 Run 验收(约 1 小时)
57
+
58
+ 选一个已确认的 Work,用 v2 跑完一个真实 Run 到 `WAITING_HUMAN` 并完成决定。**这个 Run 成功之前不算切换完成**——期间发现的问题修完再宣布切换。
59
+
60
+ 人批习惯迁移:v1 四 Gate 用户可先用 `riskPreset: legacy-four-gates`(四 Gate 完整形态),跑顺后再降到 `standard`。
61
+
62
+ ## 完成定义
63
+
64
+ - 冻结声明已提交;所有新工作走 `delivery/` + v2 Runner;
65
+ - 至少一个真实 Run 走完 Build→Verify→Review→人批闭环;
66
+ - 三栏清单与拍板结果留档(就是迁移的证据)。
67
+
68
+ 回退:v1 全部原样在 Git 里,去掉冻结声明即可回去——但双写永远禁止,回去就是整个回去。
@@ -0,0 +1,28 @@
1
+ # 安全与权限边界
2
+
3
+ 权威:[`RFC-0001 §保护动作`](../RFC-0001-product-definition.md)、[`V2-PLAN.md`](../../V2-PLAN.md) §9 不变量。设计哲学:**保护动作 = 能力移除**——不是"请 Agent 别做",而是让它做不到。
4
+
5
+ ## Runner 侧的物理边界(LOCAL_ENFORCED,均有测试)
6
+
7
+ | 边界 | 手段 |
8
+ |---|---|
9
+ | push 封禁 | worktree 级 `remote.pushurl=protected://push-blocked-by-buildbeat`——Worker 在工作区内 `git push` 无处可推(真实 remote 上实测) |
10
+ | 写范围 | `allowedPaths` 越界写入 → 不固定 candidate、`workspace.scope` BLOCK 落账、Run 停 |
11
+ | Reviewer 只读 | 步级前后快照比对,任何写入按失败落账(不变量 9) |
12
+ | 凭据隔离 | Worker env 白名单默认仅 `PATH HOME LANG LC_ALL TMPDIR TERM USER SHELL`;宿主云凭据/token 到不了子进程(`inheritEnv` 显式打开会被 doctor 降级标注) |
13
+ | 单活动 Run | 仓库级锁,一仓同时只有一个活动 Run |
14
+ | 控制文件 | workflow/policy/run 配置在主检出,不在 Worker 的 worktree 写范围内 |
15
+
16
+ merge、push、部署、`sys_client` 类生产变更**永远在 Runner 能力之外**,由人执行;Runner 至多把"merge-ready"放进 inbox。
17
+
18
+ ## 无人值守的前置条件(MVP 起强制的立场)
19
+
20
+ prompt injection 是一等攻击面:无人值守 Worker 会消费仓库内任意文件。unattended run 必须同时满足:工具白名单、出网限制、**无生产凭据**;任一不满足→降级 attended(人在环)。observe 的 diagnose 命令同理只读、同 env 白名单纪律。
21
+
22
+ ## SERVER_ENFORCED 是诚实声明
23
+
24
+ 分支保护、CI 必须、部署审批属于服务端强制;Policy 里标 `SERVER_ENFORCED` 表示"这道门在服务端",Runner 落账但不冒充能本地保证。本地挡不住的永远不要标 LOCAL。
25
+
26
+ ## 凭据红线(运维侧)
27
+
28
+ 发布/部署用的凭据只在运行时读取(如 macOS Keychain),不落文件、不落日志、不进 Git;`doctor` 检查 adapter 的 env 姿态。违反红线的配置不应通过评审。
@@ -0,0 +1,55 @@
1
+ # 故障恢复手册
2
+
3
+ 设计前提([`V2-PLAN.md`](../../V2-PLAN.md) 不变量 23):**`.buildbeat/runtime/` 整个目录随时可删**——已接受工件、Decision、Intent 草稿与分诊、已终结 Run 的压实记录全部活在 Git 面。"删了重建"是默认排障手段,不是最后手段。
4
+
5
+ ## 症状 → 处置
6
+
7
+ ### 台账报 corrupted
8
+
9
+ `status`/`inbox` 出现 `LEDGER CORRUPTED after seq=N (<原因>)`:台账在最后一条合法事件处截断视图并**拒绝追加**——恢复是人的决定,不静默修复。
10
+
11
+ 1. `buildbeat-v2 events --repo . --run RUN-X` 看合法前缀;`replay` 校验归约;
12
+ 2. 若坏的是在途 Run:通常直接废弃该 Run(worktree 里的候选仍在分支上可读),新起一个 Run;
13
+ 3. 若人为改过台账文件:从 Git 面事实重建判断,不要手补事件行。
14
+
15
+ ### Run 进程被杀 / 机器重启
16
+
17
+ ```bash
18
+ buildbeat-v2 resume --config <run-config.yaml>
19
+ ```
20
+
21
+ 在途步会以 `crashed` 关闭(事实落账),从最近 checkpoint 继续;带批准恢复时会做 candidate/plan 新鲜度检查,变了即 `APPROVAL_STALE` 转人工。恢复不了就删 runtime 重跑——候选分支与 Git 面记录不丢。
22
+
23
+ ### 锁卡住("another run is active")
24
+
25
+ 上一个 Run 异常退出可能留下仓库锁:确认真的没有活动 Run 后
26
+
27
+ ```bash
28
+ buildbeat-v2 stop --repo . --run RUN-X --reason "crashed; releasing lock"
29
+ ```
30
+
31
+ `stop` 落终态与理由;单纯锁残留也可删 `.buildbeat/runtime/` 后重来。
32
+
33
+ ### Worker 行为异常
34
+
35
+ - 输出不是信封 → `invalid-output` 按失败重试,连续同指纹自动停:修 prompt/包装脚本再 resume;
36
+ - 越界写入 → Run BLOCK 且不固定 candidate:检查 `allowedPaths` 与 Worker prompt 的范围声明;
37
+ - 超时 → 调 `timeoutMs`;超预算 → 这是刹车不是故障,人工看完再决定加预算或收 scope。
38
+
39
+ ### observe 面
40
+
41
+ - 探针一直 `unverified`:先修探针可达性——unverified 是"采不到",不是"没问题";
42
+ - 误报刷屏:`observe triage --action dismiss`,同指纹在严重度升级前不再入队;
43
+ - 删了 runtime 后 observe 周期数归零:正常——分诊记忆在 Git 面草稿里,抑制照常生效(有测试)。
44
+
45
+ ### 一切都乱了
46
+
47
+ ```bash
48
+ rm -rf .buildbeat/runtime/
49
+ ```
50
+
51
+ 然后从 Git 面重新出发。任何"长期度量/终态解释依赖 runtime"的现象都是 bug,请报告。
52
+
53
+ ## 诊断入口
54
+
55
+ `buildbeat-v2 doctor --config <run-config>`:配置可解析、workflow 无出口环、adapter env 姿态、digest 可算。`events`/`replay`/`metrics` 全部只读,可随时跑。
@@ -0,0 +1,18 @@
1
+ # BuildBeat v2 使用文档(十件套)
2
+
3
+ > 对应 [`V2-PLAN.md`](../../V2-PLAN.md) §8 M5 / 报告 B WP6.3。规范权威在 RFC/SPEC([`RFC-0001`](../RFC-0001-product-definition.md) / [`RFC-0002`](../RFC-0002-domain-model.md) / [`RFC-0003`](../RFC-0003-workflow-policy.md) / [`SPEC-0001`](../SPEC-0001-events-v1.md));本目录是操作视角,与实现冲突时以 RFC/SPEC 与代码为准并回报。
4
+
5
+ | # | 文档 | 一句话 |
6
+ |---|---|---|
7
+ | 1 | [快速开始](01-quickstart.md) | 5 分钟:装 beta → 写 run 配置 → 跑到合并决定 |
8
+ | 2 | [Workflow 编写指南](02-workflow-guide.md) | 步序、显式转换、readonly、terminal |
9
+ | 3 | [Policy 指南](03-policy-guide.md) | 四类 Policy、8 算子、三值逻辑、强制等级 |
10
+ | 4 | [Adapter 指南](04-adapter-guide.md) | Shell/Mock、env 白名单、接任意 CLI Agent |
11
+ | 5 | [Worker 合同](05-worker-contract.md) | 输入输出信封、各角色纪律 |
12
+ | 6 | [Evidence 指南](06-evidence-guide.md) | 回读制证据、状态/等级、UNVERIFIED 文化 |
13
+ | 7 | [Human Approval 指南](07-approval-guide.md) | inbox / approve / stale、批准绑定什么 |
14
+ | 8 | [v1 迁移指南](08-migration-v1.md) | 半天手工 runbook,单向迁移不双写 |
15
+ | 9 | [安全与权限边界](09-security-boundaries.md) | 保护动作=能力移除;无人值守前置条件 |
16
+ | 10 | [故障恢复手册](10-recovery.md) | 台账损坏、Run 中断、锁、runtime 全删重建 |
17
+
18
+ observe v0(探测→分层响应→Intent 草稿→人分诊)在 [快速开始 §5](01-quickstart.md) 与 [Evidence 指南](06-evidence-guide.md) 中覆盖;schema 冻结见 [`RFC-0003 §8`](../RFC-0003-workflow-policy.md)。
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "scaffoldVersion": "v1.20",
4
- "cliVersion": "1.20.0",
3
+ "scaffoldVersion": "v1.21",
4
+ "cliVersion": "2.0.0-beta.1",
5
5
  "layout": "default",
6
6
  "installedAt": "2026-08-25T00:00:00.000Z",
7
7
  "files": {
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "BUILDBEAT.md": {
17
17
  "policy": "replace-if-unmodified",
18
- "baselineSha256": "039ac488b5b3a06857e0c19002ba3fee027ba732aef23e3987c2983fb0c4358d"
18
+ "baselineSha256": "d411b53917a12e9d53f2b02e8a16292a90570d743943b183316ab0b4c69b254f"
19
19
  },
20
20
  "CLAUDE.md": {
21
21
  "policy": "replace-if-unmodified",
@@ -1,6 +1,6 @@
1
1
  # BUILDBEAT.md — 本项目的协作骨架版本标记
2
2
 
3
- **本项目使用 BuildBeat `v1.20`**(2026-06-10 初次拷入;2026-08-22 升级;2026-08-25 scoped 分发迁移,沙盘示意)
3
+ **本项目使用 BuildBeat `v1.21`**(2026-06-10 初次拷入;2026-08-22 升级;2026-08-25 scoped 分发迁移与域回复格式升级;2026-08-28 起随 v2 beta 包分发,v1 脚手架冻结于 v1.21,沙盘示意)
4
4
  **协调层布局:`默认`**(脚本在 `scripts/`;简账是从零起的项目,根上本来没别的东西 —— 接管存量项目才用紧凑布局)
5
5
  来源:<https://github.com/HaiYangBG1/BuildBeat>
6
6
 
package/example/README.md CHANGED
@@ -37,6 +37,28 @@
37
37
 
38
38
  `n/a` 必须同行带非占位的 `理由:`;`passed` 应同行指向已存在的决策表行或归档证据。`blocked` 也应说明真实阻塞,不把“还没做”包装成审批。
39
39
 
40
+ ## 域回复示例
41
+
42
+ 下面展示一期实现候选形成时,全栈视角如何面向人收口。这是回复格式示例,status 和证据文件仍是持久事实。
43
+
44
+ ```md
45
+ ## 全栈视角|✅ 已完成
46
+
47
+ ### 已做
48
+
49
+ 1. 记账主流程和月度报表已形成可验收候选。
50
+ - 证据:`pm/archive/一期/evidence/implementation.md`
51
+
52
+ ### 未做
53
+
54
+ 1. 黑盒 E2E 和带图走查。
55
+ - 原因:需要测试视角独立验收当前候选。
56
+
57
+ ### 下一步
58
+
59
+ - **本域已完成:** 下一棒是测试视角,负责黑盒 E2E 和带图走查。
60
+ ```
61
+
40
62
  ## Manifest 的教学边界
41
63
 
42
64
  - `files` 只记录这份合成快照声明的 8 个基线路径;当前文档字节与 `baselineSha256` 一致,是为了防止教材漂移,不是为 legacy 项目追认历史所有权。
package/lessons.md CHANGED
@@ -117,3 +117,11 @@
117
117
  **根因**:规则只说“稳定候选”,没有把稳定变成可核前置;又把“高风险领域”误写成“实现中一碰就立即派 reviewer”。于是 reviewer 代替了写者应先完成的自查,而 `risk-delta` 被滥用于首次 milestone 前的普通候选收敛。subagent 还分批播报 findings/进度,视觉上一个 reviewer 像开了多轮审查。
118
118
 
119
119
  **解药**:引入 **review-ready** 四项硬前置:工作包实现与写者自查完成;所有候选仓 `HEAD=candidate` 且工作树干净;受影响/全量 L3 与真渲染证据绿;无已知待修或计划改 hash。首次 milestone 前的鉴权/Secret/fail-closed 等自发现问题先集中进实现语义清单并自行收敛,不送审;只有修改已冻结对外契约或不可逆副作用才提前 `STOP_NOW + risk-delta`。每工作包每 Gate 默认一次 milestone,P0/P1 合并修完后一次 closure,P2 不复核。reviewer 单次静默核完再返回;返回前 candidate 改变就标 `SUPERSEDED` 并停止,不得把连续修补包装成 delta 链。通用原则:**独立审查应消费稳定候选,不能成为写者边实现边找问题的后台 lint。**
120
+
121
+ ## 19. 域回复各说各话,人还要自己拼交接结论
122
+
123
+ **症状**:产品视角回一屏分析,全栈视角罗列文件和实现细节,测试视角只回一个通过/不通过。人要再追问「到底做了什么、还没做什么、该谁接」,证据又和业务结果分开,很难一眼对上。
124
+
125
+ **根因**:BuildBeat 规定了 `pm/status/{视角}.md` 的持久状态写法,却只笼统要求「一屏收尾」,没有给面向人的回复一个简单统一的出口。模型便按各自任务的局部叙事优化,交接信息结构自然漂移。
126
+
127
+ **解药**:每个 AI 视角面向人收口时统一用「已做 → 未做 → 下一步」。`已做`只写功能/业务结果,证据紧跟它支持的事项;多项共用才放一条共同证据。`未做`必须写原因,同时承载未验证边界。本域完成就说下一棒是谁、做什么;未完成就说需要谁提供或确认什么;自己还能继续就不伪求助。格式只约束收口,不约束中间探索;持久真相仍在 Git/status/证据文件。通用原则:**统一交接接口,不统一模型怎么思考。**
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "@haiyangbg/buildbeat",
3
- "version": "1.20.0",
3
+ "version": "2.0.0-beta.1",
4
4
  "description": "BuildBeat: a Git-based, human-gated engineering delivery protocol for humans and AI sessions.",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "buildbeat": "bin/buildbeat.js",
8
+ "buildbeat-v2": "bin/buildbeat-v2.js",
8
9
  "solobaton": "bin/solobaton.js"
9
10
  },
10
11
  "files": [
@@ -24,10 +25,11 @@
24
25
  "check:docs": "bash tests/check-docs.sh",
25
26
  "test": "node --test tests/*.test.js",
26
27
  "test:scripts": "bash tests/test-scripts.sh",
28
+ "test:pilot": "bash tests/pilot-loop.test.sh",
27
29
  "test:skill-only": "bash tests/skill-only.test.sh",
28
30
  "test:plugin": "bash tests/plugin-marketplace.test.sh",
29
31
  "pack:check": "npm pack --dry-run",
30
- "prepublishOnly": "npm test && npm run test:scripts && npm run test:skill-only && npm run test:plugin && npm run check:docs && npm run pack:check"
32
+ "prepublishOnly": "npm test && npm run test:scripts && npm run test:pilot && npm run test:skill-only && npm run test:plugin && npm run check:docs && npm run pack:check"
31
33
  },
32
34
  "engines": {
33
35
  "node": ">=20"
package/src/constants.js CHANGED
@@ -5,7 +5,10 @@ const packageJson = JSON.parse(
5
5
  );
6
6
 
7
7
  export const CLI_VERSION = packageJson.version;
8
- export const SCAFFOLD_VERSION = `v${CLI_VERSION.split(".").slice(0, 2).join(".")}`;
8
+ // The v1 scaffold surface is frozen at v1.21 while the package version moves
9
+ // to v2 (kernel + runtime). scaffoldVersion tracks the scaffold content
10
+ // bundle, not the CLI, so existing installs see no fictitious major upgrade.
11
+ export const SCAFFOLD_VERSION = "v1.21";
9
12
  export const OUTPUT_SCHEMA_VERSION = 2;
10
13
  export const PRODUCT_NAME = "BuildBeat";
11
14
  export const LEGACY_PRODUCT_NAME = "Solobaton";