# 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)