You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Draft preview iframe opens its own assistant dock (shared sessionStorage), so an iterate turn shows two assistants and squeezes the list to ~200px at 1024px #26470
Filing gate ① a reproduced UX defect (class a, public door: the in-app assistant). reach: one browser at 1024×768, local stack, cloud PR #3297 head 4e7ee6d5 + framework pin 6390fe52, zh-CN, 2026-10-27. On an app's list page with the 助手 dock open, I asked the assistant to add a table. A 「草稿预览」 pane opened automatically. It is an <iframe> of the full console, and inside it the app's own 助手 dock was also open. Result: two assistants on screen, three columns, the record list squeezed to ~200 px (the page title cut to 「装修…」).
Batch-of: 5 · 2026-10-27 re-test of the 2026-10-25 desktop E2E after the fixes. Filed at the maintainer's request: 「完整的再测试一遍」 / 「必要的合理的建议都可以立卡」. Reviewed in-session before filing.
Business reason. "Ask the assistant to change my app" is the second thing every customer does. At a common laptop width the preview that is meant to show the change instead shows a second copy of the chat, and the real page becomes unusable until the preview is closed.
Reader who acts. The domain:ui seat: ui/packages/app-shell/src/layout.
Where (pin 6390fe52; unchanged on objectstack main)
The dock's open state is sessionStorage['ai-chat-dock-expanded'] (app-shell/src/layout/chatDockState.ts:23, read :82). A same-origin iframe shares the tab's sessionStorage.
ConsoleLayout.tsx:158 reads it unconditionally, and :241-243 mounts ChatDockPanel whenever dockEnabled && dock.expanded && !isMobile. Nothing checks ?preview=draft or window.self !== window.top.
console/ai/LiveCanvas.tsx:65-70 iframes the full console at /apps/<seg>?preview=draft.
Arithmetic: parent dock 420 px (DOCK_DEFAULT_WIDTH, chatDockState.ts:35) + iframe dock 420 px leaves ≈ 200 px for the list at 1024 px, which matches the screen.
Expected
A console rendered inside a ?preview=draft iframe mounts no chat dock and no FAB, and arguably no sidebar/topbar chrome either. The preview shows the app, not the console around it.
Dedupe
gh api search/issues on objectstack and cloud, incl. closed:
Triage: audit line · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T05:13Z
⛔ Not a claim, ⛔ not a dispatch. The filer's labels are read and kept; this is the triage line an execution seat needs before it claims.
Triage: lands in the draft preview iframe (ui/); rationale: p2 · domain:ui · area:ai. The preview frame shares sessionStorage and opens its own assistant dock. The frame should start with the dock closed, scoped to the frame, without changing the host page's state.
Claim: PM loop round 1
Session: session_017iXjUm1rujwDk7f3KT1Pkk (seat); implementing card thread session_01ADHkmPEQvCWPCD2sAQWd3D
Account: os-steve
Branch: claude/project-thread-osn00c (platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)
Worktree: the card thread's own container
Domain: domain:ui
Seat: domain:ui#1
File surface: ui/packages/app-shell/src/layout/chatDockState.ts, ui/packages/app-shell/src/layout/ConsoleLayout.tsx, their tests, one root changeset (stop on breach; explain in the report). ⛔ ui/.github/** and the root .github/workflows/ci.yml are out of bounds (maintainer's word, ui-merge epic in flight). Changeset in the root .changeset/.
Container & model: S, mode:thread, model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate), effort: medium
Clause-②: no
Metadata-protocol: none
Responsibility: n/a: renderer defect in ui/, the producing code is the cited ui file; no platform path covers it; reached through the public Console
Thread-read: 6434354707
Premise: holds (read-only premise check at origin/main, 2026-10-27T05:27Z; spot-checked by the seat)
Serial constraints cleared: none (LiveCanvas.tsx/AiChatPage.tsx left to #26469)
Dispatch order handed to the card thread by the project coordinator (three partitions: ruling / mechanism hypotheses / suggested route); the dev does not claim, and starts only once this claim names its branch.
{
"issue": 26470,
"status": "done",
"branch": "claude/project-thread-osn00c",
"pr": "https://github.com/objectstack-ai/objectstack/pull/26504",
"session": "session_01ADHkmPEQvCWPCD2sAQWd3D",
"premise_still_valid": true,
"summary": "chatDockState.ts gains isFramedConsole() (window.self !== window.top; true when the parent refuses access). readStoredDockExpanded returns its fallback and writeStoredDockExpanded is a no-op inside a frame, so the Live Canvas frame's dock starts collapsed, keeps its open/closed state in React state only, and never reads or writes the host page's ai-chat-dock-expanded. ConsoleLayout.tsx is unchanged: every reader/writer of the flag goes through these two helpers. Frame signal chosen over ?preview=draft because LiveCanvas canvasSrc drops the query once the app is materialized (same shared sessionStorage, same second dock), and the query also matches a top-level preview tab whose dock must keep working.",
"tests": "head d368ab53. New ui/packages/app-shell/src/layout/__tests__/ConsoleLayout.previewFrameDock-26470.test.tsx (real ConsoleLayout, AppShell, useChatDockState, storage helpers; only the rail body stubbed): (1) framed + host flag '1' -> no dock, launcher present; (2) framed + host '0' -> open via launcher, close via Ctrl+Shift+I, flag stays '0'; (3) framed + unset -> stays unset; (4) CONTROL top-level '1' mounts and toggle writes '0' then '1'. Run with chatDockState.test.ts, ConsoleLayout.fabYieldsToOpenDock-10899, chatDockReturnLocation, ChatDock.test, ConsoleLayout.dockBinding-10926 under os-verify-lock: Test Files 6 passed (6), Tests 33 passed (33), VERDICT command-exit 0. Ablation: chatDockState.ts restored from 00a4593a (tree only; isFramedConsole count on disk 0), new file run: 3 framed cases failed, control passed (Tests 3 failed | 1 passed (4), VERDICT command-exit 1); restored with git checkout HEAD --, hash equals HEAD blob, git diff HEAD empty. Narrowed: full app-shell suite left to CI Test UI.",
"gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at d368ab53: 35 commands, each exit 0 (captured before any pipe). --ran: '35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN' (derived zero, all 35 carry an exit code). Type check: turbo build --filter='@object-ui/app-shell^...' then pnpm --filter @object-ui/app-shell type-check (tsc --noEmit + tsc -p tsconfig.test.json): VERDICT command-exit 0. PR check-runs: in_progress at report time (not waited on).",
"dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
"line_budget": "+186 / -2 over 3 files (dispatch-gates count), under the 3000 human-merge threshold",
"files_changed": [
".changeset/26470-framed-console-dock-scope.md",
"ui/packages/app-shell/src/layout/chatDockState.ts",
"ui/packages/app-shell/src/layout/__tests__/ConsoleLayout.previewFrameDock-26470.test.tsx"
],
"deviations": "none. Forced test edits: none. Changeset patch @object-ui/app-shell with the claim's Clause-② / Metadata-protocol lines at line start.",
"mcp_calls": "3 — mcp__github__issue_read x3 (get, get_comments x2); no MCP write",
"api_writes": "2 relay writes + 1 git push — pr_create (fleet-write run 40457427209, PR #26504, assignee os-steve, body read back identical 6451 bytes); this os-dev-report comment via post-stamped. git push of claude/project-thread-osn00c (not REST).",
"open_questions": [
{
"question": "The card's Expected also says a framed console should show no assistant launcher (FAB) and arguably no sidebar/top bar. The seat delta asked only for a dock that starts closed and stays scoped to the frame, so the launcher and chrome stay. Hide them in a preview frame?",
"options": ["A keep as delivered: one click opens a frame-scoped dock inside the preview", "B also hide the launcher inside a frame (ConsoleLayout, small follow-up)", "C a chrome-less preview mode (no sidebar/top bar) as its own card, product call"],
"recommendation": "A for this card; C is a product decision for the maintainer, not a dev pick."
}
],
"out_of_scope_findings": [
"carrier: none · noted, not filed — rememberDockReturnLocation (ai-chat-dock-return-to) is not frame-scoped; maximizing from a dock opened inside a preview frame would overwrite the host's return path. Not reproduced (read-only inference), listed in the PR's Acceptance notes."
]
}
Activity
objectstack-fleet commentedon Oct 27, 2026
Triage: audit line · triage seat ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-27T05:13Z⛔ Not a claim, ⛔ not a dispatch. The filer's labels are read and kept; this is the triage line an execution seat needs before it claims.
ui/); rationale: p2 ·domain:ui·area:ai. The preview frame sharessessionStorageand opens its own assistant dock. The frame should start with the dock closed, scoped to the frame, without changing the host page's state.Generated by Claude Code
objectstack-fleet commentedon Oct 27, 2026
Claim: PM loop round 1
Session:
session_017iXjUm1rujwDk7f3KT1Pkk(seat); implementing card threadsession_01ADHkmPEQvCWPCD2sAQWd3DAccount:
os-steveBranch:
claude/project-thread-osn00c(platform-assigned card-thread branch; a card thread can push only its assigned branch, and the name carries no issue number, so this claim is the identity record)Worktree: the card thread's own container
Domain:
domain:uiSeat:
domain:ui#1File surface:
ui/packages/app-shell/src/layout/chatDockState.ts,ui/packages/app-shell/src/layout/ConsoleLayout.tsx, their tests, one root changeset (stop on breach; explain in the report). ⛔ui/.github/**and the root.github/workflows/ci.ymlare out of bounds (maintainer's word, ui-merge epic in flight). Changeset in the root.changeset/.Container & model:
S,mode:thread,model: TIER_DEFAULT (dispatch-gates --tier: no path-derived mandate),effort: mediumClause-②: no
Metadata-protocol: none
Responsibility:
n/a: renderer defect in ui/, the producing code is the cited ui file; no platform path covers it; reached through the public ConsoleThread-read: 6434354707
Premise: holds (read-only premise check at
origin/main, 2026-10-27T05:27Z; spot-checked by the seat)Serial constraints cleared: none (LiveCanvas.tsx/AiChatPage.tsx left to #26469)
Dispatch order handed to the card thread by the project coordinator (three partitions: ruling / mechanism hypotheses / suggested route); the dev does not claim, and starts only once this claim names its branch.
objectstack-fleet commentedon Oct 27, 2026
os-dev-report
{ "issue": 26470, "status": "done", "branch": "claude/project-thread-osn00c", "pr": "https://github.com/objectstack-ai/objectstack/pull/26504", "session": "session_01ADHkmPEQvCWPCD2sAQWd3D", "premise_still_valid": true, "summary": "chatDockState.ts gains isFramedConsole() (window.self !== window.top; true when the parent refuses access). readStoredDockExpanded returns its fallback and writeStoredDockExpanded is a no-op inside a frame, so the Live Canvas frame's dock starts collapsed, keeps its open/closed state in React state only, and never reads or writes the host page's ai-chat-dock-expanded. ConsoleLayout.tsx is unchanged: every reader/writer of the flag goes through these two helpers. Frame signal chosen over ?preview=draft because LiveCanvas canvasSrc drops the query once the app is materialized (same shared sessionStorage, same second dock), and the query also matches a top-level preview tab whose dock must keep working.", "tests": "head d368ab53. New ui/packages/app-shell/src/layout/__tests__/ConsoleLayout.previewFrameDock-26470.test.tsx (real ConsoleLayout, AppShell, useChatDockState, storage helpers; only the rail body stubbed): (1) framed + host flag '1' -> no dock, launcher present; (2) framed + host '0' -> open via launcher, close via Ctrl+Shift+I, flag stays '0'; (3) framed + unset -> stays unset; (4) CONTROL top-level '1' mounts and toggle writes '0' then '1'. Run with chatDockState.test.ts, ConsoleLayout.fabYieldsToOpenDock-10899, chatDockReturnLocation, ChatDock.test, ConsoleLayout.dockBinding-10926 under os-verify-lock: Test Files 6 passed (6), Tests 33 passed (33), VERDICT command-exit 0. Ablation: chatDockState.ts restored from 00a4593a (tree only; isFramedConsole count on disk 0), new file run: 3 framed cases failed, control passed (Tests 3 failed | 1 passed (4), VERDICT command-exit 1); restored with git checkout HEAD --, hash equals HEAD blob, git diff HEAD empty. Narrowed: full app-shell suite left to CI Test UI.", "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at d368ab53: 35 commands, each exit 0 (captured before any pipe). --ran: '35 derived, 35 run, 0 NOT-MEASURED, 0 UNRUN' (derived zero, all 35 carry an exit code). Type check: turbo build --filter='@object-ui/app-shell^...' then pnpm --filter @object-ui/app-shell type-check (tsc --noEmit + tsc -p tsconfig.test.json): VERDICT command-exit 0. PR check-runs: in_progress at report time (not waited on).", "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm", "line_budget": "+186 / -2 over 3 files (dispatch-gates count), under the 3000 human-merge threshold", "files_changed": [ ".changeset/26470-framed-console-dock-scope.md", "ui/packages/app-shell/src/layout/chatDockState.ts", "ui/packages/app-shell/src/layout/__tests__/ConsoleLayout.previewFrameDock-26470.test.tsx" ], "deviations": "none. Forced test edits: none. Changeset patch @object-ui/app-shell with the claim's Clause-② / Metadata-protocol lines at line start.", "mcp_calls": "3 — mcp__github__issue_read x3 (get, get_comments x2); no MCP write", "api_writes": "2 relay writes + 1 git push — pr_create (fleet-write run 40457427209, PR #26504, assignee os-steve, body read back identical 6451 bytes); this os-dev-report comment via post-stamped. git push of claude/project-thread-osn00c (not REST).", "open_questions": [ { "question": "The card's Expected also says a framed console should show no assistant launcher (FAB) and arguably no sidebar/top bar. The seat delta asked only for a dock that starts closed and stays scoped to the frame, so the launcher and chrome stay. Hide them in a preview frame?", "options": ["A keep as delivered: one click opens a frame-scoped dock inside the preview", "B also hide the launcher inside a frame (ConsoleLayout, small follow-up)", "C a chrome-less preview mode (no sidebar/top bar) as its own card, product call"], "recommendation": "A for this card; C is a product decision for the maintainer, not a dev pick." } ], "out_of_scope_findings": [ "carrier: none · noted, not filed — rememberDockReturnLocation (ai-chat-dock-return-to) is not frame-scoped; maximizing from a dock opened inside a preview frame would overwrite the host's return path. Not reproduced (read-only inference), listed in the PR's Acceptance notes." ] }Generated by Claude Code