From 857d5a8ac78771b05752edd7adb7e85edc9ee057 Mon Sep 17 00:00:00 2001 From: huangruiteng Date: Thu, 22 Oct 2026 20:31:30 +0800 Subject: [PATCH 1/4] fix(workspace): expose legacy storage recovery from failed Goal status Signed-off-by: huangruiteng --- .../workspace-progressive-status-smoke.mjs | 1 + .../src/data/workspace-progressive-status.ts | 5 ++- .../src/features/personal-workspace/i18n.tsx | 4 ++ .../personal-workspace-page.tsx | 4 +- .../workspace-settings-page.tsx | 7 ++-- .../goal-settings-backend.mjs | 5 ++- .../goal-storage.mjs | 31 ++++++++++++++-- loopx/chat_status_api.py | 10 +++++ tests/test_chat_server_cors.py | 37 +++++++++++++++++++ 9 files changed, 94 insertions(+), 10 deletions(-) diff --git a/apps/presentation/dashboard/smoke/workspace-progressive-status-smoke.mjs b/apps/presentation/dashboard/smoke/workspace-progressive-status-smoke.mjs index 82d9f4eac5..f62d0e68b0 100644 --- a/apps/presentation/dashboard/smoke/workspace-progressive-status-smoke.mjs +++ b/apps/presentation/dashboard/smoke/workspace-progressive-status-smoke.mjs @@ -117,6 +117,7 @@ try { assert.equal(loaded.length, 3); await check("access", () => json(access), ["access"], 1); await check("original source unavailable", () => json({ error_code: "goal_source_unavailable" }, 503), ["source"], 1); + await check("storage recovery does not retry without migration", () => json({ error_code: "canonical_authority_required" }, 503), ["authority"], 1); for (const body of [null, {}, [], { error_code: "future_code" }, { error_code: 5 }, { error: "permission denied" }]) { await check("unknown envelope", () => json(body), ["service"], 3); } diff --git a/apps/presentation/dashboard/src/data/workspace-progressive-status.ts b/apps/presentation/dashboard/src/data/workspace-progressive-status.ts index 18ad2463b3..009e503c4e 100644 --- a/apps/presentation/dashboard/src/data/workspace-progressive-status.ts +++ b/apps/presentation/dashboard/src/data/workspace-progressive-status.ts @@ -25,7 +25,7 @@ const directorySchema = z.object({ contract: directoryContractSchema.optional(), }); export type WorkspaceDirectory = z.infer; -export type WorkspaceLoadError = "timeout" | "network" | "service" | "source" | "access" | "revision" | "scope" | "invalid"; +export type WorkspaceLoadError = "timeout" | "network" | "service" | "source" | "access" | "authority" | "revision" | "scope" | "invalid"; export type WorkspaceReadScope = "all" | "missing"; export type WorkspaceProgress = { directory: WorkspaceDirectory; @@ -124,7 +124,7 @@ export function directoryStatusPayload(directory: WorkspaceDirectory): StatusPay }); } -async function statusFailure(response: Response, signal: AbortSignal): Promise<"access" | "source" | "service"> { +async function statusFailure(response: Response, signal: AbortSignal): Promise<"access" | "source" | "authority" | "service"> { if (!response.body) return "service"; const reader = response.body.getReader(); const cancel = () => { void reader.cancel().catch(() => {}); }; @@ -147,6 +147,7 @@ async function statusFailure(response: Response, signal: AbortSignal): Promise<" && "error_code" in payload) { if (payload.error_code === "workspace_status_access_denied") return "access"; if (payload.error_code === "goal_source_unavailable") return "source"; + if (payload.error_code === "canonical_authority_required") return "authority"; } return "service"; } catch { diff --git a/apps/presentation/dashboard/src/features/personal-workspace/i18n.tsx b/apps/presentation/dashboard/src/features/personal-workspace/i18n.tsx index b72e9bc05c..187408977d 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/i18n.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/i18n.tsx @@ -708,6 +708,8 @@ const en = { "startup.error.timeout": "The request timed out. Retry when the local service is ready.", "startup.error.network": "The connection was interrupted. Retry to reconnect.", "startup.error.service": "The Goal status could not be read. Retry later; if the problem continues, check the status source.", + "startup.error.authority": "This Goal uses an older storage format. Review its storage upgrade to restore status reads.", + "startup.storageSettings": "Review storage upgrade", "startup.error.source": "The original Goal source is unavailable. Its link is preserved; retry when the source is available again.", "startup.error.access": "The status source cannot access files or runtime directories required for this Goal. Check the permissions of the account running that source, then retry.", "startup.error.revision": "The Goal directory changed during loading. Refresh to synchronize.", @@ -2348,6 +2350,8 @@ const zhCN: Record = { "startup.error.timeout": "读取超时,可在本地服务就绪后重试。", "startup.error.network": "连接中断,请重试以重新连接。", "startup.error.service": "Goal 状态读取失败。请稍后重试;若问题持续,请检查状态来源。", + "startup.error.authority": "此 Goal 使用旧版存储,需要检查并迁移后才能恢复状态读取。", + "startup.storageSettings": "检查存储升级", "startup.error.source": "原 Goal 来源暂不可用,关联仍保留。来源恢复后可重试。", "startup.error.access": "状态来源无法访问此 Goal 所需的文件或运行时目录。请检查该来源运行账户的访问权限,修复后重试。", "startup.error.revision": "加载期间 Goal 目录发生变化,请刷新以同步。", diff --git a/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx b/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx index ba1ed3d00e..23eeca51a3 100644 --- a/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx +++ b/apps/presentation/dashboard/src/features/personal-workspace/personal-workspace-page.tsx @@ -2850,7 +2850,9 @@ export function PersonalWorkspacePage({
{t(selectedGoal.loadState === "error" ? "startup.goalError" : "startup.goalLoading")}

{t(selectedGoal.loadError ? `startup.error.${selectedGoal.loadError}` : "startup.independent")}

- {selectedGoal.loadState === "error" ? : null}
+ {selectedGoal.loadState === "error" ? selectedGoal.loadError === "authority" && !readOnly ? + + : : null}
) : selectedGoal ? ( item.key === requestedTab)?.key ?? tabs[0].key; const selectedGoal = scope === "goal" ? goals.find(item => item.goalId === initialGoalId) : undefined; const editableGoal = selectedGoal && !selectedGoal.sourceAccess?.readOnly ? selectedGoal : undefined; + const canonicalSettingsReady = editableGoal?.loadState !== "loading" && editableGoal?.loadError !== "authority"; const [ownershipRefresh, setOwnershipRefresh] = useState(0); const navigate = (nextScope: "machine" | "goal", nextGoalId?: string, nextTab?: SettingsPage) => { onNavigate({kind: "settings", scope: nextScope, @@ -248,15 +249,15 @@ export function WorkspaceSettingsPage({ /> ) : null} {tab === "ownership" && editableGoal ?
- + {canonicalSettingsReady ? : null} { setOwnershipRefresh(value => value + 1); onChanged(); }} /> - + {canonicalSettingsReady ? <> - + : null}
: null} {tab === "capabilities" && (scope === "machine" || editableGoal) ? : null} {tab === "cadence" && editableGoal ? : null} diff --git a/examples/personal-workspace-browser/goal-settings-backend.mjs b/examples/personal-workspace-browser/goal-settings-backend.mjs index 5552832d3c..3c8ae1b487 100644 --- a/examples/personal-workspace-browser/goal-settings-backend.mjs +++ b/examples/personal-workspace-browser/goal-settings-backend.mjs @@ -16,7 +16,7 @@ export async function startAuthority({unsettled = true} = {}) { " \n"; await writeFile(resolve(root, "state.md"), source); await writeFile(resolve(root, "registry.json"), JSON.stringify({ - common_runtime_root: resolve(root, "runtime"), goals: [{id: "multi-agent-projection", + common_runtime_root: resolve(root, "runtime"), goals: [{id: "multi-agent-projection", display_name: "Multi Agent Projection", repo: root, state_file: "state.md", coordination: {registered_agents: ["agent-a"]}}], })); const leases = resolve(root, "runtime/goals/multi-agent-projection/task-leases"); @@ -33,6 +33,9 @@ server = ChatHTTPServer(("127.0.0.1", 0), ChatRequestHandler) server.registry_path = Path(sys.argv[1]) / "registry.json" server.runtime_root = Path(sys.argv[1]) / "runtime" server.runtime_root_override = str(server.runtime_root) +server.selected_goal_id = None +server.scan_roots = [] +server.limit = 20 server.verbose = False print(server.server_port, flush=True) server.serve_forever() diff --git a/examples/personal-workspace-browser/goal-storage.mjs b/examples/personal-workspace-browser/goal-storage.mjs index abf03fc730..af456cc0d5 100644 --- a/examples/personal-workspace-browser/goal-storage.mjs +++ b/examples/personal-workspace-browser/goal-storage.mjs @@ -16,6 +16,12 @@ async function importSettled(browser, url, provider) { let applyCount = 0; try { const connect = () => openWorkspacePage(browser, url, {beforeGoto: async (_api, page) => { + await page.route(/\/status\.json(?:\?|$)/, async route => { + const query = new URL(route.request().url()).searchParams; + if (query.has("view") || query.has("goal_id")) { + await route.fulfill({response: await fetchWorkspaceBackend(route, authority.url)}); + } else await route.fallback(); + }); await page.route(/\/api\/chat\/goal-(storage|ownership)(?:[/?]|$)/, async route => { const parsed = new URL(route.request().url()); const response = await fetchWorkspaceBackend(route, authority.url); @@ -27,12 +33,26 @@ async function importSettled(browser, url, provider) { }}); context = await connect(); let {page} = context; + let recoveryOpened = false; async function open() { const existing = page.getByRole("region", {name: "Goal 数据存储"}); if (await existing.isVisible()) return existing; const navigation = page.getByRole("button", {name: "打开 Goal 导航", exact: true}); if (await navigation.isVisible()) await navigation.click(); await page.locator(".personal-goal-link", {hasText: "Multi Agent Projection"}).click(); + const recovery = page.getByRole("button", {name: "检查存储升级", exact: true}); + if (!recoveryOpened || await recovery.isVisible()) { + await recovery.waitFor(); + await page.getByText("此 Goal 使用旧版存储,需要检查并迁移后才能恢复状态读取。", {exact: true}).waitFor(); + await page.screenshot({path: resolve(outputDir, `goal-storage-recovery-${provider}.png`), animations: "disabled"}); + await page.setViewportSize({width: 390, height: 844}); + assert.equal(await page.evaluate(() => document.documentElement.scrollWidth > innerWidth + 1), false); + await page.screenshot({path: resolve(outputDir, `goal-storage-recovery-${provider}-mobile.png`), animations: "disabled"}); + await recovery.focus(); + await page.keyboard.press("Enter"); + recoveryOpened = true; + return page.getByRole("region", {name: "Goal 数据存储"}); + } await page.getByRole("button", {name: "Goal 设置", exact: true}).click(); await page.getByRole("button", {name: "任务所有权", exact: true}).click(); return page.getByRole("region", {name: "Goal 数据存储"}); @@ -92,7 +112,7 @@ async function importSettled(browser, url, provider) { assert.equal(await readFile(resolve(authority.root, "state.md"), "utf8"), authority.source); await panel.scrollIntoViewIfNeeded(); await page.screenshot({path: resolve(outputDir, `goal-storage-import-${provider}-mobile.png`), animations: "disabled"}); - assert.equal(context.errors.filter(e => !e.includes("ERR_FAILED")).length, 0, context.errors.join("; ")); + assert.equal(context.errors.filter(e => !e.includes("ERR_FAILED") && !e.includes("503")).length, 0, context.errors.join("; ")); } finally { await context?.close(); await authority.close(); } } @@ -104,6 +124,12 @@ const goalStorageScenario = { let writes = 0; try { context = await openWorkspacePage(browser, url, {beforeGoto: async (_api, page) => { + await page.route(/\/status\.json(?:\?|$)/, async route => { + const query = new URL(route.request().url()).searchParams; + if (query.has("view") || query.has("goal_id")) { + await route.fulfill({response: await fetchWorkspaceBackend(route, authority.url)}); + } else await route.fallback(); + }); await page.route(/\/api\/chat\/goal-(storage|ownership)(?:[/?]|$)/, async route => { if (route.request().method() !== "GET") writes++; await route.fulfill({response: await fetchWorkspaceBackend(route, authority.url)}); @@ -114,8 +140,7 @@ const goalStorageScenario = { const existing = page.getByRole("region", {name: language === "zh" ? "Goal 数据存储" : "Goal data storage"}); if (await existing.isVisible()) return existing; await page.locator(".personal-goal-link", {hasText: "Multi Agent Projection"}).click(); - await page.getByRole("button", {name: language === "zh" ? "Goal 设置" : "Goal settings", exact: true}).click(); - await page.getByRole("button", {name: language === "zh" ? "任务所有权" : "Task ownership", exact: true}).click(); + await page.getByRole("button", {name: language === "zh" ? "检查存储升级" : "Review storage upgrade", exact: true}).click(); return page.getByRole("region", {name: language === "zh" ? "Goal 数据存储" : "Goal data storage"}); } let panel = await open(); diff --git a/loopx/chat_status_api.py b/loopx/chat_status_api.py index e01f7e1331..9a1b5d3913 100644 --- a/loopx/chat_status_api.py +++ b/loopx/chat_status_api.py @@ -26,6 +26,7 @@ EffectRuntimeStartupError, effect_runtime_request_scope, ) +from .control_plane.coordination.local_authority import LocalCoordinationAuthorityUnavailable from .control_plane.runtime.public_safety import ( public_safe_compact_text, validate_public_safe_value, @@ -336,6 +337,15 @@ def _status(self, *, delivery_review: bool = False) -> None: ) ) except Exception as exc: # noqa: BLE001 - do not expose local projection failures. + # The storage owner already exposes inspection and reviewed import. + # Preserve its typed refusal, not private paths or migration payloads. + if isinstance(exc, LocalCoordinationAuthorityUnavailable) and exc.code == "canonical_authority_required": + self._send_error( + "This Goal needs a storage upgrade. Open its storage settings to review recovery.", + status=503, + error_code=exc.code, + ) + return self._send_error( "LoopX status could not be projected for the workspace.", status=500, diff --git a/tests/test_chat_server_cors.py b/tests/test_chat_server_cors.py index 5cf8c447db..6374577205 100644 --- a/tests/test_chat_server_cors.py +++ b/tests/test_chat_server_cors.py @@ -691,6 +691,43 @@ def fail(*_args, **_kwargs): server.server_close() +def test_workspace_legacy_storage_refusal_exposes_recovery_without_mutation(tmp_path) -> None: + state = tmp_path / "GOAL.md" + source = "# Original Goal\n\n## Agent Todo\n\n- [ ] Original private task\n \n" + state.write_text(source) + registry = tmp_path / "registry.json" + registry.write_text(json.dumps({ + "schema_version": 1, + "common_runtime_root": str(tmp_path / "runtime"), + "goals": [{"id": "alpha", "repo": str(tmp_path), "state_file": state.name}], + })) + server, thread = _start_server() + server.registry_path = registry + server.runtime_root = tmp_path / "runtime" + server.runtime_root.mkdir() + server.runtime_root_override = str(server.runtime_root) + try: + response = _request(server.server_port, method="GET", origin=None, path="/status.json?goal_id=alpha") + assert response.status == 503 + assert json.loads(response.read()) == { + "ok": False, + "error": "This Goal needs a storage upgrade. Open its storage settings to review recovery.", + "error_code": "canonical_authority_required", + } + response = _request(server.server_port, method="GET", origin=None, + path="/api/chat/goal-storage?goal_id=alpha") + observed = json.loads(response.read()) + assert response.status == 200, observed + assert observed["current"]["canonical"] is False + assert observed["cold_source"]["active_todo_count"] == 1 + assert observed["pending_preview"] is None + assert state.read_text() == source + finally: + server.shutdown() + thread.join(timeout=5) + server.server_close() + + def test_workspace_directory_states_no_warning_for_a_present_registry(tmp_path) -> None: registry_path = tmp_path / ".loopx" / "registry.json" registry_path.parent.mkdir(parents=True) From 1a7b84cd3f9e48d57c75f301cfe8c34ef2ec18b5 Mon Sep 17 00:00:00 2001 From: huangruiteng Date: Thu, 22 Oct 2026 20:31:40 +0800 Subject: [PATCH 2/4] docs(storage): document workspace recovery and packaged evidence Signed-off-by: huangruiteng --- docs/assets/goal-storage-recovery/desktop.png | Bin 0 -> 62486 bytes docs/assets/goal-storage-recovery/mobile.png | Bin 0 -> 30514 bytes .../local-authority-provider-selection.md | 16 ++++++++++++++++ 3 files changed, 16 insertions(+) create mode 100644 docs/assets/goal-storage-recovery/desktop.png create mode 100644 docs/assets/goal-storage-recovery/mobile.png diff --git a/docs/assets/goal-storage-recovery/desktop.png b/docs/assets/goal-storage-recovery/desktop.png new file mode 100644 index 0000000000000000000000000000000000000000..577f20666f5c9f1109f9e130366e3ec031d7e4b9 GIT binary patch literal 62486 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 DttFE< literal 0 HcmV?d00001 diff --git a/docs/assets/goal-storage-recovery/mobile.png b/docs/assets/goal-storage-recovery/mobile.png new file mode 100644 index 0000000000000000000000000000000000000000..7c37fc525fae2c784a5f5aa12db51b85cef00c6b GIT binary patch literal 30514 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�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 literal 0 HcmV?d00001 diff --git a/docs/reference/local-authority-provider-selection.md b/docs/reference/local-authority-provider-selection.md index 1c5f8a3947..2ffaf249d5 100644 --- a/docs/reference/local-authority-provider-selection.md +++ b/docs/reference/local-authority-provider-selection.md @@ -207,6 +207,22 @@ already-canonical Goals use the [reviewed File/SQLite cutover](file-authority-st Retain verified backups, stop writers, settle leases and preserve newer writes on reverse migration. Supported historical backup/format/receipt readers remain. +When an older Goal cannot load, the App preserves the storage owner's +`canonical_authority_required` error and offers **Review storage upgrade**. +This opens the existing Goal storage inspector directly, without automatic +retries or migration. Canonical-only settings wait until status can be read; +the inspector remains available after reload. Read-only sources retain their +read-only boundary. Reviewed preview, stopped writers and explicit import +confirmation are still required. Packaged desktop/mobile validation covers +File/SQLite recovery, response loss and refusal of unsettled work; this does +not establish that an installed user's Goals have been migrated. + +旧版 Goal 无法加载时,App 显示存储升级原因,并通过“检查存储升级”直接打开 +现有存储检查页,不自动重试或迁移。状态恢复前暂不加载依赖 canonical 存储的 +设置,重载后仍可检查存储。只读来源保留只读边界;迁移仍须审阅预览、停止写入 +并明确确认。打包后的桌面和手机验证覆盖 File/SQLite 恢复、响应丢失及未结算 +工作的拒绝;这些证据不代表用户已安装的 Goal 已完成迁移。 + After reviewed import or promotion, reconnect the registered Goal with ordinary bootstrap, without `--force`: From a9da49db48fe033f02c01e9266efa973dbb74460 Mon Sep 17 00:00:00 2001 From: huangruiteng Date: Thu, 22 Oct 2026 20:42:57 +0800 Subject: [PATCH 3/4] test(workspace): refresh read-only recovery checks and lint fixtures Signed-off-by: huangruiteng --- .../navigation-sorting.mjs | 3 ++- .../test_quota_acceptance_references.py | 15 ++++++++++----- tests/presentation/test_linked_goal_sources.py | 10 +++++++--- 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/examples/personal-workspace-browser/navigation-sorting.mjs b/examples/personal-workspace-browser/navigation-sorting.mjs index 76db3b8ddd..4d8dae9b2d 100644 --- a/examples/personal-workspace-browser/navigation-sorting.mjs +++ b/examples/personal-workspace-browser/navigation-sorting.mjs @@ -259,7 +259,8 @@ export const navigationSortingScenario = { await remote.getByRole("button", { name: /^(Tasks|任务)$/, current: "page" }).waitFor({ state: "visible" }); if (await remote.getByRole("button", { name: "Goal 设置", exact: true }).count()) throw new Error("Remote Goal exposed local capability settings"); await remote.getByRole("button", { name: "概览", exact: true }).click(); - await remote.locator(".goal-overview-source-note").waitFor({ state: "visible" }); + await remote.getByRole("group", { name: "工作视图", exact: true }).getByRole("button", { name: "关系图", exact: true }).click(); + await remote.getByText("此来源仅提供同步的状态与验收观察,交付链需要实时本机来源。", { exact: true }).waitFor({ state: "visible" }); if (await remote.locator(".delivery-review").count()) throw new Error("Remote Overview queried the local delivery source"); await remote.getByRole("button", { name: "任务", exact: true }).click(); await remote.locator(".personal-object-list", { hasText: "进行中" }).locator("button").first().click(); diff --git a/tests/control_plane/test_quota_acceptance_references.py b/tests/control_plane/test_quota_acceptance_references.py index 1834c211cb..1aa0f17eaf 100644 --- a/tests/control_plane/test_quota_acceptance_references.py +++ b/tests/control_plane/test_quota_acceptance_references.py @@ -67,11 +67,16 @@ def test_exact_copies_share_one_complete_source_without_changing_signed_action(w def test_different_contracts_are_retained_in_full(change): source = packet(False) changed = source["autonomous_replan_obligation"]["replan_context"]["core_goal"]["acceptance_contract"] - if change == "revision": changed["revision"] = 4 - if change == "scope": changed["scope"] = {"kind": "selected_work"} - if change == "failure": changed["verification"]["failures"] += ["New failure"] - if change == "type": changed["verification"]["passed"] = 0 # False == 0 in Python - if change == "source": changed["sources"][0]["ref"] = "message:corrected" + if change == "revision": + changed["revision"] = 4 + if change == "scope": + changed["scope"] = {"kind": "selected_work"} + if change == "failure": + changed["verification"]["failures"] += ["New failure"] + if change == "type": + changed["verification"]["passed"] = 0 # False == 0 in Python + if change == "source": + changed["sources"][0]["ref"] = "message:corrected" shared = _reference_inline_goal_acceptance(source) assert shared["autonomous_replan_obligation"]["replan_context"]["core_goal"]["acceptance_contract"] == changed assert "acceptance_contract_ref" not in shared["autonomous_replan_obligation"]["replan_context"]["core_goal"] diff --git a/tests/presentation/test_linked_goal_sources.py b/tests/presentation/test_linked_goal_sources.py index ba7b96aeb4..c383b90b29 100644 --- a/tests/presentation/test_linked_goal_sources.py +++ b/tests/presentation/test_linked_goal_sources.py @@ -364,7 +364,8 @@ def test_original_saved_findings_keep_full_text_associations_and_source_fences(w # Malformed/wrong-Goal evidence fails closed and invalidates previous pages. events = log.read_text().splitlines() - wrong = json.loads(events[-1]); wrong['goal_id'] = 'unrelated' + wrong = json.loads(events[-1]) + wrong['goal_id'] = 'unrelated' log.write_text('\n'.join([*events[:-1], json.dumps(wrong)])) with pytest.raises(HTTPError) as corrupt: request(endpoint + query) @@ -377,12 +378,15 @@ def test_original_saved_findings_keep_full_text_associations_and_source_fences(w # The prepared source adapter serves the same finding shape as the real App. source_server = RuntimeWorkspaceServer(GoalSource.parse(raw), w['tmp_path']) - worker = Thread(target=source_server.serve_forever, daemon=True); worker.start() + worker = Thread(target=source_server.serve_forever, daemon=True) + worker.start() try: with urlopen(f'http://127.0.0.1:{source_server.server_port}' + endpoint + query + '&view=findings', timeout=30) as response: assert json.load(response)['items'] == first['items'] finally: - source_server.shutdown(); worker.join(timeout=5); source_server.server_close() + source_server.shutdown() + worker.join(timeout=5) + source_server.server_close() request('/api/chat/goal-sources', {'parent_goal_id': 'research-owner', 'goal_id': 'solver-goal', 'source_namespace': namespace}) From 50e5c2388334f84723cf49014cf7ab28e29012de Mon Sep 17 00:00:00 2001 From: huangruiteng Date: Thu, 22 Oct 2026 21:07:59 +0800 Subject: [PATCH 4/4] test(workspace): follow current Chat and acceptance recovery owners Signed-off-by: huangruiteng --- examples/personal-workspace-browser/goal-showcase.mjs | 10 ++++++++++ .../personal-workspace-browser/showcase-workspace.mjs | 4 +++- examples/personal-workspace-browser/typed-actions.mjs | 7 ++++++- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/examples/personal-workspace-browser/goal-showcase.mjs b/examples/personal-workspace-browser/goal-showcase.mjs index 76bf1575bb..5c28af27fc 100644 --- a/examples/personal-workspace-browser/goal-showcase.mjs +++ b/examples/personal-workspace-browser/goal-showcase.mjs @@ -103,8 +103,18 @@ export const goalShowcaseScenario = { const errorHeight = await failure.evaluate(node => node.getBoundingClientRect().height); assert.ok(errorHeight > 0 && errorHeight <= 28, `A region failure is one announced line, not a banner (${errorHeight}px)`); await page.screenshot({ path: resolve(outputDir, "goal-showcase-region-error.png"), animations: "disabled" }); + assert.match(await page.locator(".goal-overview-progress").innerText(), /2\/4 项条件当前通过/, + "An unrelated delivery read failure does not invalidate current acceptance readback"); + state.acceptanceFails = true; + const checks = overview.locator(".delivery-acceptance-contract"); + await checks.locator(".delivery-check-summary").click(); + await checks.getByText("高级配置与诊断", {exact: true}).click(); + await checks.getByRole("button", {name: "刷新结果", exact: true}).click(); + await page.locator(".goal-overview-progress").filter({hasText: "当前保留旧快照"}).waitFor(); assert.match(await page.locator(".goal-overview-progress").innerText(), /当前保留旧快照/, "A failed owning read cannot present retained criteria as currently passing"); + state.acceptanceFails = false; + await checks.getByRole("button", {name: "刷新结果", exact: true}).last().click(); state.deliveryFails = false; await page.locator(".delivery-review-toolbar button").first().click(); await page.locator(".goal-overview-progress").filter({ hasText: "2/4 项条件当前通过" }).waitFor(); diff --git a/examples/personal-workspace-browser/showcase-workspace.mjs b/examples/personal-workspace-browser/showcase-workspace.mjs index d989315d0a..d83395f86f 100644 --- a/examples/personal-workspace-browser/showcase-workspace.mjs +++ b/examples/personal-workspace-browser/showcase-workspace.mjs @@ -123,7 +123,9 @@ export async function installShowcaseWorkspace(api, page, state) { // The check panel refreshes its owning read independently of the map. This // visual fixture supplies that same synthetic contract; real execution is // qualified by goal-acceptance-oracle.mjs against SQLite/HTTP/CLI. - await page.route("**/api/chat/goal-acceptance?*", route => route.fulfill({ + await page.route("**/api/chat/goal-acceptance?*", route => state.acceptanceFails + ? route.fulfill({status: 503, json: {ok: false, error: "acceptance temporarily unavailable"}}) + : route.fulfill({ contentType: "application/json", json: {ok: true, goal_id: goalId, provider_revision: "showcase:3", goal_acceptance_contract: acceptance.goal_acceptance_contract}, })); diff --git a/examples/personal-workspace-browser/typed-actions.mjs b/examples/personal-workspace-browser/typed-actions.mjs index 8b0a860afe..ad31936c81 100644 --- a/examples/personal-workspace-browser/typed-actions.mjs +++ b/examples/personal-workspace-browser/typed-actions.mjs @@ -1021,6 +1021,8 @@ export const typedActionsScenario = { throw new Error(`Work-Agent filter did not consistently filter task cards: ${filteredText}`); } const runtimeSelector = page.getByRole("combobox", { name: "选择聊天 Runtime" }); + if (await runtimeSelector.count()) throw new Error("Tasks view exposed a Chat executor without its composer"); + await page.getByRole("button", { name: "对话", exact: true }).click(); if (!await runtimeSelector.count()) throw new Error("Chat runtime selector is not explicitly labelled independently from work-Agent lanes"); await goalButton.click(); await tasksTab.click(); @@ -1709,9 +1711,10 @@ export const typedActionsScenario = { const previewCountBeforeAnalysis = api.actionPreviews.length; const turnCountBeforeAnalysis = api.turnRequests.length; - await page.getByRole("navigation", { name: "Goal 视图" }).getByRole("button", { name: /^(Tasks|任务)$/ }).click(); await composer.fill("做一次只读分析:判断刚刚新增的 Todo 是否与当前 Goal 一致,并在当前 Chat 返回两点理由。不要修改状态。"); await page.getByRole("button", { name: "发送", exact: true }).click(); + await page.locator(".personal-message-pending").waitFor({state: "hidden"}); + await page.getByRole("navigation", { name: "Goal 视图" }).getByRole("button", { name: /^(Tasks|任务)$/ }).click(); const taskConversationReceipt = page.getByRole("region", { name: "最近对话" }); await taskConversationReceipt.getByText("对话有新回复", { exact: true }).waitFor({ state: "visible", timeout: 10_000 }); await taskConversationReceipt.getByRole("button", { name: "转为任务草稿", exact: true }).waitFor({ state: "visible" }); @@ -1944,9 +1947,11 @@ export const typedActionsScenario = { await page.getByRole("button", { name: "关闭", exact: true }).click(); } api.nextActionPreviewDelayMs = 900; + await goalNavigation.getByRole("button", { name: /^(Chat|对话)$/ }).click(); const conversationRuntime = page.getByRole("combobox", { name: "选择聊天 Runtime" }); const conversationAgentId = await conversationRuntime.getAttribute("data-value"); if (conversationAgentId !== "codex") throw new Error(`Quick Todo actor fixture requires the selected Codex Runtime, got ${conversationAgentId}`); + await goalNavigation.getByRole("button", { name: /^(Tasks|任务)$/ }).click(); const claimedTask = taskCards.filter({ hasText: "Monitor ArcticDB #3179 LoopX comment" }); const unassignedTask = taskCards.filter({ hasText: "todo todo_1596c3a678bb" }); if (await claimedTask.count() !== 1 || await unassignedTask.count() !== 1) {