Skip to content

fix(workspace): let Back restore its source over an in-flight re-scope - #7550

Open
LIHUA919 wants to merge 1 commit into
loopx-project:mainfrom
LIHUA919:codex/chat-bundle-goal-hierarchy-20261028
Open

LIHUA919 wants to merge 1 commit into
loopx-project:mainfrom
LIHUA919:codex/chat-bundle-goal-hierarchy-20261028

Conversation

@LIHUA919

Copy link
Copy Markdown
Contributor

Goal And Delivered Outcome

  • Outcome basis / optional anchor: the required chat-bundle-browser job of Python Tests (one of the jobs checks verifies) failed on main after test(workspace): repair the remaining dashboard-browser lane failures #7508 made dashboard-browser green: run 40585213327 on 322591fb9, chat-bundle-browser (2) at goal-hierarchy.mjs:241.
  • Goal/source and gap: goal-hierarchy checks that one Back restores a source and its root scope together. The scenario selects Remote B, scopes it to operations, then goes back four entries to source A scoped to research. In the failing runs the route briefly reads source A/research, then the page re-reads Remote B with root research and rewrites the URL back to Remote B. The user is stranded on the wrong source, which is the exact case the scenario's comment describes.
  • Root cause: "只看此 Goal 及子 Goal" starts a re-scoped read of Remote B, so requestedStatusUrl is Remote B until that read commits. If Back lands before the commit, the root-change effect in dashboard-page.tsx chose requestedStatusUrl ?? route, so the in-flight re-scope beat the restored source. fix(ci): stabilize required dashboard-browser goal-hierarchy shard #6890 / d8c62a0bf made the route outrank the loaded source, but not an in-flight read of it.
  • Fix: the app writes statusUrl into the route only in commitLoadedStatus, always for the source it just loaded. So when a source is loaded and the route names a different one, the route came from Back/Forward, and that restored source now wins. When the route still names the loaded source, an in-flight user source selection is re-scoped as before, and the loaded source is still the fallback.
  • Observable before → after: Back restores source A and its research subtree instead of re-reading Remote B. Locally, goal-hierarchy failed 8/8 packaged runs and 1/2 development runs on main 843be4942. With this commit it passes 4/4 packaged and 3/3 development.
  • Issue/task and intended base: Related to CI: chat-bundle-browser and dashboard-browser shards time out on main #7389 (intermittent browser-shard failures on main). [Bug]: the required chat-bundle-browser lane is red on main — the read-only source badge repeats the visible Goal title #7378's original failure was fixed by fix(workspace): stop the read-only source badge from repeating the Goal title #7380. Base main.

Author Declaration

  • Written by: model_agent (Claude Opus, Anthropic), at the account owner's direction.

Implemented against

  • Specification and revision: the shipped goal-hierarchy contract ("A history entry restores the source and the root scope together. The restored route must drive the read") and the existing in-flight-selection rule in the same effect.
  • Criteria:
Criterion (spec clause) Disposition Symbol / path Test or command
A Back/Forward entry restores its own source and root, even while a re-scope of the loaded source is in flight implemented apps/presentation/dashboard/src/views/dashboard-page.tsx (root-change effect) LOOPX_PERSONAL_WORKSPACE_SCENARIO=goal-hierarchy packaged and development
An in-flight user source selection is still re-scoped when the root changes preserved same effect (routeRestoresSource is false while the route names the loaded source) smoke:status-source-switch-browser, smoke:status-source-switch-packaged
With no route source, the loaded source remains the fallback preserved same effect goal-hierarchy earlier sections
  • Self-check before submission: reproduced the failure on the base and traced it with temporary local logging (URL changes, status requests and the effect's inputs; not committed). The trace showed the effect selecting the in-flight Remote B request right after the restored route.

Scope And Continuation

  • Completed scope: one rule in one effect. No test changed: the existing scenario already asserts the contract and is the regression check.
  • Future-facing pass: I considered moving the target choice into data/status-request-fence.ts as a pure helper with its own unit test. The only nearby contract smoke (smoke:status-projection-contract) isn't run in CI, so a helper test there would add wiring without CI coverage. The browser scenario that runs in both required lanes covers this rule, so I deferred the move.
  • Not in this PR: the other intermittent chat-bundle-browser failures seen on recent PR runs. Each failed in a different scenario, they're tracked under CI: chat-bundle-browser and dashboard-browser shards time out on main #7389, and none reproduced as this one did.

Validation

  • Tested revision: d4c07d79b (on main 843be4942).
  • Run state: finished (local); hosted CI pending on this PR.
  • Input classes: synthetic
Check kind Result Public-safe evidence / limitation
regression_parity passed Base: goal-hierarchy fails at line 241 in 8/8 packaged runs and 1/2 development runs. Head: 4/4 packaged, 3/3 development.
real_entrypoint passed npm run smoke:status-source-switch-browser and smoke:status-source-switch-packaged (in-flight source selection and source switching).
unit passed npm run smoke:status-sources (status source catalog).
real_entrypoint passed Packaged shard 2, each scenario run on its own: 25 of 27 pass, including goal-hierarchy. The other two also fail on the unmodified base locally and pass on hosted runners: composer-session-admission:200 (fails on base 2/2 locally) and research-worker-readback (ECONNRESET from the disposable backend).
static passed tsc --noEmit on the dashboard; scripts/generate_semantic_inventory.py --changed-from HEAD reports no new vocabulary carriers.
real_entrypoint running Hosted dashboard-browser (1/2/3) and chat-bundle-browser (1/2/3) on this PR are the decisive checks.
  • Coverage and gaps: hosted Linux timing is only covered by this PR's CI. The fix changes source selection only when a URL source is loaded and the route names another source.

Frontend / Visual Evidence

  • UI impact: behavioral only. Back after scoping a remote source returns to the restored source's view; no layout or copy changed.
  • Entry points: frontend (Personal Workspace, source switcher with Back/Forward). No Lark or CLI change.

Type of Change

  • Bug fix

LoopX Area

  • Public docs or presentation surface (README, protocols, dashboard)

Technical Direction

  • Direction / acceptance reference, when applicable: operator surface; the shipped goal-hierarchy source/root restore contract.

Shared-authority RFC fixture impact

N/A

Boundary Checklist

  • Neither the diff nor this PR body/comments/attachments disclose private state, credentials, raw traces or verifier output, internal links, or local machine paths.
  • I did not duplicate maintainer-owned benchmark work.
  • I kept the change scoped to the linked issue/task.
  • No paired RFC changed.
  • Every commit includes a DCO Signed-off-by trailer.
  • This changes apps/** behavior, so it needs maintainer review and explicit merge authorization.

🤖 Generated with Claude Code

Scoping a remote source to a root starts a read of that source. Pressing
Back to an entry that names another source and root before the read
commits made the root-change effect prefer the in-flight request over the
restored route, so the page re-read the remote source with the restored
root and rewrote the URL back to it.

The app commits a route's source only from a loaded source, so a route
naming a different source than the loaded one came from Back/Forward.
That restored source now outranks an in-flight re-scope; an in-flight
source selection is still re-scoped when the route names the loaded source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Lihua <1017343802@qq.com>
@LIHUA919

Copy link
Copy Markdown
Contributor Author

dashboard-browser (2) failed on this head at goal-workspace-m2.mjs:158 (126 !== 200, "All work remains reachable"). This PR doesn't touch that path: it's the intermittent expansion race, now addressed in #7554. The scenario this PR fixes, goal-hierarchy, runs in chat-bundle-browser (2) and dashboard-browser (2). Shards 1 and 3 of both lanes passed.

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · reasoning_effort=max

动机

用户从本机研究 Goal 切到远端工作,再用浏览器返回先前研究范围时会遇到这个问题。 旧版在 Remote B 的 operations 范围读取尚未完成时返回本机 research,会停在 Remote B/research;此版恢复本机 research 及 portfolio 子 Goal。
实际编译页面在同一受控时序下恢复正确来源、根范围和来源选择器,旧读取不能再覆盖它。 本 PR 只修根范围与来源一起恢复的分支,不改服务端权限、SSH 建连策略或其他已存在的同根导航行为。

页面重新请求错误来源,URL 和同名 Goal 被旧请求覆盖,用户需要再次选择来源并找回位置。 我独立执行了编译后的真实页面与两个隔离状态后端;普通完整场景在两版都能通过,进一步控制未完成读取才明确区分出缺陷与修复。作者报告的旧复跑次数未当作本次证据。

改动思路

已有根范围 effect 负责路由仲裁,已有 fence 负责迟到读取;在该处修复优先级即可闭合真实返回路径。 本 PR 交付来源与根一起恢复,不增加持久状态或第二个导航/权限 owner。

变更前已接受的依据是 docs/development/design.md,固定修订 843be494266774b63b3de61d0adf5dd7f4f877a2。本评审将其中未编号的两条原文分别标为 NAV-HISTORY(reload/Back/Forward 保留选择)和 NAV-SOURCE(选择绑定 Goal 与来源,同名 Goal 不继承另一来源选择);这两个标签仅便于引用。当前完整读取、错误恢复和受控返回分别覆盖它们。

保留原来的显式来源选择和请求隔离更合适:无条件偏好 route 会忽略正在进行的用户选择,另起来源状态或导航框架也没有收益。现有 TypeScript owner 足以处理这个有界修复。

具体改动

完整 diff 只有 apps/presentation/dashboard/src/views/dashboard-page.tsx,+7/-2;没有 CSS、页面文案、存储格式、命令或权限变更。新值完全由当前 route 与 DataSource 派生,无手动同步声明或持久状态。默认变化已经在本 PR 明确说明:只在根范围变化且 route 来源与已加载来源不同的情况下,让恢复路由先于未完成 rescope。

关键代码讲解

  1. DashboardPage 根 effect,第3680行:先取非空 route URL,判断其是否与已加载来源不同;满足时读恢复来源。否则沿用 requested、route、loaded 及默认来源的旧回退。这使历史返回不再重新读取 B 的同名 research,同时保留普通显式切换。
  2. loadFromUrl,第3497行:请求开始时捕获 root 并使用现有 generation/selection fence。目录和子 Goal 的响应只在该 root 和请求仍当前时提交。此次没有放松这些检查;受控挂起 B、返回 A、再释放 B 通过真实读取证明旧响应不会反盖。
  3. commitLoadedStatus,第3448行:仍由原 owner 一起更新 payload、source 与路由,并在完成当前请求后清理 requested URL;不新增第二个状态提交点。它与上面的源选择和 fence 共同组成完整用户路径。

验证结果:

  • PASS:fresh npm run build:chat;原 goal-hierarchy packaged 完整场景 head13.67s、基线产品树13.75s。后者未自然失败,因此没有把一次绿测称为间歇问题已消失。
  • PASS(可判别反例):同一浏览器时序脚本仅挂起 B 的 operations 根读取,然后 history.go(-4)、释放读取。不可变 base 的产品树最终仍为 B/research,portfolio 等待失败;精确 head12.57s完成全部断言,URL、root、来源选择器和 portfolio 均回 A。本例真实 backend 相同;基线所在分支只改另一 smoke,产品文件与 843be494266774b63b3de61d0adf5dd7f4f877a2 相同。
  • PASS:原场景的403子Goal、畸形/空/缺失root、刷新恢复及390px键盘检查;独立 packaged status-source-switch、smoke:status-projection-contract、smoke:status-sources。原 source readback 不变,0 mutation、0 Turns/actions。
  • PASS:standard premerge 4直接+2选中,零失败、跳过或人工hold;严格 CQR cqr_6030cfbb45553bf2091a 与当前scope一致。检查器只验证记录结构,以上结论来自实际执行。

对主干的风险

主要风险是把普通显式选源误判成历史恢复,以及迟到响应覆盖当前根。原 source-switch 与 generation/root 隔离覆盖前者和后者;受控反例覆盖本次新优先级。范围不涉及 server authority、schema、调度或配额,也没有可选功能的关闭态宣称。源 URL 仍采用原有身份规范化,未外推所有alias变体。

实际路径是 source-built packaged 页面加真实隔离目录/状态 owner;SSH catalog/ensure 为合成 transport,控制 barrier 只是完成时序。没有核验本机正式安装或真实 SSH 服务,也没有把浏览路径恢复外推为模型长程净收益。已读作者评论中的历史CI说明;依当前评审配置未查询、轮询或等待CI。本次局部资格不证明当前main组合、全部browser catalog或其他同根导航缺陷已经解决。

我的整体评价

APPROVE。所选返回缺陷有独立 base 反例和精确 head 正向结果,现有 owner 的改动直接且可回退;未发现当前范围的阻断问题。已有根范围 effect 负责路由仲裁,已有 fence 负责迟到读取;在该处修复优先级即可闭合真实返回路径。 本 PR 交付来源与根一起恢复,不增加持久状态或第二个导航/权限 owner。

视觉审阅不适用:完整单文件diff没有DOM/CSS、可见文案或构图改动;这里只判断功能恢复。未验证范围包括正式安装App、真实SSH及独立用户理解/全站视觉质量;不宣称视觉改善。无需新增用户配置、确认或准备轮次。审批是此 head 的源码与有界路径结论;合并仍须当前原生readiness和维护者权限。

English verdict: APPROVE — head d4c07d7; controlled in-flight history restoration fails on the immutable baseline and passes here. Packaged navigation, source isolation, local validation and exact-scope quality checks pass; installed/real-SSH and broader integration remain outside this review.

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.

2 participants