Skip to content

fix(chat): persist steering retry identity before dispatch - #6254

Open
songoow wants to merge 2 commits into
loopx-project:mainfrom
songoow:codex/steering-retry-persistence-20261012
Open

songoow wants to merge 2 commits into
loopx-project:mainfrom
songoow:codex/steering-retry-persistence-20261012

Conversation

@songoow

@songoow songoow commented Oct 11, 2026 •

Copy link
Copy Markdown
Collaborator

Current integration readback: updated onto main b760c1eb35613ac84a03cb17246eaba9030db062, head f7f02ee620bb71bf8e189d3c039f44939babb4ec. Merge conflicts resolved without dropping current-main behavior. Current targeted packaged/type/build/premerge checks and exact-head author-owned review pass. Earlier full-suite results below refer to the pre-integration head, not a new whole-suite run. Maintainer review/CI/merge remain separate.

Goal And Delivered Outcome

When browser storage refused a write, live steering still dispatched with an identity retained only in memory. Losing its response and reloading could then lose the identity needed for a safe retry. Both Adjust turn and the ordinary conversation composer now save and read back the retry envelope before dispatch. Failure preserves the editable draft and states that nothing was sent; recovery keeps the same request identity.

中文:浏览器无法保存重试标识时,两个追加指令入口都保留草稿并拒绝发送;恢复存储后沿用原请求重试。

Related to #5201; base: main. This is a bounded browser retry repair, not the full asynchronous-conversation journey.

Author Declaration

  • Written by: OpenAI Codex (GPT-6 family), model_agent.
  • Specification: the reproduced failure and required outcome above. Parent contract: docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md, durable interaction, at 3054cdcc1b236d867c0f28a454672632f27965dd.
Criterion Disposition Owner / evidence
Persist the original retry identity before live steering implemented Existing steering-recovery.ts; exact write/readback and reload regression
Refuse unavailable or silently dropped storage without losing the page draft implemented Both existing send callers; three persistence tests and packaged interaction
Preserve session, turn and same-request retry implemented Existing Chat ingress/store; real HTTP/store/subprocess regression
Keep current execution and result-adoption boundaries implemented No backend, queue, inbox or permission changes; bilingual guide preserves receipt limits

Self-check read the helper, both consumers, existing recovery scenarios and backend ingress deduplication. Future-facing pass: one shared persistence result serves both controls; no new receipt, capability, provider or configuration switch.

Scope And Continuation

The default changes only when browser retry persistence fails. A draft remains editable, but page-memory retention alone no longer permits sending. This adds no work launch or automatic retry. Existing malformed-record/server reconciliation and the parent real-model correction/adoption journey retain their separate acceptance requirements.

Frontend ordinary steward/Goal conversation controls changed. CLI, Lark and backend delivery rules are unchanged. No installed runtime was replaced; maintainer review and merge remain required.

Validation

Tested product bytes: 3d7b5193dce38769b053541f10b9f01c2bfafa1d; local focused runs preceded the DCO commit with unchanged product bytes. Input classes: synthetic/public fixtures. All 51 packaged scenarios passed on these product bytes; this PR remains draft pending exact-head review and remote checks.

Check Result / boundary
Persistence unit regressions 3 passed: exact reload identity, throwing storage, silently dropped write; baseline does not provide dispatch qualification
Packaged conversation-activity Passed: both failed-storage controls send no steering request; recovery, same identity, view/reload, interruption and terminal draft isolation
tests/test_chat_turn_steering.py 29 passed through isolated HTTP, file store and protocol subprocess; native model is synthetic
Type/build and workspace contract Passed; integrity-verified Chat bundle; existing bundle-size warning retained
Standard premerge 3 direct and 13 selected checks passed, including public-boundary scan; no skips/failures in that run
Full packaged workspace All 51 scenarios passed; the steward scenario retains its explicitly unqualified readiness/correction/recovery/return beats
Installed App / real model / full repository suites Not run for this slice; no sustained-team or deployment claim

Frontend / Visual Evidence

Actual packaged baseline and candidate with synthetic conversation data at 1512×982. Baseline accepts steering despite unavailable storage; candidate retains the inline and composer drafts and reports no send. The layout, navigation and first-screen composition are unchanged. Errors stay beside the initiating control; they are not converted into another task or a misleading success.

Before After
Baseline accepts despite storage loss Candidate keeps both drafts and refuses dispatch

Shared-authority fixture impact: N/A; no provider or authority migration. DCO and public/private boundary checks completed; generated locks and local evidence are excluded.

Signed-off-by: song <liusongstep@gmail.com>
@songoow
songoow marked this pull request as ready for review October 11, 2026 17:20

@songoow songoow 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.

Reviewer: model_agent; model=GPT-6 family; provider=OpenAI; self_reported

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

动机

普通会话中的用户在执行期间追加要求。此前浏览器保存重试信息失败后仍会发送;如果服务端收到但响应丢失,再刷新页面,就可能丢失原请求身份。本 PR 让回答内的“调整本轮”和输入框先保存并读回重试信息,失败时明确显示尚未发送并保留当前草稿。正常存储下的发送、原回合绑定和同请求重试继续保留。

这次交付限定于两个 App 入口的发送前保护,不改变 CLI/Lark、队列或收件箱规则,不证明模型已经遵循新要求。完整异步工作和独立验收仍由 #5201 跟踪。这里按 PR 中自包含的故障与不变量判断;docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md 是父级流程背景,没有将整份 RFC 当作本修复的完成范围。

改动思路

沿用原有 steering-recovery.ts:页面缓存继续保存可编辑草稿,持久化函数另外返回写入后读回是否一致。两个已有发送入口在调用执行器前检查这个结果。服务端仍拥有投递、幂等和回执,浏览器缓存不获得新的执行权限。

这一小层保护放在本地草稿与派发的交界处是合适的:只加错误提示仍会丢失恢复身份,只修一个入口会留下另一条绕行路径,新增服务器消息账本则扩大了问题。当前 PR 的边界是“两入口持久化失败时均不发送,恢复后可重试”;没有新协议或配置开关。

具体改动

  • persistRequests / retainSteeringRequest 检查精确的序列化读回,涵盖写入抛错和静默丢弃;页内草稿保留。
  • MessageActivity.steer 与工作区 sendMessage 的本轮追加分支执行相同保护,错误留在原控件附近。成功回执后的清理及确认未投递后的处理沿用原逻辑。
  • 中英文错误提示和现有用户指南公开说明新失败行为;3 个持久化回归进入既有工作区验证命令。
  • 打包场景同时检查两个入口零投递、存储恢复和草稿可编辑,并保留原有丢回执、重载、回合结束和中断竞争检查。两张截图来自实际打包的合成场景。

对主干的风险

审阅头为 3d7b5193dce38769b053541f10b9f01c2bfafa1d,基线为 3054cdcc1b236d867c0f28a454672632f27965dd。持久化数据形状、Session/Turn/请求 ID 和服务端接口未变;额外成本是一遍已有小型草稿缓存的读回。默认行为仅在无法保存重试信息时改变:此前继续发送,现在保留草稿并拒绝发送。这个限制直接保护丢回执后的恢复,不额外要求用户重复填写已知信息。

当前通过:3 个持久化用例,29 个隔离 HTTP/文件存储/协议子进程测试,51 个打包工作区场景,类型/构建/工作区契约,以及标准 premerge 的 3 个直接检查和 13 个选中检查。打包发送测试的执行器事件为合成输入;HTTP 套件使用真实本地存储和协议入口。完整 CI 的 Python、平台和发布门禁仍单独等待,不能把这些局部测试写成全仓或安装态验收。

最强反例是“浏览器调用不抛错却没有保存”:新单测要求读取同一字节串才许可发送。真实浏览器的存储抛错用例则证明发送入口没有绕过此结果。有效存储下的丢响应重试仍使用原身份,结束的回合不会把草稿转投另一回合。已损坏的旧存储记录以及完整真实模型协作,未由本切片解决或认证。

我的整体评价

批准此有界修复,没有发现需要阻止该准确提交的代码问题。它把已有恢复约束落实到了两个实际入口,改动和故障范围相称;共享持久化结果已经消除了两个入口各自判断的必要,无需额外框架。父级真实协作资格、远端 CI 和维护者合并仍是独立事项。此记录是作者账户的完整自评,不代替维护者评审或授予合并权限。

English verdict: APPROVE - 3d7b519. Both live-steering entrypoints require persistent retry readback before dispatch; focused real-boundary checks and all 51 packaged scenarios pass. Remote CI, installed-runtime and live-model qualification remain separate.

@mergify

mergify Bot commented Oct 11, 2026

Copy link
Copy Markdown

This pull request has merge conflicts with main and cannot be merged
until they are resolved. Please rebase or merge the base branch, @songoow.

Choose the remote for the base repository, not an out-of-date fork.
For a fork clone, first inspect git remote -v; upstream must point
to https://github.com/loopx-project/loopx.git. If it is absent, add it
with git remote add upstream https://github.com/loopx-project/loopx.git.
Then run:

git fetch upstream
git rebase upstream/main
# Resolve each conflict, git add the resolved files, then git rebase --continue.
git push --force-with-lease origin HEAD

For a same-repository clone whose origin points to
https://github.com/loopx-project/loopx.git, use origin instead of
upstream for fetch/rebase. If you prefer merging the base, use
git merge <base-remote>/main and push normally.

Keep the DCO Signed-off-by trailer on every commit when you rebase.
https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/syncing-a-fork

@mergify mergify Bot added the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 11, 2026
Signed-off-by: song <liusongstep@gmail.com>
@mergify mergify Bot removed the needs-rebase Mergify: the pull request has merge conflicts with its base branch label Oct 12, 2026

@songoow songoow 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.

Reviewer: model_agent; model=GPT-6 family; provider=OpenAI; self_reported

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

动机

普通会话中的用户在执行期间追加要求。此前浏览器保存重试信息失败后仍会发送;如果服务端收到但响应丢失,再刷新页面,就可能丢失原请求身份。本 PR 让回答内的“调整本轮”和输入框先保存并读回重试信息,失败时明确显示尚未发送并保留当前草稿。正常存储下的发送、原回合绑定和同请求重试继续保留。

这次交付限定于两个 App 入口的发送前保护,不改变 CLI/Lark、队列或收件箱规则,不证明模型已经遵循新要求。完整异步工作和独立验收仍由 #5201 跟踪。这里按 PR 中自包含的故障与不变量判断;docs/architecture/rfcs/app-conversation-and-async-inbox-v0.md 是父级流程背景,没有将整份 RFC 当作本修复的完成范围。

改动思路

沿用原有 steering-recovery.ts:页面缓存继续保存可编辑草稿,持久化函数另外返回写入后读回是否一致。两个已有发送入口在调用执行器前检查这个结果。服务端仍拥有投递、幂等和回执,浏览器缓存不获得新的执行权限。

这一小层保护放在本地草稿与派发的交界处是合适的:只加错误提示仍会丢失恢复身份,只修一个入口会留下另一条绕行路径,新增服务器消息账本则扩大了问题。当前 PR 的边界是“两入口持久化失败时均不发送,恢复后可重试”;没有新协议或配置开关。

合入最新主线 b760c1eb35613ac84a03cb17246eaba9030db062 后复审完整差异。唯一手工冲突在 package.json,保留 steering 存储回归及主线新增的 craft browser 检查;自动合并的 composer、语言资源和指南逐项核对。浏览器已重跑两个实际入口,不把无冲突视为行为正确。

具体改动

  • persistRequests / retainSteeringRequest 检查精确的序列化读回,涵盖写入抛错和静默丢弃;页内草稿保留。
  • MessageActivity.steer 与工作区 sendMessage 的本轮追加分支执行相同保护,错误留在原控件附近。成功回执后的清理及确认未投递后的处理沿用原逻辑。
  • 中英文错误提示和现有用户指南公开说明新失败行为;3 个持久化回归进入既有工作区验证命令。
  • 打包场景同时检查两个入口零投递、存储恢复和草稿可编辑,并保留原有丢回执、重载、回合结束和中断竞争检查。两张截图来自实际打包的合成场景。

对主干的风险

审阅头为 f7f02ee620bb71bf8e189d3c039f44939babb4ec,基线为 3054cdcc1b236d867c0f28a454672632f27965dd。持久化数据形状、Session/Turn/请求 ID 和服务端接口未变;额外成本是一遍已有小型草稿缓存的读回。默认行为仅在无法保存重试信息时改变:此前继续发送,现在保留草稿并拒绝发送。这个限制直接保护丢回执后的恢复,不额外要求用户重复填写已知信息。

当前集成头复测通过:33 个隔离 HTTP/存储/协议测试、3 个持久化用例、打包 conversation-activity(两入口失败和恢复)、类型/构建/工作区契约、todo-ownership 与标准 premerge。此前旧 head 的 51 场景全量结果保留为历史证据,不宣称在新主线上重跑了全量。打包发送测试的执行器事件为合成输入;HTTP 套件使用真实本地存储和协议入口。完整 CI 的 Python、平台和发布门禁仍单独等待,不能把这些局部测试写成全仓或安装态验收。

最强反例是“浏览器调用不抛错却没有保存”:新单测要求读取同一字节串才许可发送。真实浏览器的存储抛错用例则证明发送入口没有绕过此结果。有效存储下的丢响应重试仍使用原身份,结束的回合不会把草稿转投另一回合。已损坏的旧存储记录以及完整真实模型协作,未由本切片解决或认证。

我的整体评价

批准此有界修复,没有发现需要阻止该准确提交的代码问题。它把已有恢复约束落实到了两个实际入口,改动和故障范围相称;共享持久化结果已经消除了两个入口各自判断的必要,无需额外框架。父级真实协作资格、远端 CI 和维护者合并仍是独立事项。此记录是作者账户的完整自评,不代替维护者评审或授予合并权限。

English verdict: APPROVE - f7f02ee. Both live-steering entrypoints require persistent retry readback before dispatch; current integration checks and packaged conversation-activity pass; the earlier 51-scenario run is historical evidence only. Remote CI, installed-runtime and live-model qualification remain separate.

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