@haiyangbg/buildbeat 2.0.2 → 3.0.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/CHANGELOG.md +18 -301
- package/README.en.md +6 -19
- package/README.md +6 -19
- package/SKILL.md +168 -219
- package/bin/buildbeat.js +14 -2
- package/docs/CAPABILITY-MATRIX.md +13 -55
- package/docs/README.md +12 -14
- package/docs/RELEASING.md +8 -9
- package/docs/v2/RFC-0001-product-definition.md +2 -0
- package/docs/v2/RFC-0003-workflow-policy.md +2 -0
- package/docs/v2/guide/00-how-to-talk.md +3 -3
- package/docs/v2/guide/01-quickstart.md +12 -12
- package/docs/v2/guide/03-policy-guide.md +1 -1
- package/docs/v2/guide/06-evidence-guide.md +3 -3
- package/docs/v2/guide/07-approval-guide.md +10 -10
- package/docs/v2/guide/10-recovery.md +6 -6
- package/docs/v2/guide/11-session-handoff.en.md +2 -2
- package/docs/v2/guide/11-session-handoff.md +2 -2
- package/docs/v2/guide/README.md +0 -6
- package/lessons.md +52 -71
- package/package.json +3 -8
- package/src/v2/cli/run.js +33 -23
- package/src/v2/engine/risk-preset.js +1 -1
- package/src/v2/runtime/notify.js +5 -5
- package/src/v2/runtime/overview.js +7 -7
- package/templates/ARCHITECTURE.md +1 -1
- package/templates/contracts/PROTOCOL.md +2 -10
- package/templates/gitignore.template +0 -3
- package/templates/pm/adr/README.md +1 -1
- package/templates/pm/decisions.md +4 -5
- package/templates/standards/CODE.md +1 -1
- package/templates/standards/DESIGN.md +1 -1
- package/templates/standards/REVIEW.md +2 -2
- package/templates/standards/STACK.md +2 -8
- package/templates/v2/AGENTS.md +18 -18
- package/templates/v2/BUILDBEAT.md +2 -3
- package/templates/v2/CLAUDE.md +1 -1
- package/templates/v2/run-config.example.yaml +1 -1
- package/templates/v2//346/214/207/346/214/245/345/217/260.md +6 -6
- package/bin/buildbeat-v2.js +0 -18
- package/bin/solobaton.js +0 -6
- package/docs/CHECKS.md +0 -326
- package/docs/CLI.md +0 -245
- package/docs/LEGACY-V1.16-MIGRATION.md +0 -54
- package/docs/v2/guide/08-migration-v1.md +0 -72
- package/example/.buildbeat/manifest.json +0 -45
- package/example/AGENTS.md +0 -19
- package/example/ARCHITECTURE.md +0 -39
- package/example/BUILDBEAT.md +0 -17
- package/example/CLAUDE.md +0 -7
- package/example/README.md +0 -75
- package/example/contracts/PROTOCOL.md +0 -38
- package/example/pm/NOW.md +0 -22
- package/example/pm/adr/ADR-0001-local-first-sqlite.md +0 -25
- package/example/pm/adr/README.md +0 -7
- package/example/pm/archive//344/270/200/346/234/237/evidence/gate1.md +0 -5
- package/example/pm/archive//344/270/200/346/234/237/evidence/gate2.md +0 -5
- package/example/pm/archive//344/270/200/346/234/237/evidence/gate3.md +0 -5
- package/example/pm/archive//344/270/200/346/234/237/evidence/gate4.md +0 -5
- package/example/pm/archive//344/270/200/346/234/237/evidence/implementation.md +0 -5
- package/example/pm/decisions.md +0 -20
- package/example/pm/status//344/272/247/345/223/201.md +0 -20
- package/example/pm/status//345/205/250/346/240/210.md +0 -15
- package/example/pm/status//346/265/213/350/257/225.md +0 -15
- package/example/pm//344/270/200/346/234/237-/347/234/213/346/235/277.md +0 -97
- package/example/standards/CODE.md +0 -18
- package/example/standards/DESIGN.md +0 -34
- package/example/standards/REVIEW.md +0 -16
- package/example/standards/STACK.md +0 -31
- package/src/cli.js +0 -323
- package/src/constants.js +0 -202
- package/src/doctor.js +0 -267
- package/src/planner.js +0 -251
- package/src/project.js +0 -844
- package/src/upgrader.js +0 -1249
- package/src/v2/presets/risk/legacy-four-gates.yaml +0 -44
- package/src/writer.js +0 -534
- package/templates/.claude/agents/reviewer.md +0 -62
- package/templates/AGENTS.md +0 -85
- package/templates/BUILDBEAT.md +0 -13
- package/templates/CLAUDE.md +0 -7
- package/templates/pm/NOW.md +0 -26
- package/templates/pm/changes/README.md +0 -44
- package/templates/pm/status/README.md +0 -32
- package/templates/pm//345/275/223/346/234/237/347/234/213/346/235/277.md +0 -62
- package/templates/scripts/bus-check.sh +0 -1875
- package/templates/scripts/design-preview.sh +0 -44
- package/templates/scripts/drift-check.sh +0 -112
- package/templates/scripts/pre-commit.sh +0 -74
- package/templates/scripts/verify-status.sh +0 -105
- package/templates//346/214/207/346/214/245/345/217/260.md +0 -58
package/templates/v2/AGENTS.md
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
|
-
# AGENTS.md — <项目名> 工作区 · BuildBeat
|
|
1
|
+
# AGENTS.md — <项目名> 工作区 · BuildBeat 协作契约
|
|
2
2
|
|
|
3
3
|
> 本文件走开放标准 `AGENTS.md`,由工作区下的会话按各工具自己的方式装载(Claude Code / Codex / Cursor / Gemini CLI / Aider / Zed 等多数会自动读根目录 `AGENTS.md` 或 `CLAUDE.md`;不自动读的工具由人开场贴给会话——用哪个工具就按它的文档核对一次,不要假设)。目的:每个会话开工即知道「当前工作在哪 / 我是什么视角 / 读哪 / 写哪 / 该调哪条命令」,不靠人转述上下文。
|
|
4
4
|
> **层叠规则**(标准语义):会话从被编辑文件所在目录向上收集沿途所有 `AGENTS.md` 合并,**离得越近优先级越高**。本文件只写全局的(路由 / 协作规则 / 红线),各代码子仓的局部细节写进**该仓自己的 `AGENTS.md`**。
|
|
5
5
|
> 根目录 `CLAUDE.md` 只是一行指针(兼容只认该文件名的工具),内容单点在本文件。全栈总图见 `./ARCHITECTURE.md`,按需读。
|
|
6
|
-
> **本仓运行 BuildBeat
|
|
6
|
+
> **本仓运行 BuildBeat**(运行时 `@haiyangbg/buildbeat@<版本>`,`buildbeat` 由会话调用,人不必手敲)。
|
|
7
7
|
|
|
8
|
-
## 0.
|
|
8
|
+
## 0. 工作怎么发生(一页流程)
|
|
9
9
|
|
|
10
|
-
1. **工作项**:每件事一个 `delivery/work/<WORK-ID>/`(`intent.md` 为什么做 + **止损线**(最多几个 Run / 几轮 review / 几小时,越线先问所有者"继续还是砍")+ `plan.md` 怎么做,可选 `env-facts.md` 记踩出来的环境事实);被 digest 绑定接受(`buildbeat
|
|
11
|
-
2. **代码工作跑 Run**:`buildbeat
|
|
12
|
-
3. **人怎么知道该做什么**:`buildbeat
|
|
10
|
+
1. **工作项**:每件事一个 `delivery/work/<WORK-ID>/`(`intent.md` 为什么做 + **止损线**(最多几个 Run / 几轮 review / 几小时,越线先问所有者"继续还是砍")+ `plan.md` 怎么做,可选 `env-facts.md` 记踩出来的环境事实);被 digest 绑定接受(`buildbeat accept`)前只是草稿、不产生义务。`overview` 的 `cost:` 行就是止损线的读数。
|
|
11
|
+
2. **代码工作跑 Run**:`buildbeat start --config <run-config.yaml> --attempt new` → 隔离 worktree 内 Build→Verify→Fix→Review 自动闭环 → **停在合并决定**。push、合并、部署永远是人批之后的人类动作。
|
|
12
|
+
3. **人怎么知道该做什么**:`buildbeat overview --repo .` 回答「每件事走到哪、下一步该谁」;`inbox` 只列等人批的 Run,每条后面附可复制的下一句命令;`status --run <RUN>` 回答「还在动吗、动了多久、卡没卡」。
|
|
13
13
|
4. **上线**:生产动作是人的;`release-readback` 预设 + `release` 风险预设把「做之前回读 → 人做 → 做之后回读 → 观察 → 人关窗」记成 L4 证据,任一步失败即停人批。
|
|
14
|
-
5. **observe 盯生产**:`buildbeat
|
|
15
|
-
6. **拍板台账**:平台级真实决策包一行进 `pm/decisions.md
|
|
14
|
+
5. **observe 盯生产**:`buildbeat observe run --config .buildbeat/observe.yaml` 一次=一轮只读体检;异常分层(落账→只读诊断→intent 草稿入队 `delivery/observe/intents/`),草稿**绝不自动执行**,人用 `observe triage` 分诊。
|
|
15
|
+
6. **拍板台账**:平台级真实决策包一行进 `pm/decisions.md`(从 `templates/pm/decisions.md` 拷,`pm/` 下只有这一个文件与可选的 `adr/`);Run 级批准落各 Work 的 `decisions.jsonl`;finding 裁决落 `review-findings.jsonl`。跨仓契约在 `contracts/`(单仓项目可无)。
|
|
16
16
|
7. **通知**:`.buildbeat/notify.yaml` 配一条通道(URL 只能来自环境变量),Run 停在人批 / 终态 / 疑似卡住会来找人。
|
|
17
|
-
8. **打扫**:终态 Run 留下的工作树用 `buildbeat
|
|
17
|
+
8. **打扫**:终态 Run 留下的工作树用 `buildbeat gc --repo .` 清(默认只出计划)。工作树在仓内 `.buildbeat/worktrees/`:`.gitignore` 排除 `.buildbeat/runtime/` 与 `.buildbeat/worktrees/`,测试框架的收集范围也要排除 `**/.buildbeat/**`(vitest `exclude`、jest `testPathIgnorePatterns`、pytest `norecursedirs`),否则主干测试会把旧候选的用例一起跑。
|
|
18
18
|
9. **worker 信封**:`delivery/envelope/`(从 `templates/v2/envelope/` 拷)放 `worker.sh` 与 builder / reviewer / fixer 的 prompt,run 配置 `envelope.prompts` 指向它;换工具只改 run 配置里 `--` 后的命令。**worker 环境事实(写进 prompt)**:worker 的沙箱通常**不能监听端口**,需要起服务或绑定 loopback 的集成测试交给 verify 步,worker 只跑单测与静态检查,不要反复尝试;PATH 只认 POSIX 工具(`grep -E` 不用 `rg`,`find` 不用 `fd`)或在 `requires:` 里声明;verify / 包装脚本发现环境不满足(命令不在 PATH、端口被占、后端 404)就 `exit 75`,内核会当基础设施故障停人、不派 fixer、不扣预算。
|
|
19
19
|
|
|
20
20
|
## 1. 工作包路由 —— Builder 端到端负责,会话按 AI 视角隔离
|
|
21
21
|
|
|
22
|
-
> 协作单元是需求/功能工作包(=
|
|
22
|
+
> 协作单元是需求/功能工作包(= Work)。一个 Builder 对工作包的产品判断、实现、测试、合并与发布证据端到端负责;下表是可调用的 AI 专业视角和文件写边界,不是人类岗位或固定交接流水线。共享事实走 Git(`delivery/` 与 Run 台账)。
|
|
23
23
|
|
|
24
24
|
| AI 视角 | cwd | 可写(拥有) | 只读 | 开工先读 |
|
|
25
25
|
|---|---|---|---|---|
|
|
26
|
-
| **产品**(规格/编排) | 工作区根 | `delivery/**`、`pm/decisions.md`、根规划文档、`contracts/**` | 全仓 | `buildbeat
|
|
26
|
+
| **产品**(规格/编排) | 工作区根 | `delivery/**`、`pm/decisions.md`、根规划文档、`contracts/**` | 全仓 | `buildbeat overview --repo .` |
|
|
27
27
|
| **全栈**(实现,含运维) | `<代码仓>/` | `<代码仓>/**`(Run 内受 `allowedPaths` 机器约束) | `delivery/*`、契约 | 所属 Work 的 intent/plan + `run-config.yaml` |
|
|
28
28
|
| **测试**(契约验证·E2E) | 工作区根 | `tests/**`、独立核验报告(落所属 Work 目录) | 实现 + 规格 + 契约 | 所属 Work + 契约 |
|
|
29
29
|
|
|
30
30
|
> 🔴 **边界(按项目填写)**:<新地盘 / 老地盘 / 只读模块 / 不得借道写入的目录>。
|
|
31
|
-
> 🔴 **写者≠审者的机器化**:
|
|
32
|
-
> **开工/收工护栏**:任意会话开工先各仓 `git pull`,再 `buildbeat
|
|
31
|
+
> 🔴 **写者≠审者的机器化**:Run 内置 fresh-context 只读 reviewer(快照强制,写入即失败落账);merge 门绑定 candidate + plan + 证据 digest,过期即 stale。
|
|
32
|
+
> **开工/收工护栏**:任意会话开工先各仓 `git pull`,再 `buildbeat overview --repo .`(活动 Work、等人的 Run、成本);收工前再跑一次 `overview` 并把 warning / unverified 原样写进收口。生产状态问 `observe status`,不猜。
|
|
33
33
|
|
|
34
34
|
## 1.5 UI 规范摘要(非 UI 项目可删)
|
|
35
35
|
|
|
@@ -37,17 +37,17 @@
|
|
|
37
37
|
- **界面零元注释**:上线的可见界面不得出现给"做的人"看的文字;每次上线核查门必查。
|
|
38
38
|
- UI 交付的拍板对象必须含可渲染证据(真渲染入口 + 截图 digest);静态描述不构成拍板对象。
|
|
39
39
|
|
|
40
|
-
## 2.
|
|
40
|
+
## 2. 协作规则
|
|
41
41
|
|
|
42
|
-
**① 唯一入口** —— 活动工作看 `delivery/`(`overview` / `inbox
|
|
42
|
+
**① 唯一入口** —— 活动工作看 `delivery/`(`overview` / `inbox`);不另建进度文件、状态文件或看板,进度由内核从台账与 Git 回读。
|
|
43
43
|
**② 契约落盘不喊话(双向)** —— 跨边界接口先改 `contracts/` 再动代码;收到协议声明独立核查再信。反向流:实现中发现契约不够用 → 不得就地消化,停下记契约缺口交产品域裁决。
|
|
44
44
|
**③ 交接靠 candidate hash + 台账** —— Run 停在合并决定时 candidate 已由 Git 回读固定;跨会话接力读 `delivery/work/<id>/` 即知全部事实,hash 不得编造。
|
|
45
|
-
**④ 护栏与不可逆动作** —— 开工 `overview
|
|
45
|
+
**④ 护栏与不可逆动作** —— 开工 `overview`;部署/改契约/migration 等不可逆动作前再核一次并走人批;exit 0 不消除 `warning/unverified`。
|
|
46
46
|
**⑤ 风险分轨** —— Risk Preset:`fast`(仅 merge 人批)/ `standard`(plan+merge,默认)/ `controlled`(intent+plan+merge+release)/ `release`(上线回读车道)。
|
|
47
47
|
**⑥ 核查门** —— Run 内 reviewer 只读、结构化 findings;`reviewTriage: required` 时 P0/P1 先过人分诊再派 fixer;review 每 Run 默认 2 轮封顶。**完成 = hash + 可核验证据**;标准轨最低 L3,上线必须 L4。`UNVERIFIED` 永不当作通过。
|
|
48
48
|
**⑦ 状态单点** —— 事实进 Run 证据与 Work 记录;进度看 `overview`,度量看 `metrics`(本地只读)。
|
|
49
49
|
**⑧ 视觉问题带图对比** —— 提 UI bug 必附『实现截图 ⟷ 设计稿截图』并排 + 标注差异点。
|
|
50
|
-
**⑨ 单点事实** —— 线上版本只信实查(`
|
|
50
|
+
**⑨ 单点事实** —— 线上版本只信实查(`observe status` / 部署平台);任何文档不写「当前线上 vX」;每个收敛后的真实决策包只在 `pm/decisions.md` 记一行;历史台账不回改。
|
|
51
51
|
**⑩ 真渲染拍板** —— 有 UI 的拍板对象必须是真渲染证据。
|
|
52
52
|
**⑪ 所有者可见命名进决策卡** —— 域名、服务名、环境名、自停时长、窗口时长等**所有者以后要看见或要念出来的名字与参数**,不由 worker 顺手定:进 intent 或门前决策卡(`BATCH_AT_GATE`),给推荐值和理由(用业务上听得懂的名字,不用内部术语)。
|
|
53
53
|
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
|
|
66
66
|
## 3. 红线(每个会话受约束)
|
|
67
67
|
|
|
68
|
-
1. **凭据不入 git、不出本机**:文档只标位置不写值;本地 .env gitignore + 600;机器闸 = gitleaks pre-commit;
|
|
68
|
+
1. **凭据不入 git、不出本机**:文档只标位置不写值;本地 .env gitignore + 600;机器闸 = gitleaks pre-commit;Worker 默认 env 白名单;通知 URL 只能来自环境变量。
|
|
69
69
|
2. **不 `git add -A`**:只 stage 当前工作包拥有的具体文件;各仓分别提交。
|
|
70
70
|
3. **不未授权部署**、不 force-push、不 `--amend` 已推送历史、不 `--no-verify`。Run 的合并决定只表示候选具备合并条件(`SUCCEEDED` ≠ 已合并),合并/push/发布是其后的人类动作、逐项授权。
|
|
71
71
|
4. **每次部署完必更对应仓 `CHANGELOG.md`**;部署后 `observe run` 一轮。
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
# BUILDBEAT.md — 本项目的 BuildBeat
|
|
1
|
+
# BUILDBEAT.md — 本项目的 BuildBeat 标记
|
|
2
2
|
|
|
3
|
-
**本项目运行 BuildBeat
|
|
3
|
+
**本项目运行 BuildBeat**:运行时 `@haiyangbg/buildbeat@<X.Y.Z>`(<yyyy-mm-dd> 首次接入;查看本机版本 `npm ls -g @haiyangbg/buildbeat`,查看最新 `npm view @haiyangbg/buildbeat@latest version`)
|
|
4
4
|
**装载方式**:会话读根目录 `AGENTS.md`(`CLAUDE.md` 是一行指针);驾驶手册在 BuildBeat Skill `SKILL.md` §0.5
|
|
5
5
|
**活动工作**:`delivery/work/<WORK-ID>/`(intent / plan / run-config / decisions.jsonl / runs/);信封与 worker 包装在 `delivery/envelope/`
|
|
6
|
-
**v1 遗留**:<无 | `pm/NOW.md` 等已于 <yyyy-mm-dd> 冻结只读,禁止双写>
|
|
7
6
|
来源:<https://github.com/HaiYangBG1/BuildBeat>
|
|
8
7
|
|
|
9
8
|
## 升级
|
package/templates/v2/CLAUDE.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# CLAUDE.md — 指针(🔴 勿在此处写内容)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
本工作区的会话路由、协作规则、红线,**单点在同目录的 [`AGENTS.md`](AGENTS.md)** —— 请立即读取那份。
|
|
4
4
|
|
|
5
5
|
> 本文件只为兼容「只认 `CLAUDE.md` 这个文件名的工具」而存在,**永远保持这几行**。
|
|
6
6
|
> 往这里复制任何规则 = 两份文档必然漂移(上游 `lessons.md` 第 1 条:SSOT 腐烂)。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# BuildBeat v2 run 配置样板。拷到 delivery/work/<WORK-ID>/run-config.yaml 后改 work / run / allowedPaths / workers。
|
|
2
2
|
# 路径相对本文件解析。严格 YAML 子集:只有块列表与块映射,无行内 [] / {}、无锚点、注释必须独占一行。
|
|
3
|
-
# 起跑前:buildbeat
|
|
3
|
+
# 起跑前:buildbeat doctor --config <本文件>;起跑:buildbeat start --config <本文件> --attempt new
|
|
4
4
|
repo: ../../..
|
|
5
5
|
work: WORK-X
|
|
6
6
|
# 家族名;--attempt new 自动编成 RUN-X-01/02…
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
# 指挥台 — Builder
|
|
1
|
+
# 指挥台 — Builder 怎么驱动工作(忘了怎么开场就看这页)
|
|
2
2
|
|
|
3
|
-
> 本仓运行 BuildBeat
|
|
3
|
+
> 本仓运行 BuildBeat。会话按所用工具的方式装载 `AGENTS.md`(多数工具自动读根目录 `AGENTS.md` / `CLAUDE.md`;不自动读的,开场把它贴给会话);活动工作在 `delivery/`。你基本只需说下面这几句话,命令由会话调、不用你手敲。
|
|
4
4
|
|
|
5
5
|
## 日常六句话
|
|
6
6
|
|
|
7
7
|
| 你想干什么 | 说什么 | 会话背后调什么 |
|
|
8
8
|
|---|---|---|
|
|
9
|
-
| 看现在到哪了、该谁动 | 「当前进度」/「待办是什么」 | `buildbeat
|
|
10
|
-
| 看有什么等我批 | 「有什么要我拍板」 | `buildbeat
|
|
9
|
+
| 看现在到哪了、该谁动 | 「当前进度」/「待办是什么」 | `buildbeat overview --repo .`(每个 Work 的阶段 + 下一步)+ `observe status` |
|
|
10
|
+
| 看有什么等我批 | 「有什么要我拍板」 | `buildbeat inbox --repo .`(每条附可复制的下一句) |
|
|
11
11
|
| 立一件新事 | 「开个 Work:〔一句话目标〕」→ 看完说「接受」 | 建 `delivery/work/<ID>/intent.md + plan.md` → `accept`(digest 绑定) |
|
|
12
|
-
| 让它干活 | 「开工」/「再来一轮」 | 先 `buildbeat
|
|
13
|
-
| 它是不是卡了 | 「怎么样了」/「卡住了吗」 | `buildbeat
|
|
12
|
+
| 让它干活 | 「开工」/「再来一轮」 | 先 `buildbeat doctor --config …`(配置、intent/plan 接受状态、env 姿态、预算),再 `start --config … --attempt new`(自动编号、自动作废旧等待,停在合并决定) |
|
|
13
|
+
| 它是不是卡了 | 「怎么样了」/「卡住了吗」 | `buildbeat status --repo . --run <RUN>`(耗时、历史中位数、最后输出、STALLED) |
|
|
14
14
|
| 拍板 | 「批准 / 拒绝〔RUN-ID〕」;分诊时「这条接受,那条不算」 | `approve` / `reject` / `findings adjudicate`;会话说清批的是哪一步(放行 fixer / 再跑一次 / 合并决定),非终态批准后 `resume` 续跑;合并决定只表示候选够格合并,合并/push/部署逐项另说 |
|
|
15
15
|
|
|
16
16
|
其他:生产报警看 `delivery/observe/intents/` 草稿 → 「fix_now / schedule / dismiss」;上线用 `release-readback` 预设开一个 Run,「我做完了」就是批准 `enter-apply-readback`;「打扫卫生」= `gc --repo .`(先看计划再 `--apply true`)。
|
package/bin/buildbeat-v2.js
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
// v2 runtime CLI entry. The v1 `buildbeat` bin stays frozen on src/cli.js;
|
|
4
|
-
// v2 ships as a separate entry until it takes over `latest`.
|
|
5
|
-
//
|
|
6
|
-
// Guard before loading any module: the kernel uses Node>=20 syntax, and on a
|
|
7
|
-
// machine whose default node drifted older the raw SyntaxError stack hides
|
|
8
|
-
// the actual problem (real incident: default node v14 during the meta pilot).
|
|
9
|
-
const major = Number(process.versions.node.split(".")[0]);
|
|
10
|
-
if (major < 20) {
|
|
11
|
-
console.error(
|
|
12
|
-
`buildbeat-v2 needs Node >= 20; this shell resolved v${process.versions.node}.\n` +
|
|
13
|
-
"Check `which node` / nvm default, then rerun (e.g. `nvm use 23`).",
|
|
14
|
-
);
|
|
15
|
-
process.exit(1);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
import("../src/v2/cli/run.js");
|
package/bin/solobaton.js
DELETED
package/docs/CHECKS.md
DELETED
|
@@ -1,326 +0,0 @@
|
|
|
1
|
-
# BuildBeat file-bus check specification
|
|
2
|
-
|
|
3
|
-
Status: **BuildBeat 1.20 / WP3.4 implementation baseline** · normative bus-check schema: `1` · canonical scoped package metadata is `@haiyangbg/buildbeat@1.20.0`; legacy `solobaton@1.16.3` remains the read-only v0 distribution. CLI output/manifest schema 2 and mechanical upgrade are specified separately in [`CLI.md`](CLI.md); the genuine version-increment and real multi-repository refresh evidence is archived in [`PHASE4-V1.20-PILOT-2026-08-25.md`](PHASE4-V1.20-PILOT-2026-08-25.md). None of those facts changes this bus-check schema or proves registry publication.
|
|
4
|
-
|
|
5
|
-
This document is the single semantic source for `templates/scripts/bus-check.sh` and the same-directory scripts it orchestrates. It defines what a result means, not merely how output is colored. `SKILL.md`, board templates, fixtures, and script tests must use the same tokens and finding codes.
|
|
6
|
-
|
|
7
|
-
The Node CLI does not reimplement these synchronous file-bus checks. `doctor` keeps its existing inspection taxonomy; the relationship is documented in the appendix.
|
|
8
|
-
|
|
9
|
-
## 1. Authority and evidence boundary
|
|
10
|
-
|
|
11
|
-
The check layers are:
|
|
12
|
-
|
|
13
|
-
| Layer | Authority | Boundary |
|
|
14
|
-
|---|---|---|
|
|
15
|
-
| `bus-check.sh` | one synchronous report for file-bus, Gate, evidence, reference, stack, standards, and ADR findings | may aggregate sibling scripts, but must not invent facts they did not return |
|
|
16
|
-
| `verify-status.sh` | configured L3-suite state | an unconfigured suite is `unverified`, never green evidence; `--run` exits non-zero when any configured suite fails |
|
|
17
|
-
| `drift-check.sh` | configured production-fact comparison | missing adapters, failed queries, or truncated data are `unverified`, never “no drift” |
|
|
18
|
-
| `pre-commit.sh` | consumes `bus-check --strict` plus commit-local guards | a local hook is not server-side enforcement and can be absent on another clone |
|
|
19
|
-
| `doctor` | scaffold/install inspection | does not approve Gates or duplicate the bus result taxonomy |
|
|
20
|
-
|
|
21
|
-
The scripts may confirm only repository-visible facts and configured adapter results. They cannot prove that documentation matches arbitrary source code, that a human really approved a Gate, that a deployment is healthy, or that an unscanned path is clean. Those limits must appear as `unverified` findings or coverage reasons.
|
|
22
|
-
|
|
23
|
-
## 2. File-bus invariants
|
|
24
|
-
|
|
25
|
-
The eight invariant IDs are stable. New implementations extend the registry rather than renumbering it.
|
|
26
|
-
|
|
27
|
-
| ID | Normative rule | Machine-verifiable part | Must remain `unverified` without extra evidence | Implementation route |
|
|
28
|
-
|---|---|---|---|---|
|
|
29
|
-
| INV-1 | `pm/NOW.md` points to exactly one valid current board | NOW exists; one parseable current-period line and one board pointer; target is a live regular file under `pm/`, not `pm/archive/` | whether the named period is semantically the real current priority | current script partially checks existence/rot; Phase 1 adds stable codes |
|
|
30
|
-
| INV-2 | current board, status, and actual work state do not contradict one another | parseable work-package state; resolvable candidate hashes; configured L3 freshness; explicit contradictions between machine tokens | arbitrary prose status, uncommitted work, product truth, or live runtime state with no adapter | `bus-check` + `verify-status`; unresolved scope emits `sync.unverified` |
|
|
31
|
-
| INV-3 | a completed work package has evidence | every `✅完成` work-package block has one non-empty `**证据**:` line; local paths exist; hashes resolve | external URLs, screenshots not present locally, human statements, or commands whose output was not persisted | Phase 1 `evidence.missing`; external-only evidence also emits `sync.unverified` |
|
|
32
|
-
| INV-4 | a cross-boundary change is reflected in the contract | configured provider-path hints, contract file existence/version token, and project adapters when present | a generic script cannot infer all API/schema/public-behavior changes from arbitrary code | pre-commit hint + contract section; absence of a hint is never proof of synchronization |
|
|
33
|
-
| INV-5 | a passed Gate is traceable | Gate token parses; referenced decision/evidence path or hash is syntactically valid and locally resolvable | whether the named person actually approved or the evidence is sufficient | Phase 1 `gate.pass_untraceable`; human confirmation remains authoritative |
|
|
34
|
-
| INV-6 | a Gate marked `n/a` has a reason | exact `n/a` token and a non-placeholder `理由:` value on the same line | whether the reason is substantively correct for the project | Phase 1 `gate.na_without_reason`; later project-type checks may warn |
|
|
35
|
-
| INV-7 | pointers and references resolve safely | scoped Markdown/local references stay inside the root; regular-file targets exist; Git hashes resolve in the meta repo or discovered subrepos | remote-link availability or semantic correctness of an anchor | Phase 1 `ref.broken`; network is not used |
|
|
36
|
-
| INV-8 | an incomplete check is exposed | scan truncation, skipped directories, missing tools/adapters, permission errors, and failed child checks set incomplete coverage | anything outside the observed scope | `sync.unverified` or a narrower `*.unverified` code; never a confirmed all-clear |
|
|
37
|
-
|
|
38
|
-
INV-2 and INV-4 are intentionally not reducible to a single green boolean. When only part of an invariant is observable, report the confirmed subfact and the remaining `unverified` scope separately.
|
|
39
|
-
|
|
40
|
-
## 3. Machine-readable tokens
|
|
41
|
-
|
|
42
|
-
### 3.1 Gate state lines
|
|
43
|
-
|
|
44
|
-
The board contains one list item for each fixed Gate. The canonical form is:
|
|
45
|
-
|
|
46
|
-
```md
|
|
47
|
-
- Gate1: pending
|
|
48
|
-
- Gate2: n/a | 理由: `本期无 UI 或交互面`
|
|
49
|
-
- Gate3: passed | 决策: `pm/decisions.md:42` | 证据: `pm/archive/一期/evidence/gate3.md`
|
|
50
|
-
- Gate4: blocked | 理由: `尚无获批发布窗口`
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
Parser rules:
|
|
54
|
-
|
|
55
|
-
1. Accept optional leading whitespace, then the exact list marker `- `, `Gate1` through `Gate4`, one colon, and one lowercase state: `pending`, `passed`, `blocked`, or `n/a`.
|
|
56
|
-
2. Each Gate appears exactly once. Missing lines in a legacy board produce `gate.line_missing` at `warning`; duplicates or an unknown state are protocol `error` findings.
|
|
57
|
-
3. `n/a` requires a same-line `理由:` field whose backticked value is non-empty and contains no canonical `<...>` placeholder. Otherwise emit `gate.na_without_reason` at `conflict`.
|
|
58
|
-
4. `passed` should provide at least one `决策:` or `证据:` field. A present `决策:` must be exactly `pm/decisions.md:<positive-line-number>` and that line must exist as a dated decision-table row; naming the ledger file alone is not enough. A missing or invalid trace emits `gate.pass_untraceable` at `warning`.
|
|
59
|
-
5. Gate2 `n/a` is compared only with positive UI signals: a regular `standards/DESIGN.md`, an `index.html`, a known UI package dependency, or a browser-extension UI manifest. A detected signal emits `gate.na_inconsistent` at `warning`; no signal is merely inconclusive and is never proof that the project has no UI.
|
|
60
|
-
6. `blocked` should carry `理由:`. Phase 1 may warn when it is absent, but this is not a strict blocker until a stable finding code is added here.
|
|
61
|
-
7. Natural-language Gate tables may remain for readers, but only these four canonical lines drive machine conclusions.
|
|
62
|
-
|
|
63
|
-
### 3.2 Work-package evidence lines
|
|
64
|
-
|
|
65
|
-
Within each `### WP-...` block, the canonical state and evidence fields are:
|
|
66
|
-
|
|
67
|
-
```md
|
|
68
|
-
- **状态**: ✅完成
|
|
69
|
-
- **证据**: `pm/archive/一期/evidence/report.md` · candidate `deadbee1`
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
The parser scopes a block from its `### WP-...` heading to the next heading of the same or higher level. A block containing `**状态**:` and `✅完成` must contain exactly one non-empty `**证据**:` line. Missing, duplicate, placeholder-only, or locally invalid evidence emits `evidence.missing` at `conflict`.
|
|
73
|
-
|
|
74
|
-
Machine-verifiable reference forms are:
|
|
75
|
-
|
|
76
|
-
- a backticked repository-relative regular-file path, optionally followed by `:<positive-line-number>`;
|
|
77
|
-
- a backticked 7–40 character lowercase hexadecimal Git token containing at least one letter and one digit, resolvable in the meta repo or a discovered subrepo;
|
|
78
|
-
- an `https://` reference, which is recorded but remains `unverified` unless a project adapter supplies a verified result.
|
|
79
|
-
|
|
80
|
-
Paths must not be absolute, contain traversal segments, or resolve through a symlink outside the coordination root. A valid local Gate/work-package evidence path outside `pm/archive/<期>/evidence/` remains traceable but emits `evidence.outside_archive` at `warning`; Git hashes and remote URLs have no local archive-location claim. A command name or prose claim by itself is not machine-verifiable evidence; retain it for humans and emit `sync.unverified` when no local evidence token exists.
|
|
81
|
-
|
|
82
|
-
### 3.3 Scoped reference scan
|
|
83
|
-
|
|
84
|
-
Phase 1 checks Markdown links and backticked `.md` paths in `pm/NOW.md`, the current board, and the latest three dated rows of `pm/decisions.md`. It also checks paths/hashes on canonical Gate and evidence lines. The three-row decision window keeps the live synchronization guard from retroactively blocking on historical paths that were intentionally archived; the full repository linker remains a separate source-checkout gate in `tests/check_docs.py`.
|
|
85
|
-
|
|
86
|
-
Canonical Gate/evidence paths are repository-root relative and may not contain traversal segments. For scoped legacy prose, the scanner accepts an existing source-file-relative path first, including `../` or `./` segments only when the resolved regular file remains inside the coordination root, then an existing repository-root path (and bare contract filenames under `contracts/`). Absolute paths, paths that resolve outside the root, wildcards/placeholders, overlong table fragments, and prose-only tokens are never treated as valid local evidence. Wildcards/placeholders/prose are ignored rather than mislabeled as broken regular-file references; a real path-shaped token that stays in scope but does not resolve emits `ref.broken`.
|
|
87
|
-
|
|
88
|
-
### 3.4 Optional standards
|
|
89
|
-
|
|
90
|
-
`standards/STACK.md`, `CODE.md`, `REVIEW.md`, and UI-only `DESIGN.md` are independent, project-owned optional files. If none exists, `bus-check` emits no standards finding. Every file that does exist must contain exactly once:
|
|
91
|
-
|
|
92
|
-
```md
|
|
93
|
-
> **Optional**: ...
|
|
94
|
-
> **AI write boundary**: ...
|
|
95
|
-
> **Status**: Draft
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Status is exactly `Draft` or `Confirmed`. A Draft is structurally valid but emits `standards.unconfirmed` at `unverified`; it never becomes green by implication. A Confirmed file must contain no `<...>` placeholder.
|
|
99
|
-
|
|
100
|
-
Each present file contains at least one stable, unique Rule ID whose prefix matches the filename, for example `STACK-MUST-001`, `CODE-SHOULD-002`, or `DESIGN-MAY-003`. Levels are `MUST / SHOULD / MAY`; the numeric suffix is exactly three digits. Missing metadata, illegal/duplicate/wrong-prefix Rule IDs, a placeholder in a Confirmed file, or a broken repository-local backticked reference emits one `standards.invalid` error for that file. Remote references are not fetched. This structural check never infers machine values from the standards prose; a structurally valid Confirmed STACK enters the separate observation check below.
|
|
101
|
-
|
|
102
|
-
### 3.5 Confirmed STACK observable baseline
|
|
103
|
-
|
|
104
|
-
Only a structurally valid `standards/STACK.md` with `Status: Confirmed` enters stack observation. Draft or structurally invalid files retain their existing standards finding and are not compared, so an unconfirmed declaration cannot manufacture a drift conclusion. Absence of STACK remains a legal zero-finding state.
|
|
105
|
-
|
|
106
|
-
The Confirmed file contains exactly one v1 comment block:
|
|
107
|
-
|
|
108
|
-
```md
|
|
109
|
-
<!-- buildbeat-stack-baseline:v1
|
|
110
|
-
nodeConstraint=22
|
|
111
|
-
nodeConstraint=>=22 <23
|
|
112
|
-
lockfileKind=package-lock.json
|
|
113
|
-
dockerFromImage=node:22-alpine
|
|
114
|
-
-->
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
The three keys are exact and each must occur at least once. Repeating a key declares a set. Values are trimmed, case-sensitive strings of at most 200 characters; exact duplicates collapse. A dimension with no applicable source uses one sole `n/a` value, never `n/a` plus another value. A missing/duplicated/malformed block, an unknown or missing key, or an ambiguous `n/a` set emits `stack.unverified`, not `standards.invalid`: the standards document is structurally readable, but its observable baseline is not. A canonical `<...>` placeholder in any Confirmed standard remains the earlier `standards.invalid` structural error, so the observation step is skipped.
|
|
118
|
-
|
|
119
|
-
The scanner recursively observes regular files below the coordination root, pruning `.git`, `.claude`, `.codex`, canonical `.buildbeat`, legacy `.solobaton`, dependency, coverage, build, and generated-output directories. New STACK files use `buildbeat-stack-baseline:v1`; the parser also accepts exactly one legacy `solobaton-stack-baseline:v1` block. The default bound is 200 relevant files/symlinks and can be lowered or raised with positive-integer `BUS_STACK_MAX`. It compares these exact sets:
|
|
120
|
-
|
|
121
|
-
| Dimension | Observed source | Normalization |
|
|
122
|
-
|---|---|---|
|
|
123
|
-
| Node constraints | every `.nvmrc`; every string `package.json` `engines.node` | one trimmed non-empty `.nvmrc` line; JSON value preserved after outer trim |
|
|
124
|
-
| lockfile kinds | `package-lock.json`, `npm-shrinkwrap.json`, `pnpm-lock.yaml`, `yarn.lock`, `bun.lock`, `bun.lockb` | basename only; duplicate kinds collapse |
|
|
125
|
-
| Docker FROM images | `Dockerfile` and `Dockerfile.*` FROM instructions | optional `--platform=...` removed; image token preserved; stage aliases ignored |
|
|
126
|
-
|
|
127
|
-
Observed and declared non-empty sets must match exactly. A declared `n/a` plus an observed source, or two non-empty sets that differ, emits `stack.drift` at `conflict`. A declared non-`n/a` set with no observable source emits `stack.unverified` rather than drift. Invalid JSON, a non-string Node engine, an empty/multi-line `.nvmrc`, an unreadable file, an unresolved variable in a Docker image token, missing Python needed for JSON parsing, an over-limit scan, a find/permission error, a relevant file symlink, or an unpruned directory symlink also leaves the affected scope `stack.unverified`. A definite mismatch and an incomplete remaining scope may emit both codes.
|
|
128
|
-
|
|
129
|
-
The check is report-only: it never edits STACK, version files, package manifests, lockfiles, or Dockerfiles. Findings name dimensions but do not echo raw source/config values into JSON. Matching only confirms these three observed dimensions inside the scanned regular-file scope; it says nothing about frameworks, databases, deployment health, CI, licensing, remote repositories not present below the root, or semantic compatibility.
|
|
130
|
-
|
|
131
|
-
### 3.6 Explicit multi-repository version joins
|
|
132
|
-
|
|
133
|
-
Multi-repository drift is checked only through one explicit project-owned map in `contracts/PROTOCOL.md`; directory names, architecture prose, package metadata, and live output are never guessed into version equality:
|
|
134
|
-
|
|
135
|
-
```md
|
|
136
|
-
<!-- buildbeat-multirepo-map:v1
|
|
137
|
-
repo=service-web|contract=contracts/PROTOCOL.md|deployment=web
|
|
138
|
-
repo=service-api|contract=contracts/api.md|deployment=n/a
|
|
139
|
-
-->
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
Each non-empty row has exactly `repo=<path>|contract=<path>|deployment=<app-or-n/a>` with no surrounding whitespace. `repo` is a safe coordination-root-relative path expected to match the existing `SUBREPOS` discovery (independent Git repositories one or two levels below the root). `contract` is a safe `contracts/**/*.md` path containing exactly one `契约快照对应版本` line with one backticked release token. `deployment` is either an app key in the same-directory `bus-baseline.json` used by `drift-check.sh`, or the exact value `n/a` when that repository has no deployment source.
|
|
143
|
-
|
|
144
|
-
The repository version comes only from the first non-`Unreleased` H2 in `<repo>/CHANGELOG.md`. Accepted headings are Keep-a-Changelog forms such as `## [1.2.3] - 2026-08-25` or `## v1.2`; accepted source tokens have two or three numeric components plus optional SemVer prerelease/build suffixes. One leading `v`/`V` is ignored for equality. Free-form release prose, package versions, Git tags, commit hashes, and a later convenient heading are not substituted for an invalid head source.
|
|
145
|
-
|
|
146
|
-
For each mapped repository, every successfully observed source is compared pairwise. A definite mismatch emits `sync.multirepo_drift` at `conflict` and identifies the repository, `CHANGELOG.md`, mapped contract file, and `bus-baseline.json#apps.<app>.imageTag` fact source. A missing/out-of-root repository or source, invalid/duplicate/empty map, unparseable version, missing `jq`, missing app, missing deployment baseline, mapped repository outside the bounded discovery, or discovered repository absent from the map emits `sync.unverified`; a present source skipped for symlink or permission safety emits `sync.scan_truncated` under §3.8. A definite mismatch and an incomplete third source may emit both.
|
|
147
|
-
|
|
148
|
-
No discovered repositories plus no map is a legal zero-finding state. A present map is the expected inventory, so a mapped-but-undiscovered repository remains explicitly unverified even when no nested repository was found. `deployment=n/a` compares CHANGELOG and contract only. This check is read-only and compares a local deployment baseline; it does not query production or prove that the baseline is current. `live-status.sh` and `drift-check.sh` retain those separate authority boundaries.
|
|
149
|
-
|
|
150
|
-
### 3.7 Optional ADRs
|
|
151
|
-
|
|
152
|
-
ADR files are named `pm/adr/ADR-NNNN-*.md`. The directory and all ADR files are optional; absence emits no ADR finding. Every present ADR contains exactly one canonical status line:
|
|
153
|
-
|
|
154
|
-
```md
|
|
155
|
-
- Status: Proposed
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
The only legal values are `Proposed`, `Accepted`, `Rejected`, and `Superseded`. Missing, duplicated, or unknown status emits `adr.status_invalid` at `error`.
|
|
159
|
-
|
|
160
|
-
A Superseded ADR must contain exactly one root-relative target such as:
|
|
161
|
-
|
|
162
|
-
```md
|
|
163
|
-
- Superseded by: `pm/adr/ADR-0002-new-choice.md`
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
The target must exist, must itself have a legal status, and the chain must terminate without self-reference or cycles. Otherwise emit `adr.superseded_broken` at `conflict`. The script checks link integrity only; it cannot prove the architectural decision is correct or genuinely approved.
|
|
167
|
-
|
|
168
|
-
### 3.8 Mechanical scan boundaries
|
|
169
|
-
|
|
170
|
-
`sync.scan_truncated` is the common non-blocking result when a relevant local source is present or a bounded scan started, but the checker deliberately did not inspect the entire scope. Its message contains one stable reason token and its `path` names the skipped repository-relative source when known:
|
|
171
|
-
|
|
172
|
-
| Reason | Condition | Operator response |
|
|
173
|
-
|---|---|---|
|
|
174
|
-
| `reason=limit` | scoped-reference or STACK observation count exceeds `BUS_REF_MAX` / `BUS_STACK_MAX` | inspect what was omitted; raise the relevant limit only when the larger scope is intentional, then rerun |
|
|
175
|
-
| `reason=symlink` | a relevant coordination, evidence, standards, ADR, STACK, contract, repository, or deployment-baseline path traverses an in-root symbolic link | independently inspect the target or materialize the required fact as an in-root regular file; the checker does not follow it |
|
|
176
|
-
| `reason=permission` | the current process cannot read a relevant file, search a mapped repository directory, or complete filesystem traversal | restore only the minimum read/search access needed for the check, or provide a readable evidence artifact, then rerun |
|
|
177
|
-
|
|
178
|
-
This finding means “coverage stopped here,” not “the source is missing” and not “the source is valid.” A completed-work evidence reference that resolves only through a symlink or unreadable file therefore remains unverified and does not additionally become `evidence.missing`; an absent or unsafe path still follows its narrower missing/broken rule. Domain findings may coexist: for example, a Confirmed STACK scan can emit both `sync.scan_truncated` for the exact mechanical boundary and `stack.unverified` for the affected comparison dimensions.
|
|
179
|
-
|
|
180
|
-
Intentional exclusions such as `.git`, `node_modules`, build output, and vendor directories do not each produce findings because those trees are outside the declared observation scope. Raw OS error text and temporary absolute paths are not copied into JSON; an unlocatable traversal failure uses `path="."`. Any `sync.scan_truncated` sets `coverage.complete=false` but does not block strict mode. It must be reported in handoff evidence and cannot be converted into an all-clear by exit 0.
|
|
181
|
-
|
|
182
|
-
## 4. Result levels
|
|
183
|
-
|
|
184
|
-
Every finding has exactly one level:
|
|
185
|
-
|
|
186
|
-
| Level | Meaning | Strict by default |
|
|
187
|
-
|---|---|---|
|
|
188
|
-
| `confirmed` | a positive or neutral fact was directly observed | no |
|
|
189
|
-
| `warning` | a risk or traceability weakness exists, but no invariant conflict is established | no |
|
|
190
|
-
| `unverified` | the tool cannot reliably decide within the observed scope | no; must stay visible |
|
|
191
|
-
| `conflict` | a project declaration contradicts an observed fact or omits support required by an invariant | yes |
|
|
192
|
-
| `error` | protocol structure is malformed or the requested check cannot produce a trustworthy report | yes |
|
|
193
|
-
|
|
194
|
-
Levels are not a cosmetic mapping from legacy emoji or from `error/warning/info`. The implementation must construct the semantic finding first, then render human or JSON output from that same finding.
|
|
195
|
-
|
|
196
|
-
`confirmed` never means “the whole project is healthy.” If `coverage.complete` is false, the report cannot print or encode an unqualified all-clear.
|
|
197
|
-
|
|
198
|
-
## 5. Finding-code registry
|
|
199
|
-
|
|
200
|
-
Namespaces are reserved as follows:
|
|
201
|
-
|
|
202
|
-
| Namespace | Scope |
|
|
203
|
-
|---|---|
|
|
204
|
-
| `sync.` | NOW/status/L3/scan/remote and general coordination state |
|
|
205
|
-
| `gate.` | four-Gate tokens and traceability |
|
|
206
|
-
| `evidence.` | work-package evidence requirements |
|
|
207
|
-
| `contract.` | cross-boundary contract synchronization |
|
|
208
|
-
| `ref.` | local path, Markdown, and Git reference integrity |
|
|
209
|
-
| `stack.` | optional `STACK.md` observation and drift |
|
|
210
|
-
| `standards.` | optional standards structure/rules |
|
|
211
|
-
| `adr.` | optional ADR structure and supersession links |
|
|
212
|
-
|
|
213
|
-
The initial registry is:
|
|
214
|
-
|
|
215
|
-
| Code | Level | Condition | Phase |
|
|
216
|
-
|---|---|---|---|
|
|
217
|
-
| `sync.now_bloated` | `conflict` | NOW/status live coordination layer exceeds the configured rot limits | legacy behavior; code in Phase 1 |
|
|
218
|
-
| `sync.ghost_hash` | `conflict` | a canonical status hash cannot resolve in any known repo | legacy behavior; code in Phase 1 |
|
|
219
|
-
| `sync.production_drift` | `conflict` | configured drift adapter confirms a changed production fact | legacy behavior; code in Phase 1 |
|
|
220
|
-
| `sync.multirepo_drift` | `conflict` | explicitly mapped CHANGELOG, contract, and/or deployment-baseline versions disagree | Phase 3 / WP3.3 |
|
|
221
|
-
| `sync.l3_stale` | `warning` | configured suite evidence is absent, unreadable, or older than `BUS_L3_MAX_AGE_DAYS` (default `7`) | Phase 1 |
|
|
222
|
-
| `sync.l3_unconfigured` | `unverified` | no real L3 suite is configured | Phase 1 |
|
|
223
|
-
| `sync.scan_truncated` | `unverified` | limit, permission, or symlink boundary leaves relevant declared scope unchecked | Phase 1; consolidated path/reason handling in Phase 3 / WP3.4 |
|
|
224
|
-
| `sync.unverified` | `unverified` | a material check boundary has no narrower registered code | Phase 1 |
|
|
225
|
-
| `gate.line_missing` | `warning` | a legacy board lacks one or more canonical Gate lines | Phase 1 |
|
|
226
|
-
| `gate.invalid` | `error` | a Gate state line is duplicated, malformed, or uses an unknown state | Phase 1 |
|
|
227
|
-
| `gate.na_without_reason` | `conflict` | `n/a` lacks a valid same-line reason | Phase 1 |
|
|
228
|
-
| `gate.na_inconsistent` | `warning` | Gate2 is `n/a` while a positive UI signal is present | Phase 3 / WP3.2 |
|
|
229
|
-
| `gate.pass_untraceable` | `warning` | `passed` lacks a resolvable decision/evidence reference | Phase 1 |
|
|
230
|
-
| `evidence.missing` | `conflict` | a completed work package lacks one valid canonical evidence line | Phase 1 |
|
|
231
|
-
| `evidence.outside_archive` | `warning` | a valid local Gate/work-package evidence path is outside `pm/archive/<期>/evidence/` | Phase 3 / WP3.2 |
|
|
232
|
-
| `ref.broken` | `conflict` | a scoped local path/hash reference is syntactically unsafe or does not resolve | Phase 1 |
|
|
233
|
-
| `standards.invalid` | `error` | a present optional standard has invalid metadata, Rule IDs, confirmed placeholders, or local references | Phase 2-A |
|
|
234
|
-
| `standards.unconfirmed` | `unverified` | a present optional standard is structurally valid but remains Draft | Phase 2-A |
|
|
235
|
-
| `stack.drift` | `conflict` | a Confirmed v1 STACK baseline contradicts an observed Node, lockfile, or Docker FROM set | Phase 2-B / WP2.5 |
|
|
236
|
-
| `stack.unverified` | `unverified` | a Confirmed STACK baseline or relevant observation scope cannot be compared reliably | Phase 2-B / WP2.5 |
|
|
237
|
-
| `adr.status_invalid` | `error` | a present ADR lacks exactly one legal canonical Status | Phase 2-A |
|
|
238
|
-
| `adr.superseded_broken` | `conflict` | a Superseded ADR points to a missing/invalid ADR or creates a self-reference/cycle | Phase 2-A |
|
|
239
|
-
|
|
240
|
-
New codes require this document, positive/negative fixtures, human rendering, JSON rendering, and strict behavior to change together. A code must not silently change level between releases; that is a user-visible compatibility change.
|
|
241
|
-
|
|
242
|
-
## 6. JSON report schema
|
|
243
|
-
|
|
244
|
-
`bus-check --format=json` emits one JSON document to stdout and no human dashboard text. Diagnostics that prevent a report go to stderr.
|
|
245
|
-
|
|
246
|
-
```json
|
|
247
|
-
{
|
|
248
|
-
"schemaVersion": 1,
|
|
249
|
-
"command": "bus-check",
|
|
250
|
-
"ok": false,
|
|
251
|
-
"target": ".",
|
|
252
|
-
"findings": [
|
|
253
|
-
{
|
|
254
|
-
"code": "gate.na_without_reason",
|
|
255
|
-
"level": "conflict",
|
|
256
|
-
"message": "Gate2 is n/a without a non-placeholder reason.",
|
|
257
|
-
"path": "pm/一期-看板.md"
|
|
258
|
-
}
|
|
259
|
-
],
|
|
260
|
-
"summary": {
|
|
261
|
-
"confirmed": 0,
|
|
262
|
-
"warning": 0,
|
|
263
|
-
"unverified": 0,
|
|
264
|
-
"conflict": 1,
|
|
265
|
-
"error": 0
|
|
266
|
-
},
|
|
267
|
-
"coverage": {
|
|
268
|
-
"complete": true,
|
|
269
|
-
"reasons": []
|
|
270
|
-
},
|
|
271
|
-
"strict": {
|
|
272
|
-
"enabled": true,
|
|
273
|
-
"blocked": true
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
```
|
|
277
|
-
|
|
278
|
-
Schema rules:
|
|
279
|
-
|
|
280
|
-
1. `target` and `path` are normalized repository-relative display paths; fixture output must not contain temporary absolute paths.
|
|
281
|
-
2. Findings are ordered by the registry/check order, then path, so repeated runs on unchanged facts are byte-stable apart from messages whose documented fact changed.
|
|
282
|
-
3. `ok` is true only when there is no `conflict` or `error`. Warnings and explicit unverified coverage do not change `ok`, but remain in the report.
|
|
283
|
-
4. `coverage.complete` is false when any relevant scope was truncated, skipped, unavailable, or failed. `reasons` contains stable finding codes, not secrets or raw command output.
|
|
284
|
-
5. Counts equal the findings array exactly. Unknown levels/codes are schema errors in fixtures and consumers.
|
|
285
|
-
6. JSON never includes credential values, environment values, arbitrary source contents, private messages, or live configuration values.
|
|
286
|
-
|
|
287
|
-
Exit behavior:
|
|
288
|
-
|
|
289
|
-
| Invocation | Exit 0 | Exit 1 | Exit 2 |
|
|
290
|
-
|---|---|---|---|
|
|
291
|
-
| default human or `--format=json` | a report was produced, even with findings | not used for findings | invalid arguments or failure to produce a trustworthy report |
|
|
292
|
-
| `--strict` with either format | no `conflict`/`error` | at least one `conflict`/`error` | invalid arguments or failure to produce a trustworthy report |
|
|
293
|
-
|
|
294
|
-
`warning` and `unverified` never block strict by implication. Promoting either level into the strict set requires an explicit code-level change in this specification and the changelog.
|
|
295
|
-
|
|
296
|
-
## 7. Current versus planned implementation
|
|
297
|
-
|
|
298
|
-
The current worktree candidate implements Phase 1, the Phase 2-A structural checks, WP2.5 STACK observation, WP3.2 Gate/evidence joins, WP3.3 explicit multi-repository version joins, and WP3.4 consolidated mechanical-boundary reporting from one finding collection: human rendering, schema 1 JSON, strict blocking, canonical Gate/evidence parsing, scoped reference scanning, L3 machine findings, explicit incomplete coverage, the three legacy strict checks, optional standards metadata/Rule-ID validation, exact Node/lockfile/Docker baseline comparison, ADR status/supersession integrity, mapped CHANGELOG/contract/deployment-baseline comparison, and precise `limit`/`symlink`/`permission` reasons. Default human and JSON report modes still return exit 0 after producing a trustworthy report; `--strict` returns exit 1 only for `conflict` or `error`.
|
|
299
|
-
|
|
300
|
-
Fixtures now execute both renderings. They compare finding codes, registered levels, counts, relative paths, coverage reasons, and strict status; retained human text assertions protect operator-facing compatibility. Matching, definite-conflict, and missing-observation STACK fixtures lock the WP2.5 result boundary. Runtime-generated nested Git repositories cover WP3.3 matching, definite drift, spaces in repository paths, and unmapped coverage without checking nested `.git` metadata into this source repository. WP3.4 additionally covers reference-limit, symlinked evidence, and permission-denied evidence paths, including non-blocking strict behavior, incomplete coverage, and exact relative paths; the Shell suite currently has 221 assertions. WP1.6 has also completed the earlier example, active multi-repo projection, and real single-repo code-tree projection documented in [`PHASE1-PILOT-2026-08-24.md`](PHASE1-PILOT-2026-08-24.md). Current Phase 3 evidence remains disposable local fixtures, not a refreshed real-project pilot. Without separate release authorization and installed-project migration evidence, this remains an Unreleased candidate rather than released behavior.
|
|
301
|
-
|
|
302
|
-
WP2.5 does not extend beyond its three explicit regular-file dimensions. WP3.2–WP3.4 add separately mapped checks and honest boundary reporting, but a green STACK or multi-repository comparison still cannot be extrapolated into deployment health, semantic contract correctness, human approval, or any path outside the declared observation scope.
|
|
303
|
-
|
|
304
|
-
## 8. Three retained compatibility files
|
|
305
|
-
|
|
306
|
-
These files stay for distinct consumers and do not create a second semantic authority:
|
|
307
|
-
|
|
308
|
-
| File | Purpose | Schema 2 ownership |
|
|
309
|
-
|---|---|---|
|
|
310
|
-
| `CLAUDE.md` | thin compatibility pointer to `AGENTS.md` | `replace-if-unmodified` |
|
|
311
|
-
| `指挥台.md` | one-page human operator card | `replace-if-unmodified` |
|
|
312
|
-
| `.claude/agents/reviewer.md` | tool-specific read-only reviewer increment | `replace-if-unmodified` |
|
|
313
|
-
|
|
314
|
-
Project facts remain in AGENTS/NOW/board/contracts/status/evidence. These three files may point to those facts but must not copy them into competing SSOTs.
|
|
315
|
-
|
|
316
|
-
## Appendix: doctor comparison
|
|
317
|
-
|
|
318
|
-
`doctor` keeps `error / warning / info` and `ok = no error`; it does not migrate to the five bus levels in Phase 1.
|
|
319
|
-
|
|
320
|
-
| Doctor level | Closest display concept | Caveat |
|
|
321
|
-
|---|---|---|
|
|
322
|
-
| `error` | `error` | only within scaffold/install inspection |
|
|
323
|
-
| `warning` | `warning` | may include incomplete setup such as pending placeholders |
|
|
324
|
-
| `info` | `confirmed` when it reports an observed fact | not every info message is a project-wide confirmation |
|
|
325
|
-
|
|
326
|
-
No automated Gate or release decision may be made by mechanically converting doctor levels into bus-check levels.
|