diff --git a/PROGRESS.md b/PROGRESS.md index e5ed16f..6f61dde 100644 --- a/PROGRESS.md +++ b/PROGRESS.md @@ -208,6 +208,7 @@ T0.1 monorepo 骨架 ✅ @devops · T0.2 16 MVP 表迁移(无漂移,users st > 格式:`- [YYYY-MM-DD] @skill 完成/进展 Txx — 一句话结果 + 影响的契约/文件` +- [2026-07-10] @frontend — **✅ AC-3 后续:润色/整章重写面板内联对话气泡流**(用户反馈:不想每次开「AI 对话」抽屉才看得到对话,要在对话时就地内联可见)。抽出复用组件 `components/workbench/ConversationThread.tsx`(把抽屉内联的 `Bubble`/`readOptions`/`ACCEPT_LABEL` 提取为共享气泡列表,抽屉与内联面板共用 → 外观一致 DRY);新纯助手 `lib/workbench/inlineConversation.ts`(`mergeInlineThreads` 把已落库留痕〔本章 + 指定 kinds〕与「进行中」实时气泡按 id 去重合并、复用 `groupByThread` 定序;`toPendingView` 合成未落库气泡〔`meta._pending/_streaming` UI 标记〕;`isPendingView/isStreamingView/readSegment`)+ **RED→GREEN 9 单测**。RefinePanel/ChapterRewritePanel 内联渲染 `role=log` 滚动气泡流(本章 refine/rewrite + 其 clarify 往复 **∪** 本轮进行中气泡:流式 token 逐字进气泡、缓冲的 clarify Q&A 亦实时可见),输入框置底像聊天;**pending→persisted 无重影**(进行中气泡结束即清、已落库经 `mergeById` 去重);**fail-soft**(历史加载失败仍显示本轮实时气泡,不阻塞回炉/重写);气泡「再接受/回填」复用既有 DRAFT-only HITL 回调(drift-safe,正文仍只在验收才变);clarify gating/abort/停/接受悉数保留。**抽屉保留原样**(底栏仍可开,跨章/项目级全量历史浏览)。**门禁全绿**:lint/typecheck 干净 · vitest **715 passed**(706 基线 + 9)· `test:coverage` 通过(`lib/**` 95.48% ≥ 80)· `build` OK。仅动 `apps/web/`。 - [2026-07-09] @qa — **✅ AC-4 E2E + #1/#6 真源围栏守卫|AI 对话(聊天记录)AC-1..AC-4 全交付**(计划 §6/§8)。**E2E**(`tests/test_ai_chat_history_e2e.py`,真 pg、**零 LLM 无网关**——纯 CRUD 侧记录,镜像 `test_t6_toolbox_e2e.py` 的 `e2e_sm` 生命周期)覆盖 §6 全 6 用例:① 缓冲多轮线程一批落库(作者含糊→AI 反问〔选项进 meta〕→作者答→AI 定稿,同 `thread_id`/`seq` 0..3)→ GET newest-first(`seq`/`role`/`thread_id`/`meta{options,version_no,segment}` 往复保真、全文 content 未截断);② 作用域分区(章级 ∪ 项目级 `chapter_no IS NULL`——`?chapter_no=N` 两者都返回、缺省仅项目级、项目级现于任一章抽屉);③ 跨多批 newest-first + `limit/offset` 分页 + `kind` 过滤;④ **append 只写 `ai_messages`**(UsageLedger/Chapter/ChapterReview/WorldEntity/Job 逐表零变化、`usage_ledger` 恒 0 证无网关)、GET 只读不建行;⑤ 未知项目 POST/GET 皆 404、非法 role/kind·空 messages·超上限 content/meta 五类 422 且失败零落库;⑥ clarify-abandon 代理(服务端无部分写路径,只持久化被显式 POST 的已定线程)。**围栏**(`tests/test_ai_messages_not_in_generation_path.py`,AST 静态守卫,**能变红**):memory/orchestrator 两目录 23 文件无一 import/引用 `AiMessage*`/`ai_message_repo`(Name/Attribute/Import 全扫)+ `MemoryRepos` 捆绑与 `assemble` 形参都不含它 + 植入违规自证探测器非空——把 ai_message repo 接进 `assemble()` 会直接失败(已用真 assemble.py 源注入验证变红)。守 #1/#6:聊天记录是 append-only 旁路侧记录(同 `usage_ledger` 物种),绝不喂 prompt/记忆注入。**门禁全绿**:ruff/format 干净 · mypy **238 文件** · **`alembic check` 无漂移** · pytest **1002 passed**(992 基线 + 10:E2E 6 + 围栏 4)。gotcha 已登记(ai_messages 真源围栏 = code-review BLOCKER)。仅动 `tests/` + `memory/gotchas.md` + `PROGRESS.md`,**未碰任何产品代码**。 - [2026-07-09] @frontend — **✅ AC-3 gen:api + AI 对话 hook/抽屉 + 五类交互留痕**(计划 §4,`dce882c`/`ddf7fa0`/`59f2f60`/`33a9b76`)。**gen:api**(`dce882c`):`POST/GET /projects/{id}/ai-messages` + `AiMessage*` 4 schema 入 `schema.d.ts`(openapi.json 为 gitignore 构建产物),`lib/api/types.ts` re-export 码生成名。**核心**(`ddf7fa0`):`lib/workbench/aiConversation.ts` 纯视图模型(`kindLabel/kindBadge`、`bubbleSide`、`groupByThread` 按 `(created_at,seq)` 组内+线程定序〔**绝不单靠 created_at**——同批共享 created_at 靠 repo 的 seq 消歧〕、`partitionByScope`〔本章 ∪ 项目级〕、`acceptActionFor`〔rewrite→替换整章 / continue·generator→插入正文 / refine→回填选段 / clarify→无〕)+ 11 单测;`lib/workbench/useAiConversation.ts` Workbench 级单实例(懒加载去重 + `mergeById` 防并发覆盖 + 乐观插入/正位对账/失败回滚,**fail-soft 绝不 throw 进生成/HITL**〔守 #3 意图〕;`silent` 直投供无抽屉的工具箱页)+ 9 renderHook 测试;`components/workbench/AiConversationDrawer.tsx` 克隆 ContextDrawer 的 a11y(`role=dialog/log`、`aria-live` additions、Esc、focus trap、还原焦点、prefers-reduced-motion),本章对话 + 项目级生成两段气泡、clarify 只读选项芯片、ai 气泡挂 DRAFT-only 再接受。**hook 返回产物**(`59f2f60`):四生成 hook 加返回值(`RefineVersion|null`/`string|null`/`RewriteVersion|null`/`GeneratorArtifact|null`,向后兼容,补成功用例断言)。**五处接线**(`33a9b76`):RefinePanel/ChapterRewritePanel 结束后 append `[author(意见/答复), ai(产出)]`,**clarify buffer-until-concluded**——澄清 Q&A(原含糊意见→AI 反问〔选项进 meta〕→作者答复)缓冲,随最终产出批一起落库同 `thread_id`,**纯放弃不记**;refine ai 行 meta 存 `version_no`+原选段(每版重锚);ContinuePanel ai-only(续写无作者输入)meta `candidate_index`;GeneratorRunner append `[author(字段摘要,meta{tool_key,input_fields}), ai(渲染预览,meta{tool_key,output_kind})]`(空产物不记,`lib/toolbox/aiSummary.ts` 纯助手+5 单测),InlineToolbox 挂本章号、ToolboxPage silent 项目级(`chapter_no=null`);Workbench 挂 hook 单实例 + 抽屉 + 底栏「AI 对话」入口(`AI_CONVERSATION_ENABLED` 灰度)+ 三个再接受回调(成功关抽屉+toast、refine 漂移不盲替换)。**留痕永不改「是否/何时写正文」**——正文仍只在验收事务落库(守 #3)。**门禁全绿**:lint/typecheck 干净 · vitest **706 passed**(681 基线 + 25:aiConversation 11 + useAiConversation 9 + aiSummary 5)· `test:coverage` 通过(`lib/**` 95.44% ≥ 80,新纯模块/hook 全测)· `build` OK。→ 剩 **AC-4 @qa** E2E(计划 §6)+ P4 #1/#6 围栏。 - [2026-07-09] @backend — **✅ AC-2 repo + append/list 端点 + schema + 契约**(计划 §3,`c675a74`)。repo `packages/core/ww_core/domain/ai_message_repo.py`(`AiMessageRepo`/`SqlAiMessageRepo`/`AiMessageView`/`AiTurnRow`,经 `ww_core.domain` 导出):`append`(一批多条 bubble → 批内 `seq`=enumerate 0 基位置、同 `thread_id`、meta 新 dict 不原地 mutate、`add_all`+一次 flush+refresh,**只 flush 不 commit**) + `list_for_chapter`(`created_at DESC, seq DESC` newest-first;`chapter_no` 非 None → 本章 ∪ 项目级 `IS NULL`,None → 仅项目级;可选 `kind`;`limit/offset`)。schemas `apps/api/ww_api/schemas/ai_messages.py`:批级 append 信封 `AiMessageAppendRequest{thread_id,chapter_no(ge=1)|null,kind,tool_key,messages}` + `AiMessageInput{role,content(min1,max200_000),meta(序列化≤50_000)}` + `AiMessageView` + `AiMessageListResponse{messages}`;`Literal` 为 kind/role 枚举权威(边界 422)。端点 `apps/api/ww_api/routers/ai_messages.py`(prefix `/projects`,tag `ai-messages`,已注册 main):**`POST /projects/{id}/ai-messages`**(201,项目 404,校验 422,append 只 flush + 端点 `commit()`) + **`GET /projects/{id}/ai-messages?chapter_no=&kind=`+`PageDep`**(200,newest-first,只读)。**这是显式记录写入**——五个生成端点逐字节不变、只读(守 #3);`ai_messages` 旁路侧记录,`assemble()`/agent 永不读(守 #1/#6)。注入缝 `get_ai_message_repo`。**TDD**:repo 真 pg 单测 9 passed(seq 0..n-1 / 同 thread_id / `created_at DESC,seq DESC` / union 含 NULL / 分页 / flush-only 跨 session 不可见);端点集成 12 passed(round-trip / 本章∪项目级 / kind 过滤 / 404×2 / 422×5〔非法 role/kind、空 messages、空 content、超上限 content、超上限 meta〕 / commit 边界 / 响应 key 集合不泄漏)。**门禁全绿**:ruff/format 干净 · mypy **238 文件** · **`alembic check` 无漂移**(本任务不加模型)· `export_openapi` 成功(新端点+4 schema 已入表面)· pytest **992 passed**(971 基线 + 21)· 新模块 cov router 100%/schemas 100%/repo 97%(余 Protocol `...` 桩),全局 89%。契约 **C3 扩(AC-2)已登记「稳定」** → **@frontend AC-3 须 `cd apps/web && pnpm gen:api`** 后消费码生成名。