Skip to content

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

Closed

Description

@objectstack-fleet

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:

  • objectstack preview iframe dock assistant: 0.
  • objectstack 草稿预览 助手 iframe: 0.
  • objectstack ChatDock iframe: 0.
  • objectstack DOCK_EXPANDED_STORAGE_KEY: 0.
  • cloud 草稿预览 两个助手: 0.

Activity

  1. added
    bugSomething isn't working
    pm:queueReady for the PM dispatch loop
    domain:uiDomain lane — seat card indexed by label:pm:seat
    area:aiAI-native — agent / tool / skill metadata, and the MCP surface an agent drives
    on Oct 27, 2026
  2. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    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.

    Generated by Claude Code

  3. added
    pm:dispatchedDispatched to a dev agent by /pm-dispatch
    and removed
    pm:queueReady for the PM dispatch loop
    on Oct 27, 2026
  4. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    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.

  5. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area:aiAI-native — agent / tool / skill metadata, and the MCP surface an agent drivesbugSomething isn't workingdomain:uiDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions