← all pages

Content engine: the build plan

Content engine + Studio Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Ship an app-resident content engine (blocks + document runtime + logic graph + tiny formulas), an agent-first Studio (headless CLI + Mac UI), a gated publish pipeline (sbapi registry, content.stickbash.com, signed packs, staged rollout) and an exact-match proof set. All new skins, maps, kill films and taunts then ship from our server with no app update.

Build order (the user, 6 Nov: "u build one by one, first map engine, then animation engine, like that"): the engines are built one after another, each finished end to end before the next starts:

  1. Stage 1: the shared core, only what maps need.
  2. Stage 2: the MAP engine.
  3. Stage 3: the ANIMATION (kill film) engine.
  4. Stage 4: the SKIN engine.
  5. Stage 5: the TAUNT / EMOTE engine.
  6. Stage 6: the shared catalogue, Studio polish and launch readiness.

Within an engine, tasks marked [par] can split between two lanes.

Architecture:

Tech Stack:

Spec: docs/superpowers/specs/2026-11-06-content-engine-design.md (APPROVED 6 Nov; all 15 decisions made). Section numbers below (§x) refer to it. Executors read both.

Global Constraints

Review Focus

  1. A phone that is offline or slow at app open. The splash must give up after ~10 s and enter the menu with cached packs. A half-downloaded pack must never register. Pinned packs must survive an LRU sweep. Test: Task C.3 partial_download_never_registers, lru_keeps_pinned; Task C.10 splash_offline_continues.
  2. A joiner whose app is older (ENGINE_SIM differs) or outside the rollout bucket. The room must still form, with engine maps not offered and nobody refused. Test: Task M.8 older_engine_sim_room_plays_builtins, rollout_bucket_outsider_can_fetch_room_pack.
  3. A document that is valid but pathological. Examples: a logic graph at every cap at once, a formula dividing by a signal that is 0, a counter at i16 max that keeps adding. It must run within budget with no exception and give deterministic output. Test: Task C.4 logic_caps_all_at_once, counter_i16_saturates; Task C.5 formula_div_zero_is_zero.
  4. A pack pulled while a room is playing its map, or while players own its items. The match finishes unchanged, dependents cascade, and nothing crashes on the next fetch. Owned items fall back or hide. Test: Task C.9 kill_list_cascades_dependents; Task M.8 pulled_map_finishes_round; Task K.6 pulled_owned_item_falls_back.
  5. The same document on ARM (phones, M1 Mac) and x64 (VM). Replicated state bytes, the gore-independent film hash and Q16.16 formula bits must be identical. Test: Task 2 detspike_cross_arch_digest_equal; Task C.5 fixed_golden_vectors.

Stages, sizes and lanes

Sizes are lane-days of build. "Effective" adds ~15 % for review rounds. Each stage ends with its engine's done definition passing.

Stage What Build (lane-days) Effective Can split into 2 lanes?
1 Shared core for maps the 3 map de-risk spikes, the document model + schema generator, the pack format + hashes + store, the loader / validator / budget meter, the logic graph, the formula set (map slots), seeded streams, the agent CLI (validate / lint / explain / preview / play / gate / diff / publish-to-test), the server registry + content list + kill list + approval, content.stickbash.com, the phone fetcher + splash 36-42 41-48 yes: core (B) / CLI + server (C)
2 MAP engine today's map blocks + the 23 new map blocks + the shared T1 blocks, bots on data maps, protocol 145 + online pack checks + relay, the bundle lane (map sounds), proof maps identical, the map gate, Studio map editing (agent-first, then the visual editor), the map playbook 50-60 58-69 yes: blocks / proof (B) and net / Studio (C)
3 ANIMATION engine the film runtime spike, the film blocks on the page-film engine, the 16 new film blocks, the kill-page → Studio motion import, the 3 gore levels + online film state, protocol 146, the 6 proof films identical, the Studio film timeline, the film playbook 42-52 48-60 yes: runtime + proof films (A) and new blocks / import / Studio (C)
4 SKIN engine the Shapes.shader material / pattern feature, cosmetic blocks, the 8 new skin blocks, premium attachments (film / ammo / sparks / burst / feed), the loadout extension (protocol 147), owned-item pinning + fallback, the 6 proof cosmetics identical, Studio skin editing, the skin playbook 22-27 25-31 yes
5 TAUNT / EMOTE engine performance blocks, the 6 new taunt blocks, the taunt ContentRef (protocol 148), the 4 proof performances identical, Studio taunt editing, the playbook 12-15 14-17 partly
6 Catalogue + polish + launch the shared catalogue (shop / pass / rooms / customize / kill shop / album / CatalogExport / sbapi auto-pick), Studio polish across kinds, the reference-phone pipeline step, store notes + the first submission, drills, the end-to-end agent rehearsal 12-16 14-18 (+ a store-review week) partly
Total 174-212 200-243

Building one engine at a time costs a little more than the old interleaved plan, about +10 %. Each engine gets its own Studio editing and its own end-to-end done pass, and some core work comes back when a later engine first needs it. In return, each engine is usable as soon as it is finished.

Calendar (honest; agents run daily, review latency included)

Engine lanes Map engine done (end of Stage 2) Launch-ready (end of Stage 6)
1 lane ≈ 14-17 weeks ≈ 30-36 weeks (7-8 months)
2 lanes (split inside each engine) ≈ 9-11 weeks ≈ 19-23 weeks (4½-5½ months)
3 lanes ≈ 8-9 weeks ≈ 16-19 weeks (3¾-4½ months)

Lanes inside each stage

Writing the detail. The first 3 tasks are written to full step detail below. Every other task carries its files, interfaces, tests and acceptance. The lane that starts a stage first runs a short writing-plans pass to expand that stage's tasks into numbered steps in the same style. No stage starts without its expanded steps committed to this file.


File map (the game repo, StickBrawl/Assets/_Game/Scripts/)

Path Responsibility
Engine/Core/ Unity-free, no using UnityEngine: Units.cs, Fixed.cs (Q16.16), Doc.cs, Compiler.cs, PackFormat.cs, Logic.cs, Timeline.cs, Formula.cs, Streams.cs (seeded rng, FNV-1a), Validate.cs (errors with JSON paths + hints), Schema.cs (block parameter declarations → JSON Schema), Ed25519.cs (verify only)
Engine/Runtime/ Unity side: PackStore.cs, EngineLoader.cs, BudgetMeter.cs, EngineWriter.cs, RoomTable.cs, ContentFetch.cs (splash + background), later ContentCatalog.cs
Engine/Blocks/Map/, Shared/, later Film/, Cos/, Perf/, Common/ one file per block or small block group; each block is a class with [Block("id")] and typed Param<T> fields
Engine/Map/EngineMap.cs, EngineMapScript.cs map document → ArenaDef + a MapScript subclass driven by blocks and the logic graph
later Engine/Film/EngineFilm.cs film document → PageKill.Def + hooks driving the page-film engine (Stage 3)
Engine/Lab/ (#if !SB_STORE) EngineProbe.cs (per-frame digest), the spikes' labs, Studio*.cs (CLI scenarios + the JSON-RPC server)
Core/Game.cs:~1504 scenario dispatch: add engine:* and studio:* cases beside case "killsys"
repo root tools/ tools/engine/coretest.sh (headless core tests with Unity's Roslyn + NetCoreRuntime, the paths of tools/csc_check.sh:19-32), tools/engine/tests/*.cs, tools/studio.sh, tools/engine/studio_smoke.sh

Server (stickbash-online): server/sbapi/content/ (new), server/sbapi/admin/ + dash/ (approval), server/relay/ (pack-set hash), deploy/stack/content-site.caddy.tmpl (new). Content repo (stickbash-content, new): the layout of spec §6.4.


Stage 1: the shared core, only what maps need

What Stage 1 builds and what it defers

Core part Stage 1 Deferred to
Units + quantisation, document model, compiler, schema generator ✅ none
Pack format, sha256 identity, envelope, Ed25519 verify, pack store, LRU + pinning (pins for "in a room's table" and "current content list") ✅ owned-item pins: Stage 4
Loader, validator (paths + hints), budget meter (sim never dropped) ✅ none
Logic graph (all node kinds), timeline, counters, state machines ✅ none
Formula set: parser, validator, the sim fixed-point evaluator, map inputs (time, alive, score, phase, counters / timers, own anchors' distances, tier), the kill switch ✅ the look evaluator + wearer inputs: Stage 4 (skins); film inputs: Stage 3
Seeded streams + director-compat ✅ none
EngineWriter / EngineReader ✅ (used by Stage 2's snapshot and join) EngineFilmStart: Stage 3
EngineProbe digest (shapes + positions + replicated state) ✅ voices + film joints: Stage 3
Agent CLI: schema validate lint explain fmt preview play gate(map checks) diff pack publish --channel internal|test, serve + hot reload ✅ the film / skin / taunt preview modes and gate checks: their stages
sbapi content: packs, item history, reverse deps, roles, content list, kill list, the minimal approval page ✅ owned-item rules on the dashboard: Stage 4
content.stickbash.com (Caddy template + the human Cloudflare runbook), phone fetcher + splash progress ✅ none
Unity Editor bundle lane ❌ Stage 2 (Task M.9: the first map sounds)
ContentCatalog (shop / pass / customize) ❌ (maps only need the room / vote listing: Stage 2) Stage 6
Gore rules, legacy ladder, film online state ❌ Stage 3
Shapes.shader material feature, loadout extension ❌ Stage 4

Task 1: Map document + loader spike: Backyard rebuilt from a document, identical [par] (Lane B, 4-5 days)

Retires: can a map document reproduce a code-built arena exactly, with the same ArenaDef, the same bot navigation and the same frames (D7)? The map export is lossy (MapExportLab.cs:29), so this proves the exact-geometry path.

Files:

Interfaces:

git add StickBrawl/Assets/_Game/Scripts/Engine StickBrawl/Assets/_Game/Scripts/Core/Game.cs StickBrawl/Assets/_Game/Scripts/Render/ShapeBatch.cs StickBrawl/Assets/_Game/Scripts/Level/Arenas.cs tools/engine/spike_docs/backyard.json
git commit -m "engine spike M1: Backyard from a map document, identical ArenaDef / NavGraph / frames; EngineProbe"

Acceptance: [ENGMAP] PASS at all three tiers, and the results note committed.

Task 2: Logic-graph determinism spike: fixed point, the graph, the float-free writer, across ARM and x64 [par] (Lane B or a second lane, 4-5 days)

Retires: can replicated state and formulas be bit-identical across the Mac (ARM64), the VM (x64) and phones, and can a generic payload replace hand-written Write / Read (spec §5.7, MapWreck.cs:341-352)?

Files:

Interfaces:

Acceptance: coretest green on Mac + VM with equal digests, the phone digest equal, [ENGDET] PASS host + client, and writer_has_no_float green.

Task 3: Agent CLI skeleton: studio.sh serve, validate, preview of a map, < 30 s edit → still [par] (Lane C, 3-4 days)

Retires: can agents iterate on maps without Unity builds (spec §6.5), and do the RPC + capture paths work on Mac, M2 and VM?

Files:

Interfaces:

Acceptance: the smoke test passes on Mac, M2 and VM, edit → still < 30 s on the Mac and M2, and the contract documented.

Stage 1 core tasks (after the spikes)

Task What Files Key tests Tag / lane Size
C.0 Freeze the contracts from the spikes: the document + block-param schema model ([Block], Param<T> with name type unit grid min max default expr inputs), the pack / envelope format, the room table + join fields, the CLI / RPC contract Engine/Core/Schema.cs; stickbash-online/docs/contract/engine-{docs,pack,wire}.md, studio-cli.md schema_roundtrip_tiny_arena, schema_expr_flag_on_every_param, golden byte fixtures committed seq, B + C 3
C.1 Units + quantisation (Units.Parse(string lit, Dim want) -> Q; tick 1/60 s, 1 mm, 1/65536 turn, 1e-4) Engine/Core/Units.cs units_1_2s_is_72t, units_below_one_tick_is_error, units_reject_bare_length, units_mismatch_hint seq, B 1
C.2 Document model + compiler + schema generator (Doc.Parse, Compiler.Compile(Doc, IRefResolver, out errs) -> CompiledDoc, Schema.ToJsonSchema(kind)) Doc.cs, Compiler.cs, Schema.cs compile_is_deterministic_bytes (Mac = VM sha256), compile_strips_studio_block, refs_builtin_and_pinned_deps_only, refs_reject_cycles seq, B 4
C.3 Pack format, sha256 identity, envelope, Ed25519 verify, pack store, LRU + pins PackFormat.cs, Ed25519.cs, Engine/Runtime/PackStore.cs ed25519_rfc8032_vectors, pack_hash_excludes_envelope, tampered_content_rejected, partial_download_never_registers, lru_keeps_pinned, pack_over_5mb_rejected par, B 3
C.4 Timeline + the full logic graph (every node kind of spec §5.5) + state machines Logic.cs, Timeline.cs logic_every_node_truth_table, logic_cycle_without_state_node_is_error, logic_caps_all_at_once, timeline_action_visible_next_tick, counter_i16_saturates par, B 3
C.5 Formula set, map slots: parser (≤ 32 nodes), validator (ops, the slot's allowed inputs, units), the sim Q16.16 evaluator, the map inputs, the kill switch → else Formula.cs formula_33_nodes_rejected, formula_unknown_input_path_pos_hint, formula_div_zero_is_zero, formula_units_checked, formula_kill_switch_uses_else, fixed_golden_vectors (cross-arch digest) par, B 2
C.6 Seeded streams + director-compat (reproduces MapEvents.cs:314's seed and the shared draw order, for proof maps only) Streams.cs, Engine/Runtime/DirectorCompat.cs streams_seed_from_ids_fnv, compat_stream_matches_map_director (lab: 1,000 draws equal on wreck) par, B 1-2
C.7 Loader (off the main thread), the full validator (all errors, path / rule / found / allowed / hint), the budget meter (sim never dropped) EngineLoader.cs, Validate.cs, BudgetMeter.cs validate_reports_all_errors, budget_meter_never_drops_sim, loader_zero_gc_after_warm par, C 3
C.8 Agent CLI complete for maps: schema lint explain fmt play gate(map) diff pack publish --channel internal|test; block reference pages generated with examples Engine/Lab/Studio*.cs, tools/studio.sh the spec §6.2 lint rules (one fixture each), explain_mentions_every_cue, fmt_idempotent, play_same_seed_same_report, play_report_has_all_metrics, diff_params_cost_logic_visual, gate_fails_with_block_name_over_budget, gate_runs_formulas_off_too par, C 6-7
C.9 sbapi content: packs, item history, reverse deps, roles (agent tokens ≤ gated / test; only human accounts approve live), the content list and the only-growing kill list (separate versioned documents), the minimal dashboard approval page server/sbapi/content/, admin/, dash/ go test ./server/sbapi/...: TestAgentTokenCannotGoLive, TestItemHistoryOrder, TestContentRollbackLeavesConfig, TestKillListNeverRollsBack, kill_list_cascades_dependents, TestDashApproveRequiresHuman par, C 6-7
C.10 content.stickbash.com + phone fetch: deploy/stack/content-site.caddy.tmpl (Origin CA; /p/ /e/ /b/ only; Cache-Control: public, max-age=31536000, immutable; else 404) + the runbook for the human Cloudflare steps (proxied DNS record, cache rule: cache everything, edge TTL ≥ 1 month). Agents never change DNS or Cloudflare. ContentFetch handles the splash progress ("Downloading new content… X / Y MB"), the 3 retries over ~10 s and the "new content waiting" note deploy/stack/, Engine/Runtime/ContentFetch.cs, the splash UI caddy validate; after the human steps curl -sI shows cf-cache-status: HIT on a second fetch; splash_offline_continues, splash_progress_text_exact, splash_never_blocks_over_15s par, C 3-4
C.11 Bootstrap stickbash-content. Coordinator step: create the private repo farisbasha/stickbash-content (D15). Then the layout of spec §6.4, the generated schema, templates (one-screen arena, MEDIUM follow map, hazard arena, logic-puzzle arena) and make check the content repo every_template_validates par, C 1

Stage 1 done when coretest is green on Mac + VM + phone, every C task's tests pass, and an agent can publish --channel test a tiny static map pack that a test phone downloads at the splash and plays offline. Online play comes in Stage 2.


Stage 2: the MAP engine, complete

Done definition (the coordinator, 6 Nov): an agent makes a brand-new map from the CLI, previews it, bot-tests it, passes the gates, publishes it to the test phones, and it plays online. In addition, the proof maps Backyard / Belt Line / Wrecking Yard are identical (D7), and the map Studio editing works agent-first, then visual.

Task What Key tests Tag / lane Size
M.1 Static map blocks → ArenaDef: map.frame solid traverse liquid spawns prop (from Task 1's adapter, made real) engine_backyard_arenadef_equal, navgraph_equal_backyard, the same for a lifts / pads / low-g fixture vs Military Base's pieces seq, B 3
M.2 EngineMapScript + map.piece (path / pivot / weight seesaw / breakable / crumble) + map.hazard (pendulum / kill zone / damage / push / magnet) + map.timeline + map.event + the generic payload generic_payload_roundtrip, hazards_off_disables_all, quiet_stretch_holds_cues, pace_calm_skips_chaos_only seq, B 5-6
M.3 map.art map.look map.elements + nav hints for pieces; the 58k JSON by-product elements_export_equals_MapExportLab_for_proof_maps, nav_hint_avoid_ride_wait par, B 3
M.4 New map blocks, group 1: map.zone switch door plate mover rotor (spec §7.2 rows 2-6, 19) per block: <b>_predictable_on_client, <b>_bot_rule_navgraph, <b>_budget par, B or C 4-5
M.5 New map blocks, group 2: map.laser saw crusher spikes dropper spawner (rows 7-12) the above + <b>_warning_at_least_0_6s, <b>_hazards_off par 5-6
M.6 New map blocks, group 3: map.level field belt phase tiles bumper portal (rows 13-18, 20) the above + portal_own_fighter_predicted, tiles_bitmask_snapshot par 5-6
M.7 New map blocks, group 4: map.weather camrule ambience + the shared T1 blocks a map uses (curve rng.stream cond path strings palette.set variance shape.lib) weather_night_lock_respected, variance_seeded par 3-4
M.8 Net, protocol 145: RoomTable, join fields (packSetHash, engineApi, engineSim, formulas), the arena ContentRef in room settings / vote / match start, the generic snapshot block, the relay server change, fetch-before-join with a progress bar, the no-internet Wi-Fi rule, refusal of 144 room_table_same_bytes_all_members, proto144_refused_cleanly, older_engine_sim_room_plays_builtins, rollout_bucket_outsider_can_fetch_room_pack, wifi_no_internet_intersection, pulled_map_finishes_round, go test ./server/relay/... TestJoinPackSetMismatchRefused, net_test.sh engmap 3 all [ENGNET] PASS seq after M.2, C 6-7
M.9 The Unity Editor bundle lane for map sounds (ProjectSetup.BuildContentBundles: iOS / Android / Mac / Linux; Mac / M2 first, then the VM's editor) + the bundle checker bundle_with_monoscript_rejected, bundle_envelope_records_unity_and_formats par, C 3
M.10 Engine maps in the room picker / vote / presets (the map slice of the catalogue; the full catalogue is Stage 6) engine_map_listed_and_votable, hidden_when_engine_sim_differs par, C 1-2
M.11 Proof maps identical, one task per map: Backyard, Belt Line, Wrecking Yard (director-compat stream) engine:proof:map:<id>: per-tick full state + EngineProbe zero diff, 3 rounds × 2 / 4 / 8 bots × CALM / NORMAL / CHAOS × HAZARDS on / off × LOW / MED / HIGH; then host + client online equal par per map, B 6-8
M.12 The map gate complete (spec §5.12 for maps: coverage, look checks, fairness, the reference-phone run step) gate_map_spawn_near_hazard_fails, gate_map_unreachable_spawn_fails, phone run digest equal par, C 2-3
M.13 Studio map editing, visual: the shell + library, the inspector with the expr editor, the logic-graph view with live signals, try-it vs bots (all over the CLI's documents and commands) inspector_edit_writes_same_json_as_fmt, graph_view_roundtrip_no_change, try_it_loads_without_unity_build par, C 6-8
M.14 The map playbook + recipes (door with two plates, a timed hazard cycle, rising lava at two left, a three-target vault, a seeded random event) + the annotated proof maps in examples/proof/ every_recipe_validates, every_recipe_gates_fast par, C 1-2
M.15 The done rehearsal: an agent gets a one-line brief ("a MEDIUM map: two rotating wheels over a rising-water pit, a switch that reverses them"). It follows the playbook to publish --channel test, the test phones download it at the splash, and a 2-phone online room plays it the rehearsal report: CLI transcript, stills, play metrics, gate report, the online [ENGNET] PASS seq (last), all 1-2

Stage 3: the ANIMATION (kill film) engine

Done definition: an agent makes a brand-new film from a kill-page take plus Studio blocks at all three gore levels, previews it, gates it on every fitting arena, publishes it to test phones, and it plays online (host + client hash equal). The 6 proof films are identical.

Task What Key tests Tag / lane Size
F.0 Film runtime spike (formerly Task 1 of the interleaved plan): SIX-SHOOTER from a document + a DRIP hybrid (its slab and drip line as film.prop / film.mark blocks) drive the page-film engine with zero difference; EngineProbe gains voices + film joints [ENGSPIKE] PASS on 18 cases (2 films × 3 gore × 3 tiers) seq (first), A 4-5
F.1 The tag pass of all 155 film scripts' hooks against the block list; GAPs become blocks or "legacy only" (a spec update on this branch) the results table par, A + C 2-3
F.2 film.take (incl. the legacy ladder mode) cast fit cast_gun_class_track_of, fit_refusals_equal_builtin seq, A 3
F.3 film.weaponprop prop mark cut blood soul trackedit posefix order handoff one golden lab scene per block par, A 5-6
F.4 Common film-side blocks: look grade camera clock, the film formula inputs (film time, time since trigger) golden scenes par, A 2-3
F.5 Film online state + EngineFilmStart (protocol 146) film_online_state_gore_independent, legacy_ladder_hash_matches_builtin, engine_film_host_client_hash_equal (net_test) seq, A 3
F.6 The 16 new film blocks (spec §7.3 rows 1-16) in two groups: camera / time (cam.* time.stutter) and fx / sound (fx.* snd.*) per block: golden scene, budget, <b>_never_changes_online_state par, C + A 9-11
F.7 The kill-page → Studio motion import: studio.sh import take <bake dir> wraps tools/killport (pk_pack + pk_pack2) and writes takes/*.bytes + a draft film document at three gore levels import_roundtrip_equals_pk_pack2_verify par, C 2-3
F.8 Proof films identical, one task per film: SIX-SHOOTER, THE X, DRIP, HIGH NOON (every shipping class), COLD-BLOODED, THE OFFERED HAND engine:proof:film:<key>: zero diff × gore 0 / 2 / 5 × LOW / MED / HIGH × home + 3 fitting arenas + the GLOAT hand-off par per film, A 10-14
F.9 The film gate + preview modes (every fitting arena, every level, the look checks of PORT_GATE §4) gate_film_all_arenas_report par, C 2
F.10 The Studio film timeline (tracks per block, scrubber, gore / tier / mirror toggles) timeline_edit_writes_same_json_as_fmt par, C 3-4
F.11 The film playbook + the done rehearsal the rehearsal report seq (last) 1-2

Stage 4: the SKIN engine (+ attachments)

Done definition: an agent makes a brand-new premium weapon skin (look + an attached engine film + ammo + sparks + burst + feed icon) and a new body cosmetic. They gate, publish to test, show in matches, films and previews, travel online in the loadout, and a pulled pack falls back correctly. The 6 proof cosmetics are identical.

Task What Key tests Tag / lane Size
K.1 The Shapes.shader material + pattern feature (app-shipped, precompiled) + mat.layers mat.pattern mat.animate shader_variants_unchanged_count, per-block golden scenes, perf on LOW seq, A 5-6
K.2 cos.item art premium filmrule + the look formula evaluator + wearer inputs (own state only) formula_cosmetic_cannot_read_other_player, premium_attachments_resolve par, A 3-4
K.3 New skin blocks cos.anchors+ react emitter ribbon aura per block + <b>_no_advantage_caps par, C 4-5
K.4 Loadout extension (protocol 147): 192 B cap, ContentRef per engine slot, the drop order, announced cosmetic packs in the room table loadout_worst_case_fits, drop_order_plain_first, friend_outfit_default_until_fetched seq, A 2
K.5 Proof cosmetics identical: ICE revolver (with COLD-BLOODED as its film), PLAIN skin, HOODIE, CROWN, FIRE aura, RAINBOW trail engine:proof:cos:<id>: zero diff idle / run / jump / a film / a preview card × tiers par per item, A 5-6
K.6 Owned-item rules: pin current + previous live, the fallback, hide-and-return, the dashboard's owned view pulled_owned_item_falls_back, lru_keeps_owned, engine_item_owned_survives_revision, old_save_loads_unchanged par, C 2
K.7 Studio skin editing + the skin playbook + the done rehearsal the rehearsal report seq (last) 2-3

Stage 5: the TAUNT / EMOTE engine

Done definition: an agent makes a brand-new taunt with a prop and a gloat variant, and a new emote. They gate, publish to test and play online for everyone in the room. The 4 proof performances are identical.

Task What Key tests Tag / lane Size
T.1 perf.pose face words prop clip gloat kind perf_track_equals_TauntRig_build (LOSER's keys = TauntDefs.cs's) seq, A 3
T.2 New taunt blocks perf.blend layer toss fx aim sting per block par, C 3-4
T.3 The taunt ContentRef in Ev.Taunt (protocol 148) engine_taunt_plays_on_every_client seq, A 1
T.4 Proof performances identical: LOSER (with the lasting L), CHAI BREAK, DAB, BHANGRA engine:proof:perf:<id> zero diff par per item, A 3-4
T.5 Studio taunt editing + the playbook + the done rehearsal the rehearsal report seq (last) 2-3

Stage 6: the shared catalogue, Studio polish, launch readiness

Task What Key tests Tag / lane Size
X.1 ContentCatalog + built-in adapters across shop / pass / customize / kill shop / album / previews; CatalogExport with engine; sbapi season auto-pick by ENGINE_API + live-on-platform catalog_lists_builtins_unchanged (same ids, order and prices as today's CatalogExport.Json()), TestAutopickSkipsUnplayableEngineItems seq, A 5-6
X.2 Studio polish across kinds (one library, cross-kind search, consistent inspectors, error panels) studio_ui_opens_every_proof_doc par, C 3-4
X.3 Hardening: the reference-phone run as a step for every pack (iOS + a LOW-tier Android the coordinator names); drills: rollback, kill-list cascade, formulas: off, a bad-signature pack, the CDN origin down the drill reports par, all 2-3
X.4 Store: review notes (spec §5.15, §5.5a) and the first submission with the engine and only built-in content live; budget one resubmission week approved builds seq, coordinator 1 + the review wait
X.5 The launch rehearsal: one agent per kind from a one-line brief to test, and a person approves one item to live at 10 % spec §11 items 1-6 green seq (last) 1-2

Self-review (done)