feat: M3 — 伏笔账本 + 节奏引擎 + 大纲(含并发记账 bugfix)
- 伏笔账本:纯函数状态机(OPEN/PARTIAL/CLOSED/OVERDUE) + ForeshadowLedger repo;验收后到期扫描(BackgroundTask 自建 session 置 OVERDUE);登记/状态变更端点 - 节奏 + 三审齐:foreshadow-analyst + pace-checker 并入 LangGraph 并行审(REVIEW_SPECS),collect 分列落 chapter_reviews(conflicts/foreshadow_sug/pace),review SSE 加 foreshadow/pace 事件 - 大纲:outliner Agent 产 OutlineResult(含 foreshadow_windows),POST /outline 逐章 upsert outline 表;GET /foreshadow?status= 看板 - 前端:伏笔四泳道看板(OVERDUE 琥珀) + 大纲编辑器(窗口徽标) + 节奏节拍图(▁▃▅) + 审稿页消费 foreshadow/pace SSE - bugfix(T3.8):并行三审共用请求 session 记账触发 'Session is already flushing' → foreshadow/pace 静默丢失;SqlAlchemyLedgerSink.record 改 add-only(靠端点/事务 commit),加并发回归测试 - M3 E2E:真实 DB + mock 网关零 token 走通 埋设→进展→验收后扫描 OVERDUE→看板 + 大纲含窗口 + 三审齐 SSE/留痕;E2E 暴露并钉住上述 bug - 门禁绿:mypy 111 / pytest 228(0 xfailed) / alembic 无漂移;前端 gen:api/lint/tsc/vitest 69/build
This commit is contained in:
48
PROGRESS.md
48
PROGRESS.md
@@ -8,32 +8,40 @@
|
||||
|
||||
---
|
||||
|
||||
## 当前阶段:Phase 2 (M2) · 一致性 + 验收
|
||||
## 当前阶段:Phase 3 (M3) · 伏笔 + 节奏
|
||||
|
||||
> 目标:写 → 审(一致性) → 裁决 → 验收(事务写回);**未决冲突禁验收**。**契约先行**:C6 续审 AgentSpec + 结构化输出 schema → C4 扩(并行审图/SSE) → C3 扩(review/accept/reviews)。
|
||||
> 执行波次(依赖驱动):A(T2.1‖T2.3) → B(T2.2) → C(T2.4+T2.5) → D(T2.6) → E(T2.7)。
|
||||
> 计划已定的设计决策(见变更日志 + `memory/decisions.md` 待 Wave A 落地后回写):
|
||||
> **R2** digest 提炼在事务外做、原子事务只写库(不在持开事务里跨网络调 LLM);
|
||||
> **R3** accept 为确定性事务代码、读领域表(`chapters`/`chapter_reviews`)重建真相,checkpoint 仅控制流句柄(不变量 #5);
|
||||
> **R4** accept 取该章 `max(version)+1` 晋升 `status='accepted'`,草稿行保留;
|
||||
> **R5** 裁决清单每个 conflict 必须 采纳/忽略/手改 之一,缺判决 → `CONFLICT_UNRESOLVED`。
|
||||
> 目标:伏笔账本/到期提醒/看板 + 节奏引擎 + 大纲。**契约先行**:C6 扩(foreshadow-analyst/pace-checker/outliner 三 spec + 输出 schema) → C4 扩(审图加两审分支 + outline 节点) → C3 扩(outline/foreshadow 端点)。
|
||||
> 执行波次(依赖驱动):A(T3.1‖T3.4) → B(T3.2‖T3.3) → C(T3.5) → D(T3.6) → E(T3.7)。
|
||||
> 计划已定的衔接决策:
|
||||
> **M3-a** `foreshadow` 表已在 T0.2 建齐(含 status/expected_close_from/to/progress/links 列)→ **M3 无新建表迁移**;T3.1 仅 Repository + 纯函数状态机,落 `core/ww_core/domain/`(@backend owned,同 T2.3 先例,故 T3.1 负责据实记 @backend)。
|
||||
> **M3-b** 到期扫描(T3.2)挂在**验收后**触发——接 M2 验收事务 §5.5 步骤 3 当前留的 `TODO(M3)`(人物 latest_state/伏笔更新)占位。
|
||||
> **M3-c** 第三审(foreshadow/pace)复用 M2 `build_review_graph` 的 `review_specs` 扩展点并入并行分支(C4 已稳定);**文风第四审属 M4/T4.2**,M3 先到三审齐。
|
||||
> **M3-d** 到期判据为纯函数确定性代码(非 Agent):`current_ch > expected_close_to AND status≠CLOSED → OVERDUE`。
|
||||
|
||||
| 任务 | 状态 | 负责 | 依赖 | 契约 | 备注 |
|
||||
|---|---|---|---|---|---|
|
||||
| T2.1 续审 AgentSpec + 结构化输出契约 + 网关 instructor 接线 | ✅ @llm 2026-06-18 | @llm | T1.1✅ | C6✅稳定 | `packages/agents/`+`packages/llm_gateway/`;`ContinuityReview/Conflict`(五类枚举)+`continuity_spec`(只读);`Gateway.run` 经 instructor 填 `parsed`(改 C1);25 tests 绿 |
|
||||
| T2.2 LangGraph 并行审 + collect 留痕 + review SSE | ✅ @llm 2026-06-18 | @llm | T1.3✅, T2.1✅ | C4✅扩稳定 | `orchestrator/`:`build_review_graph`(continuity 并行,可扩四审)+`collect_reviews`落 `chapter_reviews`+`normalize_review`(section/conflict);accept 接线留 T2.4;15 新测;只 flush 不 commit |
|
||||
| T2.3 摘要/审稿留痕 Repository + 章节 version | ✅ @backend 2026-06-18 | @backend | T0.2✅ | — | `core/ww_core/domain/`:`chapter_repo`(promote_to_accepted/max_version/latest_accepted)+`digest_repo`(append-only)+`review_repo`(record/list/set_decisions);纯 fake 17 新测;只 flush 不 commit(交 T2.4 事务);唯一约束 DB 级→T2.7 E2E 覆盖 |
|
||||
| T2.4 验收事务 + 冲突 gate | ✅ @backend 2026-06-18 | @backend | T2.2✅, T2.3✅ | C3✅扩 | `accept_service`(冲突 gate+R3/R4 单事务)+`digest_extraction`(R2 事务外提炼,light);`POST .../accept`;缺判→409 `CONFLICT_UNRESOLVED`+missing_indices |
|
||||
| T2.5 review API + 历史 | ✅ @backend 2026-06-18 | @backend | T2.2✅ | C3✅扩 | `POST .../review`(SSE section/conflict/done)+`GET .../reviews`(新→旧);analyst 网关;流耗尽 commit;+9 测全仓 112 passed |
|
||||
| T2.6 审稿报告页 + 冲突裁决 + 验收 gate | ✅ @frontend 2026-06-18 | @frontend | T2.4✅, T2.5✅ | — | `app/projects/[id]/review`+`components/review/*`+`lib/review/*`;gen:api 纳三端点;就地标注(R6 段级锚点)+裁决+「将更新」清单+未决禁验收;vitest 45(+21) |
|
||||
| T2.7 M2 E2E | ✅ @qa 2026-06-18 | @qa | T2.6✅ | — | `tests/test_m2_e2e.py` 2 用例真跑过(非 skip);闭环 + 零冲突直通;DB 真源断言(accepted v2 / digest 来自终稿#4 / 裁决留痕 / 三档位 ledger);无新 bug |
|
||||
| T3.1 foreshadow Repository + 纯函数状态机 | ✅ @backend 2026-06-18 | @backend | T0.2✅ | — | `foreshadow_state.py`(ForeshadowStatus+transition/is_overdue/apply_overdue_scan/InvalidTransition)+`foreshadow_repo.py`(`ForeshadowLedger*`,register/list_by_status/transition/record_progress/scan_overdue,只 flush);37 测;写侧加 Ledger 前缀避撞 C5 读侧 |
|
||||
| T3.2 到期扫描(BackgroundTask) + 登记/状态接口 | ✅ @backend 2026-06-18 | @backend | T2.4✅, T3.1✅ | C3✅扩 | accept 后 BackgroundTask `run_overdue_scan`(自建 session 置 OVERDUE);`POST/PATCH .../foreshadow` 登记/转移(重复/非法→VALIDATION 422);9 测全仓 205 passed |
|
||||
| T3.3 foreshadow-analyst + pace-checker 节点 | ✅ @llm 2026-06-18 | @llm | T2.2✅ | C6✅扩/C4✅扩 | `foreshadow_spec`+`pace_spec`(+schema)并入 `REVIEW_SPECS`(三审齐);collect 分列落 conflicts/foreshadow_sug/pace;`normalize_review` 加 `foreshadow`/`pace` 事件;~30 测;文风审留 M4 |
|
||||
| T3.4 outliner Agent + 伏笔窗口 | ✅ @llm 2026-06-18 | @llm | T1.1✅ | C6✅扩 | `packages/agents/`(outliner_spec+OutlineResult/OutlineChapter/ForeshadowWindow)+`orchestrator/outline_node.py`(run_outline 只读不写库);20 测;C6 扩稳定 |
|
||||
| T3.5 API:outline + foreshadow | ✅ @backend 2026-06-18 | @backend | T3.1✅, T3.4✅ | C3✅扩 | `GET .../foreshadow?status=`(看板,续 foreshadow.router) + `POST .../outline`(独立 outline.py,run_outline analyst→upsert outline 表+commit);outline 写侧 repo;+15 测全仓 220 passed |
|
||||
| T3.6 伏笔看板 + 大纲编辑器 + 节奏报告 | ✅ @frontend 2026-06-18 | @frontend | T3.3✅, T3.5✅ | — | `/foreshadow`(四泳道+登记/转移) + `/outline`(beats+窗口徽标) + 审稿页扩消费 foreshadow/pace(节拍图▁▃▅);gen:api 纳 M3 端点;vitest 69(+24) |
|
||||
| T3.7 M3 E2E | ✅ @qa 2026-06-18 | @qa | T3.6✅ | — | `tests/test_m3_e2e.py` 3 用例真跑(非 skip):伏笔埋设→进展→验收后扫描 OVERDUE✓ + 大纲 upsert 含窗口✓ + 三审 SSE(**strict-xfail 钉住并发记账 bug**);DB 真源断言 |
|
||||
| T3.8 [bugfix] 并行审记账并发安全 | ✅ @llm 2026-06-18 | @llm | T3.7✅ | — | `SqlAlchemyLedgerSink.record` 改 add-only(去 `await flush`);并发回归测试(RED 已验旧实现炸);E2E case3 转 XPASS(三审齐落库 foreshadow_sug=2/pace✓)。**待 @qa 解钉 T3.7 strict-xfail 收尾** |
|
||||
|
||||
**M2 出口(DoD)✅ 全部达成**:写→审(一致性)→裁决→验收(事务);未决冲突禁验收。后端门禁绿(ruff / mypy **90 文件** / pytest **114 passed** / alembic **无漂移**);前端门禁绿(gen:api / lint / tsc / vitest **45** / build);E2E 真实 DB + mock 网关零 token 走通 写→审→裁决→验收→摘要入库,DB 真源逐项断言。**M2 完成。** 下一阶段 M3(伏笔 + 节奏)见 DEV_PLAN,进入时拉入本表。
|
||||
**M3 出口(DoD)✅ 全部达成**:伏笔账本/到期提醒/看板;大纲含回收窗口;节奏报告(三审齐真持久化)。后端门禁绿(ruff / mypy **111 文件** / pytest **228 passed** / alembic **无漂移**);前端门禁绿(gen:api / lint / tsc / vitest **69** / build);E2E 真实 DB + mock 网关零 token 走通 伏笔埋设→进展→验收后扫描 OVERDUE→看板 + 大纲含窗口 + 三审齐 SSE/留痕,DB 真源逐项断言。T3.7 E2E 暴露并发记账 bug → T3.8 add-only 修复 → 解钉 xfail。**M3 完成。** 下一阶段 M4(文风)见 DEV_PLAN,进入时拉入本表。
|
||||
|
||||
---
|
||||
|
||||
## 已归档阶段
|
||||
|
||||
<details><summary>Phase 2 · 一致性 + 验收 (M2) — ✅ 全部完成(2026-06-18)</summary>
|
||||
|
||||
T2.1 续审 AgentSpec+结构化输出契约+网关 instructor 接线(C6✅稳定,改 C1:`run()` 填 `parsed`)@llm · T2.2 LangGraph 并行审+collect 留痕+review SSE(C4✅扩)@llm · T2.3 摘要/审稿留痕 Repository+章节 version(@backend,表已 T0.2 建)· T2.4 验收事务+冲突 gate(单原子事务 + R2 事务外提炼 digest)@backend · T2.5 review API+历史(C3✅扩)@backend · T2.6 审稿报告页+冲突裁决+验收 gate @frontend · T2.7 M2 E2E(真 DB+多档位 mock 网关零 token)@qa。
|
||||
出口达成:后端门禁绿(ruff / mypy 90 / pytest 114 / alembic 无漂移);前端门禁绿(gen:api / lint / tsc / vitest 45 / build);E2E 写→审→裁决→验收→摘要入库闭环、DB 真源逐项断言。设计决策 R1–R6 全兑现(见 `memory/decisions`)。
|
||||
|
||||
</details>
|
||||
|
||||
<details><summary>Phase 1 · 写章闭环骨架 (M1) — ✅ 全部完成(2026-06-18)</summary>
|
||||
|
||||
T1.1 LLM 网关接口+DeepSeek 适配器+usage_ledger 记账(C1✅稳定)@llm · T1.2 记忆 assemble 确定性选择(C5✅稳定)@backend · T1.3 LangGraph 写章节点+Postgres checkpointer+SSE(C4✅稳定)@llm · T1.4 立项+写章 draft(SSE)+PUT 自动保存(C3✅稳定)@backend · T1.5 AppShell+作品库+5 步立项向导 @frontend · T1.6 写作工作台(三栏+流式打字机+注入透明面板+自动保存)@frontend · T1.7 提供商凭据管理(Fernet 加密+测试连接)@backend · T1.8 设置页(档位路由+凭据行)@frontend · T1.9 M1 E2E(真实 DB+mock 网关零 token;暴露并修复 ledger 提交 bug)@qa。
|
||||
@@ -55,6 +63,14 @@ T0.1 monorepo 骨架 ✅ @devops · T0.2 16 MVP 表迁移(无漂移,users st
|
||||
|
||||
> 格式:`- [YYYY-MM-DD] @skill 完成/进展 Txx — 一句话结果 + 影响的契约/文件`
|
||||
|
||||
- [2026-06-18] @orchestrator — **🎉 M3 完成**(T3.8✅ 修复 + @qa 解钉 xfail)。T3.8 把 `SqlAlchemyLedgerSink.record` 改 add-only(去并行路径里唯一的 `await flush()`,靠端点/事务 commit 持久化),并发回归测试 RED 已验旧实现抛 `Session is already flushing`;@qa 移除 T3.7 case3 strict-xfail、收紧为严格正向断言(三审 section 齐 + foreshadow/pace 真发事件 + `chapter_reviews.foreshadow_sug`/`pace` 列真填 + `beat_map` 精确断言)。最终全收口门禁绿:ruff/format 干净、mypy **111 文件**、pytest **228 passed**(0 xfailed/0 failed)、**alembic 无漂移**;前端 lint/tsc/vitest 69 绿。**M3 出口 DoD 全达成。** 下一阶段 M4(文风)。
|
||||
- [2026-06-18] @orchestrator — **M3 Wave E:T3.7✅ E2E 交付 + 暴露并发 bug**。`tests/test_m3_e2e.py` 真 pg 跑通:① 伏笔 埋设→进展→验收后 BackgroundTask 扫描置 OVERDUE→看板过滤(DB 真源)✓ ② 大纲 `POST .../outline`→outline 表行+窗口+幂等 upsert+记账✓。③ 三审 SSE 用例 **strict-xfail 钉住真 bug**:三审同 LangGraph superstep 并行 + 共用请求 session 的 `SqlAlchemyLedgerSink.record`(add+`await flush`)→`AsyncSession` 非并发安全→第二/三审 flush 撞「Session is already flushing」→被 `run_review` 失败隔离静默吞成 `incomplete`→**foreshadow/pace 静默丢失**(SSE 无事件、`chapter_reviews` 列空)。M2 单审未触发。基线 **222 passed + 1 xfailed**。开 **T3.8(@llm)** 修复 → 修后 @qa 解钉 xfail → 才算 M3 达成。
|
||||
- [2026-06-18] @orchestrator — **M3 Wave D 完成**(T3.6✅)。前端三块落地:伏笔四泳道看板(`/foreshadow`,OVERDUE 琥珀 + 登记/转移乐观更新)、大纲编辑器(`/outline`,逐章 beats + 伏笔窗口徽标 + 接近回收提示)、审稿页扩消费 `foreshadow`/`pace` SSE(伏笔建议区 + 节奏节拍图 ▁▃▅,三审齐显,文风第四审留 M4)。`pnpm gen:api` 纳入 M3 端点(看板/登记/转移/大纲),松散 JSONB 字段安全收窄不手写。前端门禁绿:gen:api/lint/tsc/**vitest 69(+24)**/build。memory +1 decision +2 gotchas。下一步 **Wave E:T3.7 M3 E2E**(@qa 真 DB + mock 网关零 token)。
|
||||
- [2026-06-18] @orchestrator — **M3 Wave C 完成**(T3.5✅,C3 扩稳定)。`GET .../foreshadow?status=` 看板(续 foreshadow.router,四泳道)+ `POST .../outline`(独立 outline.py:`run_outline` analyst 网关 → 逐章 upsert `outline` 表含伏笔窗口 → 端点末尾 commit)。outline 写侧 repo 加 `Write` 前缀避撞 C5 读侧。全仓门禁绿:mypy **102 文件**、pytest **220 passed**(205→+15)。memory 登记 C3 扩 + 1 decision + 1 gotcha。下一步 **Wave D:T3.6**(@frontend 伏笔看板 + 大纲编辑器 + 节奏节拍图 + 审稿页消费 foreshadow/pace SSE,先 `pnpm gen:api`)。
|
||||
- [2026-06-18] @orchestrator — **M3 Wave B 完成**(T3.2✅)。验收后到期扫描挂 BackgroundTask(`run_overdue_scan` 自建独立 session 置 OVERDUE,接 §5.5 `TODO(M3)`)+ 伏笔登记/状态端点(`POST/PATCH .../foreshadow`,重复 code/非法转移→`VALIDATION` 422,未动 shared 错误码)。全仓门禁绿:mypy **95 文件**、pytest **205 passed**(196→+9)。memory 登记 C3 扩 + 1 decision + 2 gotchas。下一步 **Wave C:T3.5**(@backend `GET .../foreshadow?status=` 看板续接 foreshadow.router + `POST .../outline` 独立 outline.py 调 run_outline)。
|
||||
- [2026-06-18] @orchestrator — **M3 Wave B 半程**(T3.3✅,C4/C6 扩稳定)。foreshadow-analyst + pace-checker 并入 `build_review_graph`(`REVIEW_SPECS` 三审齐,文风第四审留 M4);collect 一次 record 分列落 `conflicts`/`foreshadow_sug`(扁平+kind 标记)/`pace`(整 dict);`normalize_review` 加 `foreshadow`/`pace` SSE 事件(向后兼容)。全仓门禁绿:ruff/format 干净、mypy **91 文件**、pytest **196 passed**(169→+27)。memory 登记 C4/C6 扩 + 2 gotchas。**Wave B 顺序执行**:T3.3 改完 orchestrator → 现启 **T3.2(@backend apps/api)**,对最终 orchestrator 构建、无编译竞争。
|
||||
- [2026-06-18] @orchestrator — **M3 Wave A 完成**(T3.1✅ + T3.4✅)。两 agent 并行(@backend core/domain ‖ @llm agents+orchestrator,隔离 MYPY_CACHE_DIR 避缓存竞争)。T3.1:伏笔纯函数状态机(OPEN/PARTIAL/CLOSED/OVERDUE 全转移+到期判据)+写侧账本 repo(`ForeshadowLedger*`,加 Ledger 前缀避撞 C5 读侧)。T3.4:outliner spec + `OutlineResult` schema(含 `foreshadow_windows`)+`run_outline` 节点(只读不写库,C6 扩稳定)。全仓门禁绿:ruff/format 干净、mypy **90 文件**、pytest **169 passed**(114→+37+18)。memory 登记 C6 扩 + 2 decisions + 2 gotchas。下一步 **Wave B:T3.2(@backend 到期扫描+登记接口) ‖ T3.3(@llm foreshadow/pace 第三审并入 review_specs)**。
|
||||
- [2026-06-18] @orchestrator — **进入 M3**:归档 Phase 2(M2) 至已归档;Phase 3 七任务拉入台账。沿用 M2 节奏:契约先行 + 分目录并行 + 全仓门禁收口。核对:`foreshadow` 表已在 T0.2 建齐 → **M3 无新建表迁移**;T3.1「Repository+状态机」据实记 @backend(落 `core/ww_core/domain/`,同 T2.3 先例);T3.3 复用 M2 `build_review_graph` 的 `review_specs` 扩展点加 foreshadow/pace 两审(文风第四审留 M4)。启动 **Wave A:T3.1(@backend·core/domain) ‖ T3.4(@llm·packages/agents+orchestrator)**(不同目录,无写冲突)。
|
||||
- [2026-06-18] @orchestrator — **🎉 M2 完成**(Wave E:T2.7✅)。`tests/test_m2_e2e.py` 真实 pg + 多档位 mock 网关(零 token)真跑通过 2 用例:主用例串 立项→写章 SSE→自动保存→**审稿 SSE(section/conflict)**→GET 历史→**残缺裁决触发 409 `CONFLICT_UNRESOLVED`+missing_indices(gate 事务前拦截未写库)**→全量裁决+终稿验收(200, accepted v2)→**DB 真源逐项断言**:chapters draft v1 留存 + accepted v2(content==final_text)、`chapter_digests.facts` 追溯终稿标记(证 #4 digest 从终稿非草稿)、`chapter_reviews.decisions` 写回、`usage_ledger` 三档位(writer/analyst/light)各落一条且事务已 commit;补充用例验证零冲突直通。**无新 bug**(M1 曾暴露的 ledger 提交 bug 在 M2 三档位无复发——review 流末 + accept 事务末均 commit)。最终全收口门禁绿:ruff/format 干净、mypy **90 文件**、pytest **114 passed**、**alembic 无漂移**(M2 全程零建表迁移)。M2 出口 DoD 全达成。下一阶段 **M3(伏笔+节奏)**。
|
||||
- [2026-06-18] @orchestrator — **Wave D 完成**(T2.6✅)。审稿报告页落地:`app/projects/[id]/review`(RSC 取历史)+ `components/review/*`(报告卡/就地标注/AcceptPanel)+ `lib/review/*`(SSE reducer/裁决完整性/请求体组装,纯逻辑单测)。`pnpm gen:api` 纳入 review/accept/reviews 三端点类型(不手写);SSE 沿用 `useDraftStream` 的 fetch+ReadableStream 范式;五类冲突就地朱砂锚点(R6 段级降级)+裁决(采纳/忽略/手改)+**未决禁验收 gate**+409 missing_indices 高亮+「本次将更新」清单。前端门禁绿:gen:api/lint/tsc/**vitest 45(+21)**/build。memory +1 decision +2 gotchas。下一步 **Wave E:T2.7 M2 E2E**(@qa 真实 DB + mock 网关零 token)。
|
||||
- [2026-06-18] @orchestrator — **Wave C 完成**(T2.4✅ + T2.5✅,C3 扩稳定,单 @backend agent 顺序做)。三端点入 OpenAPI:`POST .../review`(SSE section/conflict/done) + `GET .../reviews`(新→旧) + `POST .../accept`。验收:冲突 gate(裁决 `conflict_index` 须覆盖 review.conflicts 全下标,缺判→409 `CONFLICT_UNRESOLVED`+missing_indices)→ 终稿 digest 提炼在事务外(R2,light 档)→ 单原子事务 promote(R4)+digest.append(#4)+set_decisions、末尾一次 commit、失败全回滚(R3)。`build_gateway_for_tier` 统一多档位网关注入。全仓门禁绿:ruff/format 干净、mypy **83 文件**、pytest **112 passed**(+9)。memory 登记 C3 扩 + 1 decision + 2 gotchas。下一步 **Wave D:T2.6**(@frontend 审稿页+裁决+验收 gate,先 `pnpm gen:api`)。
|
||||
|
||||
Reference in New Issue
Block a user