Skip to content

fix(app): preserve readable conversation history and recover without replay - #5328

Open
huangruiteng wants to merge 4 commits into
mainfrom
codex/app-owner-continuity-0930
Open

huangruiteng wants to merge 4 commits into
mainfrom
codex/app-owner-continuity-0930

Conversation

@huangruiteng

@huangruiteng huangruiteng commented Sep 29, 2026 •

Copy link
Copy Markdown
Collaborator

Goal And Delivered Outcome

A temporarily unreadable older Session currently hides the entire App conversation. For “接着昨天的做。” / “Pick up where we left off,” readable messages should remain visible and retain their original result locations.

This change isolates failed history reads in a shared TypeScript boundary used by both steward and Goal conversations. Only missing records retry, with backoff and a visible retry control. If the selected executor’s current Session is unreadable, Send and Enter wait for that record while preserving the draft; recovery continues once in the original Session. Another executor’s readable Session cannot bypass that gate.

  • Base: main; owning contract: App conversation and async inbox RFC, roadmap R1 recovery.
  • Complete within the history-recovery scope. Native owner routing, cross-session adoption and the complete GQ02/GQ09 journey remain separate acceptance work. This PR does not claim installed App behavior.
  • Refactor: reuse the existing return reconciliation and file-backed Chat transport; remove the all-or-nothing hydration branch. Python only returns the actual persisted projection-message IDs; the existing registry-I/O census refreshes two shifted source locators without changing classifications. No new runtime, inbox, lease, authority or provider decision owner.

Validation

  • Reviewed revision: 2a0f224259be1a160991d01adb4eccd4f0488a01. Functional build/browser/runtime checks ran at 16d055fa67116f293ecb7746c9aa8eb9a950b521; the final commit only refreshes two source-line locators. Native premerge and census validation ran on final head.
  • Run state: finished.
  • Input classes: synthetic, public_fixture.
Check kind Result Evidence / limitation
static passed Dashboard npm run build: strict TS, desktop and bundled Chat asset integrity; configured Python mypy and changed-file Ruff; public/private scan and DCO.
unit passed npm run test:conversation-returns; focused chat CORS, input-validation and active-turn suites (105 passed). Exact session/message IDs and user/answer roles retain distinct records.
real_backend passed npm run smoke:conversation-history against disposable real Chat HTTP/file storage: partial read, channel isolation, missing-only retry, unchanged storage and zero Turns.
real_entrypoint passed uv run --extra test python examples/loopx-chat-server-smoke.py: projection exchange IDs equal persisted user/answer records.
integration passed npm run smoke:personal-workspace-packaged: all 25 browser scenarios. Current-session failure blocks Send and Enter, preserves the draft, resumes the exact Session once; streamed and projection-only navigation do not duplicate messages.
regression_parity passed The same production GET and packaged-browser oracles fail on immutable base 649826221289cd4cb3dd8880d016e0afbbaca0fc, then pass on head. The injected fault changes reads only. Healthy recovery and existing packaged journeys remain covered.
static passed Final-head loopx canary premerge --from-git-diff --goal-id GOAL: 16 selected and 5 direct checks; exact-scope quality receipt verified. The first run exposed stale census line locators, corrected with the existing generator and revalidated.
manual passed Before/after desktop and narrow-screen attention review with synthetic records; no horizontal overflow introduced.

Coverage: source packaging and isolated real Chat storage are verified. Live providers, full native delegation/adoption and an installed desktop rollout were not exercised. No model API calls, historical request replays or active Goal state mutations were used for validation.

Frontend / Visual Evidence

  • UI impact: changed, limited to conversation history loading/failure feedback and current-session send readiness.
  • Before: an older-read failure displays an empty conversation.

Before: readable messages disappear

  • After: healthy messages remain visible beside a compact, truthful history notice and one retry control.

After: partial history stays visible

Narrow screen: partial history

Current Session unreadable: draft retained, send waits

  • States/viewports: partial older history at 1512×982 and 390×844; current-record recovery with retained draft and disabled Send at desktop width.
  • Source data: synthetic.
  • Attention review: keep the conversation as the main content; place failure and the only recovery action near the composer. No fake model progress or additional configuration steps. Normal hero/navigation are unchanged.

Type of Change

  • Bug fix
  • Documentation update
  • Test update

LoopX Area

  • Public docs or presentation surface (dashboard)
  • Host or runtime integration

Shared-authority RFC fixture impact

N/A: no authority-store, provider-routing, promotion or compatibility-projection change. This is shared App read reconciliation using the existing Chat store and HTTP contract; the projection response adds stored message IDs without new effects.

Boundary Checklist

  • No private state, credentials, raw traces, internal links, local machine paths or generated logs/screenshots in the diff.
  • Scoped to conversation history recovery; no unrelated benchmark work.
  • Every commit has a DCO sign-off.
  • Synthetic before/after, mobile and gated-state visual evidence included.

Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng marked this pull request as ready for review September 29, 2026 21:54

@huangruiteng huangruiteng left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approval conclusion (author-owned PR; GitHub blocks formal self-approval)

Reviewed full PR at 2a0f224259be1a160991d01adb4eccd4f0488a01, against base 649826221289cd4cb3dd8880d016e0afbbaca0fc. 没有未解决的阻塞项。结论覆盖历史恢复这一可独立验收的增量;不把读取恢复视为原生委派、接收方采用或完整 GQ09 已通过。

动机

普通任务是“接着昨天的做”。旧版对所有 Session 使用 Promise.all:一个旧记录返回 503,当前可读消息也不显示,界面还可能呈现空会话。不可用的读取应当明确显示,不能成为重放任务或另建驱动的理由。此次改动使已有对话、结果位置和草稿在这种失败中可继续使用,直接改善 R1 恢复路径。

改动思路

最小的 Promise.allSettled 替换只能保住初次读取,仍缺少缺失记录恢复、实时消息去重和当前执行器的发送判定。采用现有 Chat HTTP/file store、reconcileConversationReturns 和会话恢复入口;新 useConversationHistory 只是管家与 Goal 共用的 TS 读取 owner。普通历史重读和有回传义务的轮询保持不同触发条件,但共享同一消息身份和合并规则。没有新增 capability、权限、收件箱、lease、模型调用或并行 Python 决策源。

具体改动

关键代码讲解

  • chat.ts:789 的 fetchChatHistory 保留可读快照,单次读取有超时,退避重读仅覆盖缺失项;消息身份从单独 message ID 改为 Session+message ID。现有真实 HTTP 列表按 channel/Goal/Agent 过滤,无展示截断被误当完整来源的问题。
  • use-conversation-history.ts:14 的 useConversationHistory 在当前选择的执行器上判定记录是否可读;更“新”的其他执行器 Session 不能绕过等待。旧记录恢复只补历史,不重新连接当前流。作用域切换取消旧写回,成功完整读取不持续轮询。
  • conversation-returns.ts:64 的 reconcileConversationHistory / reconcileConversationReturns 保留实时文本、缺失时的最后回传状态和原始位置;同一 Turn 的用户消息与答复分别绑定。Dashboard 给已接受消息和状态投影写入准确身份,导航回来不产生重复消息。
  • personal-workspace-page.tsx:1574 的 PersonalWorkspacePage.sendMessage 与按钮共用发送判定,Enter 也不能绕过;草稿保持,恢复后在原 Session 提交一次。中英提示、单个重试按钮和现有主题样式都放在输入区旁,桌面与窄屏已实际渲染。
  • Python chat_server.py:614 的 _record_projection_exchange 返回现有写入产生的两个 message ID,仍是原 v1 的附加字段,未增加副作用;真实服务器已逐项对照落盘消息。registry-I/O census 只修正该文件引起的两个行号变化,分类未改。
  • 单元、真实 HTTP/file-store 和已有 packaged 浏览器框架补上负例;现有 fixture 的省略执行器行为按实际 host 默认值纠正,全套 25 场景通过。RFC 将共享读取恢复及其验收边界写清。

对主干的风险

默认变化是:当前已列出的 Session 无法读取时,普通发送等待原记录恢复;旧记录不可读而当前可读时仍能发送。这是明确的正确性条件,已在 RFC、PR 和负例披露。重试会产生 GET,按 3–30 秒退避,没有任务重放;持续存储故障仍会保持等待,需要原读取来源恢复。

反向风险也验证了:只坏旧记录不应过度阻塞;只坏当前记录不能被别的执行器或 Enter 绕过;恢复不丢草稿、不重复请求;实时答复和状态投影均能跨导航保留正确身份。真正的存储故障通过隔离 Chat HTTP/file backend 验证;浏览器的执行答复为脚本化 fixture,因此不证明 live provider 或接收方实际采用。

验证包括 strict TS/打包、回传单元测试、真实 Chat server、105 项现有 Chat 回归、25 个 packaged 浏览器场景,以及相同 harness 的 base/head 反证:base 在真实 GET 和可读当前消息的浏览器断言上均失败,head 通过。最终 head 的 16 项 selected+5 项 direct premerge 检查全部通过,无失败、超时或跳过;首次 premerge 发现的 census 行号过期已用现有生成器修正。功能验证在 16d055fa6 完成;之后唯一源码差异是这两个 census 行号,最终 head 再跑原生检查和 exact-scope quality verify。未查询或等待远端 CI。

语义与 CI 对齐

沿用现有 Chat Session、Turn 和回传位置词汇,读取状态是 TS 派生投影。新增 message ID 来自已有落盘记录,不构成新的授权或协作协议。原生检查采用当前仓库本地要求,UI 另外用 strict TS、真实 HTTP 和 packaged 交互补足;没有把远端 CI 当作评审依据。

我的整体评价

APPROVE,完整交付历史恢复这一范围。 相比只吞掉异常,这个增量让用户能看见已有工作、保留输入、恢复后继续一次,且通用 TS owner 可用于管家与 Goal。相关 #5293 的原始回传定位契约继续复用;本 PR 没有借机重写委派或协调。未来扩展仍围绕该读取边界,不需要复制一个 manager 专用实现。

最强的剩余验证是安装后的原生负责人接收与采用闭环,本 PR 未声称完成它;持续性规模与损坏的 Session 索引也不在当前 HTTP 读取故障范围内。界面证据使用 PR 中的合成 before/after、窄屏和当前记录等待截图。依照仓库规则,运行时/产品变更留给维护者合并。

English verdict: APPROVE - HEAD 2a0f224 preserves readable history and exact message lineage, retries reads without replay, and resumes the original Session once. Real HTTP/store, packaged negative paths, baseline counterfactuals and final-head premerge passed; native adoption and installed rollout remain unclaimed.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant