# Astra KORGI — working technical contract (rev 2) Helios (Cursor on Icarus), 12 September 2026. Advisor acceptance of rev 1 stands: extend the existing registry/journal, keep both independent creator paths, do not presume FFmpeg, do not introduce generated-footage authoring. **This is a working technical contract, not a runtime sign-off.** The next proof is Packet 0’s map, the bounded evaluator decision, and Packet A’s reproducible evidence — not another consolidated plan. Packet 0 first-cut (static inspection at `f9beb591`) lives in [`PACKET0_MAP.md`](PACKET0_MAP.md). Evaluator decision: [`EVALUATOR_DECISION.md`](EVALUATOR_DECISION.md). Packet A receipt: [`PACKET_A_RECEIPT.md`](PACKET_A_RECEIPT.md). ## Identity (keep source and deploy separate) | Item | Value | Status | |---|---|---| | Source commit | `f9beb5910dc8123ffcf797de6c6ad9e18cdd2274` (tag `korgi/railway-studio`) | recorded | | Live studio | https://korgi-production.up.railway.app | visible UI only | | Railway project / service / env | `korgi` `c6588640-db83-4bf5-9aaa-834644c78400` / `da16edb6-4a72-4516-ab38-b75715a2277c` / production `05acf70e-a35d-465a-97ef-610b9bac5dbf` | recorded | | Last SUCCESS deploy | `9298f5e8-2c43-444e-adee-4c5c86617cef` (2026-09-11T18:24:28Z) | recorded | | Deployed git SHA on the live page | none | **unproven** that production matches `f9beb591` | The live page shows 24-frame/12-fps state, Draw/Animate, repeated A1 exposures, Save/Open, and explicit migration. That is the visible interface. It does **not** prove drawing, persistence, MCP binding, or export. The four defects below remain **Helios static-inspection findings at `f9beb591`**, not tests the advisor independently executed. 1. `handleMcpRequest` calls `callRegistryTool` and returns `_meta.mutated` but never assigns `session.project` / `session.journal`. 2. Stdio uses `Content-Length` framing; `initialize` advertises protocol `2024-11-05`; the sidecar defaults to `defaultProject()` with studio `*`. 3. `ingestInto` stores `scanRaster` metadata (`width/height/channels/mime/sourceId`) and empty cel planes; pixel `data` is not written there. 4. `muxWebm` writes one video track, one cluster with Timestamp 0, and clamps SimpleBlock timestamps with `Math.min(32767, ms)`. `satsuei-delivery` refuses `mp4`/`gif`/`webm` (`E_BAD_CONTAINER`). Audio-in-movie is **not implemented**. ## Spine (unchanged) One KORGI. Two complete paths on the existing project/command core: - **Mitchell solo:** generate visuals, place as cels, time against music, revise in language, export — without drawing and without an artist. - **Artist solo:** originate cels from blank on the drawing desk, time them, export — without Mitchell or a generator. - **Together (later):** same editable shot. Optional. If one person leaves, the other can finish. Generated artwork is not “generate the whole movie.” Video out, cels in. Conceptual content model (Project → Sequence → Shot → Tracks → Cels → Exposures → Takes → Cues) is a **mapping requirement**. It is not permission to replace the existing schema. **Neither solo path passes by borrowing the other person’s missing capability.** ## 1. Packet 0, then narrow Packet A ### Packet 0 For each required capability return: ```text Capability → existing registry action → state owner → persistence path → evaluator → evidence/status ``` First cut: [`PACKET0_MAP.md`](PACKET0_MAP.md). Dual-sheet acceptance blocker and the chosen single evaluation route: [`EVALUATOR_DECISION.md`](EVALUATOR_DECISION.md). That decision does not block Packet A. ### Packet A — one authoritative project Session write-back is a useful regression fix. It is **not** permission to keep two production projects (MCP vs Studio) and synchronize them. - Authoritative Project Host / binding: required; at `f9beb591` it was **not implemented**. - Independently mutable MCP and Studio production copies: **prohibited architecture**. Require this trace through the **intended client** (Cursor on Icarus; record actual client version and a successful protocol exchange): ```text Open project X → user-approved binding to X → inspect revision → change name (`korgi.settings.setName`) → change follow-drawing-peg (`korgi.peg.setFollow`) → read both changes → observe both in Studio → save → restart and reopen X → verify both changes remain ``` Also test: unauthorized mutation; stale expected revision; project switch invalidating the old binding; repeated operation ID without a second mutation; proposal-only and refused calls leaving production content unchanged. The Project Host validates binding and grant against trusted state. A model-supplied `studio *` must never create authority. `korgi.peg.setFollow` is the second action because its implementation only writes `followDrawingPeg`. `korgi.film.setClock` with `{loop}` always remaps `exposureColumns` via `fitLength`/`compactRuns` even when length is unchanged — it is not a harmless setting. Minting (`korgi.draw.mintDrawing`) and production holds (`korgi.film.editCelHold`) stay STUDIO_ONLY. Later language/generation workflows depend on that restriction: a future operator must receive deliberately authorized access, not impersonate Studio or bypass the existing refuse list. #### Protocol clarification (attached) Standard MCP stdio is newline-delimited JSON-RPC. Protocol messages — not diagnostic logging — belong on `stdout`. The framing correction is justified. ([MCP stdio, 2026-07-28](https://modelcontextprotocol.io/specification/2026-07-28/basic/transports/stdio)) Do **not** merely replace the advertised version string. The July 28, 2026 specification makes requests stateless and removes protocol-level sessions. ([MCP changelog](https://modelcontextprotocol.io/specification/2026-07-28/changelog)) Test the actual Cursor client and implement **its** supported lifecycle. Keep KORGI’s project binding and durable state independent of that lifecycle. Packet A is not a wholesale protocol upgrade. ## 2. Packet B proves pixels Keep the reuse fixture: ```text A1×2 A2×2 A1×2 A3×2 blank×2 ``` Receipt must show: ingested pixels in drawing/composition views and rendered frames; only the second A1 exposure run unique and edited; first A1 use unchanged; explicit blanks preserved; second level and camera move restored after **clean** reopen (no original-tab memory, no cached object URLs); undo/redo preserving those distinctions. Staged ingest: inject failures before and after byte storage. An incomplete ingest must not earn “Saved,” and must not damage the previously committed revision. ## 3. C and D stay independent — and equally necessary After native cels can be stored, displayed, exposed, and reopened, C and D may advance in parallel. **C — “generated inside KORGI” means all of:** requested through KORGI; tracked as a durable KORGI job; returned through validated asset ingestion; reviewed and accepted in the project; available after reopen without repeating generation. The provider may run elsewhere. The creator must not need a hidden download/import/cleanup procedure. For an Icarus-local provider, name and test the authenticated connection between the durable job system and that provider. Do not leave that connection implicit. No PixelLab spend. **D —** the artist originates the shot from blank using the drawing desk. Generation remains optional. Artist cleanup must not become Mitchell’s fallback. ## 4. Export acceptance Image sequence + WAV + sync sheet is an **intermediate engineering receipt**. It does not satisfy the promised exported movie with sound. WebM can carry video and audio tracks; whether KORGI can produce that delivery remains an implementation gate. ([WebM container](https://www.webmproject.org/docs/container/)) Do not interpret “lift the timestamp clamp” as “remove a `min()` and write larger values into the same field.” Matroska Block/SimpleBlock timestamps are signed 16-bit values **relative to their cluster timestamp**. ([Matroska notes](https://www.matroska.org/technical/notes.html)) Inspect `muxWebm` in `src/lib/stage-render-movie.ts` and implement valid cluster-relative timing. Today that muxer writes a single cluster at Timestamp 0 and no audio track. Require both: 1. The selected 10-second take exported with the intended audio synchronization. 2. A cheap synthetic export crossing the reported 32.767-second failure point. This does **not** require a longer generated production scene. Hero shot: explicitly **240 frames at 24 fps**. New Project stays `24@12`. Do not silently migrate existing projects. `migrateLegacyLoop` remains an explicit Film action. ## 5. Working defaults | Decision | Direction | |---|---| | First MCP client | Cursor on Icarus; record the actual client version and successful protocol exchange. | | First shot | Doorway/hesitation, unless Mitchell explicitly substitutes Wax Catch. | | First provider | One existing-shop provider that passes the integrated job-to-pixels test. No PixelLab spend. | | First movie route | Investigate the existing WebM path early. If unsuitable, return a bounded encoder decision for Mitchell; do not introduce FFmpeg by assumption. | Keep Drive-only git (`gdrive`, no GitHub `origin`) and owner-assisted phone restrictions. ## Receipt labels Every later claim is **unproven**, **failed**, **not implemented**, or **passing** — never “looks like it works.” **Policy is not a receipt label.** Silent migration and PixelLab spend are **prohibited** / **restricted**. Do not record them as missing features. ## Packet A handback See [`PACKET_A_RECEIPT.md`](PACKET_A_RECEIPT.md). In-process Project Host + two actions + negative tests are **passing**. Live Cursor Settings enrollment and live Studio boot attach remain **unproven** / **not implemented**. Next work is Packet B pixels, not another consolidated plan.