This pack gates Phases 2–5, so the parts a build has to honour are written down here rather than inferred from a mock. Six things are contract: the route map, the responsive states, the clearance boundary, the persona IDs, the member lifecycle, and the portrait recipe — the last two added by Khoa's scale ruling, which replaced the five-card room with an information architecture for 100+.
"Jimmy" instead of
fan.verite-hand.v1, the rename becomes a migration./create/unit, not /create/crew-room and no longer
/create/warroom. A route is an identifier, so it carries the most durable locked
token. Unit is the load-bearing word of the design lock; crew room is display
flavour that can still move at the Bindi gate, and amending the map to follow it would churn the
contract twice. So the address bar says /unit while the heading says
“crew room” — exactly the rule §4 already applies to persona IDs, which is
why it needed no new argument. Renamed once. Scope-checked as product-local: no external
deep-link contract references it (Keystack covers /film/* only) and we are
pre-launch, so no redirects are owed./create/unit, /create/:runId/plan, /my-work and
/admin/bench, none of which are routes, and it invented six query parameters no code
reads. It also missed /studio entirely — which is where Create actually lives.
Everything below is now split into what EXISTS and what we are ADDING, so the next
ratification is against reality rather than against prose. Evidence column says how each row was
established: walked means I signed in to staging and clicked it; source means read
at f5ce242, the commit staging serves.The top-level IA is two modes, on an icon rail: Analyze — real films → measured grammar — and Create — grammar → generated films. Every route below sits in one of them.
| Route | Mode | Surface | Real params | Evidence |
|---|---|---|---|---|
/ | Analyze | Library home — measured titles, two ways in | ?filmId= legacy, redirects to the path form | walked |
/film/:filmId | Analyze | The measured spine — 01 Identity · 02 Shot grammar · 03 Rhythm · 04 Dialogue · 05 Evidence · 06 Use as a style, with a persistent Instrument Readout | ?tab= | walked |
/film/:filmId/cuts/:assetId | Analyze | Re-cut editor | ?draft= | source |
/studio | Create | Create workspace — Projects · Cuts · Media | ?contentType=director (the “Directors” nav item) ·
?filmId= legacy | walked |
/studio/:filmId | Create | Create for one film | — | source |
/demo-access | — | Demo gate | ?next= |
walked |
/sign-in · /sign-up · /forgot-password |
— | Auth set | ?next= | walked |
/settings/account | — | Account | — | source |
/api/auth/[...all] · /api/auth/enforcement | — | Auth handlers — enforcement is a capability with no surface | — | source |
/api/demo-access · /api/video | — | Gate and video handlers | ?url= · ?t= | source |
The complete set of query parameters any code reads:
tab · draft · filmId · t ·
next · draftTrailer · contentType ·
url. There are no others.
Two additions only, and both sit inside the existing two-mode IA rather than beside it. The earlier map failed because it proposed a parallel hierarchy; this one extends what is there.
| Route | Mode | What it adds | Why here |
|---|---|---|---|
/studio/unit | Create | The crew room — your fourth unit, search-primary at 100+ members | Studio already carries Projects · Cuts · Media. The unit is a fourth tab in a rack
that exists, not a new hierarchy. This replaces the invented
/create/unit. |
?fan=fan.*.v1 | Create | Deep link opening one member’s dossier | The only parameter we add. It follows the shape of the real ones and it never carries a search key. |
| Was mapped | Verdict | What is true instead |
|---|---|---|
/create/* (unit, conditioning, plan, keyframes, render, cuts) |
retire | Create lives at /studio. The stages are states of one Studio
run, not six routes. |
/my-work · /my-work/:filmId | retire | / is the library. There is no second one. |
/admin/bench | retire | Admin is a clearance on existing surfaces, per §3 — not a route. |
?scene= ?shot= ?school= ?pace=
?era= | retire | No code reads any of them. Roster facets are UI state until someone asks for shareable filtered views. |
Three, per my own OwnerMind pattern, and the same breakpoints the Instrument already uses.
| Width | Funnel | Stage | Unit drawer |
|---|---|---|---|
| Desktop ≥1200px | 246px, persistent | fluid | 400px, collapsible to 0 — the toggle says Show unit when hidden |
| Tablet <1200px | hidden | full width | hidden; reachable from the stage header |
| Phone <900px | hidden | full width | overlay, never a squeezed third column — fixed inset, own scroll, sticky header so the way out is always visible |
The rule underneath: a pane is never narrowed below the width its content needs. When there is not room it becomes an overlay or it goes away and says how to get it back. A 400px drawer squeezed to 180px is worse than no drawer.
The same crew room, two audiences. The user face is the cinematic one; admin is the workshop that runs the unit. Nothing in the user face is a subset of a corpus view — the corpus is not rendered to users at all, which is what makes the provenance private.
Display names are a skin. These IDs are what everything downstream stores.
| Internal ID | Display name | Specialty tag | Coverage | Lifecycle stage — derived |
|---|---|---|---|---|
fan.verite-hand.v1 | Jimmy | handheld verité | 55 sc / 299 sh | 4 — verified · bio: Greengrass |
fan.slow-bloom.v1 | Mei | saturated interior | 41 sc / 186 sh | 4 — verified · bio: Wong Kar-wai |
fan.held-breath.v1 | Dara | long-lens compression | 38 sc / 241 sh | 3 — bio published · Bigelow |
fan.long-room.v1 | Vera | static deep-focus master | 29 sc / 97 sh | 1 — in measurement · under the recipe floor |
fan.cut-reflex.v1 | Otis | kinetic montage | 47 sc / 512 sh | 2 — measured · not attributed |
Every member passes through four stages: in measurement measured bio published verified. What makes this a contract item rather than a styling one is that the stage is computed, never stored.
stageOf(member) reads
coverage against the recipe floor, whether a bio has been generated, and whether a human has
verified it — in that order. A stored stage is a field that can drift out of agreement
with the numbers printed next to it, and at a hundred members nobody notices when it does. A
derived one cannot lie. If a build adds a stage column for query convenience it
must be a materialised view of the same function, never a writable field.At 100+ members portraits stop being artworks and become the output of a template driven by each grammar’s own measured visual parameters. The full spec, the five reference outputs and a live renderer are on the portrait recipe page; three things from it are contract:
(fingerprint, id) and is never re-rendered under a finished film. A re-measured
member is .v2 and gets a new portrait by construction — the same rule as
§4, now load-bearing twice.Three of the five parameters — colour statistics, contrast and key angle, source aspect — are not in the fingerprint index today. All three are cheap frame statistics on a pass that already walks every frame. Named here because a recipe that silently depends on fields nobody produces is a drawing, not a spec.
The .v1 is load-bearing. A member re-measured on more
titles is a new id, not an edited one — otherwise a lineage sibling cut months ago
silently claims a grammar it was never cut against. Renaming is a skin change; re-measuring is
a new version.
Khoa-directed, and it changes framing rather than layout. The same fan conversation continues from a terminal over MCP, so the panel must not read as a chat that begins when it opens:
proposals →
accept 2 is as natural in a terminal as in the panel.Design only. No build authorised by this page; the route map is a design position on URL shape, not a routing decision. QA risk tier: T3. Measurements illustrative; the contract items are not.