# VSIL Drift Audit — VibeCoder Internal — 2026-09-15 **Lane:** id 9 (vibecoder-standalone-mavis) — read-only **Source HEADs:** vibecoder-standalone `cc55e6b`; fv-module-gallery `4d8139d`; VPS-vsile side at `/opt/vibecoder-bridge/` **Reference:** VSIL Establishment Plan Phase 3 (Cycle G audit) **Output feeds:** Phase 4 (alignment vs evolution) --- ## §1 — Scope of the audit Six classes of VSIL "users" identified: | ID | Surface | File roots | Status | |---|---|---|---| | S1 | Cinema editor | `src/host/editor/VSILEditor.tsx` + `Canvas.tsx` + `LayersPanel.tsx` + `Composer.tsx` + `Inspector.tsx` + `Timeline.tsx` | REAL | | S2 | Preview host | `src/host/mounts/PreviewHostVSIL.tsx` | REAL | | S3 | Cinema backend (server.cjs) | `server.cjs:5007-5300` (cycle 11/12 routes: vsil/scene, origin/to-vsil, vsil/round-trip, cinema/*, POST /api/agent/cinema/render) | REAL | | S4 | Image-analysis pipeline | VPS `/opt/vibecoder-bridge/vsil.cjs`, `vsil-meme.cjs`, `vsil-scene.cjs`, `origin-to-vsil.cjs`, `screenshot-structure.cjs`, `meme-renderer.cjs`, `meme-caption-engine.cjs`, `meme-templates.cjs`, `image-processing.cjs`, `image-block-builder.cjs`, `ocr.cjs` | REAL (constitutional side) | | S5 | JSON schema (data side) | VPS `ui-schema/vibescope/scene.json` | REAL (JSON Schema v7) | | S6 | Agent tool surface | `src/agent/tools.ts:529-560` (`create_vibescope_scene`, `patch_vibescope_scene`) | REAL | | S7 | DNA / motion | `src/host/workspace/dna/dna-types.ts:60-170` (`MotionPrimitive`, `DnaKeyframe`, `DnaAnimationTrack`) | REAL (separate lineage, NOT vsil-namespace) | | S8 | Render CLI | NONE FOUND | NOT FOUND | Surface-level totals: **7 VSIL-user surfaces + 1 not-found**. Cinema, Image Editor, Meme Builder, UI Composer, Render CLI are explicitly named by the dispatch; only 4 of 5 have material implementations. Render CLI does not exist. --- ## §2 — Constructs inventoried per surface ### Scene shape (what fields does "scene" have?) | Surface | Fields | File:line | |---|---|---| | S1 Cinema | `id, assetId, camera, lighting, atmosphere, regions` | `capability-types.ts:18` | | S2 Preview | same as S1 (re-export via VSILScene) | `capability-types.ts:18` | | S3 server.cjs cycles 11/12 | screen-shot returns structure-only; round-trip wraps the structure | `server.cjs:5051-5080` | | S5 JSON schema (`scene.json`) | `id, name, layers, durationMs, camera{position, lookAt, fov}, transitions{in,out,easing}` | `ui-schema/vibescope/scene.json:8-72` | | S6 agent tool | `id, name, durationMs, layers` | `tools.ts:529-543` | | S7 DNA | `keyframes, animations, timeUnit, frameRate, loop` (animation-only; layered ON TOP of canvas content rather than being a scene) | `dna-types.ts:160-167` | | **vsil-renderer.cjs (b3037)** | `id, camera{width,height}, lighting, regions` (an *INVENTED* shape; doesn't match any of the above) | `vsil-renderer.cjs:9` | **Conflict 1:** Camera shape exists in 3 distinct forms. - S1/S2: `CameraState { angle, distance, target: [number,number,number] }` — 3D-style with angle+distance - S5 JSON schema: `camera { position: number[3], lookAt: number[3], fov: number }` — 3D-style with explicit position+lookAt - S3/vsil-renderer: `camera: { width, height }` — 2D-style with image dimensions **Conflict 2:** S5 scene.json has `name` (human-readable), `durationMs` (1-30s), and `transitions{in,out,easing}` — none of S1/S2 carry these. The on-disk format (S5) is richer than the in-memory TS shape (S1). ### Region shape (what fields does "region" have?) | Surface | Fields | File:line | |---|---|---| | S1 Cinema summary | `RegionSummaryForVSIL { id, bounds: {x,y,w,h} }` — 4 fields, NO content/type/style | `capability-types.ts:19` | | S1 Layers panel | `LayerEntry { id, name, visible, locked, region?: any }` — declaration tier, shape left to `region: any` | `LayersPanel.tsx:30-36` | | S2 vsil-renderer (PROMPT #16) | `region = { id, type: 'shape'|'text'|'image', shape?, bounds, fill?, content?, style?, transform?, layer }` — 9 fields, own taxonomy | `vsil-renderer.cjs:9` | | S5 scene.json layer | `layer = { kind: 'background'|'foreground'|'overlay', content, opacity, zIndex }` — 5 fields, name+opacity+stack instead of x/y/w/h | `ui-schema/vibescope/scene.json:23-50` | | S4 vsil.cjs | `region = { vsil: 'vsil:region', regionId, role?, ..., }` — block-taxonomy with `vsil:` namespace prefix | `vsil.cjs:93-115` | | S6 agent tool | layer = `{kind, content, opacity, zIndex}` — same as scene.json | `tools.ts:541` | | S4 meme templates | `region = { id: 'vsil:region:1', bounds, role: 'caption-top' }` — overlaps with vsil.cjs but adds `role` | `meme-templates.cjs:50-60` | **Conflict 3:** "Region" has 6 distinct shapes. Only S1 Cinema summary and S4 vsil.cjs agree on the bare `id + bounds` subset. Everything else INVENTS additional fields: | Invention | Inventor | Overlap with canonical? | |---|---|---| | `kind: 'background'|'foreground'|'overlay'` | S5 scene.json + S6 tools | NONE in vsil.cjs or capability-types | | `content` field (string) | S5 scene.json + S6 tools | DIFFERENT (string URL vs. typed vsil:component) | | `opacity: 0..1` | S5 + S6 | NONE in vsil.cjs | | `zIndex: integer` | S5 + S6 | NONE in vsil.cjs | | `type: 'shape'|'text'|'image'` | vsil-renderer (S2 augmented by PROMPT #16) | NONE in canonical | | `shape: 'rect'|'ellipse'|'circle'` | vsil-renderer | NONE in canonical | | `style: { fontSize, color, align, fontFamily, fontWeight }` | vsil-renderer | NONE in canonical | | `transform: { x, y, rotation, scale }` | vsil-renderer | NONE in canonical | | `role: 'caption-top'|'caption-bottom'|'tweet-header'|...` | meme-templates | NONE in canonical | | `text: 'TOP TEXT'`, `maxFontSize: 80` (template-specific) | meme-templates | NONE | | `visible: boolean`, `locked: boolean` (panel state) | LayersPanel | NONE in canonical (these are UI metadata, not scene) | ### Transform / geometry | Surface | Geometry | File:line | |---|---|---| | S1/S2/S3/S4 | `bounds: { x, y, w, h }` (rectangle, 2D) | ubiquitous | | S5 JSON schema | `position: number[3], lookAt: number[3], fov` (3D world coords, camera-level) | scene.json:55-71 | | S7 DNA | `KeyframeProperties { x, y, scale, rotation, opacity }` (animation-only, no bounds rectangle) | dna-types.ts:115-122 | | vsil-renderer | `transform: { x, y, rotation, scale }` (translation separate from bounds) | vsil-renderer.cjs:30 | ### Style (per surface) | Surface | Style | File:line | |---|---|---| | S1/S2/S4 canonical | NONE (style inline on `vsil:component.props`) | vsil.cjs:80-90 | | S2 vsil-renderer (PROMPT #16) | `{ fontSize, color, align, fontFamily, fontWeight }` nested under `region.style` | vsil-renderer.cjs | | S4 meme-caption-engine | `caption.text`, `caption.position`, `caption.align`, `caption.maxFontSize` flat | meme-caption-engine.cjs (functions _estimateTextWidth etc.) | | S7 DNA | `Easing` (cubic-bezier named) | dna-types.ts:80 | ### Animation / temporal | Surface | Time dimension | File:line | |---|---|---| | S1/S2 (Canvas + Preview) | NONE — render is one-shot per scene | (no time field) | | S5 scene.json | `durationMs: 1000-30000` (scene-level); `transitions{in,out,easing}` per scene | scene.json:14-18, 70-78 | | S7 DNA | `keyframes[]`, `animations[]`, `timeUnit`, `frameRate`, `loop` | dna-types.ts:160-167 | | vsil-renderer | NONE — uses no animation | — | **Conflict 4:** Animation lives in **3 places** with **3 different vocabularies**. None of them interoperate. - S5 scene.json: scene-level `durationMs + transitions` - S7 DNA: per-layer `keyframes + animation tracks` - vsil-renderer (PROMPT #16): none — cinema-style animation not yet supported ### Grouping / hierarchy | Surface | Grouping | File:line | |---|---|---| | S1/S2 canonical | NONE — flat `regions: RegionSummary[]` | capability-types.ts:18 | | S5 scene.json | NONE — flat `layers: array` | scene.json:23 | | S4 vsil.cjs | `vsil:layout: 'stack'|'row'|'grid'` + `vsil:component.children[]` (nested) | vsil.cjs:117-141 | | S1 Composer.tsx | `kind: 'group'` (DAG-style graph nodes), DIFFERENT semantic | Composer.tsx:27 | | S4 origin-to-vsil | `vsil:component.children[]` (nested) | origin-to-vsil.cjs | **Conflict 5:** "Grouping" means three different things: - S5 scene.json: none (flat layer array) - S4 canonical: recursive `vsil:component.children[]` - S1 Composer.tsx: DAG graph (`ComposerNode { kind: 'group' }`) ### Camera / lighting | Surface | Camera | Lighting | |---|---|---| | S1/S2 | `CameraState { angle, distance, target }` | `LightingState { key, fill, rim, ambient }` | | S5 JSON schema | `{ position[3], lookAt[3], fov }` | NONE on the layer level (only `transitions.in/out`) | | S4 vsil.cjs / vsil-scene.cjs | `vsil:capability { vsil: 'vsil:capability', camera, lighting, atmosphere }` | atmosphere = `{ fog, gradient, particles }` | 3 camera shapes, 3 lighting shapes, **no overlap** between the S1 CapabilitySide and the on-disk JSON schema. ### Atmosphere Present in S1/S2/S4 canonical as `{ fog, gradient, particles }` (dna-types). ABSENT in S5 scene.json. ABSENT in vsil-renderer (b3037). --- ## §3 — Constructs INVENTED per surface | Surface | Invented construct | Source | |---|---|---| | S1 Layers panel | `visible`, `locked` (UI panel state, not scene shape) | `LayersPanel.tsx:30-36` | | S1 Composer | `ComposerNode.kind: 'input' \| 'transform' \| 'filter' \| 'output' \| 'group'` + `ComposerNode.x`/`y` (DAG graph, NOT scene structure) | `Composer.tsx:27` | | S1 Canvas | 4 hardcoded demo layers `layer-bg/layer-scene/layer-fx/layer-ui` with pixel `bounds` (placeholder, not real VSIL) | `Canvas.tsx:120-127` | | S2 vsil-renderer | `region.type: shape/text/image`, `region.style.fontSize/align/...`, `region.transform` | `vsil-renderer.cjs:9` | | S4 meme-templates | `region.role: 'caption-top'\|...`, `caption.maxFontSize` | `meme-templates.cjs:50-100` | | S5 scene.json | `kind: 'background'/'foreground'/'overlay'`, `opacity`, `zIndex` | `scene.json:23-50` | | S6 agent tool | inherits scene.json shape | `tools.ts:529-560` | | S7 DNA | `MotionPrimitive` 10 types + `DnaKeyframe` + `DnaAnimationTrack` | `dna-types.ts:60-170` | --- ## §4 — Drift matrix ### 4a — Used consistently across all surfaces NONE. There is no single field, namespace, or shape present in **all 7** surfaces. ### 4b — Used in some (≥2 surfaces) but with **field-level divergence** | Construct | Surfaces that agree on field name | Disagreement | |---|---|---| | `region.id` | All 7 (S1-S7) | S4 vsil.cjs uses `regionId` vs. everything else's `id` | | `region.bounds.x/y/w/h` | S1/S2/S3/S4 canonical + meme-templates + vsil-renderer | NOT used by S5 (uses `kind+opacity+zIndex` instead) or S6 (same), NOT used by S7 (uses `x,y,scale,rotation,opacity` instead) | | `camera.*` | All 7 surfaces that have a camera | **3 different shapes** (CameraState angle+distance; JSON schema position+lookAt+fov; vsil-renderer width+height) | | `lighting.*` | S1, S2, S4 canonical (canonical has key+fill+rim+ambient; vsil-renderer has `key/fill/back` after b3037's mapping) | S5 + S6 have no lighting field at all | | `durationMs` | S5 + S6 (1-30s scene-level) | NOT in S1/S2/S3/S4 canonical; S7 DNA uses `timeUnit: 'seconds'\|'frames'` instead | ### 4c — Contradicted between surfaces | Construct | Conflict | |---|---| | Camera shape | S1/S2 (3D `angle/distance/target`) vs. S5 (3D `position/lookAt/fov`) vs. S2 vsil-renderer (2D `width/height`) — **3 incompatible cameras** | | Region representation | S5 scene.json (string `content` + `kind` + `zIndex`) vs. S4 canonical (`vsil:component` nested under region) vs. S2 vsil-renderer (typed primitives with `style`/`transform` flat-ish) | | Animation vocabulary | S5 (`durationMs + transitions`) vs. S7 DNA (`keyframes + animation tracks`) — orthogonal | | Grouping | S5 (flat layers) vs. S4 canonical (recursive `vsil:component.children`) vs. S1 Composer (DAG) | ### 4d — Ignored (canonical has it, surface omits it) | Construct | Canonical surface | Ignored by | |---|---|---| | `atmosphere.{fog,gradient,particles}` | S1/S2/S4 | S5 (scene.json), S6 (tools), S2 vsil-renderer | | `vsil:layout {stack,row,grid}` | S4 vsil.cjs | S1, S2, S3, S5, S6, S7 | | `vsil:component.children[]` | S4 vsil.cjs | All others (no nesting anywhere outside S4) | | `vsil:SEMANTIC_TAGS (7 tags)` | S4 vsil.cjs:29 | S1, S2, S3, S5, S6, S7 | | `vsil:capability` block | S4 vsil-scene.cjs inferScene (canonical pipeline output) | S1/S2/S3 surfaces use CameraState from TS; they ignore the `vsil:` block tag | | 13 `vsil:component` types (button/input/...) | S4 vsil.cjs:25-27 | S1/S2/S3/S5/S6/S7 (no use of the type taxonomy) | ### 4e — Missing (canonical would have it, no surface has it) | Construct | Should exist per Cycle G? | |---|---| | A clean `vsil.Scene` type that synthesises S5 + S1/S2 + S4 canonical | YES — but doesn't exist | | `kind` as a STRING ENUM in canonical | partial — S5 has it, S4 doesn't | | Round-trip-safe serialization | maybe S3 vsil/round-trip does it, but it's a server-side path; not exposed to clients | | Live "render preview" in inspector | uses PNG (PROMPT #16 vsil-renderer); doesn't interop with the canonical vsil:capability pipeline | --- ## §5 — VSIL → App compatibility matrix | Construct | Cinema | ImgEdit | Meme | UI Comp | Render CLI | Notes | |---|---|---|---|---|---|---| | `vsil:region` (id+bounds) | ✅ uses | ⚠️ partial (uses `region: any`) | ✅ uses (`vsil:region:1`, `vsil:region:2`) | 🚫 invented alternative (DAG nodes) | NOT FOUND | Region summary misses content; meme uses `role` | | `vsil:component` (typed props) | 🚫 invented (`region.type: shape/text/image`) | NOT FOUND | ✅ uses (via `vsil:memeCaption`) | 🚫 invented alternative (DAG nodes) | NOT FOUND | Component taxonomy (13 types) UNUSED by Cinema | | `vsil:layout` (stack/row/grid) | 🚫 invented | NOT FOUND | ❌ absent | 🚫 invented alternative (DAG) | NOT FOUND | Layer ordering by `zIndex` instead | | `vsil:bitmap` (uri/embedded) | ⚠️ partial (PNG render ignores bitmap) | NOT FOUND | ✅ uses | NOT FOUND | NOT FOUND | Cinema render path uses inline SVG, no bitmap load | | `vsil:capability` (camera+lighting+atmosphere) | ⚠️ partial (CameraState/LightingState in TS, no `vsil:` tag) | NOT FOUND | ✅ uses | NOT FOUND | NOT FOUND | `atmosphere` ignored by Cinema & UI Comp | | `vsil:structure` (top-level block) | ❌ absent | NOT FOUND | ✅ uses | ❌ absent | NOT FOUND | Cinema uses `VSILScene` flat, not `vsil:structure` | | `vsil:memeCaption` | ❌ absent | NOT FOUND | ✅ uses (canonical) | ❌ absent | NOT FOUND | Only meme has it | | Animation (`durationMs`) | ⚠️ partial (in S5 schema; absent from S1 in-memory) | NOT FOUND | ❌ absent | ❌ absent | NOT FOUND | Timeline UI exists but doesn't surface to scene shape | | Animation (keyframes) | ⚠️ partial (S7 DNA) | NOT FOUND | ❌ absent | ❌ absent | NOT FOUND | DNA is orthogonal, doesn't feed cinema | | Region types (`shape`, `text`, `image`) | 🚫 invented | NOT FOUND | 🚫 invented (`memeCaption`) | NOT FOUND | NOT FOUND | All three overlay BOTH the bare `id+bounds` AND the canonical block taxonomy | **Legends:** - ✅ uses = surface consumes the canonical construct directly - ⚠️ partial = uses a related concept but with own shape - ❌ absent = explicitly no support - 🚫 invented alternative = uses own construct instead --- ## §6 — Phase 6 — Vibe Agents usage Per dispatch: **REQUIRED, NOT OPTIONAL**. Probed: ``` $ ssh root@185.249.73.178 "python3 /opt/vibecoder-bridge/diagnostics/groq_runner_v2.py test" FAIL $ ssh root@185.249.73.178 "python3 -c 'from groq_runner_v2 import call_groq; print(call_groq(\"Reply with: ping\"))'" RESULT: None ``` The runner's `test` mode returns `FAIL` (a state-monitor value, not a draft). The `call_groq` import path returns `None` (the runner is wired but every call short-circuits to `None`). **Result: Vibe Agents unavailable.** Per dispatch rule: "If the runner is unreachable or returns FAIL/None: Report the exact failure IN THE REPORT. State 'Vibe Agents unavailable: '. Draft natively. Note 'delegation: 0% this dispatch'. Do NOT silently fall back." This dispatch uses **0% delegation**. All prose drafted natively. Failure surfaced in §6 + bulletin + return tuple (per dispatch instructions to surface the gap). The failure is consistent with what was already known from PROMPT #15/PROMPT #16 baselines: runner returns `None`, no Vibe Agents cascade available. --- ## §7 — Recommendations (READ-ONLY — DO NOT IMPLEMENT) The dispatch is READ-ONLY. Recommendations are observations, not actions: 1. **Cycle G audit (this dispatch) is complete.** Output feeds Phase 4 of the VSIL Establishment Plan. 2. The 7 surfaces do not share a single scene shape. Phase 4 alignment work would need to decide which shape is canonical for v1.0 (likely something like the S4 `vsil:structure` root-block + `vsil:capability` + nested `vsil:component` + flat `vsil:region` — but that's a Phase 5 decision). 3. Render CLI does not exist. The dispatch queries it but there's no such tool in either the local clone or VPS. 4. S1 Cinema `Canvas.tsx` still carries a 4-layer placeholder (`layer-bg/layer-scene/layer-fx/layer-ui`) — pre-PROMPT #16 work. 5. PROMPT #16's `vsil-renderer.cjs` introduced a 5th distinct scene/region shape (type+style+transform). That's a Cycle G finding for any future v1.0 ratification. 6. S5 scene.json and S6 agent tool `create_vibescope_scene` agree on `kind/content/opacity/zIndex`. If v1.0 unifies on those, S5+S6 are already aligned. --- ## §8 — File:line citations (consolidated) | Construct | File:line | |---|---| | `VSILScene` in TS | `capability-types.ts:18` | | `CameraState`, `LightingState`, `AtmosphereState` | `capability-types.ts:15-17` | | `RegionSummaryForVSIL` | `capability-types.ts:19` | | VSIL COMPONENT_TYPES (13) | `vsil.cjs:25-27` | | VSIL SEMANTIC_TAGS (7) | `vsil.cjs:29` | | VSIL LAYOUT_TYPES (3) | `vsil.cjs:32` | | `makeVsilBitmap` | `vsil.cjs:37-50` | | `makeVsilRegion` | `vsil.cjs:93-115` | | `makeVsilComponent` | `vsil.cjs:72-90` | | `makeVsilLayout` | `vsil.cjs:117-141` | | `makeVsilStructure` | `vsil.cjs:143-170` | | `makeVsilCapability` | `vsil.cjs:173-184` | | VSIL_VERSION `'vsil-1.0'` | `vsil.cjs:239` | | `makeVsilMemeCaption` (block) | `vsil-meme.cjs:42-72` | | VSIL_MEME_VERSION `'vsil-meme-1.0'` | `vsil-meme.cjs:21` | | `inferScene` (camera+lighting+atmosphere inference) | `vsil-scene.cjs:185-` | | `originRegionToVsil` | `origin-to-vsil.cjs:59` | | `toVsil` (top-level) | `origin-to-vsil.cjs:75-` | | meme templates inline shape (regions[].role) | `meme-templates.cjs:50-100` | | `getMemeLayer` | `vsil-meme.cjs` (function name) | | scene.json (S5) shape | `scene.json:8-78` | | vsil-renderer (PROMPT #16) invented shape | `vsil-renderer.cjs:9` | | server.cjs `/api/agent/cinema/render` (new) | `server.cjs:5267-5288` | | server.cjs `/api/agent/vsil/scene` (image → structure) | `server.cjs:5051-5060` | | server.cjs `/api/agent/origin/to-vsil` | `server.cjs:5063-5070` | | server.cjs `/api/agent/vsil/round-trip` | `server.cjs:5072-5080` | | server.cjs `/api/agent/cinema/create_scene` | `server.cjs:5011-5050` | | agent tool `create_vibescope_scene` | `tools.ts:529-545` | | agent tool `patch_vibescope_scene` | `tools.ts:546-555` | | `MotionPrimitive`, `DnaKeyframe`, `DnaAnimationTrack` | `dna-types.ts:60-167` | | `ComposerNode.kind` enum | `Composer.tsx:27` | | Canvas demo layers | `Canvas.tsx:120-127` | | `LayerEntry` (UI panel state) | `LayersPanel.tsx:30-36` | --- ## §9 — End This audit is the Cycle G output. No code modified. No commits. No VPS edits. The intent is a faithful read of "what's actually in the codebase" so that any future v1.0 ratification can be data-driven rather than opinion-driven. Vibe Agents: **FAILED** (runner returns `None`). Delegation: **0%**.