文档:接单化 review 收口第二轮写进 ADR、实施计划与共享记忆

- ADR 的后续更新补第二轮:§4 的拒单载荷 `kind` 收成 typed 枚举与并发拒单身份改成回合身份、§5 的回合身份口径覆盖拒单载荷、§6 的可留痕判据收掉 `ProjectRootUnanchored`、§7 的"同级提示"补上认不出的拒单
- 实施计划加「review 收口第二轮(2026-09-24)」一节,记下拒单表与界面提示口径的现状
- 决策记录追加同日第二条:五条决策、明确不做、两条待决策(连接收束时序、接单后落盘失败的双通道)与影响范围 / 验证证据
This commit is contained in:
2026-09-24 16:24:38 +08:00
parent 85d69a29a9
commit 2f5e0b0ede
3 changed files with 64 additions and 0 deletions
@@ -146,3 +146,10 @@
后续更新(2026-09-24,接单化 review 收口):§2 补"终态的写点在整轮结束之后"与"封口返修要求不是回合
失败"两条不变式;`docs/technical/【技术方案】DirectProject Codex原始历史与异常恢复-2026-09-04.md`
"终态由事实判定"一段同步改写;`docs/project-memory/shared-memory/decision-log.md` 追加同日条目。
后续更新(2026-09-24,接单化 review 收口第二轮):§4 的拒单载荷 `kind` 收成 typed 枚举
`DirectTurnFailureKind`,线上形状与取值不变)、并发拒单的两个身份改成回合身份;§5 的"回合身份由
`clientTurnId` 推导"补上"命令边界的拒单载荷也不例外";§6 的可留痕判据收掉 `ProjectRootUnanchored`
(它与 `ProjectRootUnusable` 同类,是用户自己就能修的文件系统事实);§7 的"同级提示"补上认不出的
拒单(拒单不产生终态事件,聊天里必须由命令边界补一条说明)。失败说明的可见文案口径记在
`docs/project-memory/shared-memory/decision-log.md` 同日第二条。
@@ -1,5 +1,48 @@
# 决策记录
## 2026-09-24 接单化 review 收口(第二轮):失败载荷分类、拒单身份与提示口径
- 决策(失败载荷的 `kind` 收成 typed 枚举):新增 `DirectTurnFailureKind``Serialize + Deserialize + TS`
`kebab-case`,7 个变体,含先前两份名单都漏登记的 `turn-interrupted`),`DirectTurnError::wire_kind`
返回 `Option<DirectTurnFailureKind>`。线上仍是 `{kind, message}`、取值不变,只有 TS 侧从裸 `string`
变成可穷尽收窄的联合类型;全仓没有按 `failure.kind` 分流的代码,它只给界面选语气。
- 决策(并发拒单的两个身份是回合身份):`DirectThreadManager::accept_turn` 冲突时返回占用对象的
`turn_id``DirectTurnReservation::accept` 把这一轮请求的 `clientTurnId` 传成
`incoming_invocation_id`。改动前这两项是进程内 UUID`TurnAlreadyRunning` 的"同一轮仍在处理中"
分支永远命中不了,也与"回合身份由 `clientTurnId` 推导"的口径冲突。占用对象自己的 `token` 仍是
UUID`complete_direct_thread_turn_if_reserved` 靠它配对),只换错误载荷里的两项。
- 决策(目录锚不定的拒单不再写诊断):`DirectTurnError::ProjectRootUnanchored``is_reportable()`
拿掉,与 `ProjectRootUnusable` 同类——符号链接 / 权限 / 目录被删都是用户自己就能修的文件系统事实。
改动前它被命令边界覆写成 `direct-codex-failure:v2` 收口文案,界面上那句"无法锚定 Direct 调用项目
目录:{cause}"被内部诊断串顶掉;现在界面按 `Display` 显示,也不再进 `.agent/runtime/errors`
可留痕的拒单只剩 `environmentNotReady` / `hostStateUnavailable`
- 决策(认不出的拒单也要在聊天里有同级提示):`environmentNotReady` / `hostStateUnavailable` 除上报 +
横幅外,再补一条与用户消息同级的提示——拒单没有接单、不产生 `turn.completed`,否则那条乐观用户
气泡后面永远没有解释(改动前的注释"宿主已经把它放进了 `turn.completed.failure`"对拒单不成立)。
文案走 `projectRuntimeVisibleRejectionError`:取宿主收口文案里已脱敏的摘要与建议,**不套阶段标签**
(拒单这一轮没有开始,阶段只会是默认值);非结构化错误仍只走横幅(它可能发生在接单之后)。
- 决策(失败说明的文案口径):`projectRuntimeVisibleError` 补上宿主 `Display` 事实句的模式
`执行通道已断开` / `等待模型回合结束达到硬上限` / `宿主任务提前结束` / `收尾历史失败` 一族),
并给落盘那档补上不带"失败"二字的事实句;不回落宿主原文(`TransportClosed` 的原文带 `exitStatus=` /
`stderrClass=`)。同时修掉收口文案的版本口径:解析只认 `v1`、宿主发的是多一段 `code=``v2`
脱敏摘要一直命中不了。口径定为"不加模式就只会看到通用文案",写在 `directTurnFailure.ts` 的注释里。
- 明确不做:不改线上载荷形状与 `kind` 取值;不加新的失败阶段取值(拒单仍落默认阶段);不动
`ProjectRootUnanchored` 之外的拒单分类。
- 待决策(本轮没改代码,见交接清单):① "失败事实先于连接收束"的时序保证
`fail_game_creator_codex_app_server_connection` 先置 `inner.closed``record_execution_turn_failure`
200ms 看门狗可能抢先把它收束成 `Interrupted`);② 接单之后历史落盘失败仍从命令返回 `Err`
同一个失败经事件与命令两条通道下发(前端模型把 `Err` 当"这一轮没开始")。
- 影响范围:Rust `apps/ai-game-creator-shell/src-tauri/src/agent/{direct_turn_error.rs,direct_turn_failure.rs,direct_turn_accept.rs,direct_thread_manager.rs,direct_runtime/user_input.rs}`
前端 `src/features/agent-runtime/model.ts``src/view/project-development/chat/{conversation/directCodexConversation.ts,conversation/directTurnFailure.ts,controller/useDirectProjectChatController.ts}`
`src/view/project-development/chat/generated/DirectTurnFailureKind.ts`
`tests/{agentRuntimeModel.test.ts,directThreadChat.test.ts,appSurface/chat-composer.suite.ts,appSurface/project-conversation.suite.ts}`
文档 `docs/adr/【ADR】DirectProject命令接单化-2026-09-23.md``docs/technical/【实施计划】DirectProject命令接单化-2026-09-23.md`
- 验证:Rust `cargo test --bins "agent::"`900 passed / 5 ignored)、定向
`cargo test --bins "agent::direct_turn_error"`15 passed)、`cargo fmt`;前端
`npx vitest run tests/{appSurface.test.ts,directRunAnalytics.test.ts,directProjectTurn.test.tsx,agentRuntimeModel.test.ts,directThreadChat.test.ts}`
277 passed / 9 skipped)、`npm --prefix apps/ai-game-creator-shell run typecheck``npm run check:encoding`
`git diff --check`。真实客户端观感未复核。
## 2026-09-24 接单化 review 收口:终态写点、返修控制流、终止判据与失败投影
- 决策(终态的写点在整轮真正结束之后):Direct 回合先固定终态判定的上下文,`turn.completed` 的写出
@@ -80,3 +80,17 @@
- `cargo test export_bindings` 会重写全部 `chat/generated/`(引号风格漂移),跑完要 `git checkout --`
掉不是本次新增的文件。
- 本机 rust 全量 `--bins` 测试会挂在 mock server 的 `inet_csk_accept` 上,用 `--bins "agent::"` 之类过滤跑。
## review 收口第二轮(2026-09-24
第 3 步的拒单表与第 4 步的界面口径按 review 收口后的状态为准:
- 失败载荷的 `kind` 从裸 `string` 收成 typed `DirectTurnFailureKind`7 个变体,含先前漏登记的
`turn-interrupted`);线上形状与取值不变,TS 侧只是变成可穷尽收窄的联合类型。
- 并发拒单(`TurnAlreadyRunning`)的两个身份改成回合身份:`existingInvocationId` 是占用对象的
`turnId``incomingInvocationId` 是这一轮请求的 `clientTurnId`;占用对象自己的 `token` 仍是 UUID。
- 可留痕的拒单只剩 `environmentNotReady` / `hostStateUnavailable``projectRootUnanchored` 归到
"用户自己就能修"那一档,不再写诊断、界面按 `Display` 显示。
- 聊天里的提示分两条通道:认得的拒单给 `Display` 原文;认不出的拒单(宿主 / 环境事实)除上报 + 横幅
外也补一条同级提示,文案取宿主收口文案里的脱敏摘要与建议(不带阶段标签)。失败说明的文案映射
口径见 `docs/project-memory/shared-memory/decision-log.md``conversation/directTurnFailure.ts`