feat: M4 文风 + M5 生成/多provider/Skill + Kimi Code 订阅接入 + 本地联调修复

M4(文风): style-auditor 双轨(提取指纹/漂移第四审)+ jobs 长任务框架(zombie reaper) + 回炉 refine + GET /style read-back。
M5(生成+扩展): worldbuilder/character-gen(入库 continuity 409 gate + partition_writes 白名单 + schema→JSONB 形变);
  网关多 provider 回退链/熔断/能力降级(Anthropic/Gemini 适配器);Skill registry + 表权限沙箱 + 规则;
  前端 角色生成器/世界观/Codex/规则页/技能库/⌘K 命令面板。
K1(Kimi Code 订阅接入): OAuth device-flow(kimi-code)+ 静态 Console key(kimi-code-key)两路径;
  coding 端点 KimiCLI 伪造头(实测 UA allow-list 门禁,缺则 403)+ JSON 模式结构化(thinking ⊥ tool_choice)。
本地联调修复: CORS 中间件;assemble 注入 premise+「写第N章」指令(修空 prompt 400);
  GET /outline·/draft read-back + 大纲/工作台/审稿页重载;写页 client/server 常量边界 + notFound 健壮化;
  字数 toLocaleString locale 水合;审稿页终稿从已存草稿 seed(修 accept 422)。
门禁: backend ruff/mypy(157)/alembic 无漂移/pytest 451 · frontend lint/tsc/vitest/build。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yaojia Wang
2026-06-20 10:39:58 +02:00
parent 5fb7bfb1de
commit 765dbdfbd4
161 changed files with 17330 additions and 208 deletions

View File

@@ -8,33 +8,60 @@
---
## 当前阶段:Phase 3 (M3) · 伏笔 + 节奏
## 当前阶段:K1 · Kimi Code OAuth订阅 plan 接入)
> 目标:伏笔账本/到期提醒/看板 + 节奏引擎 + 大纲。**契约先行**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`
> **背景**:用户要求接入 Kimi Code 订阅 plandevice-flow OAuth。**已知情接受 ToS/封号风险**——研究确认:用订阅 plan 调用需伪造官方客户端 `User-Agent` + `X-Msh-*` 头Kimi ToS 视为违规、可能封停会员(见变更日志研究结论)。用户明确选择此路径(非合规的 API Key 路径)。与既有 API-key провайдер `kimi` **分离**,新增独立 provider `kimi-code` 以便切换
> **集成契约(研究确认,实现时对照 `github.com/picassio/pi-kimi-coder` 校验)**
> - device flow`POST https://auth.kimi.com/api/oauth/device_authorization`client_id `17e5f671-d194-4dfb-9706-5516cb48c098`env `KIMI_CLIENT_ID` 可覆盖scope `kimi-code`)→ 返回 user_code/verification_uri/device_code/interval轮询 `POST https://auth.kimi.com/api/oauth/token`grant device_code处理 authorization_pending/slow_down。refresh同 token 端点 grant refresh_token。
> - 推理base `https://api.kimi.com/coding/v1`OpenAI 兼容model `kimi-for-coding``Authorization: Bearer <access_token>` + **必需伪造头**`User-Agent`(如 `KimiCLI/1.x`) + `X-Msh-Platform`/`X-Msh-Version`/`X-Msh-Device-Name`/`X-Msh-Device-Model`/`X-Msh-Os-Version`/`X-Msh-Device-Id`(持久 UUID)。缺头→403
> - tokenaccess ~15min / refresh ~30d → **建网关时按需刷新**(临近过期刷新并持久化)。存储:`provider_credentials` 加 `auth_type`(api_key|oauth) + `oauth_enc`(Fernet 加密 JSON `{access_token,refresh_token,expires_at}`)
> **执行波次**A(@db 加列+迁移 ‖ @llm Kimi coding 适配器) → B(@backend OAuth device 服务 + 端点 + store + `_build_provider_adapter` 接线) → C(@frontend 设置页连接/轮询/断开 + 路由档位) → D(@qa E2E device-flow mock + 头断言)
> **测试纪律**device flow 注入 fake httpx零联网适配器断言伪造头集token 刷新逻辑单测E2E mock auth+coding 两端点
| 任务 | 状态 | 负责 | 依赖 | 契约 | 备注 |
|---|---|---|---|---|---|
| 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 APIoutline + foreshadow | ✅ @backend 2026-06-18 | @backend | T3.1✅, T3.4 | C3✅扩 | `GET .../foreshadow?status=`(看板,续 foreshadow.router) + `POST .../outline`(独立 outline.pyrun_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 收尾** |
| K1.1 provider_credentials 加 auth_type + oauth_enc 列 | ✅ | @db | — | C2扩 | 完成models 加 auth_type/oauth_enc + api_key_enc 改 nullable迁移 `1f011c42bd4d`alembic check 无漂移。⚠️ K1.3 @backend 须把 `StoredCredential.api_key_enc``bytes\|None`(见下方请求 + memory|
| K1.2 Kimi coding 适配器(伪造头 + OAuth bearer | ✅ | @llm | — | C1扩 | 完成:`adapters/kimi_code.py`(KimiCodeAdapter 子类化 OpenAICompatAdapter + 伪造头 + 稳定 device_id)`build_adapter``kimi-code` 分支UA 验证为 `KimiCLI/1.5`pi-kimi-coder 仅设 UAX-Msh-* 为契约附带,见 C1扩 校正11 测全绿 |
| K1.3 OAuth device 服务 + 端点 + store + 接线 | ✅ | @backend | K1.1,K1.2 | C3扩 | 完成:`services/kimi_oauth.py`(start/poll/refresh,注入 httpx Protocol)+3 端点(start 202→jobs 后台轮询/disconnect/status,复用 run_job)+`StoredCredential` 收口(api_key_enc→nullable+auth_type/oauth_encK1.1 的 2 mypy red 已消)+store `upsert_oauth_credential`/`delete_credential`+`_build_provider_adapter` OAuth 按需刷新(300s 缓冲)。**token 不进 job 结果/日志/响应**。全仓门禁绿(ruff/format/mypy **154**/alembic 无漂移/pytest **430**)。OpenAPI 加 3 端点→**@frontend K1.4 须 `pnpm gen:api`** |
| K1.4 设置页 Kimi Code 连接流 | ✅ | @frontend | K1.3 | — | 完成:`gen:api` 纳入 3 OAuth 端点;`KimiCodeOauth` 连接区(显 user_code+开授权页+轮询 job→已连接/断开)+ 可编辑档位路由(含 `kimi-code:kimi-for-coding`);纯逻辑 `lib/settings/{kimiOauth,providers}` + 25 新 vitest前端门禁全绿gen:api/lint/typecheck/vitest 155/build。运行时验真 auth.kimi.com 留 K1.5 |
| K1.5 K1 E2E | ✅ | @qa | K1.4 | | `tests/test_k1_kimi_oauth_e2e.py`(4 用例,真 pg)device-flow(pending×2→成功)→加密 token 真落 pg(无明文+回环)→建网关断言 KimiCodeAdapter coding base+伪造头+bearer→refresh-on-build 更新存量 token(DB 真源)→disconnect 清除token 全程不进 job 结果/状态/start 响应。全仓门禁绿(ruff/format/mypy **154**/alembic 无漂移/pytest **434**)。**K1 完成,可封板** |
**M3 出口DoD✅ 全部达成**伏笔账本/到期提醒/看板;大纲含回收窗口;节奏报告(三审齐真持久化)。后端门禁绿ruff / mypy **111 文件** / pytest **228 passed** / alembic **无漂移**前端门禁绿gen:api / lint / tsc / vitest **69** / buildE2E 真实 DB + mock 网关零 token 走通 伏笔埋设→进展→验收后扫描 OVERDUE→看板 + 大纲含窗口 + 三审齐 SSE/留痕DB 真源逐项断言。T3.7 E2E 暴露并发记账 bug → T3.8 add-only 修复 → 解钉 xfail。**M3 完成。** 下一阶段 M4文风见 DEV_PLAN进入时拉入本表。
**K1 出口DoD✅ 全部达成**作者在设置页用 Kimi Code OAuth 登录device flow显 user_code + 开授权页 + 轮询 job→ token Fernet 加密入库(`oauth_enc`,全程不进 job 结果/日志/响应)→ 把档位路由到 `kimi-code:kimi-for-coding` → 建网关时构 `KimiCodeAdapter`coding base + 伪造 UA/X-Msh-* 头 + bearer→ token 临近过期建网关时自动刷新并回写。后端门禁绿ruff/format 干净 / mypy **154** / alembic **无漂移** / pytest **434**前端门禁绿gen:api/lint/tsc/vitest **155**/buildE2E`tests/test_k1_kimi_oauth_e2e.py` 4 用例device-flow mock 零联网走通DB 真源逐项断言(含 token 不泄漏 + refresh-on-build + disconnect 清除)。**K1 完成。** **⚠️ 仍需用户用真账号对真 auth.kimi.com/api.kimi.com 做一次联网冒烟device-flow 需伪造官方客户端 UA → ToS 视为违规、可能封停会员用户已知情自担E2E/单测仅验逻辑、不联网。**
---
## 状态M1M5 全部完成(含 M5 三项收尾余项已清理)
> **当前无活跃阶段。** Phase 05M1M5已全部交付M5 的三项非阻塞收尾余项①Codex 读端点、②Anthropic/Gemini 真实适配器选择、③`packages/skills` 纳入 workspace亦已清理。各阶段详情见下方「已归档阶段」+「变更日志」。
> 最终门禁(本次全绿):后端 ruff/format 干净、mypy **144 文件**、alembic **无漂移**、pytest **400 passed**;前端 lint/typecheck 干净、vitest **130 passed**、build OK。
> **下一步若继续**DEV_PLAN §4 的 P2/后续(向量检索 / 真任务队列 / 全书一致性扫描 / 社区市场),进入时把对应任务拉入本表。
> **仍开放的非阻塞备注**@devops 复核根 `uv.lock`@backend 改了 `packages/skills/pyproject.toml` deps 后已 `uv sync` 重建 ww-skillsAnthropic/Gemini 真实回退已接线(`build_adapter` 工厂 + 按 provider 选适配器)但尚未对真 SDK 联网验证(单测/E2E 用 OpenAI 兼容 mock
---
## 已归档阶段
<details><summary>Phase 5 · 生成 + 多 provider + 扩展 (M5) — ✅ 全部完成2026-06-19</summary>
T5.1 worldbuilder + character-gen 节点C6✅扩群像防雷同注入已生成+已有 + 入库前 continuity 校验缝 `precheck_generated_cards`@llm · T5.4 网关多 provider 韧性C1✅扩Anthropic/Gemini 适配器 + 回退链 + `CircuitBreaker` + tenacity 退避 + 能力协商/降级 `served_by.degraded`,无 OpenAPI 形变)@llm · T5.5 Skill 运行时 + 规则C8 + C3✅扩`SkillRegistry.load` 越权声明拒绝 + 表权限沙箱 filter_reads/partition_writes + `POST /rules`@backend · T5.2 生成/入库 APIC3✅扩world/characters generate 预览 + POST characters 入库双 gatecontinuity 预检 409 + partition_writes 白名单 + schema→JSONB 形变 + GET rules/skills`build_gateway_for_tier` 接线 chain_from_routing 回退)@backend · T5.3+T5.6 角色生成器 + 世界观设计器 + 设定库 Codex + 规则页 + 技能库 + 命令面板⌘K@frontend · T5.7 M5 E2E + 切 provider真 Gateway deepseek 失败→openai 回退、DB ledger 记实际服务方、能力降级)@qa
出口达成后端门禁绿ruff/format 干净 / mypy 142 / pytest 391 / alembic 无漂移,复用 T0.2 既有表零建表迁移前端门禁绿gen:api / lint / tsc / vitest 125 / buildE2E 真 DB + mock 多 provider 零 token 走通。**M5 完成 → M1M5 全部交付。** 三非阻塞余项①Codex 读端点、②Anthropic/Gemini 真实适配器选择、③`packages/skills` 纳入 workspace随后于同日全部清理见变更日志 follow-up #1#4)。
</details>
<details><summary>Phase 4 · 文风 (M4) — ✅ 全部完成2026-06-19</summary>
T4.2 style-auditor 双轨 + 第四审C6✅扩/C4✅扩`style_extract_spec`(analyst,16 维指纹带证据,不进 review 图) + `style_drift_spec`(name="style",light,第四审并入 REVIEW_SPECS) + `refiner_spec`(writer 纯文本)REVIEW_SPECS 四审齐 + collect/SSE 加 style@llm · T4.1 jobs 长任务基建C3.5✅;`JobRepo`/`SqlJobRepo` + `run_job` 独立 session + lifespan zombie reaper@backend · T4.3 API style + refineC3✅扩`POST /style` 202+jobs BackgroundTask、`GET /style` 最新指纹、`POST /refine` 同步 diff 不写库)@backend · T4.4 文风页 + 漂移 + 回炉 + job 轮询(`useJobPoll` 状态机 + StyleUpload/FingerprintView + 审稿页第四审 StylePanel + RefineView diff 采纳合入)@frontend · T4.5 M4 E2E学文风→202 job→后台跑完→指纹真落 pg version+1 + 第四审 SSE/`chapter_reviews.style` 真填 + 回炉不写库)@qa
出口达成后端门禁绿ruff/format 干净 / mypy 115 / pytest 296 / alembic 无漂移,全程零建表迁移,复用 T0.2 预留的 `style_fingerprint`/`chapter_reviews.style`/`jobs`前端门禁绿gen:api / lint / tsc / vitest 96 / buildE2E 真 DB + mock 网关零 token 走通 学文风→第四审打分→回炉DB 真源逐项断言。@docs 已把 `GET /style` 回写 ARCH §7.2/PRODUCT_SPEC §6。
</details>
<details><summary>Phase 3 · 伏笔 + 节奏 (M3) — ✅ 全部完成2026-06-18</summary>
T3.1 foreshadow Repository + 纯函数状态机OPEN/PARTIAL/CLOSED/OVERDUE 全转移 + 到期判据 + `ForeshadowLedger*` 写侧 repo@backend · T3.4 outliner Agent + 伏笔窗口C6✅扩`outliner_spec` + `OutlineResult`(含 foreshadow_windows) + `run_outline` 只读节点)@llm · T3.3 foreshadow-analyst + pace-checker 节点C6✅扩/C4✅扩并入 REVIEW_SPECS 三审齐 + collect 分列 + SSE foreshadow/pace 事件)@llm · T3.2 到期扫描 BackgroundTask + 登记/状态接口(验收后 `run_overdue_scan` 自建 session 置 OVERDUE + `POST/PATCH .../foreshadow`,重复/非法→VALIDATION 422@backend · T3.5 API outline + foreshadowC3✅扩`GET .../foreshadow?status=` 看板 + `POST .../outline` upsert outline 表含窗口)@backend · T3.6 伏笔看板 + 大纲编辑器 + 节奏报告(四泳道 + beats+窗口徽标 + 审稿页节拍图▁▃▅)@frontend · T3.7 M3 E2E伏笔埋设→进展→验收后扫描 OVERDUE + 大纲含窗口 + 三审 SSEstrict-xfail 钉住并发记账 bug@qa · T3.8 [bugfix] 并行审记账并发安全(`SqlAlchemyLedgerSink.record` 改 add-only 去 `await flush`,解 AsyncSession 并发 flush 冲突xfail 转 XPASS 后解钉)@llm
出口达成后端门禁绿ruff / mypy 111 / pytest 228 passed0 xfailed/0 failed/ alembic 无漂移,`foreshadow` 表已 T0.2 建齐无新建表前端门禁绿gen:api / lint / tsc / vitest 69 / buildE2E 真 DB + mock 网关零 token 走通DB 真源逐项断言。T3.7 暴露并发记账 bug → T3.8 修复 → 解钉 xfail。
</details>
<details><summary>Phase 2 · 一致性 + 验收 (M2) — ✅ 全部完成2026-06-18</summary>
T2.1 续审 AgentSpec+结构化输出契约+网关 instructor 接线C6✅稳定改 C1`run()``parsed`@llm · T2.2 LangGraph 并行审+collect 留痕+review SSEC4✅扩@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
@@ -63,6 +90,45 @@ T0.1 monorepo 骨架 ✅ @devops · T0.2 16 MVP 表迁移无漂移users st
> 格式:`- [YYYY-MM-DD] @skill 完成/进展 Txx — 一句话结果 + 影响的契约/文件`
- [2026-06-20] @frontend**✅ 接上两个新读端点:大纲页 / 写作工作台重访时回显已存内容**。`pnpm gen:api` 纳入 `GET .../outline` + `GET .../chapters/{no}/draft` + schema `DraftView``lib/api/types.ts``DraftView` 别名。新增两个 RSC 读 helper仿 `fetchForeshadow`/`fetchProject` 服务端读、无 CORS`fetchOutline(projectId)``OutlineChapterView[]`200 解包 chapters**任何错误/空降级为 `[]`** 不阻塞进页),`fetchDraft(projectId,chapterNo)``DraftView|null`(复用 `getJsonOrNull`**404→null 当空编辑器**,不抛)。**大纲页**(`outline/page.tsx`) 进页 `fetchOutline``initialChapters` 种入 `OutlineEditor``useOutline` 已据非空初值置 `ready`)→ 重访显已生成大纲;生成流照常覆盖所显章节。**写作工作台**(`write/page.tsx` + `Workbench`) 进页 `fetchDraft``content` 作编辑器初值(`useState(initialText)`)→ 重访重载已写正文404/新章 → `""` 空编辑器;**SSE 流式写 + AbortController + PUT 自动保存全不动**(流起始空、仅 streaming/done/aborted 变化才覆盖,初值不反扑活跃流);导出 `WORKBENCH_CHAPTER_NO`(原 `M1_CHAPTER_NO`)供页面拉对应章草稿。新增 `lib/api/server.test.ts`(5 vitestmock fetch 验解包/降级/404→null)。前端门禁全绿gen:api / lint / typecheck / vitest **160**(155→+5) / build。文件`lib/api/{types,server,server.test}.ts` · `app/projects/[id]/{outline,write}/page.tsx` · `components/workbench/Workbench.tsx`。消费 contracts C3扩@backend 两读端点)。
- [2026-06-20] @backend**`GET /projects/{id}/chapters/{no}/draft` 草稿读端点(补缺口,镜像 GET /outline**。写作工作台先前只有 `POST .../draft`(SSE 流写)+`PUT .../draft`(自动保存) 无读端点 → 重访工作台编辑器空白、看似「未保存」(其实 `chapters` 行在库)。补对称读侧:`GET /projects/{id}/chapters/{no}/draft` → 200 `DraftView{project_id,chapter_no,volume,status,version,content,length}`**比 PUT 的 `DraftResponse``content`**——读侧需正文重建编辑器);无草稿行/正文空白 → **404 `NOT_FOUND`**(工作台据此呈现空编辑器,仿其它缺资源端点)。**直接复用既有 `chapter_repo.get_draft`**(同续审 `_resolve_review_draft` 读缝,`ChapterDraftView` 已含全字段,无新 repo 方法/view只读不写库多版本固定返草稿版次(`DRAFT_VERSION=1`)。文件:`schemas/projects.py`(+`DraftView`) · `routers/projects.py`(+GET endpoint+import) · `tests/test_projects.py`(+2回灌正文 / 无草稿 404)。**全仓门禁绿**ruff/format 干净、mypy **154 Success**、alembic **无漂移**、pytest **444 passed**442→+2。OpenAPI 新增 1 端点 → **@frontend`cd apps/web && pnpm gen:api`** + 工作台初次加载拉已保存草稿回灌编辑器。记 contracts C3扩。
- [2026-06-20] @backend**`GET /projects/{id}/outline` 大纲读端点(补缺口,仿 Codex 读端点)**。大纲页先前只有 `POST .../outline`(生成+落库)无读端点 → 重访页面已落库大纲不回显、看似「未保存」。补对称读侧:`GET /projects/{id}/outline` → 200 `OutlineResponse{chapters:[OutlineChapterView{no,volume,beats:list[str],foreshadow_windows}]}`(与 POST **同形**,按 chapter_no 升序);项目存在无大纲 → **200 空列表**(非 404项目不存在 → 404 `NOT_FOUND`。**复用 C5 读侧**:扩 `OutlineRepo`(domain) + `SqlOutlineRepo`(assemble 读侧) 加 `list_for_project`(仿 Character/WorldEntityRepoorder_by chapter_no既有 `get` 不动);新注入缝 `get_outline_read_repo`(仿 `get_rules_read_repo`)。beats DB JSONB `{"beats":[...]}` → 解包裸 `list[str]`(同 POST。文件`routers/outline.py`(+GET) · `services/project_deps.py`(+dep) · `domain/repositories.py`(+protocol method) · `memory/sql_repositories.py`(+impl) · `tests/{test_outline.py(+3),fakes_projects.py(+FakeOutlineReadRepo)}` + 补 2 既有 outline faketest_memory/test_projects满足扩展后的 protocol。**全仓门禁绿**ruff/format 干净、mypy **154 Success**、alembic **无漂移**、pytest **442 passed**439→+3。OpenAPI 新增 1 端点 → **@frontend`cd apps/web && pnpm gen:api`** + 大纲页初次加载拉已持久化大纲。记 contracts C3扩。
- [2026-06-19] @llm**K1.2 修头校正:恢复 opencode 规范的完整 7 头UA `KimiCLI/1.37.0`**。先前误信 `picassio/pi-kimi-coder`UA-only把头集裁成仅 UA是分歧/错误参考导致的误修——真源改为 `ooojustin/opencode-kimi``src/headers.ts`+`src/constants.ts`1:1 镜像 kimi-cli v1.37.0,已重新拉取 master 核对)。`kimi_code_headers()` 现发 7 头:`User-Agent=KimiCLI/1.37.0` + `X-Msh-Platform=kimi_cli`(字面常量)+ `X-Msh-Version=1.37.0` + `X-Msh-Device-Name`hostname ASCII 化)+ `X-Msh-Device-Model``kimi_device_model()`macOS=`macOS {mac_ver} {machine}`+ `X-Msh-Os-Version``platform.version()`+ `X-Msh-Device-Id`(稳定 32 位无连字符 `uuid4().hex`env `KIMI_DEVICE_ID` 优先→否则持久化 `~/.kimi/device_id`)。恢复 `kimi_device_id()`/`kimi_device_model()` 助手 + 重加 importsos/uuid/socket/platform/pathlib+ `__init__` 重导出。文件:`packages/llm_gateway/ww_llm_gateway/adapters/kimi_code.py` + `__init__.py` + 两测(断全 7 头键 + 固定字面值 + device-id 32 位小写 hex 稳定 + host 派生值非空 ASCIIenv 注入保 CI 确定)。更 contracts C1扩7 头 + opencode 真源)+ gotchapi-kimi-coder 分歧→回退。门禁绿ruff/format 干净、mypy 干净27 文件、pytest **60 passed**packages/llm_gateway。无 OpenAPI 形变。
- [2026-06-19] @backend**K1.3 修正device authorization 重新带 `scope=kimi-code`**(实测 401 后修。K1.5 联网实测登录拿到真 JWT 但调 `api.kimi.com/coding/v1``401 Invalid Authentication`——根因 token 缺 coding entitlement省略了 scope`start_device_authorization` 请求体加 `scope=kimi-code`=`{"client_id":<id>,"scope":"kimi-code"}`,模块常量 `KIMI_CODE_SCOPE`scope 只放 device-authtoken 交换/刷新不带。文件:`apps/api/ww_api/services/kimi_oauth.py` + 单测 `test_kimi_oauth_service.py``test_start_device_authorization_parses_response_and_sends_scope``data["scope"]=="kimi-code"`)。修正 C3扩 contract + decision「省略 scope」表述 + 加 gotcha。无 OpenAPI 形变,前端无需 re-gen。门禁绿ruff/format 干净、mypy 干净、pytest **101 passed**apps/api
- [2026-06-19] @orchestrator**🎉 K1 完成 + 独立复核Kimi Code OAuth 订阅 plan 接入)**。波次 A(K1.1 @db 加列+迁移 ‖ K1.2 @llm KimiCodeAdapter)→B(K1.3 @backend OAuth device 服务+端点+store+接线)→C(K1.4 @frontend 连接流+可编辑路由)→D(K1.5 @qa E2E) 全绿,契约先行、零返工、无新 bug。研究先行device flow at auth.kimi.com、client_id、伪造 UA/X-Msh-*、coding base、kimi-for-coding、access~15m/refresh~30d+ 对照 pi-kimi-coder/ooojustin/lemon07r 校验(省略 scope 匹配 kimi-cli v1.41.0+)。最终独立复跑确认:后端 ruff/format 干净、mypy **154 文件**、alembic **无漂移**(首个新迁移=provider_credentials 加 auth_type/oauth_enc)、pytest **434 passed**;前端 vitest **155**/build。能力闭环设置页 device-flow 登录→token Fernet 加密入库(`oauth_enc`,不泄漏)→路由 `kimi-code:kimi-for-coding`→网关构 KimiCodeAdapter(伪造头+bearer)→临过期自动刷新。**封号风险用户已知情接受**;与既有 API-key provider `kimi` 分离可切换。**唯一未尽**:对真 auth.kimi.com/api.kimi.com 的真账号联网冒烟(含封号风险,用户自担)——代码/E2E 仅验逻辑零联网。
- [2026-06-19] @qa**K1.5 ✅ K1 E2EKimi Code OAuth device-flow 全 mock → 真 pg**。新增 `tests/test_k1_kimi_oauth_e2e.py`4 用例,零联网,真 pg`POST .../oauth/start`→202 `{job_id,user_code,verification_uri,interval}`fake httpx 跑 device-auth + token(pending×2→成功) 全程;后台 `run_job` 轮询跑在**真 e2e_sm session**override `get_session_factory`→e2e_sm + monkeypatch 模块级 `kimi_oauth._default_http_client`→同一 scripted fake + `kimi_oauth.asyncio.sleep`→no-op端点 device-auth 走 `_default_http_client` dep 同样指 fake`GET /jobs/{id}` doneresult `{connected:true,provider:"kimi-code"}`**DB 真源**`provider_credentials``auth_type="oauth"`/`oauth_enc` 非空/`api_key_enc` null密文不含明文 token + 解密回环 access/refresh`GET .../oauth/status` connected 无 token。② 存 oauth + `tier_routing` writer→`kimi-code:kimi-for-coding``build_gateway_for_tier``KimiCodeAdapter`,其 `_client` 带 coding base `https://api.kimi.com/coding/v1` + UA `KimiCLI/1.5` + 全 X-Msh-* + `api_key`(=bearer)=存量 access token。③ 临近过期 oauth 包 → `_build_provider_adapter` 触发刷新fake `project_deps.kimi_refresh` + 字符串 target monkeypatch `project_deps.httpx.AsyncClient`)→ 适配器用新 token + `oauth_enc`(DB 真源)更新为新包。④ `POST .../oauth/disconnect`→凭据行清除DB 真源无 oauth。**token 全程负向断言:不进 job 结果/状态响应/start 响应/密文明文**。全仓门禁绿ruff/format 干净、mypy **154 Success**、alembic 无漂移、pytest **434 passed**430→+4。memory 记 1 gotcha。**K1Kimi Code OAuth 订阅 plan 接入)全 5 子任务 ✅,可封板。⚠️ 仍未对真 auth.kimi.com/api.kimi.com 联网验证(含封号风险,用户自担)。**
- [2026-06-19] @frontend**K1.4 ✅ 设置页 Kimi Code OAuth 连接流 + 可编辑档位路由**`pnpm gen:api` 纳入 K1.3 的 3 端点OAuthStart/Disconnect/StatusResponse`lib/api/types.ts` 加 3 别名。纯逻辑node-env vitest`lib/settings/kimiOauth.ts``connectPhase` 状态机 idle/awaiting/connected/error + `toDeviceDisplay`/`authOpenUrl`/`toConnectionStatus`/`jobConnected`/`formatExpiresAt`16 测)+ `lib/settings/providers.ts` 扩(`KNOWN_PROVIDERS``kimi-code`(auth:oauth, model:kimi-for-coding) + `API_KEY_PROVIDERS`/`TIERS`/`defaultModelFor` + 路由草稿纯函数 `toRoutingDrafts`/`applyProviderChange`/`draftsToRoutingInput`9 测)。组件:`useKimiOauth` hook**复用 `useJobPoll`**connect=POST start→展示 user_code+`window.open` 授权页+轮询 job→done 拉 statusdisconnect=POST→复位+ `KimiCodeOauth.tsx`连接区user_code 用 `<output select-all tabIndex=0>` 可读可选可聚焦 + motion-safe`ProvidersSettings.tsx` 改:档位路由从只读→**可编辑**per-tier select provider + model input + 保存 PUTAPI-key 凭据行只列 `API_KEY_PROVIDERS`OAuth 提供商有独立连接区,无 key 输入),挂入 `KimiCodeOauth``server.ts``fetchKimiOauthStatus``page.tsx` `Promise.all` 拉 providers+oauth 状态传 `kimiOauth` prop进页即显连接态。**job 结果无 token只读 connected**。前端门禁全绿gen:api / lint / typecheck / vitest **155 passed**130→+25/ build。memory 记 1 gotcha。**⚠️ 运行时对真 auth.kimi.com 设备授权 + 真 api.kimi.com 调用验证留 K1.5/手动(含封号风险,用户自担)。**
- [2026-06-19] @backend**K1.3 ✅ Kimi Code OAuth device-flow 服务 + 端点 + store + 网关接线C3 扩稳定)**。新增 `apps/api/ww_api/services/kimi_oauth.py``start_device_authorization`/`poll_token`/`refresh`,注入 `AsyncHttpClient` Protocol 零联网;`TokenSet`+`encrypt_oauth_bundle`/`decrypt_oauth_bundle` 复用 Fernet`needs_refresh` 300s 缓冲client_id env `KIMI_CLIENT_ID` 可覆盖、device authorization 省略 scope+ `routers/kimi_oauth.py``POST .../oauth/start`→202 `{job_id,user_code,verification_uri,...}`+ BackgroundTask `run_job` 后台循环轮询→成功存加密 oauth_enc+job done(结果只 `{connected,provider}`)`POST .../oauth/disconnect``{disconnected}``GET .../oauth/status``{connected,expires_at}` 无 token+ `schemas/kimi_oauth.py`3 schema+ 注册 main.py。`services/credentials.py``StoredCredential``auth_type`/`oauth_enc``api_key_enc``bytes|None`**K1.1 的 2 处 mypy red 消除**`SqlCredentialStore` 读新列 + `upsert_oauth_credential`/`delete_credential``upsert_credential` 显式置 api_key 态。`services/project_deps.py``_build_provider_adapter``kimi-code`/`auth_type=oauth``_resolve_kimi_code_token`(解密→临近过期则经 httpx 刷新+持久化→access token 喂 `build_adapter("kimi-code",…)``provider_deps.py` `_PROVIDER_BASE_URLS``kimi-code`。**token 全程不进 job 结果/日志/响应**(仅 Fernet 密文存 oauth_enc。TDD 先红后绿:`tests/test_kimi_oauth_service.py`(11) + `test_kimi_oauth_endpoints.py`(5) + `test_kimi_code_wiring.py`(3)fake httpx 零联网)。**全仓门禁绿**ruff/format 干净、mypy **154 源文件 Success**、alembic **无漂移**、pytest **430 passed**400→+30。OpenAPI 新增 3 端点 + 3 schema → **@frontend K1.4 须 `pnpm gen:api`**。memory 记 C3 扩K1.3+ 1 decision + 2 gotcha。**⚠️ 真 auth.kimi.com/api.kimi.com 联网验证(含封号风险)留 K1.5,用户自担。**
- [2026-06-19] @llm**K1.2 ✅ Kimi Code 订阅 plan 适配器C1 扩稳定)**`packages/llm_gateway/ww_llm_gateway/adapters/kimi_code.py``KimiCodeAdapter` **子类化 `OpenAICompatAdapter`**coding 端点 OpenAI 兼容,复用 complete/stream/结构化/瞬时错误包装/capabilitiesprovider 固定 `kimi-code`(与 API-key `kimi` 分离);`build_kimi_code_client(access_token, base_url?)``AsyncOpenAI(api_key=access_token, base_url="https://api.kimi.com/coding/v1", default_headers=kimi_code_headers())`——access_token 当 bearer伪造头随客户端发。`kimi_code_headers()``User-Agent` + 全 `X-Msh-*`(Platform/Version/Device-Name/Device-Model/Os-Version/Device-Id)。`kimi_device_id()`env `KIMI_DEVICE_ID` 优先,否则确定性 `uuid5` 缺省(**绝不每次随机**,稳定且来源可测/可配。model `kimi-for-coding` **不硬编码**(经 `.complete(req, model)` 传入,路由关注点)。`factory.build_adapter``provider=="kimi-code"` 分支;包 `__init__` 导出全部符号。**契约校正(已对照 `github.com/picassio/pi-kimi-coder` `extensions/index.ts`**:参考实现对 coding API **仅**设 `User-Agent: "KimiCLI/1.5"`(精确值,已采用)、**未**设 X-Msh-* 头——与 PROGRESS 契约「缺 X-Msh→403」不符本实现以验证到的 UA 为准 + 附带 X-Msh-* 客户端标识头(真客户端会发、额外标识无害、最大化避免 403**真 api.kimi.com 联网验证头集是否足够留 K1.3/K1.5(含封号风险,用户自担)**。TDD 先红后绿;`tests/test_kimi_code_adapter.py`(8) + `tests/test_kimi_code_factory.py`(3),不联网(断 base_url + default_headers + 稳定 device_id + 工厂分派)。门禁绿(隔离 `MYPY_CACHE_DIR=.mypy_cache_k12` 已清理ruff/format 干净、mypy **27 源文件 Success**、pytest **58 passed**47→+11。**@backend 行动K1.3**`_build_provider_adapter` 对 provider `kimi-code``build_adapter("kimi-code", api_key=<刷新后的 access_token>, base_url=…)`token 刷新/获取归 K1.3。**无 OpenAPI 形变**,前端无需 re-gen。memory 记 C1 扩K1.2)契约 + 1 gotcha。
- [2026-06-19] @db**K1.1 ✅ `provider_credentials` 加 OAuth 列C2 扩稳定)**`packages/db/ww_db/models.py` `ProviderCredential`:① 加 `auth_type: Mapped[str]`(`Text, nullable=False, server_default="'api_key'"`,值 api_key|oauth);② 加 `oauth_enc: Mapped[bytes|None]`(`LargeBinary, nullable=True`,持 Fernet 加密 JSON `{access_token,refresh_token,expires_at}`);③ `api_key_enc``nullable=True`(`Mapped[bytes|None]`OAuth-only 行无 api_key、既有 api_key 行保值)`UniqueConstraint(owner_id,project_id,provider)` 不变。**首个新迁移**M1M5 全零建表)`migrations/versions/1f011c42bd4d_provider_credentials_oauth_columns.py`down_revision=`220ca2e3d53f`up=add_column auth_type/oauth_enc + alter api_key_enc→nullabledown 逆向autogenerate 仅这 3 op 无 noise手修模板重复 import + 改本仓 ruff 样式(见 gotcha`upgrade head` 已应用、`alembic check` **无漂移**。门禁ruff/format 干净、pytest **400 passed**、alembic 无漂移;**mypy 余 2 处 `arg-type` 错(均在 @backend `apps/api/ww_api/services/credentials.py`,因 api_key_enc 改 nullable 打穿K1.3 吸收,见下方 @backend 请求)**。memory 记 C2 扩 + 2 gotcha。
- **[请求 → @backendK1.3]**K1.1 把 `provider_credentials.api_key_enc` 改 nullable`bytes|None`),打穿到你拥有的 `apps/api/ww_api/services/credentials.py` mypy 报 2 处 `arg-type``StoredCredential.api_key_enc: bytes` ↳ 现 `bytes|None`dataclass line 28 + store line 75/97@db 不越权改 apps/api。K1.3 接 OAuth store 时把 `StoredCredential.api_key_enc``bytes | None`(并加 `auth_type`/`oauth_enc` 字段 + OAuth 读写路径mypy 即全绿。oauth_enc 持 Fernet 加密 JSON `{access_token,refresh_token,expires_at}`key=`settings.credential_enc_key`,同 api_key_enc
- [2026-06-19] @orchestrator**🎉 M1M5 全部交付 + M5 余项收尾完成**。五个里程碑Phase 05全部 ✅M5 三项非阻塞余项 + 本次台账归档共四项 follow-up 已清:**#1** Codex 读端点(`GET /projects/:id/characters` + `GET .../world_entities`@backend+ 前端接线CodexPage 拉全量真源,去「会话内回显」局限,@frontend**#2** `build_adapter` provider→适配器工厂 + anthropic mypy 修复(@llm`build_gateway_for_tier` 按 provider 选适配器启用 Anthropic/Gemini 真实回退(@backend**#3** `packages/skills` 纳入 uv workspace + skill implregistry/permissions`ww_core.domain` 迁入 `ww_skills`@backend@devops 加 SDK**#4** 本次把 M5/M4/M3 三段折叠进「已归档阶段」、顶部改短状态行(@orchestrator)。最终门禁全绿:后端 ruff/format 干净、mypy **144 文件**、alembic **无漂移**、pytest **400 passed**;前端 lint/typecheck 干净、vitest **130 passed**、build OK。台账已归档当前无活跃阶段。
- [2026-06-19] @frontend**M5 follow-up #1 ✅ Codex 展示真源(解余项①)**(消费 @backend C3 扩 Codex 读端点,无契约变更)。先 `pnpm gen:api` 纳入 `GET /projects/:id/characters``CharacterListResponse{characters?}`+ `GET .../world_entities``WorldEntityListResponse{world_entities?}`+ `lib/api/types` 加 2 别名。`lib/api/server``fetchCharacters`/`fetchWorldEntities`200 空列表非 404仿 `fetchForeshadow`codex routeServer Component`Promise.all` 拉 项目+人物+世界观全量 → 传 `CodexPage` 初始数据。`CodexPage` 人物 tab 渲染**跨会话持久化真源**(刷新不再空),本会话新入库卡经纯函数 `mergeCharacterCards`(按 name 去重、持久化优先、不重复合并补显generate→ingest 后仍即时见新行);世界观 tab 渲染入库真源(本期无世界观入库端点,故只真源 + 生成器预览,无 session 合并);时间线维持 P2 占位。纯逻辑 `lib/generation/cards.{mergeCharacterCards,mergeWorldEntities}` + 5 node-env 单测。前端门禁全绿gen:api/lint/tsc/**vitest 130**125→+5/build。**Codex「会话内回显」局限已去除**(解 gotcha + PROGRESS 余项①。memory 把 Codex 缺口 gotcha 标 RESOLVED。
- [2026-06-19] @backend**M5 follow-up R1 + R3 ✅**(三 fix与并行 @llm `llm_gateway` 改动 disjoint。**R1-Codex 读端点**(解余项①):加 `GET /projects/:id/characters``CharacterListResponse`+ `GET /projects/:id/world_entities``WorldEntityListResponse`),复用 C5 读侧 `SqlCharacterRepo`/`SqlWorldEntityRepo`(经 `get_memory_repos`,不动 assemble+ 反向 JSONB 解包(`{"items":[...]}`→list/`{"text":...}`→str/`{"rules":[...]}`→listregister mainC3 扩稳定。**R3-skill 迁包**(解余项③):`skill_registry.py`+`skill_permissions.py``ww_core.domain` **迁入** `packages/skills/ww_skills/``ww_skills/__init__` 改直接导出删门面importer`generation.py`/`project_deps.py`/`test_generation.py`)改 `from ww_skills import …`skill 单测移 `packages/skills/tests/`13 测);删 ww_core.domain 两模块+__init__ 导出;`packages/skills/pyproject.toml` deps 校准(去 `ww-core`、补 `ww-llm-gateway`+`sqlalchemy``uv sync` 重建。**R1#2-build_adapter 接线**(解余项②的 apps 侧;@llm`build_adapter` 工厂 + @devops 的 anthropic/google-genai SDK 均已落地import 实解非 transient`build_gateway_for_tier``_build_provider_adapter`(原 `_build_openai_compat_adapter`)改调 `ww_llm_gateway.build_adapter(provider, api_key=…, base_url=…)`——Anthropic/Gemini 传 base_url=None 走原生适配器,去掉直接 `AsyncOpenAI`/`OpenAICompatAdapter` import。门禁绿隔离 `MYPY_CACHE_DIR=.mypy_cache_r1backend` 已清理ruff/format 净、mypy **101 文件 0 error**、pytest `packages/core packages/skills apps/api` **246 passed**226→+20+10 迁移 skill 测 +3 Codex 读端点测 + 其余)。两新端点入 OpenAPI验证 get 存在。memory 登记 C3 扩Codex 读端点)+ C8 实现位置更新 + build_adapter 接线 + 3 decisions。**@frontend 行动**`cd apps/web && pnpm gen:api` 纳入 `GET characters`/`GET world_entities`CodexPage 初始列表拉全量去掉「会话内」局限(解 gotcha Codex 缺口)。**@devops 行动**:复核根 `uv.lock`@backend 改了 `packages/skills/pyproject.toml` deps`uv sync` 重建 ww-skills。**M5 三非阻塞余项①②③ 至此全部清除。**
- [2026-06-19] @llm**R2 follow-up #2 ✅ 真多 provider 适配器选择**C1 扩 follow-up #2 稳定;接 @devops 已加 `anthropic`+`google-genai` SDK 之后)。① **修真 SDK 装上后的 mypy 报错**`instructor.from_anthropic(self._client)` 重载只收 SDK 具体 `AsyncAnthropic|...``AnthropicClient` Protocol 不匹配 → adapter 内 `cast("AsyncAnthropic", self._client)``TYPE_CHECKING` import零运行时硬依赖选中 AsyncInstructor 重载。gemini 走 `response_schema` 非 instructor**无**该类错。② **新增 provider→适配器工厂** `factory.build_adapter(provider, *, api_key, base_url=None) -> ProviderAdapter`(包 `__init__` 导出):`anthropic``AnthropicAdapter``{gemini,google}``GeminiAdapter`、其余→`OpenAICompatAdapter(provider, AsyncOpenAI(...))`;从 api_key 构真实客户端factory 处 `cast` 跨 Protocol read-only-attr 约束adapter 仍声明 Protocol 形参、测试替身缝完好)。新增 `tests/test_build_adapter_factory.py` 6 测(按 provider 名断分派,不联网)。**门禁绿**(隔离 cacheruff/format 净、mypy **24 源文件 0 错**、pytest **47 passed**41→+6全仓 `mypy packages apps` **144 文件 Success**anthropic.py 报错确认消除、gemini 无同类错)。无 OpenAPI 形变served_by 不出 API前端无需 re-gen。**@backend 可在 `build_gateway_for_tier``build_adapter` 替换「一律 OpenAICompatAdapter」启用 anthropic/gemini 真实回退。** 记 1 gotchaProtocol vs 真 SDK cast 边界)。
- [2026-06-19] @orchestrator**🎉 M5 完成 + 独立复核 ✅**Wave CT5.3+T5.6 ✅ + Wave DT5.7 ✅)。波次 A(T5.1‖T5.4‖T5.5)→B(T5.2)→C(T5.3+T5.6)→D(T5.7) 全绿,契约先行、零返工、无新 bug。最终独立复跑确认后端 ruff/format 干净、mypy **142 文件**、**alembic 无漂移**M5 复用 T0.2 既有 world_entities/characters/rules/skills 表全程零建表迁移、pytest **391 passed**;前端 tsc 干净、**vitest 125 passed**。**M5生成+多provider+扩展)出口 DoD 全达成**worldbuilder/character-gen 生成→预览→入库continuity 409 gate + partition_writes 白名单 + schema→JSONB 形变);网关多 provider 回退/熔断/能力降级(真 Gateway 回退链E2E 验主失败→fallback 服务 + 记账记实际 providerSkill registry + 表权限沙箱 + 规则页/技能库/命令面板(⌘K)。**M1M5 全部交付。** 非阻塞余项:① Codex 读端点缺口(无 GET characters/world_entities现以生成+会话内回显管理);② Anthropic/Gemini 真实回退待 @devops 加 SDK + 按 provider 选适配器类E2E 用 OpenAI 兼容 mock 验证回退);③ `packages/skills` 纳入 uv workspace现 impl 落 ww_core.domain + façade。建议下一步清理 PROGRESS 把 M3/M4/M5 折叠归档,或处理上述余项。
- [2026-06-19] @qa**M5 Wave DT5.7✅ M5 E2E + 切 provider**(真 pg + mock 多 provider零 token无契约变更`tests/test_m5_e2e.py` 3 用例:**① 群像生成→入库闭环**mock 网关按 `req.output_schema` 路由 CharacterGenResult/WorldGenResult/ContinuityReview`POST /world/generate` 预览 + `POST /characters/generate` 预览 3 卡 → `POST /characters` 入库**双 gate**——precheck 有冲突且未 `acknowledge_conflicts`**409 CONFLICT_UNRESOLVED**+`details.conflicts`(并断言此刻 characters 表无行,守不变量 #3)→ 带 `acknowledge_conflicts=true` 重发 201**DB 真源**断言 characters 行真落 pg + **schema→JSONB 形变**traits/speech_tics→`{"items":[...]}`、arc→`{"text":...}`、tags/relations 直落 list`rejected_tables`partition_writes 合法路径4 条 ledger。**② 切 provider 回退**HTTP 角色生成跑在**真 `Gateway`**(非 stubdeepseek(每次 `complete``TransientProviderError` 耗尽重试)→openai 回退链上,端点仍 200`served_by` 不出 API故经 **DB 真源 `usage_ledger`** 断言实际服务方 = **openai(fallback)≠deepseek(primary)**ARCH §4.5 记账记实际服务方)。**③ 能力降级**`structured_output=False` 唯一 provider 直测 `Gateway.run``served_by.degraded=True`§4.4)。坑:生成网关是**请求 scope 依赖**`get_worldbuilder_gateway`/`get_character_gen_gateway`/`get_precheck_gateway`),直接 `app.dependency_overrides` 注假网关即可,**无需** monkeypatch `build_gateway_for_tier`(与 M4 学文风后台自建网关不同。全仓门禁绿ruff/format 净、mypy **142 文件**、**alembic 无漂移**、pytest **391 passed**388→+3。**未发现 REAL bug**。**M5 出口 DoD 全达成** → orchestrator 可封 M5。
- [2026-06-19] @frontend**M5 Wave CT5.3+T5.6✅ 生成 + 设定库 + 规则 + 技能 + 命令面板**(消费 C3 扩 T5.2 + C8/T5.5,无契约变更)。先 `pnpm gen:api` 纳入 5 端点world/characters generate + characters ingest + GET rules + GET skills+ `lib/api/types` 加 12 别名。**T5.3**:① **角色生成器**UX §6.6`components/generation/CharacterGenerator`:一句话 brief + 数量(112) + 定位 → `POST /characters/generate` 预览卡 → `CharacterCardItem`(勾选入库 + 就地编辑名/弧光,默认全选)→ `POST /characters` 入库;**409 CONFLICT_UNRESOLVED 裁决流**`useCharacterGen` 捕 409 → `extractIngestConflicts` 收窄 `details.conflicts`(复用 ReviewConflict 形) → `ConflictAdjudication` 面板展示 continuity 冲突 → 作者「已知悉强制入库」= 带 `acknowledge_conflicts=true` 重发 / 「取消改卡」。② **世界观设计器** `WorldGenerator``POST /world/generate` 预览 type/name/rules本期无入库端点仅预览参考。③ **设定库 Codex**UX §6.5`codex/CodexPage` + `app/projects/[id]/codex`:人物/世界观/时间线三 tab时间线 P2 占位);`?gen=character|world` 命令面板跳转直开对应 tab。**T5.6**:④ **规则页** `rules/RulesPage` + `app/.../rules`:四级规则列表(`groupByLevel`) + 新增(`useRules` 乐观追加+回滚,仿 useForeshadow)。⑤ **技能库** `skills/SkillsPage`Server Component 纯读)+ `app/.../skills``GET /skills` 按 scope 分组只读注册表(name/tier/reads/writes)。⑥ **命令面板 ⌘K** `command/{CommandPalette,CommandPaletteMount}` + `lib/command/palette`⌘K/Ctrl+K 开关、模糊过滤(`filterCommands`)、上下循环高亮(`moveHighlight`)、Esc/Entera11y(role=dialog/listbox/option + 自动聚焦 + prefers-reduced-motion);挂 RootLayout 对全局生效,读 pathname 注入项目上下文。⑦ LeftNav `ActiveNav` 加 codex/rules/skills替换原 disabled 设定库占位。纯逻辑全单测node-env`lib/{generation/cards,rules/rules,skills/skills,command/palette}.test`。前端门禁全绿gen:api/lint/tsc/**vitest 125**(96→+29cards 12 + rules 5 + skills 3 + palette 9)/buildcodex/rules/skills 路由齐。memory 记 2 gotcha + 1 gapCodex 读端点缺口)。**M5 前端交付完成** → 下一步 **Wave DT5.7(@qa) M5 E2E + 切 provider**
- [2026-06-19] @orchestrator**M5 Wave B 收口 ✅**T5.2C3 扩稳定。5 端点入 OpenAPIworld/characters generate 预览 + characters 入库(双 gatecontinuity 预检 409 + partition_writes 白名单 + schema→DB 形变)+ GET rules/skills`build_gateway_for_tier` 接线回退链OpenAI 兼容齐Anthropic/Gemini 真实切换余量 deferred 给 T5.7 + @devops SDK。全仓门禁绿ruff/format 干净、mypy **142 文件**、**alembic 无漂移**、pytest **388 passed**371→+17。下一步 **Wave CT5.3+T5.6(@frontend 单 agent 顺序做)**——先 `pnpm gen:api`,做 角色生成器 + 世界观设计器 + 设定库 Codex + 规则页 + 技能库 + 命令面板⌘K入库流处理 409 裁决重发。
- [2026-06-19] @backend**M5 Wave BT5.2✅ 生成/入库 API**(契约 **C3 扩稳定**;消费 Wave A 的 C6扩/C8/C1扩与已合并 Wave A 无写冲突)。`routers/generation.py`+ `skills_router`,已注册 main落 5 端点:① `POST /world/generate`worldbuilder writer 网关 `run_worldbuilder`**预览**世界观,不入库,末尾 commit 落 ledger② `POST /characters/generate`character-gen writer 网关,注入已有角色防雷同 → **预览**角色卡);③ `POST /characters`(入库 **双 gate**`precheck_generated_cards` continuity 预检 analyst 网关——有冲突且未 `acknowledge_conflicts`**409 CONFLICT_UNRESOLVED**+冲突详情,作者裁决后放行;`partition_writes(character_gen_spec,...)` 白名单过滤越权写表;过 gate 写 `characters` 行,**schema list/str → DB JSONB dict 形变**);④ `GET /rules`(规则列表,复用 C5 读侧);⑤ `GET /skills`(技能库,经 registry。新写侧 repo `ww_core.domain.{character_repo(traits/speech_tics→{"items"}/arc→{"text"}),world_entity_repo(rules→{"rules"})}`(只 flush端点 commit。**T5.4 follow-up 接线完成**`build_gateway_for_tier` 据 DB `tier_routing.primary+fallback` 预备多 `OpenAICompatAdapter` + 注入 `chain_resolver=chain_from_routing(...)` 启用回退链;无路由行退回 `resolve_route`(单 providerM1 兼容无可用凭据→503。**仅 OpenAI 兼容 provider**deepseek/kimi/qwen/glm/openai——Anthropic/Gemini 真实回退需 @devops 加 SDK + provider_deps 据 provider 选适配器类(**余量 deferred 给 T5.7 切 provider**。全仓门禁绿ruff/format 净、mypy **142 文件**、**alembic 无漂移**M5 复用 T0.2 既有表、pytest **388 passed**371→+1713 生成/入库端点 + 4 网关回退接线 + 4 形变 helper。新端点入 OpenAPI验证 world/characters generate + POST characters + GET rules + GET skills 齐。memory 登记 C3扩稳定 + 2 decisions入库 gate / 形变)+ 2 gotchas。**@frontend(T5.3/T5.6) 行动**:先 `cd apps/web && pnpm gen:api` 纳入这 5 端点;入库流处理 409展示冲突→裁决勾选→带 `acknowledge_conflicts` 重发)。下一步 **Wave CT5.3+T5.6(@frontend)**(依赖 T5.2✅+T5.5✅,可起)。
- [2026-06-19] @orchestrator**M5 Wave A 收口 ✅**T5.1 + T5.4 + T5.5 三 agent 并行disjoint 目录 + 隔离 mypy cache零写冲突零返工。worldbuilder/character-gen 双 spec + 节点 + 入库前 continuity 校验缝C6扩‖ 网关多 provider 韧性Anthropic/Gemini 适配器 + 回退链 + 熔断 + 能力降级C1扩无 OpenAPI 形变)‖ Skill registry + 表权限白名单filter_reads/partition_writes+ `POST /rules`C8 + C3扩。全仓门禁绿ruff/format 干净、mypy **135 文件**、**alembic 无漂移**M5 复用 T0.2 已建的 world_entities/characters/rules/skills 表无建表迁移、pytest **371 passed**296→+75。**Wave B 衔接待办**T5.2 @backend 须处理):① 角色 schema `traits`/`speech_tics`(list)/`arc`(str) ↔ DB JSONB **dict** 形变,入库须转换;② 入库 gate 调 `precheck_generated_cards`(continuity 冲突拦截) + `partition_writes`(越权写丢弃审计);③ 补 `GET /rules` + `GET /skills` 供 T5.6 前端;④ 接线 `build_gateway_for_tier``chain_from_routing` 启用回退链T5.7 切 provider 依赖)。**@devops 待办**:加 `anthropic`/`google-genai` SDK 依赖(适配器懒 import单测不需评估把 `packages/skills` 纳入 uv workspace现 impl 落 ww_core.domain + ww_skills façade。下一步 **Wave BT5.2(@backend 生成/入库 API)**
- [2026-06-19] @llm**M5 Wave AT5.4✅ 网关多 provider 韧性**(契约 **C1 扩稳定**,仅扩 `packages/llm_gateway/`,与并行 T5.1 @llm 无文件冲突)。① **新适配器**`adapters/anthropic.py`(`AnthropicAdapter`:原生结构化经 instructor.from_anthropic 懒构建、`cache_control` 缓存断点、thinking 能力)+`adapters/gemini.py`(`GeminiAdapter``response_mime_type=json+response_schema` 结构化、thinking)——**均经注入的客户端 Protocol不硬 import anthropic/google-genai SDK单测零联网零依赖**。② **回退链 + 重试 + 熔断**`gateway.py``Gateway``chain_resolver`/`max_retries`/`breaker`(保留 `resolver=` M1 兼容→自动包成单元素链);沿链逐 provider→瞬时失败(tenacity 指数退避)重试 R 次→仍失败/熔断打开/无适配器→切下一个;首个成功者服务、非链首标 `served_by.fell_back`;链耗尽抛 `LLM_UNAVAILABLE`;记账记**实际服务方**(回退后不记主模型);流式仅首块前可切(产出后中途失败上抛不重连)。`CircuitBreaker(threshold/reset_seconds/clock)` 连续失败超阈值短时熔断、成功清零、冷却半开。③ **能力协商/降级**:结构化请求按 `capabilities().structured_output` 重排链优先选支持者;链上无支持者→降级首个可用(适配器自走 instructor JSON 提示)标 `served_by.degraded`。④ **瞬时错误契约**`errors.py``TransientProviderError`(三适配器按异常类名+status_code 包装)+网关视 `AppError(RATE_LIMITED)` 可重试。⑤ **routing.py**`resolve_chain`/`chain_from_routing`(据 DB tier_routing 去重保序)/`ChainResolver` 别名导出。⑥ `ServedBy``degraded`(向后兼容,默认 False)`pyproject.toml``tenacity>=8.2`。**23 新测**(test_fallback_chain 10/test_capability_degradation 4/test_new_adapters 7/test_multi_provider_accounting 2),包内 **41 passed**全仓门禁绿ruff/format 净、mypy **135 文件**、core+api **226 passed**(无回归)。**无 OpenAPI 形变**(served_by 不出 API前端无需 re-gen)。memory 登记 C1 扩 + 2 gotcha。**后续待办**apps/api `build_gateway_for_tier` 接线回退链(预备多适配器+传 chain_resolver=chain_from_routing 包装)、@devops 加 anthropic/google-genai SDK 依赖供真实接线。下一步 Wave B(T5.2 @backend,依赖 T5.1)。
- [2026-06-19] @backend**M5 Wave AT5.5✅ Skill 运行时 + 规则**(契约 **C8 + C3 扩稳定**;与并行 T5.1/T5.4 @llm 无目录/写冲突,隔离 `MYPY_CACHE_DIR=.mypy_cache_t55`)。① **Skill registry loader**`packages/core/ww_core/domain/skill_registry.py``SkillRecord`(frozen,skills 行声明快照) + `SkillRepo` Protocol + `SqlSkillRepo`(读 `skills` 表,裸 tier 非法→VALIDATION + `SkillRegistry.load(repo)`async每条跑 `validate_declaration`越权声明→AppError VALIDATION 加载中断frozen `dict[name,AgentSpec]`+ `get`/`names`/`list_scope`。复用 §5.1 网关机制(不重实现网关),不变量#2 只带 tier。② **表权限沙箱**`skill_permissions.py`,纯函数/不可变§5.6「声明式权限+apply 层白名单」非进程沙箱):`KNOWN_TABLES`(10 创作表白名单) + `filter_reads`(注入只喂声明 reads 表) + `partition_writes`(写库只应用声明 writes越权→rejected 供审计 log+丢弃) + `validate_declaration`(reads/writes 越界→VALIDATION)。守不变量#3allowed 仍过验收 gate不开写后门。③ **`POST /projects/:id/rules`**`routers/rules.py`,已注册 main`RuleCreateRequest{level:Literal[global/genre/style/project],content(min1)}`→**201** `RuleView{level,content}`,非法 level/空 content→FastAPI 422写侧 `domain/rule_repo.py`(`RuleWriteRepo`/`SqlRuleWriteRepo`/`RuleWriteView`,只 flush,端点 commit);喂 assemble 四级 `merge_rules`。④ 注入缝 `get_rule_write_repo`/`get_skill_registry``project_deps`。门禁绿限本任务范围ruff/format 净、`MYPY_CACHE_DIR=.mypy_cache_t55 mypy packages/skills packages/core apps/api` **0 error/94 文件**、pytest `packages/skills packages/core apps/api` **226 passed**+18 新测6 permissions + 4 registry + 2 rule_repo + 3 rules 端点 + 既有)。`POST /rules` 已入 OpenAPI验证。**实现位置决策**registry/沙箱落 `ww_core.domain`§5.6 强制点在编排/写库层 + `packages/skills` 当前非 uv workspace member根 pyproject @devops 未接线);`ww_skills` 留再导出门面,待 @devops 纳入 workspace 可迁移(见 decisions/gotchas。**@frontend(T5.6) 行动**:先 `cd apps/web && pnpm gen:api` 纳入 `POST /rules`(规则页);技能库经 `get_skill_registry`(若 T5.6 需 GET /skills 端点,请在此提请 @backend 补)。**@llm/T5.2 行动**:生成入库层用 `partition_writes` 守自定义 skill 产出白名单(仅声明 writes 表),仍过验收。
- [2026-06-19] @llm**M5 Wave A 半程T5.1✅**C6 扩稳定,与并行 T5.4 @llm/T5.5 @backend 无目录/写冲突,隔离 MYPY_CACHE_DIR。worldbuilder + character-gen 落地:① schema`packages/agents/ww_agents/schemas.py``WorldEntityCard{type,name,rules:list[str]}`/`WorldGenResult{entities}` + `CharacterRelation{name,kind,note?}`/`CharacterCard{name,role,traits,backstory,arc,speech_tics,tags,relations}`/`CharacterGenResult{cards}`——**字段对齐 `world_entities`/`characters` DB 列**供 T5.2 ingest 直映。② specspecs.py`worldbuilder_spec`(writer,reads=projects,writes=world_entities,硬规则显式 prompt)、`character_gen_spec`(writer,reads=world_entities+characters,writes=characters,**system_prompt 注入「已生成卡+已有角色」差异化要求=M5-a 防雷同**)。③ 生成节点(`packages/core/ww_core/orchestrator/generation_node.py`,模块内自有 GatewayRun Protocol不重复导出`run_worldbuilder`/`run_character_gen``build_character_gen_context` 把已有+已生成卡序列化成 `name(role)traits` 简表注入空时占位不崩独立生成、网关失败上抛、parsed 违约 ValueError只读不写库。④ **入库前 continuity 校验缝**ARCH §6.5`precheck_generated_cards(spec=continuity_spec,*,cards,world_context,characters_context,...)->list[Conflict]`——编排器追加的检查、**非 character-gen 直接互调**(守 §5.4/不变量#1T5.2 入库端点调它做 gate。门禁绿限本任务文件ruff/format 净、mypy 本任务 7 文件 0 error`packages/agents packages/core` 余 3 error 全在并行 @backend T5.5 的 rule_repo/skill 测试、pytest **246 passed**(+34 新测22 spec 契约 + 12 节点/防雷同/校验缝)。memory 登记 **C6 扩稳定**。**T5.2(@backend) 行动**`POST /world/generate`→run_worldbuilder、`/characters/generate`→run_character_gen(批量循环把已产卡传 generated_so_far)、`POST /characters` 入库前调 precheck_generated_cards gateanalyst/writer 网关复用 build_gateway_for_tier。下一步 **Wave BT5.2**(依赖本任务✅,可起)。
- [2026-06-19] @docs — spec 一致性回写:把 T4.3 顺带新增的 `GET /projects/:id/style`(最新指纹 `{dimensions, evidence, version}`,无指纹 404补进 ARCHITECTURE.md §7.2 端点表(紧邻 `POST /style` 行)+ PRODUCT_SPEC.md §6 端点清单(紧邻 `POST /style` 行),消除 code↔spec 漂移。`memory/decisions.md` 该决策的「待回写规格」flag 至此**已解决**。仅改两份 spec未动代码/测试。
- [2026-06-19] @orchestrator**M4 收官独立复核 ✅**。波次按计划走通 A(T4.2‖T4.1)→B(T4.3)→C(T4.4)→D(T4.5),每波契约先行 + 全仓门禁收口、零返工、无新 bug。最终独立复跑后端门禁确认绿ruff/format 干净、mypy **115 文件**、**alembic 无漂移**M4 全程零建表迁移,全靠 T0.2 预留的 `style_fingerprint`/`chapter_reviews.style`/`jobs` 列表、pytest **296 passed**;前端 gen:api/lint/tsc/vitest **96**/build 绿。**M4文风出口 DoD 全达成**:学文风(16 维指纹带证据,版本化,异步 jobs+zombie reaper) + 漂移打分作为第四审真持久化(review 四并行分支+SSE `style`+`chapter_reviews.style`) + 回炉同步 diff(不写库守不变量#3)。Phase 4 完成M1M4 全部交付。下一阶段 M5(生成+多 provider+Skill) 见 DEV_PLAN进入时归档 M3/M4 并拉入新表。
- [2026-06-19] @qa**🎉 M4 完成**Wave DT4.5✅ M4 E2E`tests/test_m4_e2e.py` 真 pg + 多档位 mock 网关(零 token真跑通过 3 用例:① **学文风闭环**`POST /style`→**202** `{job_id}`→BackgroundTask `run_job` 自建独立 session 跑 `run_style_extraction`(analyst 假适配器产 StyleFingerprintResult)→`SqlStyleFingerprintWriteRepo.append` 真落 pg→`GET /jobs/{id}` status=done(result.version/dims_count)→`GET /style` 最新指纹→`mode="update"` 学一次 version+1DB 真源 `style_fingerprint` 2 行(version 1/2,dimensions/evidence)+ `jobs` 2 行 done。② **写章第四审**:学文风后 assemble stable_core 含指纹→`POST .../review` SSE 四审齐(continuity/foreshadow/pace/style)无 error + `section{name:"style"}` + `style{score:72,segments:[{idx:2,score:40,label:"机翻腔"}]}` 帧真发 + `GET .../reviews` 留痕 style(dict)DB 真源 `chapter_reviews.style` 列真填。③ **回炉**`POST .../refine`→200 `{original,refined}`,refined≠original(writer 据 output_schema is None 返改写串)+ 不写库(无 chapter/review 行,不变量#3)+ writer 记账落 usage_ledger。**无新 bug**。关键坑(记 memory/gotchas):学文风 BackgroundTask 在独立 session 上**自造网关**(`build_gateway_for_tier` 从凭据建真 OpenAI 适配器)→E2E 无真凭据,须 monkeypatch `style.build_gateway_for_tier`→真 Gateway 包假适配器(ledger 绑入参 session);写侧 repo + `run_job` 默认 `SqlJobRepo` 保持真→指纹/job 真落 pg;override `get_session_factory``e2e_sm`(同测试 engine/loop)。最终全收口门禁绿ruff/format 干净、mypy **115 文件**、pytest **296 passed**(293→+3)、**alembic 无漂移**(M4 无建表迁移)。**M4 出口 DoD 全达成 → Phase 4 可归档。**
- [2026-06-19] @frontend**M4 Wave CT4.4✅ 文风页 + 漂移 + 回炉 + job 轮询**(消费 C3 扩 + C4 扩,无契约变更)。先 `pnpm gen:api` 纳入 style/refine/GET-style + jobs 类型(`lib/api/types` 加 4 别名)。① **job 轮询**:新模式 `lib/jobs/job.ts`(纯状态机 `narrowJob`/`reducePoll`/`isTerminal`/`styleLearnResult`——`GET /jobs/{id}` 是松散 `{[k]:unknown}` 裸端点须安全收窄) + `useJobPoll.ts`(setTimeout 轮询done/failed 终态停,卸载清理)。② **文风页** `app/projects/[id]/style/page.tsx`(RSC 取 project + `GET /style`→404 容忍返 null) + `components/style/``StyleUpload`(多段文本粘贴/选文件 `file.text()` 读成文本→空行切段→`POST /style`)、`useStyleLearn`(受理 202→`useJobPoll`→done 拉指纹)、`FingerprintView`(16 维行+可展开证据)。③ **审稿页第四审**`lib/review/sse.ts``StyleEvent`/`StyleDriftReport`/`reduceReview` case "style"(替换式仿 pace)/`ReviewStreamState.style`/seed`history`-style 收窄 `normalizeStyleDrift``lib/style/style.ts``StylePanel`(◔ 整体相似度% + 漂移段一键回炉)接进 ReviewReport(seed 扩四态)。④ **回炉** `RefineView` + `useRefine`(`POST /refine`→新旧 diff→采纳把 refined 替换 finalText 中原段,经既有 draft 路径合入,不另写库守不变量#3503 优雅提示)。LeftNav 开「文风」入口(`ActiveNav` 加 "style")。前端门禁全绿gen:api/lint/tsc/**vitest 96**(+27job 12 + style 10 + style-sse 5)/build(含 `/projects/[id]/style` 路由)。memory 记 1 gotcha。下一步 **Wave DT4.5(@qa) M4 E2E**
- [2026-06-19] @orchestrator**M4 Wave B 完成 ✅**T4.3C3 扩稳定。style/refine 三端点入 OpenAPI`POST /style`(202+jobs BackgroundTask 跑 run_style_extraction→StyleFingerprintWriteRepo.append)、`GET /style`(最新指纹含证据/版本)、`POST /refine`(writer 网关同步返 {original,refined} 不写库)。全仓门禁绿ruff/format 干净、mypy **115 文件**、**alembic 无漂移**、pytest **293 passed**(+13)。`GET /style` 顺带补入(回写 ARCH §7.2/PRODUCT_SPEC §6 留 @docs)。下一步 **Wave CT4.4(@frontend)**——先 `pnpm gen:api` 纳入 style/refine/GET-style + jobs 类型,再做文风页(上传/指纹/证据) + `lib/jobs/useJobPoll` + 审稿页第四审 StylePanel + 回炉 diff。
- [2026-06-19] @backend**M4 Wave BT4.3✅ API style + refine**(契约 **C3 扩稳定**)。三端点入 OpenAPI独立 `routers/style.py`,仿 outline.py已注册`POST /projects/:id/style`**202** `{job_id}`(学文风走 jobsM4-c`job_repo.create("style_learn")`+commit → `background_tasks.add_task(run_job, session_factory, job.id, work)``work``run_job` **自建独立 session** 上自造 analyst 网关+写侧 repo → `run_style_extraction` → 拆 `dimensions_json`/`evidence_json``append`(version+1) → `{version,dims_count}``jobs.result`;无凭据 → dep 解析阶段 **503**(调度 job 前拦下,不凭空写注定失败的 job。② `POST /projects/:id/chapters/:no/refine` → 同步 200 `{original,refined}`writer 网关 `run(refiner_spec)``output_schema=None``resp.text`;不写库守不变量#3;末尾 commit 让 usage_ledger 落库)。③ **顺带补 `GET /projects/:id/style`** → 最新指纹 `{dimensions,evidence,version}`UX §6.9ARCH §7.2 原缺读端点——决策见 decisions**待 @docs 回写 ARCH §7.2/PRODUCT_SPEC §6**);不动 C5 读侧 `SqlStyleRepo`assemble 行为不变)。新建写侧 `domain/style_repo.py`(`StyleFingerprintWriteRepo`/`Sql*``append` 只 flush + `latest` 含证据/版本)`project_deps``get_style_write_repo`/`get_style_extract_gateway`(analyst)/`get_refine_gateway`(writer)。全仓门禁绿ruff/format 干净、mypy **115 文件**、**alembic 无漂移**(M4 无建表)、pytest **293 passed**(280→+13)。memory 登记 C3 扩 + 2 decisions + 1 gotcha。**@frontend 行动**T4.4 前 `cd apps/web && pnpm gen:api` 纳入 style/refine/GET style + jobs 轮询类型。下一步 **Wave CT4.4(@frontend)**
- [2026-06-19] @orchestrator**M4 Wave A 收口 ✅**T4.2 + T4.1 全绿。全仓门禁收口ruff/format 干净、mypy **111 文件**、**alembic 无漂移**M4 无建表迁移、pytest **280 passed**M3 基线 228 → +52T4.2 37 + T4.1 15。契约稳定C6扩/C4扩StyleFingerprintResult/StyleDriftReview/四审齐/SSE style 事件、C3.5JobRepo/run_job。下一步 **Wave BT4.3(@backend)**——单 @backend agent 顺序做 style/refine 两端点:新建 `StyleFingerprintWriteRepo` + `routers/style.py`(`POST /style` 202 调 `job_repo.create`+`run_job`(work=`run_style_extraction``StyleFingerprintWriteRepo.append`)`POST /refine` 同步 `refiner_spec` writer 网关返 {original,refined})C3 扩;评估顺带 `GET /projects/:id/style`
- [2026-06-19] @backend**M4 Wave AT4.1✅ jobs 长任务基建**(契约 **C3.5 稳定**,不碰 style 业务,与并行 T4.2 @llm 无目录/写冲突)。`packages/core/ww_core/domain/job_repo.py``JobRepo` Protocol + `SqlJobRepo`(create/set_running/set_progress 夹取/complete/fail/get/reap_zombies) + frozen `JobView`——状态写**只 flush**(提交归 `run_job`/端点),唯 `reap_zombies` 启动期独立调用故**自 commit**。`apps/api/ww_api/services/job_runner.py`:通用 `run_job(session_factory, job_id, work)` **自建独立 session**(仿 `run_overdue_scan`)→set_running→work→complete/异常→新 session fail异常吞不冒泡最小 `JobLifecycleRepo` Protocol + 可注入 `repo_factory` 缝。`get_job_repo` 加进 `project_deps``main.py` lifespan 在 `seed_stub_user` 后跑 reaper(M4-d幂等自 commit)。门禁绿(限本任务文件)ruff/format 干净、mypy 本任务文件 0 error(`packages/core apps/api` 余 7 error 全在 @llm 在做的 `test_style_*`)、pytest **15 新测**(13 job_repo+2 job_runner)`packages/core` **130 passed** / `apps/api` **50 passed**。memory 登记 C3.5。**T4.3 行动**`POST /style``job_repo.create` + `background_tasks.add_task(run_job, session_factory, job.id, work=…)`
- [2026-06-19] @llm**M4 Wave A 半程T4.2✅**C6 扩 + C4 扩稳定。style-auditor 双轨落地:①提取轨 `style_extract_spec`(analyst,独立生成仿 outliner,**不进 review 图**)+`StyleFingerprintResult{dimensions:[StyleDimension{name,value,evidence}]}`(16 维带证据)+`orchestrator/style_extract_node.py`(`build_style_extract_request`/`run_style_extraction`,模块内自有 GatewayRun Protocol,网关失败上抛/parsed 违约抛 ValueError,只读不写库);②漂移轨第四审 `style_drift_spec`(name="style",light,只读)+`StyleDriftReview{score=100,segments:[StyleDriftSegment{idx,score,label?}]}`(默认值即无指纹降级态)→`REVIEW_SPECS` 四审齐collect 加 `STYLE`/`extract_style`→record `style=`sse 加 `EVENT_STYLE`/`style_event`+`_section_result_events` STYLE 分支(`style{score,segments}`,字典序 continuity<foreshadow<pace<style 天然纳入);③回炉 `refiner_spec`(writer,output_schema=None 纯文本,非持久)。门禁绿ruff/format mypy **47 文件**(隔离 cache 避与 @backend T4.1 竞争)、packages/agents+core pytest **197 passed**(+37 新测双轨 spec/schema 契约 + 四审图跑通 len(calls)==4 + collect style + SSE style 事件 + 无指纹降级落库)。memory 登记 C6扩/C4扩。**T4.1(@backend) 已并行完成**→ Wave BT4.3(@backend style/refine 端点) 可起调本任务 `run_style_extraction`/`refiner_spec`
- [2026-06-19] @orchestrator **进入 M4文风**归档心智上 M3Phase 4 五任务拉入台账探查确认免重复建表`style_fingerprint` /`chapter_reviews.style` /`jobs` +`GET /jobs/:id`/读侧 `SqlStyleRepo.latest` 均已在前期建齐 **M4 无新建表迁移**`assemble` 已把指纹纳入 `stable_core` 第四审天然在 review_context 拿指纹对照无需额外注入已定决策style-auditor 双轨拆 `style_extract_spec`(analyst,独立生成,仿 outliner)+`style_drift_spec`(light,第四审并入 `REVIEW_SPECS`)学文风走 jobs+BackgroundTask(独立 session,仿 run_overdue_scan)+启动 zombie reaper回炉 refine 同步返回 {original,refined} 不写库守不变量#3)。启动 **Wave AT4.2(@llm·agents+orchestrator) ‖ T4.1(@backend·jobs 基建)**不同目录,隔离 MYPY_CACHE_DIR)。
- [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 ET3.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)**/buildmemory +1 decision +2 gotchas下一步 **Wave ET3.7 M3 E2E**(@qa DB + mock 网关零 token)。
@@ -86,3 +152,5 @@ T0.1 monorepo 骨架 ✅ @devops · T0.2 16 MVP 表迁移无漂移users st
- [2026-06-18] @devops/@db/@backend/@frontend **Phase 0 全部完成**monorepo(uv workspace + pnpm)、16 MVP 表迁移(无漂移)、FastAPI(structlog+request_id+错误信封+/jobs/:id)、Next.js(纸感 token + OpenAPITS gen:api)、CI门禁全绿API 实跑 200下一步 M1/T1.1(网关接口)。
- [2026-06-18] @docs DEV_PLAN 与规格对齐修订T0.3 加可观测性底座(structlog+request_id)、T1.1 `usage_ledger` 记账(从第一天)、T0.2/T2.3 统一建表口径( MVP 表一次建齐, T2.3 Repository)、T4.2 把文风漂移并入第四审新增 `PUT .../draft` 自动保存端点并回写 ARCH §7.2 + contracts C3
- [2026-06-17] @docs 四份规格 + CLAUDE.md + 协同系统PROGRESS/memory就绪可进 Phase 0 / T0.1
- [2026-06-19] @llm **K1.2 修头**Kimi Code 适配器 `kimi_code_headers()` 改为**** `{"User-Agent": "KimiCLI/1.5"}`删全部 X-Msh-* + `kimi_device_id`/`KIMI_DEVICE_ID`/确定性 device-id 机制K1.5 联网实测有效 token X-Msh-* 疑似触发 `401 Invalid Authentication`对齐 pi-kimi-coder = UA-only。改 `adapters/kimi_code.py` + `__init__` 导出 + 两测adapter 6 /factory 3 default_headers UA X-Msh-*)。 contracts C1扩头集 UA-only+ gotcha门禁绿ruff/format/mypy/pytest56 passed)。
- [2026-06-19] @backend **bugfix 空写章 prompt**`assemble`C5从不含项目 premise/logline/theme/title 且无写章指令 全新项目 premise产空 `stable_core`+`volatile`写章触发 LLM `400 message must not be empty`修复`MemoryRepos` 加第 8 repo `project:ProjectSpecRepo``SqlProjectSpecRepo` project_id `projects``assemble` 作品蓝本放入 `stable_core` 首段书级 spec缓存前缀 #9+ `volatile` 始终含请创作第 N 章的正文。」。 `domain/repositories.py`(+ProjectSpecView/Repo) · `memory/sql_repositories.py`(+SqlProjectSpecRepo, sql_memory_repos 装配) · `memory/assemble.py`(_build_spec_section + 注入)测试 `test_memory.py`(+bare-project/chapter-directive 两测+fake) · `test_projects.py`/`test_generation.py`( project= fake)。无 DDL/迁移只读既有列)。门禁全绿ruff/format/mypy(154 文件)/alembic check(无漂移)/pytest **438 passed** contracts C5 + gotcha消费方注意手搓 `MemoryRepos(...)` 须补 `project=`