# ID9 — r208 End-to-End Integration Plan
**Date**: 2026-08-30 | **Operator directive**: Bind r207 mounts to the constitutional operator flow Gallery → Preview → Desktop. Verify the full interaction loop region-click → inspector → preview → edit.
**Branch**: `feat/id9-r207-mount` (base: `clean/baseline-plus-wdm @ 0746358`, r206)
**Discovery-only.** No code. No pact edits. No extraction.
---
## TL;DR
r208 binds the **3 r207 mounts** (PreviewHostVSIL, InspectorHost, CompositionGraphHost) to the **constitutional operator flow** that already exists in the host. The binding is at 4 integration points (Edge Panel, Dev Panel, Gallery cascade, OS Header) + 1 replace-legacy (the iframe-based VSIL panel from r202/ID10).
**6 new files (~700 LoC)** at `avidtech6/vibecoder-standalone/src/host/integration/`:
| File | LoC | Purpose |
|------|-----|---------|
| `GalleryPreviewBridge.ts` | 150 | Adapter that wires Gallery card click → `gallery.asset.bind` cascade |
| `CompositionHostMount.tsx` | 180 | PM2-mountable wrapper for CompositionGraphHost + 5-surface state machine |
| `EditBar.tsx` | 130 | Read-only-to-write state toggle (r208 introduces guarded writes) |
| `r208-integration.ts` | 80 | Boot orchestrator — runs at Step 9.5 of host-boot.js |
| `__tests__/integration.test.ts` | 140 | 6 test cases for the full interaction loop |
| `replace-iframe-vsil.js` | 60 | Replaces the r202 iframe-based VSIL panel with the r207 mounts |
**2 LoC diffs** to `host-boot.js`:
- Line ~1989 (after `mountRealEdgePanel()`) — call `bootR208Integration()`
- Line ~803-838 (in `EDGE_PANEL_HOST.openVsilPanel`) — replace iframe with r207 mounts
**No pact edits. No iframe. No postMessage.**
---
## 1. The constitutional operator flow (Gallery → Preview → Desktop)
The VibeCoder host already has a 5-panel default arrangement (per `default-arrangement.js`):
| Panel | Position | Mounted by | Purpose |
|-------|----------|-----------|---------|
| `fvcms-cms-panel` | LEFT (pinned) | `cms-panel.js` auto-init | CMS structure/content/style |
| `fvcms-edge-panel` | RIGHT (docked) | `__fvcmsOpenEdgePanel` | Edge Launcher — 7 tiles (cms/dev/vc/history/vsil/origin/settings) |
| `fvcms-dev-panel` | auto-init | `fvcms-dev-panel.js` | Dev tools (Trace + Versions) |
| `fvcms-vibechat` | BOTTOM (docked) | `vibechat-panel.js` | VibeChat — input bar + thread |
| `fvcms-vsil-panel` | floating (r202, ID10) | `host-boot.js:803` | **IFRAME to vibescope.freshvibeapps.com** ⚠️ |
Plus the OS Header (top) with the 5 surface pills (MAIN / WORKING / DRAFT / PREVIEW / ORIGIN).
### The "Gallery → Preview" part
Per the prior ID9 work (commit `e54771c`): clicking a VSIL card in the Gallery triggers `gallery.asset.bind`, which cascades to `inspector.vsil.asset.bind`, which triggers r206's `ensureHostMounted()` → emits `composition:host-mounted`. The r207 `PreviewHostVSIL` subscribes to that event and mounts.
### The "Preview → Desktop" part (what r208 adds)
Currently the VSIL preview is an **iframe to vibescope.freshvibeapps.com** (r202 Path C). r208 replaces it with the 3 r207 mounts wired into the host's own panel system — no iframe, no postMessage. The 3 mounts live inside the `fvcms-vsil-panel` PM2 panel slot, controlled by the `fvcms-edge-panel` VSIL tile (and the OS Header PREVIEW pill).
### The "Desktop" surface-state integration
The 5 surface pills (MAIN / WORKING / DRAFT / PREVIEW / ORIGIN) on the OS Header dispatch `surface:activated` events. The r207 mounts already filter events by `targetSurface === ctx.activeSurface` (Q2 from r204 v2). r208 doesn't need to add new surface-state logic — the r207 hosts are already correct. The only new thing is the **OS Header's PREVIEW pill** dispatching the event when clicked.
---
## 2. The interaction loop (region-click → inspector → preview → edit)
The full loop, mapped to the r206 events + r207 mounts + r208 wiring:
```
┌────────────────────────────────────────────────────────────────────┐
│ 1. OPERATOR: clicks a Gallery card (operator-flow) │
│ Gallery → ctx.gallery.asset.bind({ assetId, surface, source }) │
│ │
│ 2. CASCADE: Gallery binding cascades to VSIL bind (r206 stub) │
│ ctx.inspector.vsil.asset.bind({ assetId, surface, source }) │
│ └─→ ensureHostMounted() emits 'composition:host-mounted' │
│ └─→ PreviewHostVSIL subscribes (r207 §2.1) → mounts │
│ └─→ bus.emit('vsil:asset-bound', { assetId, surface }) │
│ └─→ PreviewHostVSIL subscribes → calls loadScene │
│ │
│ 3. OPERATOR: clicks a region in the Composition overlay │
│ CompositionGraphHost.onRegionClick (r207 §2.3) │
│ └─→ bus.emit('composition:host-focus', { focusId: region }) │
│ └─→ InspectorHost subscribes (r207 §2.2) → selects │
│ └─→ VibeChat subscribes (separate) → tailors response │
│ └─→ Edge Panel subscribes (separate) → shows tile │
│ │
│ 4. OPERATOR: clicks "Edit" in the Inspector (NEW in r208) │
│ EditBar.onEditClick (r208 §3) │
│ └─→ ctx.state.mountedHosts.push('EditBar') │
│ └─→ bus.emit('composition:host-mounted', { host: 'EditBar' })│
│ └─→ EditBar renders inline transform UI │
│ └─→ operator changes a value │
│ └─→ ctx.inspector.region.transform({ regionId, op }) │
│ └─→ bus.emit('region:transformed', { regionId }) │
│ └─→ CompositionGraphHost re-renders overlay │
│ └─→ PreviewHostVSIL re-renders scene │
│ │
│ 5. OPERATOR: clicks "Lock" in the EditBar │
│ EditBar.onLock │
│ └─→ EditBar unmounts │
│ └─→ bus.emit('composition:host-unmounted', { host: 'EditBar' })│
│ └─→ back to READ-ONLY state (a788 invariant restored) │
└────────────────────────────────────────────────────────────────────┘
```
**4 user actions**, **8 r206 events**, **3 r207 hosts**, **1 new r208 EditBar**. The loop is **closed** (every action has a clear event-driven response).
---
## 3. The 4 integration points (where r208 wires into the host)
### 3.1 Edge Panel tile handler — replace the iframe
**Current** (host-boot.js:803-838):
```js
openVsilPanel: () => {
// ...
const iframe = document.createElement('iframe');
iframe.src = 'https://vibescope.freshvibeapps.com/';
// ...
mgr.addPanel({ id: 'fvcms-vsil-panel', content: wrap /* contains iframe */ });
}
```
**r208 change** (~30 LoC diff):
```js
openVsilPanel: () => {
const mgr = /* ... existing ... */;
if (!mgr) return;
const list = mgr.list();
const existing = list.panels.find(p => p.id === 'fvcms-vsil-panel');
if (existing) { mgr.activate('fvcms-vsil-panel'); return; }
// r208: render the r207 mounts (PreviewHostVSIL + InspectorHost + CompositionGraphHost)
// via the integration orchestrator. NO iframe.
const wrap = document.createElement('div');
wrap.id = 'fvcms-vsil-panel-mount';
mgr.addPanel({
id: 'fvcms-vsil-panel',
title: '🎬 VSIL Inspector',
content: wrap,
icon: '🎬',
position: { x: 80, y: 80, w: 1000, h: 720 },
});
// Mount all 3 r207 hosts into wrap via React
mgr.activate('fvcms-vsil-panel');
// bootR208Integration() handles the actual mounting (see §4.1)
}
```
**Result**: `https://vibescope.freshvibeapps.com/` is no longer loaded into the operator's desktop. The 3 r207 mounts are native React. No iframe. No postMessage.
### 3.2 Dev Panel inspector integration — replace the r202 stub
The Dev Panel has an "Inspector" tab (currently the r202 iframe stub). r208 replaces it with `<InspectorHost>` from r207. The Dev Panel is already auto-init via `fvcms-dev-panel.js` — r208 just registers a custom tab.
### 3.3 Gallery cascade wiring
`src/host/host-boot.js:2099-2101` already loads the Gallery (27 modules). The Gallery card click already cascades (via r206's `gallery.asset.bind`). r208 doesn't need to change the cascade — it just needs to ensure the **3 r207 hosts are mounted BEFORE the operator can click a Gallery card**. r208's `bootR208Integration()` runs at **Step 9.5** (after default arrangement, before VibeChat).
### 3.4 OS Header surface pills
The OS Header dispatches `surface:activated` when the operator clicks a pill. The r207 hosts already filter events by `targetSurface === ctx.activeSurface` (Q2). r208 doesn't need to change the OS Header — it just needs to ensure the r207 hosts are mounted before the operator can click a surface pill.
---
## 4. The 6 new files
### 4.1 `r208-integration.ts` (boot orchestrator, 80 LoC)
```ts
// host/integration/r208-integration.ts
// r208: Orchestrates the binding of r207 mounts into the host.
// Runs at host-boot Step 9.5 (after default arrangement, before VibeChat).
import { mountAllHosts } from '../mounts/mounts';
import { GalleryPreviewBridge } from './GalleryPreviewBridge';
import { CompositionHostMount } from './CompositionHostMount';
import { EditBar } from './EditBar';
export function bootR208Integration(): void {
const ctx = (window as any).__fvcmsStudioContext; // r206 exports this on init
if (!ctx) {
console.error('[r208] StudioContext not initialized');
return;
}
// 1. Mount the 3 r207 hosts into the fvcms-vsil-panel slot.
// (PM2 panel is created by host-boot.openVsilPanel; we just populate it.)
const slot = document.getElementById('fvcms-vsil-panel-mount');
if (slot) {
const { preview, inspector, composition } = mountAllHosts();
ReactDOM.render(
<CompositionHostMount>{preview}{inspector}{composition}</CompositionHostMount>,
slot
);
}
// 2. Wire the Gallery cascade — when operator clicks a Gallery card,
// ctx.gallery.asset.bind is called, which cascades to ctx.inspector.vsil.asset.bind.
// The bridge exposes this cascade as a window function for the Gallery.
(window as any).__fvcmsGalleryPreviewBridge = new GalleryPreviewBridge(ctx);
// 3. Mount the EditBar in the Dev Panel (separate PM2 panel).
// (R208 introduces guarded writes; r207's READ-ONLY invariant is preserved
// until the operator explicitly enables Edit mode via the EditBar.)
const editBarSlot = document.getElementById('fvcms-dev-panel-edit-bar-slot');
if (editBarSlot) {
ReactDOM.render(<EditBar ctx={ctx} />, editBarSlot);
}
console.log('[r208] Integration boot complete. 3 r207 mounts + EditBar + Bridge ready.');
}
```
### 4.2 `GalleryPreviewBridge.ts` (150 LoC)
Bridges the Gallery card click → r206 capability cascade. The Gallery is a 27-module system that already exists; r208 just adds a thin adapter that makes the cascade available to the Gallery UI.
```ts
// host/integration/GalleryPreviewBridge.ts
// r208: Adapter that wires the Gallery card click to r206's gallery.asset.bind.
// The capability layer cascades to inspector.vsil.asset.bind automatically
// (per the r206 stub in context.ts:140-153).
import type { StudioContext } from '../workspace/context';
import type { AssetId, SurfaceId } from '../workspace/primitives';
export class GalleryPreviewBridge {
constructor(private ctx: StudioContext) {}
/** Called when the operator clicks a VSIL card in the Gallery. */
async onCardClick(args: {
assetId: AssetId;
surface: SurfaceId;
source?: 'card' | 'strip' | 'lightbox' | 'preview' | 'vibechat';
}): Promise<{ ok: boolean; reason?: string }> {
// The cascade: gallery → vsil (r206)
const result = await this.ctx.gallery.asset.bind({
assetId: args.assetId,
source: args.source ?? 'card',
});
if (!result.ok) return { ok: false, reason: result.reason };
// The inspector.vsil.asset.bind emits 'composition:host-mounted' which
// the r207 PreviewHostVSIL subscribes to. No further work here.
return { ok: true };
}
/** Re-emit as a typed event for downstream subscribers. */
emitPreviewRequest(args: { assetId: AssetId; surface: SurfaceId; mode: string }) {
this.ctx.bus.emit('preview:vsil', {
slotId: 'cinematic:main' as any,
surface: args.surface,
targetSurface: args.surface,
mode: args.mode,
assetId: args.assetId,
host: 'PreviewHostVSIL' as const,
source: 'gallery' as const,
timestamp: Date.now(),
} as any);
}
}
export default GalleryPreviewBridge;
```
### 4.3 `CompositionHostMount.tsx` (180 LoC)
The PM2-mountable wrapper around CompositionGraphHost. Adds the **5-surface state machine** UI (so the operator can see which surface is active and the read-only state).
```tsx
// host/integration/CompositionHostMount.tsx
// r208: PM2-mountable wrapper for the 3 r207 hosts.
// Adds a 5-surface state machine UI + read-only indicator.
import React, { useState } from 'react';
import { useStudio } from '../workspace/context';
import { PreviewHostVSIL, InspectorHost, CompositionGraphHost } from '../mounts/mounts';
import { EditBar } from './EditBar';
export interface CompositionHostMountProps {
initialEditMode?: boolean;
}
export const CompositionHostMount: React.FC<CompositionHostMountProps> = (props) => {
const ctx = useStudio();
const [editMode, setEditMode] = useState(props.initialEditMode ?? false);
return (
<div data-r208-host="" data-surface={ctx.activeSurface} data-edit-mode={editMode ? '1' : '0'}>
<SurfaceStateBar surface={ctx.activeSurface} />
<div data-r208-tab-row="">
<button data-tab="preview" data-active="1">Preview</button>
<button data-tab="inspector">Inspector</button>
<button data-tab="composition">Composition</button>
<button data-tab="edit" onClick={() => setEditMode(!editMode)}>
{editMode ? 'Lock' : 'Edit'}
</button>
</div>
<div data-r208-tab-body="">
<PreviewHostVSIL surface={ctx.activeSurface} />
<InspectorHost initialSubMode="ast" readOnly={!editMode} />
{editMode && <EditBar />}
<CompositionGraphHost surface={ctx.activeSurface} />
</div>
</div>
);
};
const SurfaceStateBar: React.FC<{ surface: string }> = ({ surface }) => {
const surfaces = ['main', 'working', 'draft', 'preview', 'origin'] as const;
return (
<div data-r208-surface-bar="">
{surfaces.map((s) => (
<button key={s} data-surface={s} data-active={s === surface ? '1' : '0'}>
{s}
</button>
))}
</div>
);
};
export default CompositionHostMount;
```
### 4.4 `EditBar.tsx` (130 LoC)
The READ-ONLY → WRITE toggle. r208 introduces **guarded writes** (per the r207 v2 plan Q3 default): the EditBar is the only way to enable writes, and only for the duration of the edit session.
```tsx
// host/integration/EditBar.tsx
// r208: Edit-mode UI. Allows the operator to apply region transforms/presets
// while the EditBar is mounted. The r207 InspectorHost.readOnly invariant
// is preserved when the EditBar is unmounted (a788).
import React, { useState, useCallback } from 'react';
import { useStudio } from '../workspace/context';
import type { RegionId, AssetId } from '../workspace/primitives';
import type { CapabilityResult, VSILRegion } from '../workspace/capability-types';
export const EditBar: React.FC = () => {
const ctx = useStudio();
const [busy, setBusy] = useState(false);
const [lastResult, setLastResult] = useState<{ ok: boolean; reason?: string } | null>(null);
const onTransform = useCallback(async (
regionId: RegionId,
op: 'translate' | 'scale' | 'rotate' | 'reset',
params?: object,
) => {
setBusy(true);
try {
const result: CapabilityResult<{ region: VSILRegion }> =
await ctx.inspector.region.transform({ regionId, op, params });
setLastResult(result);
} finally {
setBusy(false);
}
}, [ctx.inspector.region]);
const onApplyPreset = useCallback(async (
regionId: RegionId,
presetId: string,
strength?: number,
) => {
setBusy(true);
try {
const result: CapabilityResult<{ region: VSILRegion }> =
await ctx.inspector.region.applyPreset({ regionId, presetId, strength });
setLastResult(result);
} finally {
setBusy(false);
}
}, [ctx.inspector.region]);
const activeRegion = ctx.state.activeRegionId;
return (
<div data-r208-edit-bar="" data-busy={busy ? '1' : '0'}>
<fieldset data-region-transforms="">
<legend>Transforms (active: {activeRegion ?? 'none'})</legend>
<button onClick={() => activeRegion && onTransform(activeRegion, 'translate', { x: 0, y: 0, z: 0 })}>
translate
</button>
<button onClick={() => activeRegion && onTransform(activeRegion, 'scale', { x: 1, y: 1, z: 1 })}>
scale
</button>
<button onClick={() => activeRegion && onTransform(activeRegion, 'rotate', { angle: 0, axis: 'y' })}>
rotate
</button>
<button onClick={() => activeRegion && onTransform(activeRegion, 'reset')}>
reset
</button>
</fieldset>
{lastResult && (
<div data-edit-result={lastResult.ok ? 'ok' : 'fail'}>
{lastResult.ok ? '✓' : '✗'} {lastResult.reason ?? 'applied'}
</div>
)}
</div>
);
};
export default EditBar;
```
### 4.5 `__tests__/integration.test.ts` (140 LoC)
6 test cases for the full interaction loop:
1. **Gallery → Preview cascade**: `gallery.asset.bind` cascades to `inspector.vsil.asset.bind` and emits `composition:host-mounted`
2. **Preview → Inspector (region-click)**: `composition:host-focus` event triggers `region:selected` → InspectorHost updates
3. **Inspector → Preview (sub-mode change)**: InspectorHost sub-mode change does NOT trigger preview re-render (READ-ONLY)
4. **EditBar enabled → region transform → preview re-render**: full loop
5. **EditBar disabled → InspectorHost.readOnly=true** (a788 invariant restored)
6. **Surface pill click → all 3 hosts filter events by new surface** (Q2)
### 4.6 `replace-iframe-vsil.js` (60 LoC)
Replaces the r202 iframe-based VSIL panel mount with the r207 mounts. Run once at host-boot Step 9.5 to migrate existing operator sessions.
---
## 5. The 2 LoC diffs to host-boot.js
### 5.1 Add the r208 boot call (Step 9.5)
```js
// host-boot.js — after line 1989 (after mountRealEdgePanel())
import { bootR208Integration } from './integration/r208-integration.js';
// ...
bootR208Integration(); // r208: bind r207 mounts to the operator flow
```
### 5.2 Replace the iframe in `openVsilPanel`
The current code (lines 803-838) creates an iframe. r208 replaces lines 817-828 (the iframe creation) with a single line: `wrap.id = 'fvcms-vsil-panel-mount';`. The `bootR208Integration()` orchestrator (called once) populates the wrap with the 3 r207 hosts.
---
## 6. Wiring (event flow with full event names)
The 8 r206 events used in the full loop:
```
Gallery card click
└─→ ctx.gallery.asset.bind({ assetId, source: 'card' })
└─→ CASCADES to ctx.inspector.vsil.asset.bind (r206 stub)
└─→ ensureHostMounted() emits 'composition:host-mounted' { host: 'PreviewHostVSIL' }
└─→ PreviewHostVSIL subscribes (r207 §2.1) → setMounted(true) → renders
└─→ bus.emit('vsil:asset-bound', { assetId, surface })
└─→ PreviewHostVSIL subscribes (r207 §2.1) → ctx.inspector.vsil.loadScene()
└─→ bus.emit('vsil:scene-loaded', { sceneId })
└─→ PreviewHostVSIL re-renders
└─→ InspectorHost subscribes (r207 §2.2) → ctx.inspector.region.list()
└─→ setRegions(...) → renders region list
Composition overlay region click
└─→ CompositionGraphHost.onRegionClick (r207 §2.3)
└─→ bus.emit('composition:host-focus', { focusId: regionId, focusType: 'region' })
└─→ InspectorHost subscribes → ctx.state.activeRegionId = regionId
└─→ re-renders with active region
└─→ VibeChat subscribes (separate) → tailors response
└─→ bus.emit('region:selected', { regionId, source: 'user' })
└─→ Edge Panel subscribes (separate) → shows region tile
Inspector sub-mode change (READ-ONLY, no edit)
└─→ local state change only — no event emitted (sub-mode is UI state, not domain state)
└─→ READ-ONLY invariant preserved (a788)
EditBar enabled (operator clicks "Edit")
└─→ setEditMode(true) — local state
└─→ InspectorHost re-renders with readOnly={false}
└─→ EditBar renders inline transform/preset UI
└─→ ctx.state.mountedHosts.push('EditBar')
EditBar transform button clicked
└─→ ctx.inspector.region.transform({ regionId, op, params })
└─→ bus.emit('region:transformed', { regionId, op, params })
└─→ CompositionGraphHost re-renders overlay
└─→ PreviewHostVSIL re-renders scene
└─→ capability returns { ok, region }
EditBar disabled (operator clicks "Lock")
└─→ setEditMode(false) — local state
└─→ InspectorHost re-renders with readOnly={true} (a788 invariant restored)
└─→ EditBar unmounts
└─→ ctx.state.mountedHosts = ctx.state.mountedHosts.filter(h => h !== 'EditBar')
```
---
## 7. Aligned with prior work
- **r206** (`avidtech6/vibecoder-standalone@0746358`): StudioContext adapter, EventPayloadMap, capability bags, ensureHostMounted contract — consumed as-is
- **r207** (`aabe651` on `feat/id9-r207-mount`): the 3 mounts + capability manifests + tests — bound into the operator flow
- **a786** (FreshCards location): separate workspace, no conflict
- **a788** (Inspector): `studio/modules/vibescope/src/cards/InspectorCard.tsx` in freshvibestudio still needs the package-alias migration (a separate cross-repo change, not r208)
- **a789** (Unified Gallery Panel): `GalleryCapabilities.asset.bind` is the cascade entry — used by `GalleryPreviewBridge`
- **a791** (r205 Composition Graph Host): `CompositionGraphHost` from r207 implements the r205 Region concept — mounted in `CompositionHostMount`
- **r202** (ID10 v0.6 VSIL Path C iframe): r208 **REPLACES** the iframe-based VSIL panel with the r207 mounts (no iframe, no postMessage)
---
## 8. Drift identified
| Source | Drift | Severity | r208 resolution |
|--------|-------|----------|-----------------|
| r202 Path C: `openVsilPanel` uses iframe to vibescope.freshvibeapps.com | direct conflict with r208 constraint "no iframe" | high | r208 replaces lines 817-828 (iframe creation) with `wrap.id = 'fvcms-vsil-panel-mount'` |
| r207 v2 plan: InspectorHost is read-only by default | r208 introduces EditBar to enable writes | medium | r208 EditBar is the only path to enable writes; the r207 readOnly invariant is preserved when EditBar is unmounted |
| host-boot.js Step 9 (default arrangement) runs before Step 9.5 (r208 integration) | r208 hosts must be mounted before operator can interact with the VSIL panel | low | r208 inserts `bootR208Integration()` between Step 9 and Step 10 (VibeChat) |
| `studio/modules/vibescope/src/cards/InspectorCard.tsx` in freshvibestudio (a788) | not yet migrated to use the r207 InspectorHost | low | deferred to a separate cross-repo PR (package alias); not r208 scope |
| Dev Panel Inspector tab (r202 stub) | uses r202 iframe | medium | r208 registers a custom tab in the Dev Panel that mounts InspectorHost |
**No new pact files** for r208. The 5-surface state machine is rendered in `CompositionHostMount` as plain React + Tailwind; no constitutional concept is added.
---
## 9. The 8-step implementation plan (NOT this turn)
| # | Step | Time | What | Depends on | Risk |
|---|------|------|------|-----------|------|
| 1 | Branch from `feat/id9-r207-mount` → `feat/id9-r208-integration` | 5m | `git checkout -b` from `aabe651` | r207 | low |
| 2 | `GalleryPreviewBridge.ts` | 3h | Adapter for Gallery card click cascade | r206 | low |
| 3 | `CompositionHostMount.tsx` | 4h | PM2-mountable wrapper + 5-surface state UI | r207 | medium |
| 4 | `EditBar.tsx` | 3h | READ-ONLY → WRITE toggle + transform/preset UI | r207 | medium |
| 5 | `r208-integration.ts` | 2h | Boot orchestrator | 2,3,4 | low |
| 6 | `replace-iframe-vsil.js` | 1h | Replaces the r202 iframe mount | 3 | low |
| 7 | `__tests__/integration.test.ts` | 4h | 6 test cases for the full interaction loop | 2,3,4 | low |
| 8 | `host-boot.js` 2 LoC diffs | 30m | Add `bootR208Integration()` call + replace iframe | 5,6 | low |
| 9 | Playwright smoke | 3h | Click Gallery card → see Preview mount → click region → see Inspector update → click Edit → see EditBar → click transform → see preview re-render | 1-8 | medium |
**Total**: 20-21h, 3-4 days end-to-end.
---
## 10. The 1 thing to remember
> **r208 binds the r207 mounts to the existing operator flow, not invents a new one.** Gallery card click already cascades via r206; PreviewHostVSIL already subscribes to `composition:host-mounted`; InspectorHost already subscribes to `region:selected`. r208 adds 3 things: the EditBar (r208-introduced writes), the GalleryPreviewBridge (Gallery-aware adapter), and the iframe replacement. The interaction loop is **already 80% there**; r208 closes the last 20%.
---
## 11. The 3 open questions for operator
| # | Question | Default if no answer |
|---|----------|---------------------|
| Q1 | **Edit scope**: r208 introduces writes via EditBar. Allow all 4 region ops (translate/scale/rotate/reset) + presets, or just `reset` for v1? | all 4 ops + presets (the EditBar's purpose is enabling writes) |
| Q2 | **EditBar placement**: in the VSIL panel (`fvcms-vsil-panel`) only, or also in the Dev Panel (`fvcms-dev-panel`)? | both — Dev Panel gets a dedicated "Edit" tab, VSIL panel has the EditBar inline when edit mode is toggled |
| Q3 | **VPS deploy now or wait for Playwright smoke**? | wait for Playwright smoke (operator must verify the loop works end-to-end before deploying) |
---
## 12. Cross-references
- r206 commit `0746358` on `clean/baseline-plus-wdm` — the contract r207 binds to
- r207 commit `aabe651` on `feat/id9-r207-mount` — the 3 mounts r208 binds into the operator flow
- a786 / a787 / a788 / a789 / a791 — design plan inputs
- a795 / a797 / a799 — r207 plans + impl report (predecessors of r208)
- a558 (VibeCoder audit, 2026-08-12) — the operator-flow overview
- r202 Path C — the iframe-based VSIL panel that r208 replaces
- ID10 v0.6 (plan a643) — the constitutional operator flow + 5-panel default arrangement
---
**Discovery-only. No code. No pact edits. No extraction. No implementation.**
— vibecoder-standalone-mavis (thread 9)