Skip to content

fix(workspace): distinguish status access failures - #4282

Merged
huangruiteng merged 5 commits into
loopx-project:mainfrom
xyx2002OvO:codex/workspace-status-access-fix
Sep 14, 2026
Merged

huangruiteng merged 5 commits into
loopx-project:mainfrom
xyx2002OvO:codex/workspace-status-access-fix

Conversation

@xyx2002OvO

Copy link
Copy Markdown
Contributor

Summary

  • Return workspace_status_access_denied for verified file/runtime access denial on validated per-Goal status requests; HTTP remains 500 and the public error message remains fixed/redacted.
  • Display actionable English/Chinese access guidance. Only recognized access failures stop browser automatic retries; manual retry remains available and ordinary 5xx/network/timeout failures retain three attempts.
  • Bound error-body reading to 16 KiB and the existing request deadline. Preserve cancellation, source/revision fences and successful peer snapshots. Refresh the shipped chat bundle without pruning existing assets.

Issue Or Task

  • Implements the diagnostic TODO documented in docs: track workspace status access error diagnostics #4222.
  • Scope: three product-source files, focused validation, the canonical bug/contract note, and generated chat delivery artifacts.
  • No directory/full-status, HTTP 200 health, Chat action, state-machine, authority, registry, filesystem permission or Effect runtime retry changes.
  • Future-facing pass: reuse existing typed runtime exceptions in a private API-boundary classifier; no new capability, dependency, provider or generic framework.

Validation

  • Tested revision: 45e3e20139997d1c1c69f023d7926dfcc6aaadce
  • Run state: finished
  • Input classes: synthetic, public_fixture
Check kind Result Public-safe evidence / limitation
unit / integration passed python -m pytest tests/test_chat_server_cors.py tests/test_status_server_cors.py tests/test_status_server_fast_path.py -q: 94 passed after committing. Real HTTP handler with injected exception cases covers typed causes, Windows lock negatives, redaction and unaffected routes.
unit passed Dashboard npm run smoke:workspace-progressive-loader: 25 checks passed after committing, including streamed limits, damaged/legacy bodies, cancellation, timeout and HTTP precedence.
static passed npm run build completed TypeScript and desktop/chat builds; existing large-chunk warning remains. Focused ruff and git diff --check passed.
real_entrypoint passed Packaged progressive browser smoke: 13 checks, bounded concurrency 2; bilingual desktop/mobile access state, retry counts, peer isolation and revision fencing. HTTP fixtures are controlled, not a real backend claim.
real_backend passed Production serve_chat plus isolated Windows NTFS ACL and Chromium: deny one synthetic Goal history file; directory/peer 200, affected Goal redacted 500/access code; restore original ACL, manually retry to 200. Browser requests: peer 1, affected Goal 2 including manual recovery. No active/shared state used.
static passed Public-boundary scan completed on the changed documentation, smokes, Python tests and API source; generated-bundle path/key scan also clean. The empty isolated scan registry produced only a missing-runtime warning.
integration blocked python examples/dashboard-demo-readiness-smoke.py stops in the macOS LaunchAgent script on Windows with WinError 193. No unrelated platform changes bundled.
static not_run Remote required checks are pending PR creation; full repository suites and macOS/Linux real-permission E2E were not run locally.

Coverage and gaps: focused checks exercise the changed classifier/parser/retry path and actual Windows permission recovery; not a claim of full cross-platform or all-provider qualification. Build/browser/ACL runs used the same product source and bundle now committed. A scoped independent implementation review found no blocking source findings; it did not independently rerun the tests or inspect minified output.

Frontend / Visual Evidence

  • UI impact: changed (error copy only; existing layout and Retry control reused).
  • Before: all 5xx displayed “本地服务暂时不可用,请重试继续加载。” / “The local service is temporarily unavailable. Retry to continue.”
  • After: recognized access failures ask users to check the account running the status source; unknown 5xx use neutral “Goal status could not be read” wording.
  • States and viewports: synthetic access-error screenshots reviewed locally at desktop 1440×960 and mobile 390×844; English/Chinese rendering also checked. Owner approved the preview before commit/push.
  • Source data: synthetic.
  • Public visual-attachment gap: screenshots remain local and are not attached or committed; reviewers can reproduce the changed state with npm run build && npm run smoke:workspace-progressive in the dashboard directory.

Type of Change

  • Bug fix
  • Documentation update
  • Test update

LoopX Area

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

Technical Direction

Shared-authority RFC fixture impact

N/A: no authority, provider conformance or runtime-routing changes.

Boundary Checklist

  • Diff/body exclude private state, credentials, raw traces, internal links and local machine paths.
  • No maintainer-owned benchmark work duplicated.
  • Change stays scoped to the linked diagnostic TODO.
  • Public before/after screenshot attachments (local synthetic preview approved; attachment gap disclosed above).
  • Every commit has a DCO sign-off.

Rollback: revert this cohesive PR, including the paired frontend/backend mapping and generated bundle; no persistent data migration is involved.

@xyx2002OvO

Copy link
Copy Markdown
Contributor Author

CI follow-up for 45e3e20139997d1c1c69f023d7926dfcc6aaadce: all triggered workflows have finished. Check results: 23 passed, 5 skipped, 2 failed (windows-powershell, merge-gate).

The Windows failure is tests/test_windows_install.py::test_windows_installer_promotes_release_and_runs_doctor at the quota.returncode == 0 assertion (line 188).

DCO, all four Python shards, Dashboard acceptance, Stage2c, static checks, and desktop/release builds passed. This PR does not change the Windows installation test or quota path; no unrelated fix was added and no merge was performed.

中文摘要:首轮 CI 已结束,Windows 安装测试的同一失败已在本 PR 基线主干复核。该既有阻塞未在本 PR 中顺带修复;合并检查仍未通过,继续保持错误诊断这一限定 scope。

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

动机

该 PR 将 Workspace 按 Goal 的状态读取失败从笼统的 500/service 区分为可行动的 access 错误,并让前端只对真正的临时失败自动重试。目标与现有渐进式加载、固定错误文案及隐私边界一致。

改动思路

服务端复用现有 ChatStatusRequestMixin 的异常边界,从 errno/winerror、EffectRuntime 类型化诊断及有限 cause/context 链识别权限拒绝;只有 Goal-scoped status 请求返回 workspace_status_access_denied。前端以 16 KiB 上限读取错误体,将该码映射到 terminal access,普通 5xx 仍走既有三次重试,手动 Retry 仍可用。这样没有改变 HTTP 兼容性,也没有暴露私有诊断。

具体改动

关键代码讲解

  • loopx/chat_status_api.py:_status_access_denied:精确匹配 EACCES/EPERM、Windows 5/65 和 permanent io_permission_denied,拒绝 ENOSPC、启动超时、伪造字段及错误 cause 借用。
  • ChatStatusRequestMixin:仅在 requested_goals 存在且没有 views 时附加错误码,目录/聚合路由保持旧响应形状。
  • workspace-progressive-status.ts:statusFailure:有界读取/解析 5xx body,保留 abort 语义并将 access 与 service 分流。
  • loadWorkspaceGoalSnapshots:access 不自动重试,成功 peer 不受影响;新增双语提示和浏览器场景覆盖恢复路径。

对主干的风险

发现一个合并前阻塞:exact head 974f41d32d5b2f05ee12071a0bdfca1eaa8bf997 与当前 origin/main 的真实 git merge-tree --write-tree 在 loopx/web/chat/index.html 发生内容冲突。两边引用不同的打包 JS/CSS hash,GitHub 也报告 mergeStateStatus=DIRTY。若直接选一侧,可能让入口引用过期或不存在的 chunk;该风险无法由服务端单测替代。请先 rebase,保留与最新生成 assets 匹配的 index,再重跑 packaged browser smoke。当前 head 上的 tests/test_chat_server_cors.py tests/test_windows_install.py 为 46 passed、4 skipped;dashboard smoke 因 review checkout 未安装 vite 而未执行。

我的整体评价

错误分类、重试隔离和双语反馈的实现边界清晰,focused HTTP tests 通过;但 shipped chat 入口仍不可干净合并,且 UI smoke 尚未完成,因此当前不能批准。请解决 index/assets 冲突并验证普通 5xx 三次重试、access 不自动重试及手动恢复后再请求 re-review。当前结论:需要修改。

English verdict:

REQUEST_CHANGES: The access-error implementation is well-scoped and 46 focused tests pass (4 platform skips), but exact head 974f41d32d5b2f05ee12071a0bdfca1eaa8bf997 has a real merge conflict in loopx/web/chat/index.html, the packaged JS/CSS entry. Rebase onto current main, reconcile the matching generated assets, run the dashboard browser smoke, and request re-review.

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

动机

该 PR 将 Workspace 按 Goal 的状态读取失败从笼统的 500/service 区分为可行动的 access 错误,并让前端只对真正的临时失败自动重试。目标与现有渐进式加载、固定错误文案及隐私边界一致。

改动思路

服务端复用现有 ChatStatusRequestMixin 的异常边界,从 errno/winerror、EffectRuntime 类型化诊断及有限 cause/context 链识别权限拒绝;只有 Goal-scoped status 请求返回 workspace_status_access_denied。前端以 16 KiB 上限读取错误体,将该码映射到 terminal access,普通 5xx 仍走既有三次重试,手动 Retry 仍可用。这样没有改变 HTTP 兼容性,也没有暴露私有诊断。

具体改动

关键代码讲解

  • loopx/chat_status_api.py:_status_access_denied:精确匹配 EACCES/EPERM、Windows 5/65 和 permanent io_permission_denied,拒绝 ENOSPC、启动超时、伪造字段及错误 cause 借用。
  • ChatStatusRequestMixin:仅在 requested_goals 存在且没有 views 时附加错误码,目录/聚合路由保持旧响应形状。
  • workspace-progressive-status.ts:statusFailure:有界读取/解析 5xx body,保留 abort 语义并将 access 与 service 分流。
  • loadWorkspaceGoalSnapshots:access 不自动重试,成功 peer 不受影响;新增双语提示和浏览器场景覆盖恢复路径。

对主干的风险

发现一个合并前阻塞:exact head 974f41d32d5b2f05ee12071a0bdfca1eaa8bf997 与当前 origin/main 的真实 git merge-tree --write-tree 在 loopx/web/chat/index.html 发生内容冲突。两边引用不同的打包 JS/CSS hash,GitHub 也报告 mergeStateStatus=DIRTY。若直接选一侧,可能让入口引用过期或不存在的 chunk;该风险无法由服务端单测替代。请先 rebase,保留与最新生成 assets 匹配的 index,再重跑 packaged browser smoke。当前 head 上的 tests/test_chat_server_cors.py tests/test_windows_install.py 为 46 passed、4 skipped;dashboard smoke 因 review checkout 未安装 vite 而未执行。

我的整体评价

错误分类、重试隔离和双语反馈的实现边界清晰,focused HTTP tests 通过;但 shipped chat 入口仍不可干净合并,且 UI smoke 尚未完成,因此当前不能批准。请解决 index/assets 冲突并验证普通 5xx 三次重试、access 不自动重试及手动恢复后再请求 re-review。当前结论:需要修改。

English verdict:

REQUEST_CHANGES: The access-error implementation is well-scoped and 46 focused tests pass (4 platform skips), but exact head 974f41d32d5b2f05ee12071a0bdfca1eaa8bf997 has a real merge conflict in loopx/web/chat/index.html, the packaged JS/CSS entry. Rebase onto current main, reconcile the matching generated assets, run the dashboard browser smoke, and request re-review.

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

动机

该 PR 将 Workspace 按 Goal 的状态读取失败从笼统的 500/service 区分为可行动的 access 错误,并让前端只对真正的临时失败自动重试。目标与现有渐进式加载、固定错误文案及隐私边界一致。

改动思路

服务端复用现有 ChatStatusRequestMixin 的异常边界,从 errno/winerror、EffectRuntime 类型化诊断及有限 cause/context 链识别权限拒绝;只有 Goal-scoped status 请求返回 workspace_status_access_denied。前端以 16 KiB 上限读取错误体,将该码映射到 terminal access,普通 5xx 仍走既有三次重试,手动 Retry 仍可用。这样没有改变 HTTP 兼容性,也没有暴露私有诊断。

具体改动

关键代码讲解

  • loopx/chat_status_api.py:_status_access_denied:精确匹配 EACCES/EPERM、Windows 5/65 和 permanent io_permission_denied,拒绝 ENOSPC、启动超时、伪造字段及错误 cause 借用。
  • ChatStatusRequestMixin:仅在 requested_goals 存在且没有 views 时附加错误码,目录/聚合路由保持旧响应形状。
  • workspace-progressive-status.ts:statusFailure:有界读取/解析 5xx body,保留 abort 语义并将 access 与 service 分流。
  • loadWorkspaceGoalSnapshots:access 不自动重试,成功 peer 不受影响;新增双语提示和浏览器场景覆盖恢复路径。

对主干的风险

发现一个合并前阻塞:exact head 974f41d32d5b2f05ee12071a0bdfca1eaa8bf997 与当前 origin/main 的真实 git merge-tree --write-tree 在 loopx/web/chat/index.html 发生内容冲突。两边引用不同的打包 JS/CSS hash,GitHub 也报告 mergeStateStatus=DIRTY。若直接选一侧,可能让入口引用过期或不存在的 chunk;该风险无法由服务端单测替代。请先 rebase,保留与最新生成 assets 匹配的 index,再重跑 packaged browser smoke。当前 head 上的 tests/test_chat_server_cors.py tests/test_windows_install.py 为 46 passed、4 skipped;dashboard smoke 因 review checkout 未安装 vite 而未执行。

我的整体评价

错误分类、重试隔离和双语反馈的实现边界清晰,focused HTTP tests 通过;但 shipped chat 入口仍不可干净合并,且 UI smoke 尚未完成,因此当前不能批准。请解决 index/assets 冲突并验证普通 5xx 三次重试、access 不自动重试及手动恢复后再请求 re-review。当前结论:需要修改。

English verdict: REQUEST_CHANGES: The access-error implementation is well-scoped and 46 focused tests pass (4 platform skips), but exact head 974f41d32d5b2f05ee12071a0bdfca1eaa8bf997 has a real merge conflict in loopx/web/chat/index.html, the packaged JS/CSS entry. Rebase onto current main, reconcile the matching generated assets, run the dashboard browser smoke, and request re-review.

xyx2002OvO and others added 5 commits September 14, 2026 09:52
Signed-off-by: Tartar <xiaoyx67@mail2.sysu.edu.cn>
Signed-off-by: Tartar <xiaoyx67@mail2.sysu.edu.cn>
Signed-off-by: Tartar <xiaoyx67@mail2.sysu.edu.cn>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
Signed-off-by: huangruiteng <14976749+huangruiteng@users.noreply.github.com>
@huangruiteng
huangruiteng force-pushed the codex/workspace-status-access-fix branch from 974f41d to f1eec27 Compare September 14, 2026 02:04
@huangruiteng

Copy link
Copy Markdown
Collaborator

Rebased and refreshed against current main at 4e73428ff3f170578a3be12bde15c2612cf55f99.

Addressed the requested changes:

  • resolved the loopx/web/chat/index.html conflict by rebuilding the packaged chat entry from the rebased dashboard sources;
  • replaced the stale generated entry with index-C6eFCYni.js and updated bounded asset retention, so the index references an existing matching JS/CSS pair;
  • stabilized the progressive-loading browser smoke around the revision-resync retry race.

Validation on the rebased checkout:

  • npm run build:chat (TypeScript check + Vite chat build passed);
  • npm run smoke:workspace-progressive-loader (25 checks passed);
  • npm run smoke:workspace-progressive (browser smoke passed: ordinary 5xx retry, access no-auto-retry, manual recovery, bilingual and mobile paths);
  • python -m pytest -q tests/test_chat_server_cors.py tests/test_windows_install.py (46 passed, 4 skipped on macOS);
  • source-checkout python -m loopx.cli --format json canary premerge --from-git-diff --no-progress (18 selected checks passed, including public-boundary scan; no manual holds).

The previously requested packaged-entry and browser-smoke blockers are addressed. GitHub checks for this updated exact head are currently running; merge will wait for the required checks to finish green.

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

Re-reviewed the rebased exact head f1eec27 against main 4e73428. The packaged chat entry now points to the rebuilt existing JS/CSS pair, the progressive retry smoke is stable, and all required GitHub checks are green. Approving for merge.

@huangruiteng
huangruiteng merged commit c5e43a1 into loopx-project:main Sep 14, 2026
30 checks passed
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