文档:回合顺序修复写进 ADR、实施计划与共享记忆
- ADR:补「开口用户条目先于整轮里的一切失败」这条顺序不变式(发点在接单 + 落盘之后、起 codex 之前),以及界面「回合归属只认身份」的口径 - 实施计划:新增「回合顺序修复(2026-09-24)」一节,写清现场、根因、两条改动与回归用例 - decision-log:新增同日决策(宿主发点提前 + 前端按身份归位、收口早退不吞说明) - pitfalls:新增同日条目,并记下排查提示——先分清逻辑回合的 turn.started / turn.completed 与 app-server 协议的 turn/start 请求
This commit is contained in:
@@ -162,3 +162,12 @@
|
||||
失败事实写进执行适配器**之后**才让"连接已死"对看门狗可见(`closed` 不再兼作去重标志,去重改用私有的
|
||||
`connection_end_claimed`),否则 200ms 看门狗可能抢先把它收束成 `Interrupted`,那一轮退化成"本轮已结束、
|
||||
没有原因";失败事实是在模型终态那一刻被快照进终态上下文的,晚补记无用。
|
||||
后续更新(2026-09-24,回合顺序修复:开口用户条目先于整轮里的一切失败):§2 补一条**顺序不变式**——
|
||||
本轮的开口用户条目是这一轮的**第一条运行态条目**,发点在"接单成立、用户条目落盘成功、起 codex 之前"
|
||||
(`emit_direct_thread_user_item`,调用点在 `direct_runtime/user_input.rs` 的命令主体),不再等 `turn/start`
|
||||
应答。它以前在 `turn/start` 之后才下发,于是"接单到 `turn/start` 之间"的失败(连不上 app-server、执行器
|
||||
未通过验收、历史注入失败)没有用户条目可挂:界面把失败说明按位置落进**上一轮**的分区,显示成"错误
|
||||
在用户消息上面",上一轮还顶替本轮显示耗时(现场:17:22:46 发的那条消息下面显示上一轮的 15.6 秒),
|
||||
本轮的用户气泡再自成一个 0.0 秒的假回合;下一条消息同样看不到自己的失败说明。§7 的界面口径据此补上
|
||||
"回合归属只认身份":失败说明条目带 `turnUserItemId`,投影层按开口条目身份分组,本地乐观气泡按身份挂回
|
||||
自己的回合;reducer 的收口早退也不再吞掉"订阅重建只回放生命周期锚点"时那条还没写进界面的失败说明。
|
||||
|
||||
@@ -9470,3 +9470,13 @@ CI 上 `background_agent_runtime_recovers_stale_running_before_pending_task` 在
|
||||
- 影响面:`server-rs/crates/api-server/src/{config.rs,modules/game_distribution.rs}`、`server-rs/crates/shared-contracts/src/game_distribution.rs`、`packages/shared/src/contracts/gameDistribution.ts`、`src/components/game-distribution/gameDistributionGuards.ts`(含新增测试)、`deploy/{nginx,container,env}`、`scripts/check-game-distribution-media-e2e.mjs`、`package.json`、平台与运维主规范。
|
||||
- 边界:SpacetimeDB 表结构与公开契约字段不变(`entryUrl` 仍是 string),只是取值从绝对 URL 变为相对路径;历史版本已冻结的绝对值不改写,admin 页与详情页展示口径不变。线上 dev / release 的 nginx 已按同源路径改动并 reload,`/etc/genarrative/api-server.env` 已删除模板变量;api-server 未重启,新写入要等下次重启。
|
||||
- 验证:`cargo check -p api-server --tests`、`cargo test -p api-server game_distribution`(27 passed)、`cargo fmt --all --check`、`npx vitest run src/components/game-distribution`(57 passed)、`npm run check:nginx-spa-routes`、`npm run check:encoding`(5060 文件)、`npm run check:doc-index`、`git diff --check` 全部通过;三份 nginx 模板渲染后 `nginx -t` 语法通过;dev 线上实测 `/games/game_2dcd…4955/` 与 `./assets/index-2Ws3zHlS.js` 均 200。
|
||||
|
||||
## 2026-09-24 DirectProject 失败说明按回合身份归位:开口用户条目发点提前到接单之后
|
||||
|
||||
- 背景:用户在同一个项目里连发消息,每条都在**连接获取阶段**就失败(执行器版本未通过逐次审批协议验收),界面上"错误显示在用户消息上面",上一轮还顶替本轮显示耗时(现场 15.6 秒),本轮气泡自成一轮显示 0.0 秒;后面再发一条,说明落进更早的分区里,用户以为"这条没报错"。区分两个 `turn/start`:逻辑回合的 `turn.started` 由接单动作发出(成对、一定有);app-server 协议的 `turn/start` 请求在连接拿到之后才发。失败发生在后者之前。
|
||||
- 根因:本轮的**开口用户条目**(`item_completed`,身份 `direct-codex:{clientTurnId}:user`)原来在 app-server `turn/start` 应答之后才下发,于是"接单到 `turn/start` 之间"的失败没有用户条目可挂;前端 `buildDirectChatTurns` 按**条目顺序**分回合,失败说明只能落在上一轮末尾,而本轮的乐观气泡被排在所有正式条目之后 → 渲染成"错误在用户消息之上"。
|
||||
- 决策(宿主):开口用户条目的**发点**提前到"接单成立、用户条目落盘成功、起 codex 之前"(`emit_direct_thread_user_item`,调用点 `direct_runtime/user_input.rs` 的命令主体),删掉 `turn/start` 之后那一处;线上仍然只有一处下发,不变式变成 `接单 → 开口用户条目 → 整轮里其余一切`。
|
||||
- 决策(前端):回合归属只认**身份**——失败说明条目带 `turnUserItemId`(reducer 写),`buildDirectChatTurns` 按开口条目身份分组(同一身份的条目永远同一轮),本地乐观气泡按身份挂回自己的回合而不是另开一轮;reducer 的收口早退只挡重复终态,不再吞掉"订阅重建只回放生命周期锚点"时那条还没写进界面的失败说明(`direct_thread_manager.rs` 的 `lifecycle_anchor`)。
|
||||
- 影响面:`apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs`、`.../agent/direct_runtime/user_input.rs`、`.../chat/conversation/{directThreadChat.ts,directTurnPresentation.ts}`。
|
||||
- 边界:`project.jsonl` 里的用户条目依旧只在首屏 / 翻页时读进前端,本轮不改读取时机——开口条目的运行态下发 + 身份归位已经让"说明挂错回合"不成立。
|
||||
- 验证:宿主 `cargo test --bins "agent::"`、`the_opening_user_item_is_emitted_before_anything_that_can_fail_in_the_turn`、`direct_project_turn_does_not_forward_codex_user_echo_as_chat_items`(补上同一发点);前端 `directTurnPresentation.test.ts` 的"本轮用户条目没到时,失败说明按身份挂回自己那一轮,本地气泡不再自成假回合"、`directThreadChat.test.ts` 的两条(身份字段、收口早退不吞说明)。
|
||||
|
||||
@@ -5960,3 +5960,12 @@ Cocos Creator 根目录由 `package.json.creator.version` 与普通 `assets/`
|
||||
- **处理(现行口径)**:`createChannelConfig()` 从基线 `src-tauri/tauri.conf.json` 读完整 client 窗口对象后展开、只覆盖 `title`(`readBaseClientWindow()`),渠道配置不得再出现"只写 `title`"的窗口对象。新增守卫:`build-release.test.mjs` 用同语义的 merge patch 复现 Tauri 合并并断言 `label=client` / `decorations=false` / 1280x800 / min 1280x720 且承载 `http:default` 的 capability 必须包含该 label;`check-config.mjs` 增补基线 `decorations !== false` 失败关闭。
|
||||
- **验证**:`node --test apps/ai-game-creator-shell/scripts/build-release.test.mjs scripts/cargo-features.test.mjs scripts/release-oss.test.mjs scripts/prepare-macos-codex.test.mjs`(60/60)、`node apps/ai-game-creator-shell/scripts/check-config.mjs` 通过;`createChannelConfig('dev', …)` 实测输出含 `label: client` 与 `decorations: false`。修复后的安装包尚未重新构建与安装,真机观感与登录链未复核。
|
||||
- **关联**:`apps/ai-game-creator-shell/scripts/build-release.mjs`、`apps/ai-game-creator-shell/scripts/build-release.test.mjs`、`apps/ai-game-creator-shell/scripts/check-config.mjs`、`apps/ai-game-creator-shell/src-tauri/capabilities/main.json`、`docs/technical/【技术方案】AGC客户端更新检查与下载-2026-08-31.md`。
|
||||
|
||||
## 2026-09-24 DirectProject 失败说明显示在用户消息之上、下一条消息看起来"没报错"
|
||||
|
||||
- **现象**:连发几条消息,每条都在连接阶段失败(执行器版本未通过验收)时,界面上"错误出现在自己消息的上面",上一轮底下显示"本轮结束于 <本轮结束时刻> · 耗时 15.6秒",自己这条底下显示"耗时 0.0秒";再发一条,失败说明落进更早的分区,用户以为这条没有报错。
|
||||
- **原因**:① 本轮的开口用户条目(`item_completed`)原来在 app-server `turn/start` 应答之后才下发,连接阶段失败走不到那一步 → 事件流里只有逻辑回合的一对事件,没有开口条目;② 前端 `buildDirectChatTurns` 按条目顺序分回合,失败说明(assistant 条目)只能挂在"当前回合"(上一轮)末尾;③ 本地乐观气泡被排在所有正式条目之后,于是自成一轮(无边界 → `Math.max(endedAt, startedAt)` 兜底出 0.0 秒),上一轮则借用了本轮的终点(15.6 秒)。另一条独立漏洞:reducer 的收口早退(`!turnRunning && live 为空`)会整条吞掉"订阅重建只回放生命周期锚点"时那条失败说明。
|
||||
- **处理(现行口径)**:开口用户条目的发点提前到"接单 + 落盘成功、起 codex 之前"(`emit_direct_thread_user_item`),线上仍只有一处下发;回合归属改成按身份(失败说明带 `turnUserItemId`,同一身份的条目永远同一轮),本地气泡按身份挂回自己的回合;收口早退改为"说明还没写进界面就不早退"(只补说明与终点,不重开回合、不抬高冻结终点)。
|
||||
- **排查提示**:先分清两层 —— 逻辑回合的 `turn.started` / `turn.completed`(Thread Manager,一定有、成对)vs app-server 协议的 `turn/start` 请求(连接拿到之后才发)。"失败说明挂错回合"永远先看这条顺序,不要先怀疑事件丢了。
|
||||
- **验证**:宿主 `the_opening_user_item_is_emitted_before_anything_that_can_fail_in_the_turn`、前端 `本轮用户条目没到时,失败说明按身份挂回自己那一轮,本地气泡不再自成假回合` 与 `收口早退不吞掉还没写进界面的失败说明(订阅重建只回放生命周期锚点)`。
|
||||
- **关联**:`apps/ai-game-creator-shell/src-tauri/src/agent/codex_app_server/mod.rs`、`.../agent/direct_runtime/user_input.rs`、`.../chat/conversation/{directThreadChat.ts,directTurnPresentation.ts}`、`docs/adr/【ADR】DirectProject命令接单化-2026-09-23.md`。
|
||||
|
||||
@@ -100,3 +100,23 @@
|
||||
(`CodexAppServerInner::closed` 不再兼作去重标志,去重改用私有的 `connection_end_claimed`,
|
||||
`closed` 在 `record_execution_turn_failure` 之后才置位);回归用例
|
||||
`connection_death_records_the_failure_fact_before_the_watchdog_seals_the_turn` 把看门狗真正跑起来钉这条。
|
||||
## 回合顺序修复(2026-09-24)
|
||||
|
||||
现场:用户在同一个项目里连发几条消息,每条都在 `turn/start` 之前失败(执行器版本未通过验收),
|
||||
界面上"错误显示在用户消息上面",上一轮还显示出本轮的耗时(15.6 秒),本轮气泡自成一轮显示 0.0 秒;
|
||||
后面再发一条,失败说明落进更早的分区里,用户以为"这条没报错"。
|
||||
|
||||
根因是**一条顺序**:本轮的开口用户条目原来在 `turn/start` 应答之后才下发,而失败说明按"当前回合"
|
||||
归位(前端按条目顺序分回合),于是接单后、`turn/start` 前的失败没有用户条目可挂。
|
||||
|
||||
- 宿主:用户条目改成"落盘成功、起 codex 之前"下发(`emit_direct_thread_user_item`),删掉 `turn/start`
|
||||
之后那一次;不变式:`接单 → 开口用户条目 → 整轮里其余一切`。
|
||||
- 前端:失败说明带 `turnUserItemId`,`buildDirectChatTurns` 按身份分组(同一身份的条目永远同一轮),
|
||||
本地乐观气泡按身份挂回自己的回合而不是另开一轮;收口早退只挡重复终态,不再吞掉还没写进界面的失败说明。
|
||||
- 回归用例:宿主 `the_opening_user_item_is_emitted_before_anything_that_can_fail_in_the_turn`、
|
||||
`direct_project_turn_does_not_forward_codex_user_echo_as_chat_items`(补上同一发点);
|
||||
前端 `本轮用户条目没到时,失败说明按身份挂回自己那一轮,本地气泡不再自成假回合`、
|
||||
`失败说明带上它所属回合的身份,用户条目没到时投影层也能归位`、
|
||||
`收口早退不吞掉还没写进界面的失败说明(订阅重建只回放生命周期锚点)`。
|
||||
- 已知边界:`project.jsonl` 里的用户条目依旧只在首屏 / 翻页时读进前端,本次不改这条读取时机——
|
||||
开口条目的运行态下发与身份归位已经让"说明挂错回合"不再成立。
|
||||
|
||||
Reference in New Issue
Block a user