Files
cc-web/.planning/2026-08-12-task-status-runtime-reliability/findings.md
2026-08-13 00:34:37 +08:00

41 lines
4.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

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.

# Codex App 任务状态自动分类发现
## 已确认事实
- 真实 tracked 会话能够看到并调用 `ccweb_task_update`,但多数主模型不会主动维护任务列,因此工具可见不等于自动机制有效。
- 用户明确拒绝新增“任务分类模型”配置,也拒绝 Hook 和 MCP reload。
- 最终方向是服务端复用当前 Codex App 会话已经解析的 Provider、模型和现有认证,发起一次无工具结构化分类请求。
- 当前 Provider 若只有 Codex/ChatGPT 登录态而没有普通 API 凭据,则分类应安全跳过并保持原状态,不能提取或冒用登录令牌。
- 输出必须经过 JSON 解析、严格 Schema、动态启用列、expectedVersion 四层校验;任何失败都保持状态。
## 已落地结论
- 当前会话模型由 `codexAppModelSettings()` 解析;local 模式读取当前 `model_provider` 的 Responses 配置及其普通 API Key,custom 模式只读激活 Profile。
- 分类客户端独立实现 `/responses` 严格 JSON 请求,不复用只支持 Chat Completions 的摘要客户端;请求明确 `tools: []`、`tool_choice: none`。
- 分类事件只接在持久化成功的用户消息与成功主轮次完成;运行事件、失败、中断和回滚不分类。
- `TaskBoardService.updateStatus(expectedVersion)` 负责动态列验证和最终写入,actor 使用独立 `classifier` 审计来源。
- 自动 turn 前 reload 已删除;人工 reload API 和动态任务 MCP 继续作为人工/调试能力存在。
- 普通会话保存必须保护磁盘上版本更高的 `taskTracking`,否则异步分类结果会被持有旧 session 的主轮次覆盖。
- 严格输出的长度限制由本地解析器执行,发给 Provider 的 JSON Schema 避免可选字符串长度关键字,以提升 OpenAI-compatible Responses 实现的兼容性。
- 当前环境的实际 `cch` Provider 支持普通 API Key 与 Responses SSE;分类请求必须解析 `response.output_text.done/delta`,不能假定完成事件的 `output` 一定含文本,也不能等待服务端主动断开连接。
- 当前对话的一次真实请求已验证完整 Provider 链路:使用当前模型 `gpt-5.6-sol`、低推理强度和动态任务快照,1465ms 返回严格结果并判定仍为 `in_progress / 处理中`;验收过程未写生产 session。
## 第一轮代码定位
- `session.model` 经 `codexAppModelSettings()` 解析为模型名与推理强度;这应作为分类请求的模型来源。
- Codex App custom Profile 可直接提供 `apiBase/apiKey`;local 模式只有在当前 Responses Provider 存在普通 API Key 时才可分类,纯 OAuth/token 登录态安全跳过。
- 现有 `callSummaryApi()` 只实现 `/v1/chat/completions` 且没有严格 Schema,不能直接拿来当分类器,但其超时/HTTP 请求框架可参考。
- 当前 `startCodexAppTurn()` 仍在每轮调用 `ensureTaskBoardMcpToolsFresh()`,旧自动状态方案的 reload 接线确实存在。
- `TaskBoardService.updateStatus()` 已支持 `expectedVersion` 乐观并发与动态启用列校验,但 actor 目前只允许 `user/mcp`;分类器需要独立审计来源或明确复用内部来源契约。
- 生命周期服务目前只记录事件;需要继续确认轮次完成事件携带的最终助手文本入口,分类不应继续借生命周期事件自动迁移固定列。
## 触发与并发接线结论
- 普通用户消息在 `handleMessage()` 持久化后进入 Codex App;分类可在保存后异步入队,不阻塞主轮次。
- 运行中插入消息由 `handleCodexAppSteerMessage()` 异步持久化,只有 `turn/steer` 成功或旧 turn 已结束并转为新 turn 时才应入队;失败回滚的消息不得分类。
- 成功轮次的最终助手文本与清洗后的工具调用在 `handleCodexAppTurnComplete()` 已完整可用;仅 `!completionError && !interrupted && !userAborted` 时触发完成分类。
- `TaskBoardService.getTask()` 提供当前状态、摘要、version;`getStatusDefinitions()` 提供动态列;`updateStatus(expectedVersion)` 可承担最终原子写入。
- 当前 actor source 允许 `user/mcp/hook/default`。自动分类需要新增明确的 `classifier` 审计来源,不能伪装成 MCP。
- 旧生命周期服务不自动迁移任务列,只负责反归档等确定性元数据;可以保留,但 `startCodexAppTurn()` 中的 MCP fingerprint/reload 必须从自动主链路移除。
- 分类请求使用当前 Codex `custom` 激活 profile 的 `apiBase/apiKey` 与 `session.model`。`local` 登录态没有普通 API 凭据时记录 unavailable 并保持状态。