Repository navigation
fix(workspace): preserve Goal selection across source history - #6868
Conversation
Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com>
|
This pull request has merge conflicts with Choose the remote for the base repository, not an out-of-date fork. 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 HEADFor a same-repository clone whose Keep the DCO |
loopx-agent
left a comment
There was a problem hiding this comment.
Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
当前 head 71a87800b522df321fa9cc8a8a39bd3934222fd3 未发现阻塞性代码问题。审阅完整5文件 proposal、+39/-3;实际比较基线 52e4c258e362965a88fc4f46a55c9a1fb28901a1。主干冲突/集成资格与当前代码批准分开。
动机
受影响的是在多个运行来源之间查看 Goal、再用浏览器后退继续原研究的用户。 此前切到另一个 Goal 列表后再后退,旧来源的数据可能把恢复中的已选 Goal 清空;现在等目标来源完成读取后再校正选择。 可观察结果是后退回到原 Goal 和原研究节点,前进或重载仍保持各自来源;真正无效的选择继续被清理。 该切片只验证当前源码构建的只读工作区;已安装宿主、实时可写主控制面及最新主干集成仍须分别验证。 这修复的是用户回到原工作位置的路径;不应要求用户因为一次来源切换重新选择相同 Goal 和研究节点。
改动思路
来源身份和浏览器导航已由现有 status 请求 fence 与路由 owner 管理,本次只在已有选择校正处等待一致快照,并用 replace 避免生成伪历史。 本次边界是既有多来源只读旅程的 Goal 选择恢复,不增加来源权限、持久状态或新的导航框架。 用户选择的 URL 是导航意图,原生来源回读才说明该来源有哪些 Goal。来源切换时二者可能短暂不一致,此时不能用旧列表证明新地址的 Goal 不存在。当前来源成功提交后,真实无效的选择仍需校正;自动校正应覆盖当前历史项,用户主动切换才产生新的导航记录。
以下为该 head 的源码分支说明,实际执行证据见后文:
| 情况 | 校正动作与结果 |
|---|---|
| 正在读取,或路由与已载入来源不同 | 暂不清理 Goal,等目标来源提交 |
| 当前来源已载入,Goal 真实不存在/列表为空 | 清空 Goal,替换当前历史项 |
| 选择来源不可用 | 保持所选来源,显示错误并重试原读取 |
具体改动
独立依据是不可变基线中的 App 会话 RFC。原验收表 Scope 的 A→B→A/迟到读取,在本次来源切换与原节点恢复中 implemented;Result 的离开后继续读取与失败仅重读,在92条分页历史和原来源恢复中 implemented;Authority 由既有来源 scope/只读拒绝继续 implemented;Packaging 的桌面、窄屏、重载、不可用子路径已有当前构建证据,但完整安装态 criterion 仍 deferred,缺口是上述 installed/current-main composition。作者截图属于展示材料,不能代替这些执行结果。
关键代码讲解
DashboardPage的选择校正 effect:新增 loading/来源一致性判断,两个自动清理分支改为 replace,并补足依赖;有效原 Goal 不再被旧来源列表清掉。commitLoadedStatus:既有物理 namespace 绑定与来源提交。相对初始地址先绑定来源,跨物理来源清理研究节点;相同 Goal ID 不等于同一来源节点。loadFromUrl:既有读取、loading、archive 与错误生命周期;新判断直接复用这些事实,没有另存一套来源状态。statusRequestCanCommit:既有 typed generation/selection/projection fence,字节未变;迟到响应仍不能覆盖新选择。
独立 Ego 比较使用实际 Chat Vite 配置及同一转移依赖:基线只加载不可变旧 dashboard 模块,当前版本走原生 Chat builder。全 diff 中只有该 frontend 模块改变产品执行行为,其余是浏览器回归和3张合成来源截图;所以这是受控模块反事实,不是另装完整基线。两边都由真实 RuntimeWorkspaceServer/GoalSourceReader/Explore 投影提供 HTTP,Goal 和历史记录是合成输入,没有使用活跃 Goal 或可写主控制面。
基线 Retained Goal/route0→Distinct→后退后,来源显示 Retained,但 goalId 被清空并回到管家总览。当前 head 在同样路径和延迟读取下保留原 Goal/route0;前进选择 other-goal 后重载、反向切回并后退、同 Goal ID 的 Fresh 来源节点隔离均通过。当前来源中的无效 Goal 与确认空列表仍清理,纠正后历史没有多加一项;恢复来源后可重新进入原 Goal。
对主干的风险
反向风险是新 guard 过宽、让真正失效的 Goal 永远不被清理。已通过真实无效 ID 和空来源两分支检验;空来源首次探针命中既有2秒 status cache,仍读到此前有效内容,随后独立 HTTP 确认空数据、重载清理与恢复均通过。该首次超时保留为缓存条件的测试记录,未写成产品失败或放宽断言。
Fresh 503 时旧 Retained 标题和图均不再展示;失败重试保持 Fresh,来源修复后仍回到 Fresh Goal 和92/92记录。桌面与390px的完整视口、来源/目标/只读状态及失败恢复已实际查看;文档宽度与视口均390。早期截图捕捉到既有入场动画,最终截图等有限动画结束后另行检查。没有增加配置、澄清或确认轮次,来源选择与原浏览器操作就是既有最短任务路径。
独立本地验证:17 native source/HTTP tests passed,dashboard 类型检查、source catalog 与 status projection 两个 smoke、原生 Chat 构建通过。标准 premerge 为 4 direct+7 selected+1 public-boundary check,无 failure/manual hold;构建 chunk advisory 保留。360次浏览器/恢复观察请求均为 GET,另外单独负向 POST 得到405;没有把这次显式拒绝混进“零写请求”计数。驱动曾误用等待参数与歧义按钮选择器,已按实际 DOM 唯一定位修正,均不作产品成功/失败证据。未查询或等待 CI。
语义与 CI 对齐
本次 reuse_existing:复用既有 source.kind、URL、Goal ID、loading 与请求 fence,无新 capability/provider、Enum、持久状态或权限。自动纠正从 push 改为 replace 是已披露的本地行为变化。它不决定哪些主体获准执行,只决定何时可以用当前来源校正导航;目录/状态可读不授予写入。既有只读/source/Goal/origin 拒绝由原后端保留,独立源测试和405反例支持该边界。
我的整体评价
APPROVE,justified_increment。 long_horizon 为 preserved:原工作地址与回读连续性保留,未证明模型采用、持续效果或总成本收益;user_experience 在已有多来源浏览器旅程范围 improved。六行 frontend 增量复用现有 owner,比新增来源导航存储/框架合比例;没有新增版本兼容层或需删除的双轨 owner。本次同域简化就是利用现有 history replace 和类型化来源事实。
当前静态代码与构建旅程有充分决定性证据;Mergify 所报 main 冲突仍需作者集成处理,新 head 必须重核评审。当前较旧分支未执行最新主干的新层级组合,不能借这次批准称其已集成或已安装。没有合并、升级、撤评审或发送跨任务消息的授权推论。
English verdict: APPROVE — 71a87800b522df321fa9cc8a8a39bd3934222fd3 against 52e4c258e362965a88fc4f46a55c9a1fb28901a1. Baseline Back loses the selected Goal; current built UI preserves original Goal/node across disjoint/same-ID sources, reverse navigation, reload and delayed reads. Invalid/empty selection cleanup and source503/retry/recovery remain usable;390px fits.17 native tests, types, focused smokes/build and local premerge pass. Synthetic read-only source records with real HTTP/projector, not installed or latest-main integration. The target conflict remains a separate readiness hold; CI was not consulted.
# Conflicts: # apps/presentation/dashboard/src/views/dashboard-page.tsx
|
Hi @loopx-agent, the DCO If the log confirms a missing |
There was a problem hiding this comment.
Reviewer: model_agent; provider=OpenAI; runtime_reported
Approval conclusion (author-owned PR; GitHub blocks formal self-approval)
评审 6868@3c2b702e1be1009eff54698e0316000c4a26a399。上一轮已在 71a87800b 确认六行前端增量没有阻塞性问题;本头把当前 main 合入以解除冲突,并在新的精确头重新取证。
动机
受影响的是在多个运行来源之间查看 Goal、再用浏览器后退回到原研究的用户。旧行为是:切到另一个 Goal 列表后再后退,旧来源仍在内存里的 Goal 列表会把恢复中的已选 Goal 判成无效并清空,用户被迫重新选择。修复后只在「当前来源已提交」时校正选择,真正不存在的 Goal 与空列表仍会被清理。
改动思路
冲突只在 apps/presentation/dashboard/src/views/dashboard-page.tsx 的选择校正 effect。main 近期为 root Goal 子树读取加了 isLoading && search.rootGoalId 的守卫,而本分支的守卫是 isLoading || (source.kind === "url" && search.statusUrl !== source.label)——前者是后者的子集,因此保留分支的守卫即可同时满足两种意图;依赖数组同时保留 search.rootGoalId,让子树范围变化仍然触发重新校正。其它文件自动合并。
具体改动
相对 main 的净差异为 5 个文件、+39/−4。
apps/presentation/dashboard/src/views/dashboard-page.tsx:选择校正 effect 的守卫改为「正在读取,或路由上的statusUrl与已提交来源不一致时直接返回」,两个自动清理分支使用replace以免生成伪历史;依赖数组同时保留source.label(来源切换)与search.rootGoalId(子树范围变化)。examples/personal-workspace-browser/runtime-source-workspace-browser-smoke.mjs:扩展真实 HTTP 场景,覆盖来源切换后的浏览器后退、前进后重载、同一 Goal ID 但不同物理来源的节点隔离,以及无效 Goal 与空来源仍被清理。examples/personal-workspace-browser/evidence/source-history-return/:三张合成截图(before/desktop/phone),只作展示材料,不作为执行证据。
没有新增来源权限、持久状态或导航框架;来源身份与请求 fence 仍由既有 statusRequestCanCommit 与路由 owner 管理。
对主干的风险
守卫变宽的反向风险是「真正失效的 Goal 永不被清理」,这由既有无效 ID 与空来源两个分支覆盖,且两个自动清理分支改为 replace,不会产生伪历史。本头实测:tests/presentation/test_goal_source.py + tests/presentation/test_runtime_workspace.py 共 17 项通过;dashboard tsc --noEmit 干净;npm run smoke:runtime-source-workspace(真实 RuntimeWorkspaceServer/GoalSource HTTP + 构建产物)通过。未查询或等待托管 CI;已安装宿主与最新主干的层级组合仍不在本轮资格内。
我的整体评价
结论 APPROVE。冲突解决保留了 main 的子树范围语义,也保留了本 PR 的「来源未提交前不清选择」;净差异仍是有界的六行前端改动加回归场景,验证在本头真实通过。
English verdict: APPROVE - 3c2b702. The branch's loading/source-mismatch guard subsumes main's rootGoalId guard, the rootGoalId dependency is retained, and 17 native source/HTTP tests plus the dashboard typecheck and the focused runtime-source browser smoke pass on this head.
Switching between runtime sources with different Goal IDs could erase the previous Goal selection and add automatic cleanup entries to browser history. Back then returned to the workspace overview instead of the selected Goal. Goal reconciliation now waits for the loaded source and route to agree, and replaces invalid selections instead of adding history entries.
The existing packaged browser regression now covers different Goal IDs in both directions, alongside same-ID source isolation, research-node selection, reload, Back/Forward, source failure/retry and narrow layout. The new case fails against main
52e4c258eand passes with this fix.Validation at
71a87800b522df321fa9cc8a8a39bd3934222fd3:This is a scoped navigation fix using the existing source and route owners. Validation uses synthetic Goal records through the real HTTP reader and packaged Chat surface. The screenshots below are synthetic packaged browser evidence; the visible composition is preserved.
Before, desktop:
After returning to the original Goal and research selection:
Narrow viewport after source recovery: