Files
writer-work-flow/PROGRESS.md

279 lines
135 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# PROGRESS — 多 Agent 协同任务台账
> 多 agent 共享的**唯一协同入口**。开工前读这里 + `memory/`;认领任务、尊重依赖、完成即更新。
> 完整任务定义见 `DEV_PLAN.md`;本台账只展开**当前阶段**,进入新阶段时再把该阶段任务拉进来。
> 协同规则见 `CLAUDE.md` →「多 Agent 协同」。
**状态图例**:⬜ 待办 · 🔵 进行中(注明 @skill + 日期) · ✅ 完成 · ⛔ 阻塞(注明等什么)
---
## 当前阶段QA-CR · 全项目 Code Review 整改批
> **背景**[2026-06-26] 对全仓做了一次**七维度 Code Review**(后端 Python 规范 / LangGraph 最佳实践 / 后端 FastAPI 架构 / 前端编程规范 / 前端架构 / 应用安全 / 依赖时效6 个专科 reviewer 并行 + 依赖自查。绿门禁下仍揪出 **2 CRITICAL + 13 HIGH + 一批 MEDIUM/LOW**——再次证伪「测试过=没问题」。架构本身成熟、不变量纪律强provider 中立 / HITL accept 单写 / checkpoint 仅控制流 / SecretStr 全覆盖);**确认无虞**SSRF`base_url` 仅来自硬编码 `_PROVIDER_BASE_URLS`,无用户 URL 入网)/ SQL 注入(全 ORM 参数化)/ XSS无 `dangerouslySetInnerHTML`/`eval`/ 错误信封不泄栈密钥 / Kimi 用 RFC 8628 device flow 无 CSRF 面。
> **整改 DoD**CRITICAL + HIGH 全部 ✅ 且各自补回归测试MEDIUM 择批清理;门禁全绿(后端 ruff/format/mypy/pytest + alembic 无漂移;前端 lint/tsc/vitest/build。**守 §Definition of Done**:每项 TDD 先红后绿、完成即小步 commit。
> **落地顺序**:① 本周 CR-C1/C2 + 两资源泄漏H1/H2+ Fernet keyH8② 合并前 计费两项H3+ request_idH4+ max_lengthH9+ 前端三 HIGHH10/H11/H12③ MEDIUM/LOW 技术债批。
> **依赖纪律**CR-C1升 Next须 `pnpm install` 重锁 + `pnpm build` 验证、**升级后轮换全部应用密钥**(与 CR-H8 Fernet key 联动。CR-H4/H9 改 schema → 若动 OpenAPI 形参须 `pnpm gen:api` + `memory/contracts.md` 记一笔。无 DB 迁移预期。
| 任务 | 状态 | 负责 | 依赖 | 备注 |
|---|---|---|---|---|
| CR-C1 🔴 升级 Next.js 修 RCE + React 补丁 | ✅ | @frontend | — | `f4c2c4e` next 15.1.3→**15.5.20**registry backport 线,避 16.x 大迁移、react/react-dom 19.0.0→**19.2.7**、eslint-config-next/@types 同步;`pnpm install` 重锁 + `pnpm build` 绿;`pnpm audit` next/react/react-dom 无 high/critical`lib/security/dependencyFloors.ts` 版本下界守卫。**⚠️ 运维待办(用户执行)**CVE 号无法对真库核验(升级后 `pnpm audit`/GitHub advisory 复核)+ 升级后轮换全部应用密钥 |
| CR-C2 🔴 多章链设 `recursion_limit` | ✅ | @backend | — | `ed0a679` **前提证伪**langgraph 1.2.5 默认上限=10007非 25、count≤50→~200 步,**无实活崩溃**;仍加显式**顶层** `recursion_limit=count*4+10`(防御硬化);测断言 config 键(行为「跑长链完成」测会 vacuous |
| CR-H1 🟠 Kimi OAuth 轮询不占 DB 会话 | ✅ | @backend | — | `ca8fbc8` 轮询移出会话:`_poll_for_token`(无会话)+`_run_kimi_oauth_poll`,仅最终 persist 走 run_job 短会话;`job_runner` 未动(与 style_learn 共享) |
| CR-H2 🟠 修 `httpx.AsyncClient` 泄漏 | ✅ | @backend | — | `5dd336b`+`26f10d0` 请求级依赖改 `_http_client` 生成器(`async with``aclose`);两处测 override 跟随改,堵住 E2E 误触真网 |
| CR-H3 🟠 Anthropic 结构化输出记真实 usage | ✅ | @llm | — | `cb8fddf``create_with_completion``raw.usage`,弃硬编码 0修计费腐蚀 |
| CR-H4 🟠 `request_id` 贯通网关日志 | ✅ | @llm | — | `51fe9f4`+`e08b01a` LlmRequest 加可选 `request_id` + **条件透传**(仅非 None否则覆盖 contextvars 反退化 sync/SSE 追踪);`llm_call`+两处 `llm_provider_failed` 全锁测。契约 C1-扩 |
| CR-H5 🟠 `thinking` 字段:实现或删除 | ✅ | @llm | — | `afeac51` 删死字段 `LlmRequest.thinking`YAGNI`Capabilities.thinking`(异名活字段);回写 ARCH/contracts |
| CR-H6 🟠 流式路径加 per-provider 重试 | ✅ | @llm | — | `8a2b1b0` `_stream_with_retry` 对称 run仅首 token 前重试mid-stream 失败照抛(不变量 §4.5 |
| CR-H7 🟠 `TOOLBOX` 注册表不可变 | ✅ | @backend | — | `25d48b7` `Final[Mapping]=MappingProxyType(_TOOLBOX_BY_KEY)`(仿 SPECS |
| CR-H8 🟠 `.env.example` 移除可用 Fernet key | ✅ | @devops | — | `baa41d3` 换不可用占位符Fernet 拒绝→照抄即启动失败)+ 轮换提示。**⚠️ 真 key 仍在 git 历史,曾用该 key 的环境须轮换(用户)** |
| CR-H9 🟠 API 文本输入加 `max_length` | ✅ | @backend | — | `e1a24a2`+`d6b53d0` 全请求文本字段加上限api_key≤512/brief≤1e4/final_text≤2e5/segment≤2e4/directive≤2e4/instruction≤2e3…+ **2 MiB body 中间件 413 兜底** + `PAYLOAD_TOO_LARGE`。契约 C3`gen:api` 无漂移 |
| CR-H10 🟠 前端 `errorCode` 去重 | ✅ | @frontend | — | `5665cc9` `lib/style/{useRefine,useStyleLearn}` 统一 import 自 `generation/cards` |
| CR-H11 🟠 Drawer 关闭还原焦点 | ✅ | @frontend | — | `6e2b478` 行为本分支早已修;提取 `lib/a11y/useRestoreFocus` + renderHook 回归测试 + DRYDrawer/ContextDrawer 共用) |
| CR-H12 🟠 RefineView 取消在途 refine | ✅ | @frontend | — | `5c02792` useRefine 暴露 `abort`setState-free+ AbortController + aborted 守卫弃迟到响应RefineView cleanup 调用 + 真 deps |
| CR-M1 🟡 后端架构整改批 | ⬜ | @backend | — | `outline.py:162` volume 下推 DB 过滤;`generation.py:326`/`toolbox.py:431` N+1 INSERT→`bulk_create``jobs.py:28` 裸 ORM→repo`provider_deps.py:91` 去私有 `_client`(加 `probe_connection()`);列表端点加分页。⚠️`assemble.py:155` 8 串行查询:**AsyncSession 不支持同一 session 并发,`gather` 须每查询独立 session**,不可照搬 |
| CR-M2 🟡 网关/adapters 整改批 | ⬜ | @llm | — | `gateway.py:90` `is_open()` 副作用违 CQS`pricing.py` 未知 model 静默记 0 → 加 warningadapter `str(exc)` 入异常消息可能带 vendor 响应体→只留类名+status |
| CR-M3 🟡 LangGraph 链健壮性 | ⬜ | @llm | — | `chain_runner.py:124` accept commit 后 `run_overdue_scan` 非幂等且失败无法 resume→部分进度空洞幂等化或纳入事务`chain_runner.py:159` 改用公开 `get_state().next` 替私有 `__interrupt__``chain/nodes.py:213` 链内 4 审串行→并行/复用 review 子图 |
| CR-M4 🟡 前端 key/a11y/cleanup 批 | ⬜ | @frontend | — | 可编辑列表去 index-key`CharacterGenerator.tsx:135`/`GeneratorRunner.tsx:178`/`ForeshadowCard.tsx:68`SSE `KNOWN_EVENTS``stop`(核对 `memory/contracts.md`ARIA 补全AppShell nav label / NavDrawer aria-controls / ForeshadowCard `<dl>` 结构ProjectWizard 步骤焦点;`ReviewReport.tsx:301` setTimeout 卸载清理 |
| CR-M5 🟡 前端 TS 边界类型收紧 | ⬜ | @frontend | — | `lib/api/server.ts:34` `parseJsonBody` 加最小结构校验;`useAccept.ts:60` `ApiErrorEnvelope` 从生成 schema 派生;`applyFix.ts` `hasApplicableFix` 改类型谓词去 `as string` |
| CR-L1 🟢 LOW 清理批 | ⬜ | @backend·@llm·@frontend | — | `chain.py:256` 静默回退加 warningSSE 端点补 OpenAPI `text/event-stream` 声明;冗余 `as`/`.valueOf()` cast 清理;测试脚本 `print`→logging |
| CR-D1 🟡 抬高后端依赖下界(可选升级评估) | ⬜ | @devops | — | `pyproject.toml` 下界过旧(`langgraph>=0.2.40`/`anthropic>=0.34`),抬到接近 lockfile 实锁版本保可复现;后端实锁版本均当前。可选评估 vitest 3.x / tailwind 4.x |
> **[2026-07-08] CRITICAL + HIGH 全部 ✅ 落地**14 项 + 4 项低危收尾),多 agent 并行开发(@llm/@backend/@devops/@frontend 四簇串行整合,各 TDD 红→绿、逐项补回归测试)。**门禁全绿**:后端 ruff/format 干净 · mypy **229** · alembic **无漂移** · pytest **934**;前端 lint/tsc 干净 · vitest **669** · build OK · coverage **95.41%**。**14 项对抗式复核 0 problem**skeptic 逐条实证 test 非 vacuous。落地含 3 处前提证伪C2 非实活崩溃/H4 sync-SSE 已由 contextvars 贯通/H11 行为本分支已修)。**MEDIUM/LOWCR-M1..M5 / L1 / D1按计划择批后清理暂 ⬜。**
>
> **维度小结**:后端 FastAPI 架构 0C/2H/7M·Python 规范 0C/4H/6M·LangGraph 1C/2H/5M·前端 React 0C/2H/9M·前端 TS 0C/1H/8L·安全 0C/2H/4M·依赖 1C。后端依赖全部当前大版本线前端唯一关键缺口=Next RCE。
---
## 进行中写作工作台重构writing-first· 分支 `feat/writing-first-workspace`
> **背景**[2026-07-07] 用户对写作体验提 8 点反馈,产品主张升级为 **writing-first 工作台**——进来即写、所有工具/AI 动作从编辑器内按需调用并回填正文、元数据由内容渐进生成。多 agent 工作流扎根代码→Web+GitHub 调研→三方设计→四镜头对抗评审→定稿)产出 DEV_PLAN`scratchpad/writing-first-workspace-DEVPLAN.md`**ephemeral 未入库**;灵感/取舍见 `memory/selectable-write-prompts.md`)。
> **已拍板决策**:进来即写=**延迟落库**(首次击键才建占位项目 + 列表过滤空稿);可选提示词 MVP=**纯前端** directive→volatile不改 `DraftStreamRequest` 契约、不动 `write_craft.md` 字节 → 金标准零回归);预设 MVP=先只上内置;续写=多候选卡点选插入。
> **纪律**:全程 TDD 小步提交,回填全守 HITLAI 绝不 auto-replace点选/接受才落草稿);`/refine`、`/rewrite` 只读不写库(不变量 #3。**门禁全绿**:前端 vitest **678** / lint / tsc / build / coverage **95.36%**;后端 ruff / mypy **229** / pytest **955**(含 WFW-9 clarify E2E/ alembic 无漂移。**WFW-0~9 全部交付**WFW-5/6/7 多 agent 并行 → `3dd7d28`WFW-8 整章重写跨栈 → `6ed9c89`+`542c2ab`**WFW-9 三段全交付** M1 `1652ad9`+`e30c933` / M2 `4a09f27`..`8e29b33` / M3 `ea9a9d9`+`a703a90`,契约 C-Rewrite+C-Clarify 见 `memory/contracts.md`)。**未 push、未开 PR**(等用户示意)。
| 任务 | 状态 | 负责 | 依赖 | 反馈# | 备注 |
|---|---|---|---|---|---|
| WFW-0 进来即写(延迟落库) | ✅ | @frontend | — | #5 | `8389572` `/write`(DraftComposer) + `lib/start/useDeferredDraft`(懒建占位项目+种首章草稿,双重幂等,空进空出不落库) + 落地页 CTA「直接开始写」主/「先立项」辅 |
| WFW-1 润色 / 再沟通 | ✅ | @frontend | — | #1#2 | `2f0b841` `useRefine`(同步/refine,版本栈,再沟通=上一版产出+新意见再回炉) + `refineApply`(接受回填按内容重锚,原文变则提示重选) + RefinePanel 内联卡 + Editor 上报选区 |
| WFW-2 续写(多候选) | ✅ | @frontend | WFW-0 | #2 | `9195cf3` `useContinue`(continue 生成器 with_prior_chapter 读前文,多候选累加) + ContinuePanel 候选卡点选插入章末 + flush 后读最新草稿 |
| WFW-3 内联工具箱 + 金手指露出 | ✅ | @frontend | — | #4#8 | `04f4785` `useToolboxTools`(客户端拉描述符) + InlineToolbox(列非 legacy 生成器含金手指) + `GeneratorRunner``onInsertText`(文本产物插入正文) |
| WFW-4 AI 写作三槽(文风/剧情/自定义) | ✅ | @frontend | — | #3 | `44b0b8a` `directive.ts``PLOT_PRESETS` + `composeDirective` 合并;DirectivePanel 拆文风/剧情两组 chips + 自定义。纯前端零契约,`write_craft.md` 字节不变 |
| WFW-5 内容感知书名 | ✅ | @frontend | — | #6 | `3dd7d28` 纯前端零后端 MVP`buildManuscriptExcerpt`(首尾摘录+硬上界) + GeneratorRunner「用当前正文」按钮把摘录填 briefbook-title 据正文反推。**后续更佳版**:后端富化 book-title.md + `with_manuscript` 策略(未做) |
| WFW-6 侧栏 IA 收敛ContextDrawer | ✅ | @frontend | — | #7 | `3dd7d28` 加法式 ContextDrawer 右侧速查抽屉 + 底栏「速查」按钮;设定库/大纲**完整只读速查**,伏笔/规则/文风**摘要+跳全宽页**(后续可补真实数据)。`CONTEXT_DRAWER_ENABLED` 一键回滚、旧侧栏/全宽页路由全保留 |
| WFW-7 首次 AI 写作前极轻 genre 采集 + 无大纲降级 | ✅ | @frontend | WFW-0 | — | `3dd7d28` 无题材首次写章前弹 GenrePicker(临时并入本次 directive 不落库) + chapters 空时「尚无大纲,将按设定自由生成」提示,杜绝无题材 slop |
| WFW-8 整章级「再沟通/重写」(对话式迭代) | ✅ | @backend·@llm·@frontend | — | 新#1 | `6ed9c89`(后端)+`542c2ab`(前端)。后端 SSE `POST .../rewrite``rewrite.md` 教条 + `rewrite_node` + `RewriteStreamRequest`,复用 assemble 记忆注入,只读不写库、工具非写节点、守 #3/#7/#9);前端 `useChapterRewrite`(版本栈)+`ChapterRewritePanel`+底栏「整章重写」:给意见→流式重写整章→多轮迭代→接受某版才替换正文(HITL)。契约 C-Rewrite。用户反馈「整章不满意要跟 AI 交流」 |
| WFW-9 M1 AI 反问澄清refine 侧路线A 两阶段) | ✅ | @backend·@llm·@frontend | — | 新#2 | `1652ad9`(后端)+`e30c933`(前端)。多agent并行(后端整片‖ChoiceChips)+主线集成。非流式预检 `POST .../refine/clarify``ClarifyDecision`(结构化,analyst,只读,失败回退放行)+clarify_refine spec/教条(SPECS#24);既有 refine 未改。前端 `useClarify`+`ChoiceChips`+`clarify.ts`(foldClarifications/门控)+RefinePanel 门控接线:意见<10字或点帮我理清方向」→AI反问选项折答案进instruction走既有refine契约 C-Clarify。**M1 refine 侧完成M2/M3 见下两行** |
| WFW-9 M2 AI 反问澄清rewrite 整章重写路径 | | @backend·@llm·@frontend | | #2 | `4a09f27`+`6fd6375`(后端)+`9b32743`+`4b1088a`+`8e29b33`(前端) agent 串行整合新非流式预检 `POST .../rewrite/clarify``ClarifyDecision`(复用 M1 schema/`run_clarify`)+ `clarify_rewrite` spec/教条(章级,SPECS 2425,prompt_hashes +1)+`RewriteClarifyRequest{feedback,prior_draft?}`(仅取有界 3000 字摘录喂 analyst,不整章入 LLM);只读不写库失败放行前端 `useRewriteClarify`+`toVM/PROCEED` 提取入共享 `clarify.ts`(DRY)+`ChapterRewritePanel` 门控(镜像 RefinePanel):意见<10字或帮我理清方向」→反问折进 feedback走既有 rewrite SSE契约 C-Clarify ;gen:api 纳入新端点 |
| WFW-9 M3 澄清 UX 打磨 + E2E | | @frontend·@qa | | | `ea9a9d9`(a11y):refine/rewrite 两面板 AI 反问块加 `role=status` 向读屏动态播报(WCAG 4.1.3 Status Messages)。`a703a90`(E2E):`tests/test_wfw9_clarify_e2e.py` 7 用例真 pg+mock 网关零 token——refine/rewrite 含糊反问 / 清晰放行 / 失败开路(parsed=None→200 need_clarification=false,不 500) / 只读不写业务表但记 usage_ledger / 404无产品 bug。**深度视觉/交互 QA(真起前端浏览)为人工验收事项** |
| WFW-9 M2 AI 反问澄清rewrite 路线A 两阶段 | 后端 | @llm·@backend | WFW-8·WFW-9 M1 | #2 | `4a09f27`(llm)+`6fd6375`(后端)。镜像 M1非流式预检 `POST .../rewrite/clarify``RewriteClarifyRequest{feedback(必给),prior_draft(可选)}``ClarifyDecision`(复用同一 schema,analyst,只读,失败回退放行)+`clarify_rewrite_spec`/教条 `clarify_rewrite.md`(segment整章,SPECS#25);既有 `.../rewrite` SSE 未改端点只喂 prior_draft 开头 3000 字摘录(不整章入 LLM)、日志脱敏契约 C-Clarify()。门禁绿:后端 ruff/format·mypy229·pytest948·alembic 无漂移。**前端仍欠 `pnpm gen:api`+M2 UI 接线(仿 RefinePanel 门控 ChapterRewritePanel) + M3 UX/E2E 待办** |
| WFW-9 E2E两阶段 AI 反问澄清refine+rewrite | | @qa | WFW-9 M1·M2 | #2 | `tests/test_wfw9_clarify_e2e.py` 7 用例真 pg + mock 网关provider/adapter M2/T6 范式 tokenrefine 含糊反问1问 / refine 明确放行rewrite 含糊反问 / rewrite 明确放行失败开放(网关产非 ClarifyDecision仍200 need_clarification=false 500 且仍记账)、只读(seed chapter 字节一致+ review/digest ) usage_ledger 真落 analyst 一行404 信封响应绝不回灌原文摘录无产品 bug门禁绿:ruff/format·mypy 本文件净·pytest 955 passed |
---
## 已封板T6 · 创作工具箱(通用生成器框架)✅
> **背景**对标竞品「创作工具箱」——把每个「XX 生成器」实现为声明式 skill`AgentSpec` 的设计本意),用一条**通用执行路径**驱动。用户已定:① 走**通用 skill 框架**(非逐个硬编码)② 封面/图像本期跳过 ③ 文本生成器全做(上架已有 3 + 新建 8。完整设计见 `~/.claude/plans/creation-toolbox-generators.md`。
> **P1 目标DoD**`GeneratorTool` 描述符 + `TOOLBOX` 注册表 + 通用 `GET /skills/toolbox` & `POST /projects/{id}/skills/{tool_key}/generate` 端点 + **1 个最简生成器(脑洞)端到端打通**mock 网关 E2E 零 token。证实「加生成器 = 加一份声明」这条路。
> **执行波次**A(@llm 脑洞 spec + IdeaListResult schema + brief_only context 策略 + 通用 run 路径) → B(@backend GeneratorTool/TOOLBOX 注册表 + 通用 toolbox/generate 端点 + response schema + 接线 build_gateway_for_tier) → C(@qa 脑洞 generate E2E真 DB + mock 网关,断言 unknown key 404 / 无 provider 503 / 仅记 ledger 不写业务表)。
> **契约纪律**B 改 OpenAPI → `memory/contracts.md` 记 C 扩 + `PROGRESS.md` 记一笔(前端 P2 才 `pnpm gen:api`)。守不变量 #2只声明 tier/#3预览不写库。**预计无 DB 迁移**descriptor 在代码、复用既有表)。
| 任务 | 状态 | 负责 | 依赖 | 契约 | 备注 |
|---|---|---|---|---|---|
| T6.1 脑洞 spec + IdeaListResult schema + brief_only context + 通用 run 路径 | | @llm | | schema/spec | 完成`schemas.py` `Idea`/`IdeaListResult``specs.py` `brainstorm_spec`(light, reads=[projects], writes=[])`generation_node.py` `build_brief_context` + **通用 `run_generator`** `spec.output_schema` 校验 parsed不绑定具体类型任一声明式生成器共用两包 ruff/format/mypy 干净新增 13 + 全包 252 passed 无回归。**@backend T6.2 可起 `ww_agents` `brainstorm_spec`/`IdeaListResult` `ww_core.orchestrator` `run_generator`/`build_brief_context`** |
| T6.2 GeneratorTool 描述符 + TOOLBOX 注册表 | | @backend | T6.1 | C3扩稳定 | `packages/skills/ww_skills/toolbox.py`(描述符类型,frozen) + `toolbox_registry.py`(`TOOLBOX` 11 + `get_tool`)。25+7 |
| T6.3 通用端点 toolbox/generate(+ingest) | | @backend | T6.2 | C3扩稳定 | `routers/toolbox.py` 3 端点 + `schemas/toolbox.py` + `services/toolbox_context.py`( dispatch) + `get_tier_gateway_builder` 注入缝generate 预览仅 commit ledgeringest 复用 continuity 409 + partition_writes 白名单未知 key 404 / provider 503 |
| T6.4 E2Etoolbox 全路径 | | @qa | T6.3 | | `tests/test_t6_toolbox_e2e.py` 5 用例真 pg + mock 网关零 token列表 11 keybrainstorm 预览仅 ledger 零业务写(#3)、glossary ingest 409ack 放行真落 world_entitiesunknown 404 provider 503token 不泄漏无端点 bug |
| T6.5 7 新生成器 spec+schema + with_outline_chapter | | @llm | | schema/spec | `schemas.py` +7 输出 schema`specs.py` +7 spec(book-title/blurb/name/golden-finger/glossary/opening/fine-outline只声明 tier #2)、`generation_node.py` +`build_outline_chapter_context`309 passed |
| T6.6 工具箱落地页 + 声明驱动 Runner | | @frontend | T6.3 | | `app/projects/[id]/toolbox/page.tsx`(RSC) + `components/toolbox/{ToolboxPage,ToolCard,GeneratorRunner}` + `lib/toolbox/*`(纯函数) + LeftNav工具箱」+ K `nav-toolbox`/`action-gen-*`legacy 3 跳现页vitest 155279/build OK |
| P2 收尾限流/noopener/Committable | | @backend+@frontend | | | 限流`decisions.md` 记延后(单用户原型)noopener Committable 经查本分支早已修`provider_deps.py` 残留 `type:ignore` SDK 私有属性探活,load-bearing 保留 |
**T6 出口DoD✅ 达成**通用执行器驱动全部 8 个新生成器 + 工具箱落地页声明驱动后端门禁绿ruff/format/mypy **195**/alembic **无漂移**/pytest **583**前端门禁绿gen:api/lint/tsc/vitest **279**/buildE2E mock 网关零 token 全路径走通。**实景 browse 复验工具箱卡片栅格脑洞预览词条入库待做。** 后续可选 P5封面图像轨道 / 自定义 skill 运行期 schema / 收敛已有 3 竖井)。
---
## 已封板Prompt 管理重构方案A+ 全量 prompt 重写 ✅
> **背景**:把 21 个内置 agent 的 `system_prompt` 散文从 `specs.py` Python 常量外置为 `.md` 文件,并统一内置/用户 skill 的只读解析入口。设计真源 `docs/design/prompt-management.md`;契约 `memory/contracts.md` C6-ext决策/坑见 `memory/{decisions,gotchas}.md`2026-06-24。**多 agent 工作流交付**TDD + 并行开发 + 交叉验证评审。
| 任务 | 状态 | 负责 | 备注 |
|---|---|---|---|
| 方案A 步骤13`spec_model`/`prompt_loader`/`prompts/*.md`×21/`schema_catalog`/`SPECS`/`REVIEW_RESERVED_NAMES` | | @llm | 金标准 sha256 取运行时值`SPECS[name] is *_spec` 同一实例三集合 name 恒等 |
| 方案A 步骤45`SpecResolver`内置纯内存零 DB+ SkillRegistry 入库守卫前移 + `toolbox_registry` 桥接 `SPECS` | | @backend | 守卫锚 `REVIEW_RESERVED_NAMES set(SPECS)` 12 生成器 `*_spec` 直接 import |
| 打包/CI`.gitattributes eol=lf` + wheel `artifacts` `prompts/*.md` + `agents-wheel-smoke` 冒烟`structlog` 补声明 | | @devops | 裸装 `import ww_agents; assert SPECS` 通过`.gitattributes` 须完整嵌套路径 |
| 集成回归#12 编排器无回归 + #15 apps/api import-smoke`*_spec is SPECS[name]`+ #16 CI 冒烟 | | @qa | 内容无关长青 |
| 全量重写 21 prompt 内容任务对齐 + prompt 工程最佳实践schema 契约/不变量保持 | | @llm/@qa | 激进重写金标准 fixture 重生成护栏全验无占位/ model /中文/≤1 LF/四审只读 |
**出口DoD✅**后端门禁绿 ruff/format clean · **mypy 209** · **pytest 744 passed**缓存断点前块字节稳定不变量 #9金标准守 schema 变更前端零影响 `pnpm gen:api`)。已合并 `develop`外置 wave `4f561da`重写 wave `eb356c4`)。**后续可选**编排器 + apps/api 3 路由切 `SpecResolver` 后删 `*_spec` 导出
---
## 已封板K1 · Kimi Code OAuth订阅 plan 接入)✅
> **背景**:用户要求接入 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 两端点。
| 任务 | 状态 | 负责 | 依赖 | 契约 | 备注 |
|---|---|---|---|---|---|
| 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 202jobs 后台轮询/disconnect/status,复用 run_job)+`StoredCredential` 收口(api_key_encnullable+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+伪造头+bearerrefresh-on-build 更新存量 token(DB 真源)→disconnect 清除token 全程不进 job 结果/状态/start 响应全仓门禁绿(ruff/format/mypy **154**/alembic 无漂移/pytest **434**)。**K1 完成可封板** |
**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
出口达成后端门禁绿ruff / mypy 90 / pytest 114 / alembic 无漂移前端门禁绿gen:api / lint / tsc / vitest 45 / buildE2E 写→审→裁决→验收→摘要入库闭环、DB 真源逐项断言。设计决策 R1R6 全兑现(见 `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+SSEC4✅稳定@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
出口达成后端门禁绿ruff / mypy 68 / pytest 57 / alembic 无漂移前端门禁绿gen:api / lint / tsc / vitest 24 / buildE2E 闭环走通。
M2 起可补的 M1 占位:本章助手/注入透明面板、向导主角/世界观字段、档位路由可写。
</details>
<details><summary>Phase 0 · 基建与栈修订 — ✅ 全部完成2026-06-18</summary>
T0.1 monorepo 骨架 ✅ @devops · T0.2 16 MVP 表迁移无漂移users stub@db · T0.3 FastAPI 骨架 + config + 错误信封(带 request_id) + OpenAPI + `GET /jobs/:id` + structlog ✅ @backend · T0.4 前端骨架 + 纸感 token + OpenAPI→TS gen:api ✅ @frontend · T0.5 CI含 pg service + alembic 漂移校验)✅ @devops · T0.6 架构栈修订回写规格 ✅ @docs
出口达成backend 门禁绿、frontend 门禁绿、API 实跑 200 带 `x-request-id`
</details>
---
## 变更日志append-only最新在最上
> 格式:`- [YYYY-MM-DD] @skill 完成/进展 Txx — 一句话结果 + 影响的契约/文件`
- [2026-07-08] @llm/@backend/@devops/@frontend**✅ QA-CR CRITICAL + HIGH 整改批全部落地**14 项 + 4 低危收尾)。多 agent 工作流:先 14 个只读 agent 逐项**扎根真实代码**产精确修复+测试规格(纠出 3 处台账前提漂移),再按 owner 四簇**串行整合**入单工作树(避免并发写树 + repo 级 `ruff format .` 竞态),各 TDD 红→绿、逐项补回归测试、逐 fix 小步提交,末尾 14 个 skeptic **对抗式复核**(实证每条 test 非 vacuous0 problem。**关键落地/纠偏**C1 next 15.1.3→**15.5.20**+react **19.2.7**`pnpm audit` 清、`dependencyFloors.ts` 下界守卫,**CVE 号无法对真库核验+密钥轮换为用户运维事项**C2 **前提证伪**langgraph 默认上限 10007 非 25无实活崩溃仍加显式顶层 `recursion_limit`H4 request_id **条件透传**(否则覆盖 contextvars 反退化H2 修请求级 httpx 泄漏时**揪出 E2E 会误触真网**override 跟随修H9 全文本字段上限+2 MiB body 中间件 413 兜底(契约 C3`gen:api` 无漂移H8 `.env.example` 换不可用占位符(**真 key 仍在 git 历史,曾用环境须轮换**)。**门禁全绿**:后端 mypy 229/pytest **934**/alembic 无漂移;前端 vitest **669**/build/coverage 95.41%。契约 C1-扩LlmRequest.request_id+ C3H9 caps。**MEDIUM/LOW 择批后清理。** 提交 `cb8fddf``dd6d2fc`19 提交)。
- [2026-07-08] @backend**✅ QA-CR 后端整改 5 项TDD逐 fix 提交)**。**CR-C2**`chain_runner.run_chain_job``graph.ainvoke` 传显式 top-level `recursion_limit=count*NODES_PER_CHAPTER+HEADROOM`(防御硬化,命名常量)。**CR-H1**Kimi OAuth 设备轮询移出 DB 会话——新增 `_poll_for_token`(纯 HTTP)/`_make_persist_work`/`_run_kimi_oauth_poll`,仅最终持久化经 `run_job` 开短会话(防连接池饥饿;删 `_make_poll_work`)。**CR-H2**:请求级 httpx 客户端改**生成器依赖** `_http_client``async with ... yield`,请求结束 aclose 修泄漏);`_default_http_client` 保留供后台裸调E2E + 端点测试 override 键跟随改 `_http_client`。**CR-H7**:冻结 `TOOLBOX` 为只读 `MappingProxyType``_TOOLBOX_BY_KEY` 私有底 dict + `Final[Mapping]`,仿 SPECS。**CR-H9**:用户请求字符串字段补 `max_length`providers/generation/projects/style/foreshadow/rules/templates命名常量无魔数样本列表长度+每条双上界)+ 新错误码 `ErrorCode.PAYLOAD_TOO_LARGE`(413) + 应用级 `body_size_limit_middleware`(2 MiB按 Content-Length 拦截自建 413 信封)`main.py` 注册。**门禁全绿**ruff/format 干净 · mypy **229 文件**0 错)· pytest **928**+23recursion_limit 1 / poll-no-session 1 / http-gen 1 / toolbox-readonly 1 / input-size 19[17 参数化 + samples 1 + body413 1])· **无 DDL/无迁移**。记 contracts C3CR-H9新增 `maxLength` + `PAYLOAD_TOO_LARGE`)。→ **@frontend`pnpm gen:api`**(请求字段现有 `maxLength`;本 cluster 未代跑)。守不变量 #3/#8/#9
- [2026-07-06] @backend/@llm/@frontend**✅ 灵感⑦ 群像按定位配比·缩减版 + §0 归属纠偏develop 直提)**。角色群像生成支持「按定位配比」下发。**契约变更** `CharacterGenerateRequest``role_mix:dict[str,int]|None`——`model_validator(mode="after")` 定义与既有 `count` 的关系在场时校验非空、每项≥1、总和≤`MAX_GENERATE_COUNT`=12并把 `count` 归一为各值之和(构造期归一化,忽略客户端 count缺省退回单一 `role`+`count`。**§0 归属纠偏**`build_character_gen_context`+`run_character_gen``ww_core/orchestrator/generation_node.py`)确为 **@llm 域**——加末位默认 `role_mix=None` 关键字参,在场时注入「角色定位配比」块(保插入序、确定性、无时间戳,守 #6/#7 assemble 纯函数;覆盖单一 role 行);`routers/generation.py` 穿 `role_mix=body.role_mix``character-gen.md` 加「按配比严格分配 role、各定位之和=总数」纪律 → **regen `prompt_hashes.json`**(仅 character-gen 哈希变,**不进 SPECS→不 bump 计数**)。**前端** `cards.ts``sanitizeRoleMix`(去空/去重/clamp≥1/按 12 截断)+`roleMixTotal`+`buildCharacterGenerateRequest` 第 4 参 roleMix`useCharacterGen` `CharacterGenInput.roleMix` 穿参;新 `RoleMixEditor.tsx` + `CharacterGenerator` SegmentedControl 单一/配比双模。**TDD**schema 校验 7 例总和≤12/空 dict/非正值拒绝)+ context 注入 2 例 + run 穿参 1 例 + 前端 cards 构造/clamp 5 例 + hook renderHook 1 例。**门禁全绿**:后端 ruff/format 干净 · mypy **222** · pytest **858**+11· 无迁移(未动模型,未跑 alembic前端 gen:api/lint/typecheck 干净 · vitest **543**+6· coverage 95%cards.ts 100%)· build OK。记 contracts C3。守不变量 #2/#6/#7/#9。**无 DB 迁移**。
- [2026-07-06] @llm/@db/@backend/@frontend**✅ 灵感③ 人物塑造 advisory 审develop 直提)**。写→审链新增第五审「人物塑造」:**advisory 单维——仅建议、不阻断验收**(不进 conflicts、不碰 `assert_conflicts_resolved`、**不入 `REVIEW_RESERVED_NAMES`**D2只做人物塑造、不做氛围氛围噪声大折进 style/pace。**新 SPEC** `characterization_spec``tier="analyst"` 不写 model`reads=("characters",)` 以人物卡 motive/appearance 为客观锚点,`writes=()` 只读,`prompts/characterization.md` **显式忽略文本长度与辞藻华丽度**、引用逐字片段+置信度对抗 LLM-judge 冗长/辞藻偏见)+ schema `CharacterizationReview{issues:[…character/aspect/where/quote/diagnosis/suggestion/confidence]}`(全字段默认值守解析韧性)+ 注册 `SCHEMA_CATALOG["characterization"]`**计数三处 22→23**`specs.py` assert / `test_prompt_loader.py` len / `schema_catalog.py` docstring+ **regen `prompt_hashes.json`**(仅加一条,无其余漂移)。**DB** `chapter_reviews` 加 1 列 `characterization`**JSONB nullable**,迁移 `f6a7b8c9d0e1`nullable 免 backfill。**契约变更** `ReviewHistoryItem`+`ReviewView``characterization`;接线链 `graph.py REVIEW_SPECS` 末位追加 + `chain/nodes.py ReviewRecordRepo` + `collect.py {CHARACTERIZATION/extract_characterization/ReviewRecorder/collect_reviews}` + `review_repo.py {Protocol/SqlReviewRepo/_to_view}` + `sse.py {EVENT_CHARACTERIZATION/characterization_event/_section_result_events}`normalize 按 sorted 键自动纳入,字典序排最前不打乱既有四审断言)。**前端** `lib/review/{sse.ts,history.ts,useReviewStream.ts}` + 新 `CharacterizationPanel.tsx`advisory 只展示、**无裁决 UI**、按置信度降序 + 低置信度折叠控注意力预算)+ `ReviewReport.tsx` 挂面板 + 双 seed。**门禁全绿**:后端 ruff/format 干净 · mypy **221** · pytest **848**+核心 char 审 12 + agents spec 11 + api accept 2 等)· alembic 无漂移;前端 gen:api/lint/typecheck 干净 · vitest **536**+10 含 `test_characterization_does_not_block_accept` 对应前端 reducer/normalize/parse· coverage 95% · build OK。记 contracts C3+C4。守不变量 #2/#3/#9。依赖 ⑧motive/appearance 已入 CharacterCard 契约,作客观锚点)。
- [2026-07-06] @backend/@llm/@frontend**✅ 灵感⑤ AI 立项方案生成+预填develop 直提)**。向导阶段project 未建)一键推演结构化书级蓝图预填立项向导。**新 SPEC** `project_plan_spec``tier="analyst"` 不写 model`reads=()`/`writes=()` 纯预览,`prompts/project-plan.md`+ schema `ProjectPlanResult`(书名候选 list + 时空背景/叙事结构/故事核心/结局设计/基调,**全字段默认值守解析韧性**+ 注册 `SCHEMA_CATALOG["project-plan"]`**计数三处 21→22**`specs.py` assert / `test_prompt_loader.py` len / `schema_catalog.py` docstring+ **regen `prompt_hashes.json`**(仅加一条)。**新端点** `POST /skills/project-plan/generate`**不带 project 前缀**绕开 toolbox 404`ProjectPlanGenerateRequest`(全字段 `max_length` CR-H9`brief``str|None` 令 codegen 可选)→ `ProjectPlanView`**种子门控**缺 genre/logline→422无凭据→503。复用 `build_brief_context`+`run_generator``run_generator`/`_build_request``project_id` 放宽 `uuid.UUID|None`——向导无 projectledger.project_id 本 nullable新缝 `get_project_plan_gateway`analyst。**零迁移**。**前端** `wizard.ts``mapPlanResultToWizardForm`(书名/结构/基调→对应字段;时空背景/结局设计→折进 premise **不静默丢**;结局取向/视角预设枚举不臆造)+ `applyPlanPatch`**仅回填空字段、保护已编辑**+ `canGeneratePlan`/`toPlanSeedRequest` + `useProjectPlan` hookrenderHook 测试)+ `ProjectWizard.tsx` 第 2 步 `PlanAssistant`(生成→预览→按字段回填)。**门禁全绿**:后端 ruff/format 干净 · mypy **218** · pytest **814**+新端点 6 + agents spec 8 测)· alembic 无漂移(零 ORM 变更);前端 gen:api/lint/typecheck 干净 · vitest **526**+28· coverage 95%wizard/generation 100%)· build OK。记 contracts C3 新端点。守不变量 #2/#3/#9。依赖 ④(已交付)。
- [2026-06-26] @orchestrator**全项目 Code Review七维度完成 → `QA-CR` 整改批立项**。6 个专科 reviewer 并行(后端 FastAPI 架构 / Python 规范 / LangGraph 最佳实践 / 前端 React 架构 / 前端 TS 类型安全 / 应用安全)+ 依赖时效自查212 py + 168 tsx 全覆盖。绿门禁下仍揪出 **2 CRITICAL + 13 HIGH + 一批 MEDIUM/LOW****C1** Next.js 15.1.3 RCECVE-2025-66478「React2Shell」App Router+RSC 受影响,升 15.1.9/15.5.7/16.x + 轮换密钥);**C2** 多章链缺 `recursion_limit`(默认 25 supersteps、每章 4 节点→超 ~6 章即崩批量产卷不可用。HIGH 含 Kimi OAuth 占 DB 会话 / httpx 泄漏 / Anthropic 计费记 0 / request_id 未贯通 / `.env.example` 提交可用 Fernet key / 文本输入无 `max_length` / 前端 errorCode 重复 / Drawer 焦点 / RefineView 未取消。**确认无虞**SSRFbase_url 仅硬编码)/SQL 注入(全 ORM/XSS无 dangerouslySetInnerHTML/错误信封不泄密/Kimi device-flow 无 CSRF。已登记 `QA-CR` 任务表CR-C1/C2 + CR-H1..H12 + CR-M1..M5 + CR-L1 + CR-D1按 owner 分派 @frontend/@backend/@llm/@devops,落地顺序见当前阶段 background。**本批为评审立项,尚无代码改动。**
- [2026-06-23] @orchestrator**🎉 多章工作流链Chain Workflow交付 + 多 agent 交叉评审 + CRITICAL 修复 + 合并 developmerge `513bf71`**。对标星月「一键多章」+ 差异化「每章过四审、遇冲突才停人」。设计契约 `docs/design/chain-workflow.md`commit `5ee9799`)。**多 agent 逐学科建造**(契约先行、目录单写者):**C1 @llm**(`7f3eaab`) LangGraph **cyclic 链图** `orchestrator/chain/{state,nodes,graph}.py``build_chain_graph`write→review→decide→accept 循环 + **interrupt-on-conflict** + resume删死代码 `build_write_graph``write_node` 本体留用7 单测 mock 网关+fake session+MemorySaver·**C2 @backend**(`29349dc`) 服务/3 端点/schema/checkpointer 接线(见下条)·**C3 @db**(`548b7ab`) langgraph 检查点 4 表迁移 `d3e4f5a6b7c8``autocommit_block` 避开 `CREATE INDEX CONCURRENTLY` 与 alembic 事务死锁;`env.py` `include_object` 豁免这 4 表防漂移误报)·**C4 @qa**(`061792d`) E2E `tests/test_chain_workflow_e2e.py` 真 pg + mock 网关零 token无冲突两章全自动 + 冲突→interrupt→awaiting→resume→accept。**3 路对抗交叉评审**python/fastapi/不变量)在**绿门禁下仍揪出 1 CRITICAL + 7 HIGH**——证伪"测试过=没问题"CRITICAL=链把**绑请求 session 的 gateway** 传进 BackgroundTask后台跑时 session 已关→write/review 的 `usage_ledger.record()` 写进死 session **静默丢失**(链计费全丢,违 #1E2E 清了 ledger 却没断言其存在故漏掉)。**修复**(`d1ea83b`):网关改 `chain_gateway_builder` 按节点 session 重建(仿 `digest_gateway_builder`/`style.py`);日志脱敏(`_classify_job_error`+`exc_type`,去 `str(exc)`§5resume 原子 claim `JobRepo.claim_awaiting_to_running`(防并发双跑同 thread_id非 awaiting→409+ 所有权校验(`JobView.project_id`跨项目→404`ChainResumeAccepted`(去 start/count=0 哨兵);删死导入 `extract_conflicts`**补回归断言**(链 `usage_ledger` 必有行 + `chapter_reviews` 每章一行)。**出口DoD✅**:后端门禁绿 ruff/format 干净 · mypy **194 Success** · alembic **无漂移**(业务表零迁移,复用 `jobs.status=awaiting_input` + `result.awaiting_chapter`;唯一新 DDL=langgraph 检查点表)· pytest **608 passed**+6 回归测)。首次真正启用 LangGraph checkpointer/interrupt。守不变量 #1/#3/#4/#5/#9。**剩余下一步(未做)**:① 前端链 UI`pnpm gen:api` 纳入 run/resume + 发起页/进度轮询/awaiting 裁决续跑面板,复用 `ConflictAdjudication`);② §12 文档回写 `ARCHITECTURE.md §5.2`(补 cyclic 链图 + 更正现状:写章直连流式/单章 accept 为事务/链图首启 checkpointer③ 未 push 远端。可选:续写/扩写节点入链UGC 链市场需多租户deferred
- [2026-06-23] @backend**✅ Chain Workflow C2多章链 服务+端点+schema+checkpointer 接线,分支 `feat/chain-workflow`**。承 C1(@llm)链图(`build_chain_graph` §3.3),落地服务/端点壳:① **3 端点**`routers/chain.py``POST .../chains/{key}/run`→202 `ChainRunAccepted``POST .../chains/runs/{job_id}/resume`→202`GET /jobs/{id}` 复用。校验count 1..50→422、未知 chain_key→404、项目不存在→404、resume job 不存在→404、resume 非 awaiting→**409 新码 `CONFLICT`**、无凭据→503。② **schema**`schemas/chain.py``ChainRunRequest/ChainRunAccepted/ChainResumeRequest``ConflictDecision` 复用)。③ **服务**`services/chain_runner.py``run_chain_job` 仿 `run_job` 壳自建独立 session 驱动链图set_running→ainvoke→据 `__interrupt__``awaiting_input``done`/`failed``build_accept_op` 在 apps/api 装配验收事务闭包注入图节点,守 #3/#4token 不入 result/日志)+ `services/chain_deps.py``get_checkpointer_factory`:运行时 `AsyncPostgresSaver` 上下文 / 测试 MemorySaver。④ **零迁移**§7复用 `jobs`,新增 `status="awaiting_input"` + `JobRepo.set_awaiting`awaiting 章经 `result.awaiting_chapter`;新错误码 `ErrorCode.CONFLICT`(409)。⑤ **新网关缝**`project_deps.build_chain_gateway`/`get_chain_gateway`(按请求 tier writer/analyst/light 分派——单档网关恒返该档会错路由 review/digest见 gotcha+ `get_digest_gateway_builder`。**单测**`apps/api/tests/test_chain.py` 12 用例mock 网关 + MemorySaver + fake session/accept_op无 DB/无网络/无真 LLMrun→202、resume→202、未知 key 404、count 越界(>50/0) 422、resume 非 awaiting 409、项目/ job 不存在 404、run_chain_job 无冲突→done+written 满、冲突→awaiting→resume→done、错误脱敏、accept_op 冲突缺判→CONFLICT_UNRESOLVED。**全仓门禁绿**ruff/format 干净、mypy **193 Success**、alembic **无漂移**(无 ORM 变更、pytest **600 passed**。守不变量 #1/#3/#4/#5/#9。记 contracts C-Chain 稳定 + 2 decision + 3 gotcha。**唯一新增 DDLlanggraph 检查点表)= C3 迁移;前端链 UI = 契约稳定后 @frontend follow-up本期非目标。**
- [2026-06-22] @orchestrator**🎉 T6 创作工具箱(通用生成器框架)全工具箱交付 + 独立复核(分支 `feat/t6-creation-toolbox`**。多 agent 并行波次Wave 0@llm T6.5 ‖ @backend 描述符类型 ‖ P2 收尾)→ Wave A@backend T6.2+T6.3 TOOLBOX+端点合龙,契约稳定点)→ Wave B@frontend T6.6 ‖ @qa T6.4)→ Wave C 收口,目录单写者零写冲突、契约先行、零返工。**@llm T6.5**`ww_agents` +7 输出 schema + 7 specbook-title/blurb/name/golden-finger/glossary/opening/fine-outline只声明 tier #2+ `build_outline_chapter_context`with_outline_chapter 策略)。**@frontend T6.6**`gen:api` 纳入 3 端点;`app/projects/[id]/toolbox/page.tsx`(RSC) + `components/toolbox/{ToolboxPage,ToolCard,GeneratorRunner}` + `lib/toolbox/*`(声明驱动纯函数,按 `input_fields` 渲染表单、按 `output_kind` 渲染预览、可入库者复用 `ConflictAdjudication` 走 409→ack+ LeftNav「工具箱」+ ⌘K `nav-toolbox`/`action-gen-*`legacy 3 跳现页不回归。**@qa T6.4**`tests/test_t6_toolbox_e2e.py` 5 用例真 pg + mock 网关零 token**未发现端点 bug**。**P2 收尾**:限流→`decisions.md` 记延后单用户原型noopener/Committable 经查本分支早已修;`provider_deps.py` 残留 `type:ignore` 为 SDK 私有属性探活、load-bearing 保留。**最终独立复跑全仓门禁绿**:后端 ruff/format 干净、mypy **195 Success**、alembic **无漂移**descriptor 在代码、复用既有表零建表迁移、pytest **583 passed**;前端 gen:api/lint/tsc/vitest **279**/build OK。守不变量 #2(只声明 tier/#3(预览不写库、入库经验收 gate/#9system_prompt 进缓存前块)。**"加生成器=加一份声明" 经实证8 个新生成器复用同一通用执行器 + 同一前端组件)。** **实景 browse 复验(工具箱卡片栅格→脑洞预览→词条入库)待做。** 后续可选 P5封面图像轨道 / 自定义 skill 运行期 schema / 收敛已有 3 竖井。
- [2026-06-20] UX计划 B0(可控版)+F1(控件) — **✅ 本章注入透明 可控版(分支 `feat/ux-b0-controllable-injection`,提交 `0d473e7` 后端 + `6449c31` 前端,未合 develop**。在 B0 读端点之上加作者微调,守不变量 #6「确定性选择」的作者兜底。**后端**(@backend/@db)`PUT /projects/{id}/chapters/{no}/injection``InjectionOverrideRequest{pinned,excluded,recent_n(1..20→422)}``InjectionResponse`(新增回显 `pinned`/`excluded``selected[].reasons` 可含新值 **`author_pin`**`select_relevant_entities``pinned/excluded` frozenset 入参pin 强制纳入加 author_pin / excluded 强制剔除且**优先于 pin**`assemble``override` 关键字参recent_n 覆盖回看章数);**GET injection + PUT + draft 流式端点同读同一覆盖**(看到的=写章用的)。持久化:**新表 `chapter_injection`**(迁移 `ad2c4c663daf`,唯一 `(project_id,chapter_no)`;复用 outline 行污染 beats 已否决)+ 新 `domain/injection_repo.py``InjectionOverride`/`EntityRef`/`SqlInjectionOverrideRepo`upsert 只 flush 端点 commit。**前端**(@frontend)`gen:api` 纳入 PUT + 新 schema`lib/workbench/injection.ts` override 纯函数(`currentOverride`/`withPinToggled`/`withExcluded`/`withRestored`/`withRecentN`/`isPinned`,钳 1..20`useInjection``saving` 态 + `togglePin/exclude/restore/setRecentN`PUT 后以服务端确定结果为准、写失败可读文案不改本地态);`ChapterAssistant` 每实体 📌置顶/✕排除 + 「近 N 章」步进器 + 「已排除」恢复区。**全仓门禁绿**:后端 ruff/format/mypy **163**/alembic 无漂移/pytest **476**;前端 lint/tsc/vitest **183**/build。记 contracts C3 再扩。**实景 browse 复验待做。** UX 计划余项R1/R2/R3 审稿人体学 + Tier4。
- [2026-06-20] UX计划 M1+M2 — **✅ 移动端可用(纯前端,分支 `feat/ux-m1-m2-mobile` 提交 9b893a6**。救活手机端390px写→审主路径。**M1 导航响应式抽屉**:抽出纯逻辑 `lib/nav/items.ts``GLOBAL_NAV_ITEMS`/`projectNavItems`/`isNavItemActive` + `ActiveNav` 类型6 vitest桌面静态侧栏与移动抽屉共用避免漂移新增通用 `Drawer`(遮罩点击/Esc 关闭/打开聚焦面板,复用 `CommandPalette` a11y 模式,`lg:hidden`+ `NavDrawer`(汉堡 `aria-label=打开导航` + 左抽屉)+ `NavItems``LeftNav``hidden lg:block``AppShell` 顶栏加汉堡。**M2 工具条不溢出 + 移动可达**`Workbench` 工具条改 `flex-wrap`390px 不再横切「尚未保存」);`ChapterList`/`ChapterAssistant` 抽出 `ChapterListContent`/`AssistantContent``Workbench` 经左/右 `Drawer``<lg` 触达目录/助手。**实景 390px 复验browse**:汉堡显示 + 静态导航 `display:none`、抽屉开合(聚焦 + Esc 关闭、工具条两行无横向溢出、助手抽屉真注入面板。前端门禁绿lint/typecheck 干净 · vitest **177**(171→+6) · build OK。无后端/契约变更。文件:`lib/nav/{items,items.test}.ts`(新) · `components/{Drawer,NavDrawer,NavItems}.tsx`(新) · `components/{AppShell,LeftNav}.tsx` · `components/workbench/{Workbench,ChapterList,ChapterAssistant}.tsx`。**UX 计划余项**B0 可控版(PUT override) + F1 控件 + R1/R2/R3 审稿人体学 + Tier4。
- [2026-06-20] UX计划 F3+F4 — **✅ 流式进度感 + 友好错误文案(纯前端)**。F4`apps/web/lib/errors/messages.ts``friendlyError(code,fallback)`→中文文案 + 可选「去设置提供商」动作;覆盖后端 `ErrorCode` + 前端 `NETWORK/STREAM_FAILED`;未知码回退原 message+4 vitest写作页 `Workbench` 与审稿页 `ReviewReport` 的错误块改用之,不再直接暴露 raw error code。F3`Workbench` 工具条字数计数器流式时变「生成中… N 字」+ 朱砂 `motion-safe:animate-pulse`(尊重 prefers-reduced-motion停后回「字数 N」`text.length`无后端改动。前端门禁绿lint/typecheck/vitest **171**/build。文件`lib/errors/{messages,messages.test}.ts` · `components/workbench/Workbench.tsx` · `components/review/ReviewReport.tsx`。无契约变更。
- [2026-06-20] UX计划 B0(读)+F1 — **✅ 本章注入透明(读端点 + 右栏真面板)**。兑现差异化信任牌「看到的=写章用的」(不变量 #6把先前写作页右栏「M1 暂未接 / M2 开放」的过时假占位换成真数据。**后端**(@backend)`GET /projects/{id}/chapters/{no}/injection``InjectionResponse{project_id,chapter_no,selected:[{kind,name,reasons[]}],recent_n}`,调既有 `assemble()` 回放确定性 `SelectionTrace`**无 LLM、无 commit、无 DDL**项目不存在→404无大纲→`selected:[]`。文件:`schemas/injection.py`(新) · `routers/projects.py`(+GET+2 import) · `tests/test_injection.py`(新,3 测)。**前端**(@frontend)`gen:api` 纳入端点;纯逻辑 `lib/workbench/injection.ts`(理由/类型→中文徽标 + 4 vitest) + `useInjection` 读 hook`ChapterAssistant` 改 client 组件列出选中实体 + 入选理由徽标(本章点名/主角常驻/近章出现/伏笔窗口)+ 空/载/错三态,「四审」段改指向审稿页;`Workbench``projectId/chapterNo`。**全仓门禁绿**:后端 ruff/format/mypy **159 Success**/alembic 无漂移/pytest **454 passed**;前端 lint/typecheck/vitest **167 passed**/build。记 contracts C3扩。**B0 余项可控版PUT override pin/排除/recent_n + selection 加参 + draft 同读 override + 持久化)+ F1 可控控件待后续。**
- [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)。
- [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 DT3.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 CT3.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` 三审齐文风第四审留 M4collect 一次 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.4outliner 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 BT3.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.1Repository+状态机据实记 @backend `core/ww_core/domain/` T2.3 先例T3.3 复用 M2 `build_review_graph` `review_specs` 扩展点加 foreshadow/pace 两审文风第四审留 M4)。启动 **Wave AT3.1(@backend·core/domain) ‖ T3.4(@llm·packages/agents+orchestrator)**不同目录无写冲突)。
- [2026-06-18] @orchestrator **🎉 M2 完成**Wave ET2.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)**/buildmemory +1 decision +2 gotchas下一步 **Wave ET2.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 提炼在事务外(R2light )→ 单原子事务 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 DT2.6**(@frontend 审稿页+裁决+验收 gate `pnpm gen:api`)。
- [2026-06-18] @orchestrator **Wave B 完成**T2.2✅,C4 扩稳定)。审稿子图落地`build_review_graph`(STARTcontinuity 并行审collectEND可扩四审) + `collect_reviews` `chapter_reviews` 留痕 + `normalize_review`(SSE `section`/`conflict`)M1 `build_write_graph` 不动划清边界本任务到 collect+归一缝为止`interrupt`/accept 事务接线交 T2.4对齐 R3accept 从领域表重读checkpoint 仅控制流)。全仓门禁绿ruff/format 干净mypy **80 文件**pytest **103 passed**memory 登记 C4 + 3 gotchasreducer/add_node 重载/失败隔离两层)。下一步 **Wave CT2.4+T2.5** @backend agent 顺序做验收事务+冲突 gate / review API+历史避免 apps/api 路由+OpenAPI 写冲突)。
- [2026-06-18] @orchestrator **Wave A 完成**T2.1 C6 稳定 + T2.3✅)。两个 fresh agent 并行@llm packages/agents+llm_gateway @backend core/domain目录不相交无冲突)。**补上 M1 遗留网关缺口**`Gateway.run()` instructor 接通 `output_schema→LlmResponse.parsed` C1 contracts 变更日志)。T2.3 写侧三 repo章节 accepted 晋升/digest append/审稿留痕+裁决 flush commit T2.4 事务全仓 compose 门禁绿ruff 干净format 干净mypy **77 文件**pytest **89 passed**memory 已登记 C6+C1 变更+2 decisions+3 gotchas下一步 **Wave BT2.2**(@llm 并行审图+collect 留痕+review SSE依赖 C6+C4)。
- [2026-06-18] @orchestrator **进入 M2**归档 Phase 1(M1) 至已归档Phase 2 七任务拉入台账计划核对两处偏差并据实修正(1) **T2.3「Repository 逻辑」落 `packages/core/ww_core/domain/`@backend owned而非 `packages/db`**——DB MVP + 唯一约束 `(project_id,chapter_no,version)` 已在 T0.2(@db) 一次建齐M2 无新建表迁移 T2.3 @backend 承接 Repository 逻辑(2) **网关结构化输出缺口**`Gateway.run()` 当前不消费 `output_schema`/不填 `LlmResponse.parsed`instructor 未接线续审依赖此归入 T2.1(@llm)。启动 **Wave AT2.1(@llm·packages/agents+llm_gateway) ‖ T2.3(@backend·core/domain)**不同目录无写冲突)。
- [2026-06-18] @orchestrator **🎉 M1 完成**Wave ET1.9 E2E✅)。真实 DB + mock 网关 E2E 走通 立项写章 SSE自动保存DB 真源断言projects/chapters/usage_ledger)。**E2E 暴露并修复一个生产 bug**draft SSE 端点未提交注入 ledger 的请求 session`SqlAlchemyLedgerSink` 按设计只 flush commit——写库事务归编排层导致真实写章的 `usage_ledger` 行被回滚丢失违背成本账本从第一天」)。修复draft 端点流耗尽后 `await session.commit()`E2E 改用请求 session ledger去掉手动 commit 以回归校验该提交最终全门禁绿ruff / mypy 68 / pytest **57** / alembic 无漂移前端 gen:api/lint/tsc/vitest 24/build 绿
- [2026-06-18] @orchestrator **Wave D 完成**T1.5+T1.6+T1.8✅,单前端 agent)。`pnpm gen:api` 重生成客户端含全 M1 端点路由 `/`(作品库)、`/projects/new`(5 步向导)、`/projects/[id]/write`(工作台 SSE 打字机++自动保存)、`/settings/providers`(脱敏+测试连接+能力徽标)。前端门禁全绿gen:api/lint/tsc/**test 24**/buildM1 占位 API 支撑未造假端点单章导航本章助手/注入透明面板(M2)、向导主角/世界观字段折叠进 premise档位路由只读下一步 Wave ET1.9 E2E(@qa, mock 网关)。
- [2026-06-18] @orchestrator **Wave C 完成**T1.4 立项+写章 API**C3 稳定**M1 端点全落)。记忆网关编排器串成 HTTP5 端点入 OpenAPI写章 SSE(token/done/error) + 幂等自动保存lifespan 幂等 seed stub user owner_id FK 缺口)。网关从凭据构建测试经 dependency_overrides mock全仓 compose 绿ruffmypy **68 文件**pytest **56 passed**后端/编排全部完成下一步 Wave D单个前端 agent T1.5+T1.6+T1.8同一 Next 应用合并做 `pnpm gen:api`避免 apps/web 写冲突
- [2026-06-18] @orchestrator **Wave B 完成**T1.3 编排器/C4稳定 + T1.7 凭据/C3部分)。两个 fresh agent 并行 ~9098k tokens fork )。全仓 compose 门禁绿ruffmypy **61 文件**pytest **48 passed**修了跨包测试碰撞apps/api `fakes.py``fakes_providers.py`root mypy 排除 `conftest.py` 解决多 rootless conftest 同名)。⚠ **Wave C 前置**DB stub user projects/usage_ledger/provider_credentials.owner_id FKusers.idT1.4 须先幂等 seed stub user(`uuid(int=1)`)。下一步 Wave CT1.4(@backend 立项+写章 SSE+自动保存依赖 C4)。
- [2026-06-18] @orchestrator **Wave A 完成**T1.1 + T1.2✅,契约 C1/C5 稳定)。全仓 compose 门禁绿ruff 干净mypy 45 文件pytest **27 passed**9 基线 +10 网关 +8 记忆)。T1.1 网关由 orchestrator 内联实现 fork stream idle timeout 早夭零产出T1.2 记忆由 fork 完成下一步 Wave BT1.3(@llm 写章节点+SSE依赖 C1+C5) + T1.7(@backend 凭据依赖 C1)。
- [2026-06-18] @orchestrator **进入 M1** Phase 1 九任务拉入台账并归档 Phase 0新增 workspace 成员 `packages/llm_gateway`(ww-llm-gateway) + `packages/core`(ww-core) openai/instructor/langgraph/langgraph-checkpoint-postgres/cryptography/tenacity `pyproject.toml` members+mypy_path 已更`uv sync` 通过基线门禁全绿(ruff/mypy 27 文件/pytest 9 passed)。记录 decision`assemble` 返回中性文本以解耦 T1.1T1.2启动 Wave AT1.1 @llm + T1.2 @backend)。
- [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=`
- [2026-06-20] @frontend **UX R1+R2 完成**审稿裁决人体学纯前端无后端改)。R1冲突卡内联命中段预览——新纯函数 `lib/review/snippet.ts` `where` N 解析 1-based 段号 取终稿对应段截断预览无段号/越界/空段null 回退跳转」),`ConflictCard` `snippet` prop 渲染朱砂引用块R2冲突按 type 分组 + 严重度排序设定违例>能力不符>时间线倒错>地理矛盾>性格漂移,未知殿后)+ 组计数徽标 + 「跳到下一条未裁决」(按显示顺序环回)+ 主次裁决按钮(采纳改法=朱砂主、忽略/手改=次级)——新纯函数 `lib/review/grouping.ts``groupConflicts`/`displayOrder`/`nextUnresolvedInOrder`**分组只改显示顺序、每条携原始 index守 conflict_index 覆盖 range 不变量**`ReviewReport` 改分组渲染。TDDsnippet 8 测 + grouping 10 测。前端门禁绿lint/tsc/**vitest 201**(+18)/build。分支 `feat/ux-r1-r2-review-ergonomics`。下一步(按 planR3 验收前清单 → Tier4。
- [2026-06-20] @frontend**UX R3 完成**(验收前清单 HITL gateUX §7.4,纯前端无后端改,续 `feat/ux-r1-r2-review-ergonomics`)。新纯函数 `lib/review/accept-preview.ts``buildAcceptPreview`:据现有 client state 列「本次验收将更新」——晋升版次 + 提炼章节摘要 + 写回裁决(有冲突时) + 验收后伏笔到期扫描(可能置 OVERDUE) + 伏笔建议待登记提醒(有建议时))。**只列后端 accept 事务确实做的事**(核对 `projects.py` accept 端点promote+digest+decisions+overdue 扫描;**不**声称改人物 latest_state/自动落库伏笔建议);带「以上为预期,最终以验收回执为准」免责。`AcceptPanel``foreshadowCount` prop + 未阻断时渲染清单,`ReviewReport``foreshadow.length`。TDD4 测。前端门禁绿lint/tsc/**vitest 205**(+4)/build。下一步按 planTier4T4-a 顶部 AI 工具条 / T4-b 本章指令框+风格预设)。
- [2026-06-22] @backend**✅ T6.2+T6.3 创作工具箱通用端点稳定**(通用生成器框架后端落地,分支 `feat/t6-creation-toolbox`)。新 `ww_skills.TOOLBOX`(11 条legacy 3 + 新 8) + `get_tool``toolbox_registry.py`descriptor 在代码无迁移。3 新端点(`routers/toolbox.py`,已注册):`GET /skills/toolbox`描述符列表legacy 携 `legacy_route``codex?gen=world|character` / `/outline`)、`POST .../skills/{tool_key}/generate`(按 `spec.tier` 经新注入缝 `get_tier_gateway_builder` 建网关 → `run_generator` 结构化预览,**不写库**仅落 ledger未知/legacy→404、项目不存在→404、无凭据→503`POST .../skills/{tool_key}/ingest`(仅 `ingest!=None` 工具world_entities 走 **continuity 预检 409 gate**(`acknowledge_conflicts` 放行) + `partition_writes` 白名单 + schema→JSONB 写库outline 细纲按 idx 拼 beats upsert不可入库→422。PURE context 派发 `services/toolbox_context.build_toolbox_context`4 策略,缺章/大纲→空节拍不报错。response/request schema `schemas/toolbox.py`concrete 子模型,非裸 dict。守不变量 #2/#3/#9。TDD注册表 7 + context 8 + 端点 11 = **+26 测**。**全仓门禁绿**ruff/format 干净、mypy **183 Success**(隔离 cache、alembic **无漂移**无新迁移、pytest **578 passed**。OpenAPI 新增 3 端点 → **@frontend`cd apps/web && pnpm gen:api`**T6 前端前置)。记 contracts C3 扩T6.2/T6.3)。
- [2026-06-20] @frontend**Tier4 完成**T4-a 全局 AI 工具条 + T4-b 本章指令直通生成,分支 `feat/ux-tier4-ai-toolbar`,未并 develop。T4-a`lib/nav/ai-tools.ts`(aiToolItems) + `components/AiToolbar.tsx` 服务端组件AppShell 顶栏下仅项目页渲染(写本章/审稿/大纲/设定库/工具箱常驻一排,写本章=朱砂主动作),用 `--chrome` CSS 变量统一 chrome 高度(项目页 7rem=header4+toolbar3余 4rem6 个固定高度页改用 `calc(100vh-var(--chrome,4rem))` 适配。T4-b全链后端 `assemble/_build_volatile``directive` 形参(「本章指令」段领衔 volatile**绝不入 stable_core**,守缓存前缀不变量 #9`stream_draft` 加可选 body `DraftStreamRequest{directive}` 透传、`directive_len` 入 log 不记原文、不持久化无迁移,重生成 TS 客户端;前端新 `lib/workbench/directive.ts`(STYLE_PRESETS + composeDirective 纯函数)、`useDraftStream.start(p,no,directive?)` 非空时发 JSON body、Workbench 加可折叠「本章指令」textarea + 风格预设 chips。TDDai-tools 4 测 + directive 4 测 + assemble directive 测 + draft 端点 directive/向后兼容 2 测。门禁全绿:后端 ruff/format/mypy(163 文件)/**pytest 479 passed**;前端 lint/tsc/**vitest 213**/build。契约记 contracts C3 扩T4-b
- [2026-06-28] @backend/@frontend**UI Phase G 后端依赖补齐**`ProjectResponse` 增加 `updated_at` / `pending_review_count``chapters``updated_at` 迁移 `8c1d2e3f4a5b``SqlProjectRepo` 聚合项目自身、章节、审稿时间作为最近编辑,并按草稿是否晚于最近 accepted/review 统计待审稿章数。前端 `pnpm gen:api` 后项目库默认按最近编辑排序,新增“待审稿”筛选,作品卡显示最近编辑与待审稿徽标。契约记 `memory/contracts.md` C3 扩UI 计划记 `docs/design/ui-improvement-plan.md` 0.16。
- [2026-06-29] @frontend/@qa**UI review follow-up 修复完成**:补 `lib/review/chapterNav.ts` 使新增章导航测试可运行;`ReviewSectionPanel` 改为本地 open 状态,避免用户折叠后重渲染强制弹开;`ReviewReport.hasReport` 纳入 clean review新增 `tests/test_project_metadata_e2e.py` 用真实 DB 覆盖项目最近编辑/待审稿统计口径。验证:前端 lint/typecheck/vitest **490 passed**/build后端 ruff/format/mypy、pytest **763 passed**;浏览器抽样 review/settings 无 console error/横向溢出。
- [2026-07-06] @frontend**✅ 灵感⑥ 关系图谱(缩减版)+ D4 完成**(纯前端,无后端契约/迁移/gen:api。新增 `lib/characters/graphLayout.ts`(纯逻辑:`roleStyle` role→分组配色关键词映射、`buildGraphNodes`/`buildGraphEdges`(kind→标签`DEFAULT_RELATION_LABEL` 命名常量)、`countDanglingRelations``layoutGraph`(@dagrejs/dagre 一次性确定性初始坐标、中心→左上、不可变)、`buildRelationshipGraph` 端到端)——**仅用现有 `CharacterCardView.relations={name,kind,note}`**:边按 name-join、kind 作中文标签、节点按 role 上色,无 closeness/阵营(数据不存在,不硬造);悬空边(引用未入库角色)跳过并计数。新增 `components/characters/RelationshipGraph.tsx``'use client'`React Flow @xyflow/reactCodexPage 经 `dynamic(ssr:false)` 挂载于人物 tab显式容器高度 h-[28rem] + `import '@xyflow/react/dist/style.css'` + prefers-reduced-motion 关 fitView 动画 + 纸感 CSS 变量配色 + 悬空计数提示)。依赖:`@xyflow/react@^12.11.2`+`@dagrejs/dagre@^3.0.0`(见 contracts.md 2026-07-06。TDDgraphLayout **+22 测**role 映射/节点去空重名/kind 标签+默认/悬空跳过/自指跳过/无向去重/边 id 唯一/悬空计数/布局确定性+不可变/端到端);组件走人工/E2E。前端门禁全绿lint 干净 · typecheck 干净 · **vitest 565 passed** · **coverage lib 95.4%graphLayout.ts 97.6%** · **build OK**codex 路由 7.58 kBReact Flow 懒加载独立 chunk。注`pnpm build` 门禁与运行中的 `next dev`(3001) 共享 `.next` → 触发 dev 服务临时 500stale chunk非代码缺陷、dev watcher 下次重编自愈,未重启服务。