本目录是 raguide 项目的工程验证总账。每个里程碑(M0 / M1 / M2a / M2b / M2c)必须经过一次以"用户视角能直接观测的现象"为准的 live 验证,才能宣称工程完成。
2026-05-24 当天 Gate 3 首次 live 起 docker-compose + 真 LLM + 真 Langfuse 跑通 M2c。一条 query抠出 8 个真 bug(infra 5 + 后端依赖 4 + schema 双包装 3,去重后约 8 个独立根因),其中包括 commit 70e66c7 在 M0 阶段修复过、却被后续 refactor 22f5b98 静默丢掉的 ClickHouse healthcheck。
→ 教训:410 个单测全绿 + spec review 通过,只证明代码层 + mock 边界自洽。没有任何一个里程碑被证明在真实 Docker + 真实 LLM + 真实外部服务上跑得通。整个测试套件在每条集成边界都有 mock,因此对"shape drift / version skew / 配置回归"这类 bug 完全失明。
本目录的目的就是把这块盲区逐里程碑、按真实用户视角填满,并把每次发现的反例固化进 CI,让回归再也无法静默发生。
每个里程碑写一份 mN-<topic>.md checklist,每条都满足"用户视角能直接观测"的标准。该里程碑工程通过 当且仅当:
- checklist 全部 ✓ ——每条都能在当天 fresh clone + fresh docker volume 的环境下重现
- 至少一条 live integration smoke 加进 CI(
.github/workflows/),且当下 green - 期间发现的所有 bug 已 commit 或写进
_findings.md并标"deferred + 原因" - 里程碑文档末尾 2-3 句结论(什么活了 / 什么还有挂账)
"代码完成"≠"工程完成"。两者必须分开记账。
每发现一个 bug 立即走:
- 复现:写一条最短可复现命令(终端 / curl / docker exec / pytest 用例皆可),贴进
_findings.md - 诊断:root cause 一句话写清,不允许"重启就好了"
- 修:当场修。不允许"先记账,全跑完再回头一锅修"
- 验:
make或uv run pytest三件套 + 重跑当初暴露 bug 的命令 - commit + push:单 bug 单 commit,message 含 root cause + 复现 + 修复 + 影响范围
- 登账:在
_findings.md追加一行(日期 / 里程碑 / 一句话 / commit SHA)
例外:若一个 bug 范围超出当前里程碑(例如 M0 session 发现 M2b 的 bug),允许在 _findings.md 记 deferred → mN 并附理由,但当前里程碑的 checklist 不得用这条 bug 当借口跳过。
- 一天一段:M0 → M1 → M2a → M2b → M2c(自底向上)
- 每 session 开头先写 checklist(不超过 30 min),与人对话定下;然后执行;当天闭环
- 不许把 checklist 拖到执行中再补——这等于无 checklist
为什么自底向上:每层依赖前一层。M0 不通,后面所有 M* 的 live 验证都建在沙地上。Gate 3 时 ClickHouse 回归就是这类典型——它属于 M0 层,但只在 M2b/M2c 试栈时才被发现。
每个里程碑必须至少留下一个 live smoke 在 CI,原则:
- 复用真容器:用 GitHub Actions service container 起 docker-compose 子集(不 mock)
- 断言用户视角:检查 trace 真的写入了 Langfuse、
/healthz真返 200、bucket 真存在等 - 失败必 fail PR:smoke red = 默认禁止合并(除非显式 override 并说明)
- 每个 session 只新增一条:避免一次写 5 条全 flake;每条都要稳过 3 次
CI 文件命名建议:.github/workflows/eng-mN.yml,或在 .github/workflows/ci.yml 里加 job。
Smoke ≠ unit test:smoke 跑 1-3 分钟、起真容器、可能用 LLM 调用(mock LLM 用 respx fixture 但保留 HTTP shape)。Unit test 不动这块。
append-only 流水账,每个 finding 一段:
## YYYY-MM-DD · M0 · finding-001
**Title**: ClickHouse healthcheck regressed by Langfuse compose extract
**Repro**: `cd ~/Desktop/raguide && make langfuse-up` → `Error dependency langfuse-clickhouse failed to start ... is unhealthy`
**Root cause**: commit `22f5b98 infra(langfuse): extract 6-service compose` 把 langfuse 服务从 `docker-compose.yml` 抽出到 `docker-compose.langfuse.yml`,没有把 M0 commit `70e66c7` 在原文件里修过的 `localhost → 127.0.0.1` 一起搬过去。
**Fix**: commit `487f75c` — 在新文件里重新应用同样的修复。
**CI guard**: TODO `.github/workflows/eng-m0.yml` — `docker compose -f infra/docker-compose.langfuse.yml up --wait` 必须返 0。跨 session 永久保留。新的 finding 永远 append,旧的不删。
| Session # | 范围 | 主要交付 |
|---|---|---|
| 本目录建立 | 已完成 today | README.md(即此文件) |
| M0 | scaffold + compose + CI | m0-scaffold.md + 至少 1 条 smoke 进 CI |
| M1 | Hello RAG 最小垂直切片(KB 摄入 + 单路检索 + Sonnet 回答) | m1-hello-rag.md + smoke |
| M2a | LLM Provider 抽象(Anthropic adapter / Registry / FallbackChain) | m2a-llm-adapter.md + smoke |
| M2b | 观测 + 评估(Langfuse trace + AgentEvaluator + Ragas + Judge) | m2b-obs-eval.md + smoke |
| M2c | Modular RAG 内层管道(6 stage + Self-Eval + CRAG) | m2c-modular-rag.md + smoke |
每 session 不许跨域:M0 session 只验 M0,发现的 M2c bug 写 _findings.md 标 deferred。
- M3+(前端 / 完整 Web UI):尚未实现,工程验证不覆盖
- Operator-side runbook(Gate 4 gold-set re-baseline / Gate 5 5-query smoke):归 M2c session 后期或独立 session;走完 M0-M2c 工程验证后再做
- 性能 / 压测:工程验证只关心"是否能跑通",不关心 QPS / latency p99
当且仅当:
- 所有 5 个里程碑 checklist 都 ✓
- CI 里至少 5 条 live smoke 全 green,且过去 7 天无 flake
_findings.md没有status: open的 finding- README.md 顶部"最近活动"那个表里所有 ✅ 经得起任何陌生人按图复现
才能宣称"raguide 工程完成"。在此之前任何"完成"宣传都要附加"代码层完成 / 工程层 N/N"的二元描述。
- spec doc (
docs/superpowers/specs/*.md):保留——记录的是设计真相 - plan doc (
docs/superpowers/plans/*-plan.md):保留——记录的是 task 拆分 - completion doc (
docs/superpowers/plans/*-completion.md):保留但降级——它们记录的是"代码完成",必须配套 engineering-verification 的mN-*.md才能算"工程完成" - 本目录:是最终的"工程完成"账本