Skip to content

Inspectors → Work Column: retire the bottom panel #351

Description

@jeonghun-jj-lee

Inspectors → Work Column: retire the bottom panel

Important

Problem: The Run Inspector and Device Inspector live in a native VS Code bottom panel (two WebviewViewProvider registrations, vanilla TypeScript). This wastes vertical screen space, disconnects the inspectors from the session they belong to, and adds a third chrome surface (bottom panel) to the already-present Work Column and titlebar.

Approach: Rewrite both inspectors as SolidJS components rendered as dynamic tabs inside the Work Column (the session side panel). Extend the chat_bridge.ts postMessage protocol to carry run iteration/pulse/device data from the extension host into the app. Delete the bottom panel entirely.

Approaches considered:

  • (A) Full SolidJS rewrite in-app (chosen): Native reactive rendering, app design system, one fewer webview to boot. Largest rewrite (~600 lines of vanilla TS → SolidJS) but cleanest result.
  • (B) Iframe existing webview inside Work Column: Minimal rewrite but iframe-in-iframe, double postMessage hop, style isolation problems.
  • (C) Incremental (text tab first, full later): Ships partial value quickly but temporary duplication and incomplete UX during phase 1.

Scope: Both repos — harmoniqs/amicode (extension: bridge, deletions) and harmoniqs/opencode (app: SolidJS components, tab model). The live-solve titlebar indicator is unchanged.

Assumptions: The Work Column's ~320px default width is sufficient for both inspectors (their content is primarily vertical). The existing postMessage bridge pattern (chat_bridge.ts) scales to the additional message types without architectural changes.

Acceptance Criteria

  • A solve launch auto-opens a "Run Inspector" tab in the Work Column, displaying live iteration data (iter, objective, infeasibility) and a pulse line chart
  • The Run Inspector tab shows a run picker when multiple runs exist (single tab, internal switcher)
  • On completion, the Run Inspector tab shows fidelity, iteration count, and timing
  • A device connection auto-opens a "Device Inspector" tab in the Work Column, displaying drive lines, qubit status, metrics with staleness, calibration params, and recommended actions
  • The Device Inspector tab shows a device picker when multiple devices exist
  • Both tabs are closable; closing does not discard buffered data (reopening restores state)
  • Both tabs persist per-session (switching sessions shows that session's inspector state)
  • The amicode-panel bottom panel container is removed from package.json
  • All bottom-panel webview code is deleted (run_inspector.ts, device_inspector.ts, their webview entry points, their view builders, their esbuild entries)
  • The context keys amicode.inspectorRevealed and amicode.deviceInspectorRevealed are removed
  • RunsManager posts iteration/pulse/completion data to the chat bridge instead of the deleted webview
  • The device poll loop posts to the chat bridge instead of the deleted webview
  • The pulse plot renders correctly at 320px column width and responds to column resize
  • The live-solve titlebar indicator is removed — the Run Inspector tab is the sole surface for solve status

Key Decisions

Decision Resolution Rationale
What moves Both inspectors Eliminates the bottom panel entirely — no orphaned container
Data bridge Extend chat_bridge.ts postMessage Existing pattern; no new infrastructure
Rendering SolidJS rewrite (not iframe) Design system integration, reactive signals, no iframe-in-iframe
Tab behavior Auto-open on trigger (solve/device connect), closable Matches current reveal-on-event pattern without panel chrome
Multi-run / multi-device Single tab each, internal picker Keeps tab strip clean; preserves existing mental model
Bottom panel fate Deleted No remaining content to host
Live-solve indicator Removed Redundant — the Run Inspector tab auto-opens and shows the same status

Data Contracts

Run Inspector bridge messages (extension → app):

type RunBridgeMessage =
  | { type: "run:iteration"; runId: string; iter: number; objective: number; inf_pr: number; inf_du: number }
  | { type: "run:pulse-meta"; runId: string; drives: number; knots: number; labels: string[]; bounds: [number, number][] }
  | { type: "run:pulse"; runId: string; iter: number; dt: number; values: number[][] }
  | { type: "run:completion"; runId: string; fidelity: number; iterations: number; status: string }
  | { type: "run:activate"; runId: string }
  | { type: "run:timing"; runId: string; elapsed: number }
  | { type: "run:label"; runId: string; label: string }

Device Inspector bridge messages (extension → app):

type DeviceBridgeMessage =
  | { type: "device:status"; device: string; status: DeviceStatus }
  | { type: "device:actions"; device: string; actions: NextAction[] }
  | { type: "device:activate"; device: string }

App → extension (reverse):

type InspectorReverse =
  | { type: "device:refresh"; device: string }

Constraints & Invariants

  • The Work Column tab strip must not become cluttered — inspector tabs are dynamic (appear/disappear), never permanent fixtures
  • The pulse plot must remain functional at the Work Column's minimum width (~280px)
  • Run data buffering must survive tab close/reopen within a session (same as the current retainContextWhenHidden behavior)
  • The bridge message protocol must be typed end-to-end (TypeScript interfaces shared or mirrored between extension and app)
  • The live-solve titlebar indicator is removed (the Run Inspector tab subsumes its function)

Prior Art

  • ADR 0001 (opencode): defines the Work Column as "files-changed navigator, context tree, and file tabs" — this extends it with inspector tabs
  • The existing chat_bridge.ts pattern handles theme sync, commands, file operations — inspector messages follow the same shape
  • Current inspector webviews (media/ui/views/inspector.ts, media/ui/views/device_inspector.ts) define the rendering contract

Source

Brainstorming session — Amico pulse-designer interview context.

Notes

  • The Device Inspector is currently a stub (hardware not wired in this build). The rewrite should faithfully port the rendering code so it's ready when device connections ship.
  • DeviceStatus and NextAction types from src/device_status.ts need to be accessible to the app — either duplicated as a shared type file or bridged as opaque JSON with app-side type guards.
  • ADR 0006 (paired) records the irreversible layout decision.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions