r212 Operator Chrome Consolidation — Implementation Report

Status: ✅ All green · 26/26 r212 unit tests · 44/44 r212 Playwright smoke · 0 regressions (r207/r208/r210 all still 100% green)

Date: 2026-08-30 17:12

Branch: feat/id9-r212-chrome-consolidation @ 71e6b43

Repo: avidtech6/vibecoder-standalone

Base: feat/id9-r211-merge @ 2cb3494

TL;DR

Unifies the r210 MinimalHeader, r208 EdgePanel, and r210 GalleryPanel into a single cohesive operator chrome. Adds a new SideChrome panel (fvcms-side-chrome) that replaces the developer-facing 4-tab row inside the VSIL panel with 4 user-facing placeholders (scene / inspector / composer / timeline). Adds a 5th icon to the MinimalHeader that opens the SideChrome. 148/148 total tests pass (24 r207 + 27 r208 + 27 r210 + 26 r212 unit + 44 r212 Playwright).

The r212 chrome — what the operator sees

Top chrome (r210 MinimalHeader, unchanged + 1 new icon)

┌──────────────────────────────────────────────────────────────────────┐
│ FV • vibecoder | [MAIN]                       [🖼 Gallery] [🗂 Workspace] [☰ Edge] │
└──────────────────────────────────────────────────────────────────────┘

The 5th icon (3 stacked layers SVG) opens the SideChrome. This is the new entry point in r212.

Side chrome (NEW r212 SideChrome.tsx)

┌──────────────────────────────────────────────────┐
│ 🛠 VSIL Editor                            [_ □ ×] │
├──────────────────────────────────────────────────┤
│ [MAIN]  [WORKING]  [DRAFT]  [PREVIEW]  [ORIGIN]  │  ← 5-surface state row
├──────────────────────────────────────────────────┤
│ [🎬 scene]    [🔍 inspector]                     │  ← 4 user-facing
│ [🎼 composer]  [⏱ timeline]                     │    tiles (2x2 grid)
├──────────────────────────────────────────────────┤
│                                                  │
│                                │
│  - scene      → PreviewHostVSIL (r207)           │
│  - inspector  → InspectorHost (r207, READ-ONLY)  │
│  - composer   → CompositionGraphHost (r207)      │
│  - timeline   → "VSIL Editor — coming soon"      │
│                + Lock toggle → r208 EditBar      │
│                                                  │
└──────────────────────────────────────────────────┘

The 4 user-facing tiles mirror the r202 Vibe sub-tiles (scene / inspector / composer / timeline) but with a unified naming. The 3 r207 mounts (PreviewHostVSIL, InspectorHost, CompositionGraphHost) still render — they're just labeled with user-facing names. The 4th tile (timeline) is a placeholder for the upcoming VSIL Editor.

Timeline tile in detail

┌──────────────────────────────────────────────────┐
│ ⏱ timeline                              [🔒 Lock] │
├──────────────────────────────────────────────────┤
│                                                  │
│                    ⏱                             │
│         VSIL Editor — coming soon                │
│                                                  │
│  The upcoming VSIL Editor will host the canvas,   │
│  layers, and tools for the active scene. Today,  │
│  the edit button above enables the r208 EditBar  │
│  (translate / scale / rotate / reset + presets)  │
│  for any tile.                                  │
│                                                  │
│  []        │
│                                                  │
└──────────────────────────────────────────────────┘

Click Lock → Edit: the r208 EditBar (4 region ops + presets) mounts inside the timeline tile. Click again to restore READ-ONLY (a788 invariant).

Files changed (71e6b43)

src/host/chrome/SideChrome.tsx               | +337 (NEW, React 18 component)
src/host/chrome/__tests__/SideChrome.test.tsx | +390 (NEW, 26 assertions)
src/host/header/MinimalHeader.tsx            | +36 (workspace icon: 3-stack layers SVG)
src/host/host-boot.js                       | +62 (openSideChromePanel + SideChrome import)
scripts/smoke/r212-smoke.spec.cjs            | +440 (NEW, 14 steps, 44 assertions)
scripts/smoke/screenshots-r212/              | 4 PNGs (NEW)

Net: +1151 / -3 lines. 4 new files, 2 modified files.

What the r212 chrome does

1. Top chrome — r210 MinimalHeader with 5 elements (Fv log, surface, Gallery, Workspace (NEW), Edge).

2. Side chrome — new PM2 panel fvcms-side-chrome opened via the Workspace icon. Hosts the 4 user-facing tiles.

3. Tile content — the 3 r207 mounts render inside scene/inspector/composer tiles. The 4th tile (timeline) is a placeholder for the VSIL Editor with Lock → Edit toggle that mounts the r208 EditBar.

4. Surface row — 5 surfaces (MAIN / WORKING / DRAFT / PREVIEW / ORIGIN) at the top of the SideChrome. Click any surface to switch.

5. R208 iframe patch — still active on mgr.addPanel. The legacy 4-tab row inside the r208 CompositionHostMount is preserved (for backward compatibility). r212 SideChrome is the user-facing replacement.

The 3 critical r212 details

1. Vite dual-React gotcha (r210 lesson, applied)

The SideChrome is imported statically at the top of host-boot.js:

import { SideChrome } from './chrome/SideChrome.tsx';

This is the same pattern as r210's MinimalHeader and GalleryPanel imports. Dynamic imports inside the mount function caused Vite to bundle a second copy of React (r210 lesson). Static imports ensure a single React copy.

2. CSS safety net not needed (r212 is a new component)

The r212 SideChrome is a new component — no r202-era IDs to hide. The component uses data-r212-* selectors exclusively. No CSS safety net required.

3. R208 CompositionHostMount preserved (per spec)

Per operator spec: "No removal of r207/r208 mounts." The r208 CompositionHostMount with the 4 dev-facing tabs (Preview / Inspector / Composition / Edit) is preserved. The r212 SideChrome is a separate PM2 panel that operators can open directly via the new Workspace icon. The r208 iframe patch on mgr.addPanel is still active, so opening the legacy VSIL panel still mounts the r207 hosts.

Test results

| Suite | Result |

|------|--------|

| r207 unit tests (mounts.test.ts) | 24/24 ✅ |

| r208 unit tests (r208-integration.test.ts) | 27/27 ✅ |

| r210 unit tests (MinimalHeader.test.tsx) | 27/27 ✅ |

| r212 unit tests (SideChrome.test.tsx) | 26/26 ✅ |

| r212 Playwright smoke (r212-smoke.spec.cjs) | 44/44 ✅ |

| Total | 148/148 ✅ |

r212 invariants verified

| Invariant | Status |

|-----------|--------|

| No iframe | ✅ (0 in r212 source, 0 in mount tree) |

| No postMessage | ✅ (0 in r212 source) |

| Window-level event bus | ✅ (fvcms:active-surface-changed still on document) |

| Surface targeting | ✅ (StudioContext.surface + bus.emit) |

| a788 READ-ONLY invariant | ✅ (InspectorHost readOnly=true by default) |

| R208 iframe patch | ✅ (mgr.addPanel still detects fvcms-vsil-panel) |

| R207 mounts functional | ✅ (PreviewHostVSIL, InspectorHost, CompositionGraphHost) |

| R208 EditBar functional | ✅ (Lock → Edit toggle mounts EditBar) |

| WDM togglePillHidden still works | ✅ (API preserved) |

| WDM attachEyeHandlers is NOT called | ✅ (r210) |

| 5-surface cycle works | ✅ (window.__fvcmsSetActiveSurface + 5-surface row in SideChrome) |

| Edge Panel open path | ✅ (window.__fvcmsOpenEdgePanel from r210 + r208) |

| Gallery panel open path | ✅ (window.__fvcmsOpenGalleryPanel from r210) |

| SideChrome panel open path | ✅ (window.__fvcmsOpenSideChromePanel from r212) |

What's next

1. Production deploy (operator call)

cd /workspace/vibecoder-standalone-r212
npm run build  # build the production bundle
scp -O -r dist/* root@185.249.73.178:/var/www/freshvibeapps/clients/vibecoder/

2. Cross-branch strategy (operator call)

The r212 branch is based on r211. Possible next steps:

3. Outstanding follow-ups

Verification commands

cd /workspace/vibecoder-standalone-r212

# Unit tests
npx tsx src/host/mounts/__tests__/mounts.test.ts         # 24/24
npx tsx src/host/integration/__tests__/r208-integration.test.ts  # 27/27
npx tsx src/host/header/__tests__/MinimalHeader.test.tsx  # 27/27
npx tsx src/host/chrome/__tests__/SideChrome.test.tsx     # 26/26

# Playwright smoke (Vite dev server on :5275)
npx vite --port 5275 --host 0.0.0.0 &
node scripts/smoke/r212-smoke.spec.cjs  # 44/44

Expected: 104/104 unit + 44/44 Playwright = 148/148 total.