| apps/api/agent/ask.ts | POST /agent/ask(api.raw SSE):JSON body 读取与限长 → 会话解析(新建 / 续接 / 回收后重建并注入历史上下文)→ 同会话并发 409 → 用户消息落库 → session.subscribe() 逐 delta 推送 → 助手消息按 (session_id, seq) 去重键幂等落库(带重试)→ done/error 收尾;SSE 错误一律固定文案(不透出 provider 原文,消化 BACKLOG 两条 R2 遗留) |
| apps/api/agent/store.ts(改) | 新增 maxTraceSeq()(重建会话续接轨迹 seq)、upsertMessage()(turn 级去重键幂等写);既有函数签名不变 |
| apps/api/agent/runtime.test.ts | 运行时纯逻辑测试:队列排干/失败重试/硬上限、空闲回收判定、容量逐出、历史转写裁剪 |
| apps/api/agent/ask.test.ts | 幂等写与 SSE 帧编码测试(不打真实 LLM) |
| apps/api/spike/*(改) | events.ts/events.test.ts 迁出后改为从 ../agent/events 导入;spike 其余部分保持不动(R4 随 trace 服务落地整体移除) |
| apps/web/lib/agent-api.ts | 前端数据层:生成客户端实例(base /api)+ askStream()(fetch + ReadableStream 解析 SSE)+ 相对时间格式化 |
| apps/web/components/workbench/Workbench.tsx(改) | 会话列表 / 会话顶栏标题 / 对话区改由真实 API 与 SSE 驱动;样式、布局、className、token、动画参数零改动 |
| apps/web/lib/api-client.ts | dev.ps1 gen 重新生成(生成物,不手改) |
| rounds/BACKLOG.md(改) | 勾销两条 R2 遗留(助手消息幂等持久化协议、SSE error 脱敏口径) |
| ROUNDS.md(改) | 进度表 R3 收口 |
| # | 检查 | 命令 / 期望 |
|---|---|---|
| 1 | 编译 | dev.ps1 check 通过 |
| 2 | 测试 | dev.ps1 test 全绿(含迁移后的脱敏测试与新增运行时测试) |
| 3 | 新会话流式 | 浏览器 / 输入一句话 → 助手文本逐字出现(非一次性整段);curl -N -X POST /agent/ask 观察到多帧 event: delta |
| 4 | 刷新可恢复 | 刷新页面 → 会话列表含该会话(标题=首条用户消息)、点开历史消息完整;重启 encore 后仍可恢复 |
| 5 | 续接对话 | 对同一会话再问一句、且能引用上一轮内容;进程重启(运行时会话已丢)后续接仍带上下文(历史注入) |
| 6 | 并发上限与回收 | 同会话并发第二个 ask → HTTP 409;超过 MAX_ACTIVE_SESSIONS 且无可逐出空闲会话 → 429;空闲超时后会话被 dispose()(日志可见,/agent/ask 再来时重建) |
| 7 | 轨迹仍落库 | 真实对话一轮后 SQL 查 trace_events:seq 连续、jsonb_typeof(data)='object'、data::text 无 authorization/api-key/sk-/bearer 命中 |
| 8 | SSE 脱敏 | 制造 provider 失败(临时改坏 key)→ SSE error 帧只有固定文案,原文只进服务端日志 |
| 9 | 样式零改动 | git diff 中 apps/web 无任何样式/布局/token/动画改动(仅数据源与事件接线) |
| 10 | gen client | dev.ps1 gen 重新生成后前端编译通过(npx tsc --noEmit) |
审查方式:codex /codex:review --background --base fd0f09a(thread 01a05600-b2ba-7413-9eca-7f8116a6946e)
初审 findings 5 条(3×P1 + 2×P2),全部采纳:
整改后回归:dev.ps1 check 通过;dev.ps1 test 5 文件 45/45 全绿(新增 5 条并发回归用例: claim 同步占位、pi 流式时拒绝认领、已认领会话不进逐出/回收候选、冷启动串行链临界区不重叠且 保序、单次失败不掐断链)。 真机复测:12 路并发新会话 → 8×200 + 4×429(上限精确);同一冷会话 3 路并发 → 1×200 + 2×409, 库内只有 1 轮消息(user seq 0 / assistant seq 1)、轨迹 122 条 seq 0–121 连续,无重复会话与 seq 冲突; 两轮正常对话上下文正常(「青花瓷」)。
初审结论:整改后待复审
复审第 1 轮 /codex:review --background --base 88dc2ae(thread 01a05628-23f3-7282-96d4-5ceef14e88a3), 3 条 findings(2×P1 + 1×P2),全部指向上一轮整改本身,全部采纳:
复审整改后回归:dev.ps1 check 通过;dev.ps1 test 48/48 全绿(新增 3 条:释放期间失败批次 回队并由最终 flush 重试写成功、并发 dispose 共享同一释放过程且 pi 会话只释放一次、释放 promise 落定即轨迹已提交)。真机复测空闲回收 → 重建整条路径:回收日志出现后重新提问,上下文恢复 (答出「4271」),消息 seq 0–3 正确,轨迹 103 条 seq 0–102 跨回收边界连续(无缺口、无静默丢弃)。
复审第 2 轮 /codex:review --background --base 3686528(thread 01a05632-816e-7143-bade-3a74b2a81b6b): 未发现由本次改动引入的功能性缺陷——「会话释放与重建的串行交接、失败批次回队、前端历史加载 保护逻辑均与现有生命周期约束一致」。阻塞性/明显 bug findings 清零。
补充审查(带 encore skill):初审与两轮复审走的都是 codex 内置 reviewer,而 /codex:review 不支持自定义 prompt,.claude/skills/ 又是 Claude Code 的约定、codex 不会自动加载,因此这三轮 都没有吃到 encore-code-review 这份框架清单(codex 实际读到的仓库上下文是 AGENTS.md → CLAUDE.md)。已按 10 项清单自查一遍 R3 代码,无新问题:基础设施包级声明 ✅、ES6 import ✅、 APIError(raw 端点直接写状态码是正确用法)✅、SQL 全参数化/模板字面量 ✅、请求响应类型 ✅、 无内部端点误暴露 ✅、无 pub/sub、secret() 模块级声明 + 函数内取值 ✅、无新迁移。 唯一擦边项是跨服务 import:spike/* 编译期 import agent/store、agent/events——这条规则 针对的是「调另一服务的端点」,此处是共享普通库模块;方向 spike → agent 是本轮特意调正的 (agent 不反向依赖 spike,生产构建 --services agent,system 排除 spike 时不会漏带),spike 于 R4 删除。 为免后续轮次重蹈,起初在 AGENTS.md 加了一行指向该 skill 的指针;所有者否掉了这个做法 (指针只是「请你去读」,不保证审查者真去读),改为把 skill 目录镜像给 codex。据此实测了 codex 的 skill 发现规则(仓库根放四个探针 skill,codex exec 让它枚举可用 skill 与加载路径):
| 候选目录 | codex 是否加载 |
|---|---|
| .agents/skills/ | ✅ |
| .codex/skills/ | ✅ |
| .agent/skills/(单数) | ❌ |
| skills/(裸) | ❌ |
| .claude/skills/ | ❌(仓库里本来就有 8 个,一个都没进 codex) |
取 .agents/skills/(与 同一套厂商中立约定)。落地: 子命令把 镜像过去;权威副本仍是 ( 锁版本、 升级),,漏同步的表现是审查悄悄退回旧版清单、 不报错只少查东西——这条已写进 CLAUDE.md「本地开发」段。验证:同步后 枚举, 8 个 encore skill 全部从 加载。
收口结论:PASS——阻塞性/明显 bug 类 findings 清零(复审第 2 轮零 findings); dev.ps1 check 通过,dev.ps1 test 48/48 全绿。
另发起过一轮「带 encore skill 的全轮次补充审查」,所有者裁定不必补,中止:缺陷门禁已在 复审第 2 轮清零,该轮属额外复查而非门禁要求。skill 镜像机制本身已落地并验证(见上), 从 R4 起的每轮审查都会自动吃到。
同一验收项针对性整改后连续 2 次验证仍不过 → 写 rounds/round-03/BLOCKED.md,停下呼人。禁止放宽验收标准自我通过。
验收逐项(2026-08-31,本机 Windows,encore v1.57.13,bun 1.4.0,vitest 4.1.11,模型 deepseek/deepseek-v4-flash):
实现要点与踩坑:
与计划的偏离: