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
Pulse Inspector: stage-multiplexed sidebar tab with live optimization data
Important
Problem: The sidebar "Run Inspector" tab is a static placeholder with hardcoded mock data. The data path from the extension host to the app is broken (a kind vs type field mismatch silently drops all run messages at the relay). No live optimization data reaches the SolidJS app.
Approach: Rename to "Pulse Inspector", add a stage-multiplexed segmented control (Optimization | Calibration | Compilation), fix the extension relay mismatch, wire the inspector bridge via a shared context provider, and mount the existing RunInspector component in the Optimization sub-view. Verify E2E with a real local Piccolo solve.
(B) HTTP polling fallback — avoids extension changes but loses per-iteration live updates and diverges from the bridge architecture.
(C) WebSocket bridge — over-engineered; the postMessage path already works for the dedicated inspector panel.
Scope: Two repos (harmoniqs/amicode extension, harmoniqs/opencode app). Local Piccolo runs only — cloud/remote execution out of scope.
Assumptions: The extension's run_dir_reader correctly parses AMICODE_ITER / AMICODE_PULSE protocol lines from Julia stdout and calls postRunIteration() / postRunPulse() etc. on the RunsManager. The dedicated inspector WebviewPanel (Work Column) already works — validating that the extension-side parsing is correct.
Acceptance Criteria
The sidebar tab is labeled "Pulse Inspector" with a pulse icon.
A segmented control at the top of the tab content shows three stages: Optimization, Calibration, Compilation.
Calibration and Compilation buttons are greyed out (opacity-50, pointer-events-none) with an inline "Soon" badge.
The Optimization button shows a green dot (4px) when the bridge has an active run (iterations arriving, no completion yet).
The existing RunInspector component renders inside the Optimization sub-view, receiving the bridge via context.
When no solve is running, the stage selector is visible and the RunInspector shows its empty state: "No solve yet — launch one from the chat."
When a local Piccolo solve is launched, live data flows end-to-end:
Julia emits AMICODE_ITER / AMICODE_PULSE → extension parses → broadcasts with kind: "run:*" → relay forwards to iframe → app bridge dispatches → RunInspector renders.
The pulse sparkline updates per iteration; iteration metrics (iter, objective, inf_pr/inf_du) update live.
On completion, fidelity card appears (status, F value, iterations, elapsed time) and the green dot disappears.
The tab ID throughout the codebase is "pulseInspector" (renamed from "runInspector").
Command palette title: "Open pulse inspector".
Key Decisions
D1: Extension message field — kind (not type)
All extension-to-webview messages use kind as the discriminator (kind: "theme", kind: "clipboard", etc.). The inspector bridge currently uses type, which causes the relay filter (d.kind.indexOf("run:") === 0) to fail silently. Align to kind.
createInspectorBridge() is called once in an InspectorProvider component, mounted at the session page level. Consumers use useInspectorBridge(). This ensures one listener, one state, shared across sidebar and any future Work Column integration.
D3: Stage selector — segmented control
Three inline buttons, local createSignal drives which sub-view renders. Only Optimization is clickable. The green dot reactivity: bridge.runs().size > 0 && !latestRun.completion.
D4: RunInspector component stays unchanged
The existing component (108 lines) renders correctly. Its internal "Run Inspector" title and run-selector dropdown remain — they're small and removing them would require forking the component, which is deferred.
D5: Sidebar is primary, Work Column untouched
The dedicated inspector WebviewPanel in the Work Column is a separate system (vanilla JS, inspector_webview.js). It continues to work independently. This effort does not modify or deprecate it.
Constraints & Invariants
The kind rename must be atomic across extension + app: if one side ships without the other, messages are dropped.
The extension's relay scripts (chat_panel.ts, deck/shell.ts) must NOT be modified — they already filter correctly on kind.
The command ID amicode.openInspector is stable (internal, not user-facing) — no rename needed.
Cloud/remote execution is out of scope (Raghav and Jack's domain).
Prior Art
The dedicated inspector WebviewPanel (inspector_webview.js) validates that the extension-side parsing and broadcasting works correctly — just through a different delivery path (direct postMessage to its own webview, not through the iframe relay).
The RunInspector SolidJS component and inspector-bridge.ts were merged in an earlier PR but never wired up.
Source
Brainstorming session, August 2026. Design resolved through grilling: stage-multiplexed Pulse Inspector with Optimization active, Calibration/Compilation greyed with "Soon" badges. The relay bug (type vs kind) was discovered during codebase exploration.
Notes
The dedicated inspector webview (inspector_webview.js) likely dispatches on type internally — when we rename to kind in the broadcast, we need to check whether it breaks. If it does, update its dispatch too.
Future work: wire Calibration stage (Intonato), wire Compilation stage (Legato), potentially consolidate the Work Column inspector into the same SolidJS component.
Implementation Plan
Phase 1: Extension fix (~/harmoniqs/amicode)
Rename type → kind in RunBridgeMessage and DeviceBridgeMessage unions in inspector_bridge.ts
Check the dedicated inspector webview for type dispatch — update if needed
Rebuild extension
Phase 2: App changes (~/harmoniqs/opencode)
Update inspector-bridge.ts: type → kind in types and switch statement
Create inspector-context.tsx with InspectorProvider and useInspectorBridge
Mount provider in session page layout
Rename "runInspector" → "pulseInspector" across session-side-panel.tsx, helpers.ts
Replace placeholder content with stage segmented control + <RunInspector bridge={bridge} />
Update labels: "Pulse Inspector" in tab triggers, panel menu, command title
Update entity-rail comments, CSS comment
Update test expectations
Phase 3: E2E verification
Install rebuilt extension
Launch a local Piccolo solve (e.g. X gate, 10 ns)
Confirm live data flows through to the Pulse Inspector sidebar tab
Confirm completion card renders with correct fidelity
schema_version: "1"
spec_id: pulse-inspector-sidebar-tab
type: spec
task_type: implement-slice
date: 2026-08-19
session_id: pulse-inspector-sidebar
status: draft
priority: p2
platform: transmon
tags: [spec, ui, pulse-inspector, sidebar]
linked_plan: null
acceptance:
Pulse Inspector: stage-multiplexed sidebar tab with live optimization data
Important
Problem: The sidebar "Run Inspector" tab is a static placeholder with hardcoded mock data. The data path from the extension host to the app is broken (a
kindvstypefield mismatch silently drops all run messages at the relay). No live optimization data reaches the SolidJS app.Approach: Rename to "Pulse Inspector", add a stage-multiplexed segmented control (Optimization | Calibration | Compilation), fix the extension relay mismatch, wire the inspector bridge via a shared context provider, and mount the existing
RunInspectorcomponent in the Optimization sub-view. Verify E2E with a real local Piccolo solve.Approaches Considered:
Scope: Two repos (
harmoniqs/amicodeextension,harmoniqs/opencodeapp). Local Piccolo runs only — cloud/remote execution out of scope.Assumptions: The extension's
run_dir_readercorrectly parsesAMICODE_ITER/AMICODE_PULSEprotocol lines from Julia stdout and callspostRunIteration()/postRunPulse()etc. on theRunsManager. The dedicated inspector WebviewPanel (Work Column) already works — validating that the extension-side parsing is correct.Acceptance Criteria
opacity-50,pointer-events-none) with an inline "Soon" badge.RunInspectorcomponent renders inside the Optimization sub-view, receiving the bridge via context.AMICODE_ITER/AMICODE_PULSE→ extension parses → broadcasts withkind: "run:*"→ relay forwards to iframe → app bridge dispatches → RunInspector renders."pulseInspector"(renamed from"runInspector").Key Decisions
D1: Extension message field —
kind(nottype)All extension-to-webview messages use
kindas the discriminator (kind: "theme",kind: "clipboard", etc.). The inspector bridge currently usestype, which causes the relay filter (d.kind.indexOf("run:") === 0) to fail silently. Align tokind.Data contract (wire format):
{ "source": "amicode", "kind": "run:iteration", "runId": "...", "iter": 42, "objective": 0.023, "inf_pr": 1.2e-4, "inf_du": 3.1e-5 } { "source": "amicode", "kind": "run:pulse-meta", "runId": "...", "drives": 2, "knots": 50, "labels": ["a_1","a_2"], "bounds": [[-0.2,0.2],[-0.2,0.2]] } { "source": "amicode", "kind": "run:pulse", "runId": "...", "iter": 42, "dt": 0.2, "values": [[...],[...]] } { "source": "amicode", "kind": "run:completion", "runId": "...", "fidelity": 0.9995, "iterations": 60, "status": "FINISHED" }D2: Bridge shared via SolidJS context
createInspectorBridge()is called once in anInspectorProvidercomponent, mounted at the session page level. Consumers useuseInspectorBridge(). This ensures one listener, one state, shared across sidebar and any future Work Column integration.D3: Stage selector — segmented control
Three inline buttons, local
createSignaldrives which sub-view renders. Only Optimization is clickable. The green dot reactivity:bridge.runs().size > 0 && !latestRun.completion.D4: RunInspector component stays unchanged
The existing component (108 lines) renders correctly. Its internal "Run Inspector" title and run-selector dropdown remain — they're small and removing them would require forking the component, which is deferred.
D5: Sidebar is primary, Work Column untouched
The dedicated inspector WebviewPanel in the Work Column is a separate system (vanilla JS,
inspector_webview.js). It continues to work independently. This effort does not modify or deprecate it.Constraints & Invariants
kindrename must be atomic across extension + app: if one side ships without the other, messages are dropped.chat_panel.ts,deck/shell.ts) must NOT be modified — they already filter correctly onkind.amicode.openInspectoris stable (internal, not user-facing) — no rename needed.Prior Art
inspector_webview.js) validates that the extension-side parsing and broadcasting works correctly — just through a different delivery path (directpostMessageto its own webview, not through the iframe relay).RunInspectorSolidJS component andinspector-bridge.tswere merged in an earlier PR but never wired up.Source
Brainstorming session, August 2026. Design resolved through grilling: stage-multiplexed Pulse Inspector with Optimization active, Calibration/Compilation greyed with "Soon" badges. The relay bug (
typevskind) was discovered during codebase exploration.Notes
inspector_webview.js) likely dispatches ontypeinternally — when we rename tokindin the broadcast, we need to check whether it breaks. If it does, update its dispatch too.Implementation Plan
Phase 1: Extension fix (
~/harmoniqs/amicode)type→kindinRunBridgeMessageandDeviceBridgeMessageunions ininspector_bridge.tstypedispatch — update if neededPhase 2: App changes (
~/harmoniqs/opencode)inspector-bridge.ts:type→kindin types and switch statementinspector-context.tsxwithInspectorProvideranduseInspectorBridge"runInspector"→"pulseInspector"acrosssession-side-panel.tsx,helpers.ts<RunInspector bridge={bridge} />Phase 3: E2E verification