# Astra design — locked plan (Helios / Mitchell) **Actor:** Helios (Cursor on Icarus, `centaur-macmini-1`) **Composer:** Mitchell Burns **Date:** 2026-09-13 **Status:** design locked. Engineering retained. **Not a finished creator product. Not a release.** Astra reviewed the prior handback. **Keep the packet work.** Do not treat that handback as a shippable Studio. The next build **connects existing pieces** into a signed-in authoring instrument. It does not add disconnected image-generation demonstrations. This file is the plan. [`ASTRA_INTERFACE_CONTRACT.md`](ASTRA_INTERFACE_CONTRACT.md) is the W1/W2 interface Helios owns. [`ASTRA_WORK_ORDERS.md`](ASTRA_WORK_ORDERS.md) is dispatch. [`ASTRA_BRIEF_WEB_AGENT.md`](ASTRA_BRIEF_WEB_AGENT.md) remains the historical composer brief; it does not reopen this verdict. Do not land `main`. Do not Railway-redeploy KORGI. Do not `git push origin`. Do not overwrite `gdrive:Korgi/korgi.main.zip` or `korgi.git.tgz`. PixelLab **$0**. Paid Higgsfield/OpenAI demonstration runs stay frozen. --- ## Verdict (do not reopen) | Decision | Locked | |---|---| | Engineering packets A/B/C/D/F | **Retain** as receipts. They are not product acceptance. | | Prior handback as creator product | **Rejected.** | | Release | **Not authorized.** | | Next build | Connect host, identity, grants, desk, operator, audio, and export into **one signed-in instrument**. | | Paid stills (Higgsfield dest A2, OpenAI live PNG) | Composer **REJECT**: horrible / not acetate / not production cel. Auto-accept is not approval. | | 10s / 34s mux | Engineering probe only. | | New Project | **24@12**. No silent `migrateLegacyLoop`. | | FFmpeg | Not assumed. Not a product dependency. | --- ## 1. One logical writer Hosted **Project Host** owns committed project state. The browser is a **view** plus **named transient** interaction state. MCP, CLI, the in-app operator, and the human on the desk **submit to the same authority**. Every mutating command carries: - an **operation ID** (idempotent) - an **expected revision** - an authenticated **binding** - a **destination** (project / shot / cel / layer) when the action writes picture, audio, or timing A JavaScript module singleton is **not** cross-device persistence. Measured in this tree: `getAuthoritativeHost()` in `src/lib/korgi/host/authoritative-host.server.ts` keeps one `ProjectHost` in process memory. `ProjectHost.pack()` / `openPacked()` persist **project + journal** only. Bindings live in a `Map` and are invalidated on `replaceProject`. Browser IndexedDB/OPFS (`src/lib/project-persist.ts`) is a **local snapshot**, not a hosted document. Zustand `persist` is tab-local. None of those are the product host. Two writers (MCP session copy vs Studio store copy) remain a **prohibited architecture**. Packet A’s in-process attach is the direction: `useStudio.attachProjectHost(getAuthoritativeHost())`. Cross-process and cross-device still have to serialize through the host, not through a second production document. --- ## 2. Equal capability via user-delegated action grants Equal access is **not** “everyone gets `studio *`.” It is: Mitchell+agent, art-team, and art-team+agent reach the **same creative capabilities** through **human controls and agent tools**, using **user-minted grants**. A model-supplied `studio` permission with capabilities `*` and scopes `*` **must never create authority**. Measured: `ProjectHost.mintBinding` throws `model-supplied studio * must never create authority` when `origin !== "studio"`. Packet A’s allowlist (`korgi.settings.setName`, `korgi.peg.setFollow`) is a **bind test**, not the production agent. Measured: `listActions()` is **56 named `korgi.*` + 13 `korgi.command.*` = 69**. HTTP `tools/list` (`mcp/server.ts`) returns the **full** catalog. Host execute refuses ids not in `grant.actions`. **69 listed / 2 granted** is a fake catalog. Production must **advertise only authorized actions**. `STUDIO_ONLY` on mint, ingest, holds, generation, and `importWav` is a **current restriction**, not the equal-access design. Production grants are **user-delegated** subsets of the registry, with confirmation policy honored, not transport-based vetoes (“MCP cannot draw”). Interfaces may look different; authoring capability must not. Same quality bar for you+agent / art-team / art-team+agent. There is no lower bar for “made solo with an agent.” --- ## 3. Real KORGI identity Finish **Better Auth**. Fail closed in production. A visitor is not `dev-user`. Measured: | Item | Tree | |---|---| | Package | `better-auth` ~1.6.30 | | Shipped default | `.grok/app-env.json` `VITE_AUTH_ENABLED: "false"` | | Email/password | `emailAndPasswordEnabled = false` | | No database + auth off | `requireUserId()` returns `DEV_USER_ID` `"dev-user"` | | `DATABASE_URL` set + auth off | throw (fail closed) — keep this | | Sign-in path | `SIGN_IN_PATH = "/login"` in `gates.tsx` | | Routes | `/` and `/workspace` both render ``. **No `src/routes/login`.** | Login mints **identity** for anywhere-access and for **user-minted host bindings**. It is not the Grok preview broker. Production with a real database and auth disabled must keep failing closed. Silent `dev-user` on a shared database is prohibited. --- ## 4. Canvas-first desktop / phone layout (target — not this freeze) Do **not** implement UI in W0. Target: the **drawing / composition canvas is the primary surface** on laptop and phone. Chrome (project bar, timing, generate, operator transcript, menus) is secondary and must not steal the paper. Phone already has `PhoneShell` tabs (animate / draw / mesh / stage / render / film / room). Desktop `Studio.tsx` is a denser chrome around `Stage` + `DrawPad` / `StudioGenerateBar`. The product layout should feel like one instrument with a paper, not a dashboard of disconnected tools. Operator conversation is a **dock**, not a second app. Human accept and spend confirm stay visible before dest write. --- ## 5. OpenAI Responses operator; image shops remain shops **ChatGPT-first** means a signed-in in-app operator that tool-calls `korgi.*` on the open project (OpenAI **Responses** tool-calling), with spend authorization and human accept. It does **not** mean swapping Higgsfield for `gpt-image-1`. Measured: `openai.images` is `POST /v1/images/generations` model `gpt-image-1`. `src/lib/korgi/copilot.ts` is a heuristic propose-only stub (no keys, never mutates). There is no Responses / Agents loop in the web app. ChatGPT Plus / workspace subscription is **not** API billing. Shop cost stays on shop credentials. Operator tokens stay on operator credentials. Do not conflate them. MCP stdio/HTTP and CLI **remain** for Cursor/Helios and scripts. Same registry. Not a second product. --- ## 6. keep / guide / correct as document semantics Marks are **project document**, not sidecar PNGs and not chat metaphors. | Mark | Meaning | |---|---| | **Keep this artwork** | Finished. Must remain unchanged. | | **Use this as a guide** | Interpret pose / shape / composition; replace the rough guide with finished artwork. | | **Correct this region** | Change the designated area; protect the surrounding work. | Implementation language: **masks, coordinates, validators** on the destination cel/layer. Preview is the **destination compositor** (the same evaluator / column composite the shot already uses), not a shop thumbnail. The agent must draw or edit the dest cel in the open project. Reverse handoff: agent starts, human develops, agent continues. Neither direction rebuilds the project. Measured: Generate bar is Request / Run / Prepare / Accept. No Reject in that bar. No region-intent overlay. keep/guide/correct **are not implemented**. --- ## 7. Three decisions; generation lifecycle Three distinct human decisions: 1. **Spend authorize** — money / shop quota may be used. 2. **Candidate approve** — the returned picture is acceptable as a candidate (not yet production). 3. **Apply** — write to revision + destination (cel/layer/shot). Lifecycle: ``` Draft → Spend authorized → Running → Candidate ready → Rejected → Human approved → Applied ``` Script auto-accept is **not** creator approval. Packet C paid live set `autoAccepted: true`, `creatorApproved: false`, then wrote dest A2. That path is retained as plumbing and **rejected as product**. --- ## 8. Audio General import action (keep `korgi.film.importWav` **compatible**; do not invent a parallel silent path). Required matrix: | Container | Encoding / depth | |---|---| | WAV | PCM 16 / 24 / 32-float | | AIFF | PCM 16 / 24 / 32-float | | FLAC | lossless | | `.m4a` | ALAC **and** AAC (different encodings; both required) | | MP3 | CBR and VBR | Keep **original bytes**. Decode for playback inside KORGI. No outside-KORGI conversion as the product path (no “bounce in Finder / FFmpeg then import WAV” as the supported Logic workflow). Remix must **not silently slide picture**. Picture edits stay put when the mix is replaced. Measured: `parseWav` accepts **little-endian RIFF/WAVE at 48 kHz only** (`SAMPLE_RATE_HZ = 48000`), PCM16 / packed PCM24 / IEEE float32. TimingSheet `accept="audio/wav,.wav"`. Action is `STUDIO_ONLY`. That is not the Logic import path. KORGI does not replace Logic Pro. --- ## 9. Sequencing Shot placements use the **existing project model**. `celColumns` govern production exposures. The evaluator decision **stands**: do **not** sync the production sheet into `takes`. Dual-write is prohibited. Silent `migrateLegacyLoop` is prohibited. New Project stays **24@12**. Musical timebase: picture follows the **audio clock** on playback. Timing desk already has a 48 kHz sample window; full-song placement is shot arrangement on that clock, not a second secret timeline. `MAX_SHOOTING_LEN` (14400 frames) is a clock cap, not a finished music-video walk. --- ## 10. Export First movie target: **valid WebM VP9 / Opus**. Measured today: `muxWebmAv` writes clustered SimpleBlocks + **Matroska `A_PCM/INT/LIT`** at 48 kHz. Cluster timestamp overflow at 32.767s is **fixed** (new cluster before signed-int16 relative timecode overflows). 10s and 34s Node tests exist. WebM-strict players may ignore PCM. Studio GUI “Export movie” remains WebCodecs **video-only** when the browser has no audio path. PCM mux may remain as a correctly **labeled Matroska** engineering probe. Do not call PCM-in-WebM-file a WebM product. Durable export is a **job** (request → running → artifact), not a one-shot tab download that vanishes. Tests: 10s, 34s, **full-song**. Preserve the cluster timestamp fix. No assumed FFmpeg. No ProRes claim. --- ## 11. Destination render needs its own quality gate Packet C prepare-at-shot-size is plumbing. The **accepted-frame2** still (`higgsfield-live-accepted-frame2.png`, sha256 `128f129bea116c45c85636518942db3f26b16ba3ec7888b731252c8a1f7e726a`, 1280×720, 100472 bytes) is posterized with a black region. That is a **destination compositor / apply** defect, not “the shop returned a small PNG.” W2+ must gate destination render on its own: accepted pixels on the dest cel must match the approved candidate at the declared shot size, without a silent squash, posterize, or dropped channel. Do not treat dest A2 as approved art while this gate is open. --- ## 12. Wax Catch / Night Stamp Wax Catch boards and Night Stamp dumps are **review / archive** surfaces. They are **not** completed movies and not product acceptance. --- ## 13. Four acceptances (product, not packet tests) 1. **Technical integrity** — host, grants, identity, pack/reopen, evaluator, audio bytes, export container. Receipts, not vibes. 2. **Creative parity** — you+agent, art-team, art-team+agent can perform the same authoring. Not separate SKUs. 3. **Hybrid artwork quality** — keep/guide/correct on dest cels reaches the same acetate / production-cel bar Mitchell already used to reject dest A2. 4. **Mitchell’s full-song solo MV** — import Logic soundtrack, author shots across the **full song**, export picture **and** sound, without art-team cleanup or developer intervention. Passing Packet A–F unit tests does not satisfy these. --- ## 14. What the tree is (measured, not wished) | Piece | Status | |---|---| | `ProjectHost` + expected revision + operation ID + Packet A two-action grant | passing in-process (`packet-a.test.ts`) | | Live Cursor Settings bind → Studio same object | **unproven** | | HTTP MCP `tools/list` + `tools/call` on Vite Node host | passing; catalog is the full registry | | Evaluator `celColumns` vs dump `takes` | decision recorded; Packet B readers passing as unit/host | | Pixel ingest / pack / reopen (Packet B) | passing local writer/host; browser close/reopen remainder | | Generation job / prepare / accept plumbing (Packet C) | passing as plumbing; **artwork rejected** | | Artist-from-blank fixture (Packet D) | passing fixture; **not** pointer recording; **not** artist-complete | | Clustered PCM mux 10s/34s (Packet F) | passing Node proof; GUI video-only | | Production Railway | SUCCESS `9298f5e8` = `gdrive/main` `f9beb591`. **Not** this branch. | | `gdrive/main` | `f9beb5910dc8123ffcf797de6c6ad9e18cdd2274` — **not fast-forwarded** | --- ## 15. Non-claims (this freeze does not make these true) Not green. Not released. Destination-render quality gate open. Cursor live bind unproven. Pointer-input unproven. In-app ChatGPT operator not implemented. Customer login not the shipped Studio. JS singleton is not cross-device. Fake catalog (69 / 2) remains. Audio ingest is WAV 48 kHz RIFF only. keep/guide/correct not implemented. Valid WebM VP9/Opus not implemented. Full-song solo MV is not the 10s mux test. Production Railway is not `cursor/astra-gates-0101`. Wax Catch / Night Stamp are not completed movies. Paid demonstration runs stay frozen. --- Helios, Icarus, 2026-09-13. This document locks Astra’s design as Mitchell’s plan. It does not implement it.