The Vesper Bell backlog

What's being built, what's next, and what's done. Every item links back to a bead in the repository's tracker.

Generated from .beads/issues.jsonl at commit 774abda and open and merged pull requests on GitHub.

E00Project FoundationA trustworthy engineering foundation: every change lands through a green, coverage-gated, security-scanned PR; the sim core is deterministic and replayable; content is schema-validated; a greybox testbed boots in the chosen engine; and a public backlog.html always shows what is done and what is next.37/39 done · 95%

M0 Foundation 2

  • mw-e00.33Find and fix unit tests that fail under heavy CPU loadopenP2M0bug

    Description

    Why

    During parallel agent work on 2026-10-03, pnpm test failed 1–2 tests intermittently at load average 11–33 (seen on the mw-e11.7 rebase and the mw-e11.9 branch), then passed on rerun. CI has stayed green, but a load-sensitive test will eventually flake in CI too.

    What

    Reproduce with CPU stress (e.g. run vitest with high --pool concurrency alongside a busy loop, or --repeat), identify the tests (likely wall-clock or timing-budget assertions outside tests/bench), and make them deterministic. No retries.

    Acceptance criteria

    AC-1 unit The full unit suite passes 5 consecutive runs under a documented CPU-stress reproduction.

    AC-2 unit The tests found are fixed to not depend on wall-clock timing (or moved into tests/bench).

    area:infraarea:qaepic:e00milestone:m0
  • mw-e00.30Remove finished spike prototypes from main once their runtimes landopenP3M0chore

    Description

    Why

    Spike prototypes sit outside every quality gate on purpose (spikes/README.md). Left on main they rot, confuse search results and invite imports into game code. Depth before breadth applies to the repo too: one maintained implementation beats two.

    What

    As a developer, I want finished spikes moved off main so that the only AI and engine code I find is the maintained code in src/. Tag the current spikes on an archive ref (archive/spikes-2026), delete spikes/engine-*, spikes/determinism, spikes/bench, spikes/shared (ADR-0001, mw-e00.13) and spikes/ai-architecture (ADR-0005, mw-e11.1) from main, and update the ADRs' evidence links to point at the archive ref so the evidence stays reproducible.

    Scope

    • In: Archive tag/branch, deletion, ADR link updates, the spikes ignore entries in eslint.config.js and .prettierignore (keep them if spikes/ stays as the home for future spikes)
    • Out: Future spikes (they follow the same pattern and get their own removal)

    Notes

    Do it after mw-e11.2 has its own tests for the patrol → investigate → return scenario, so the spike is no longer the only executable evidence for ADR-0005.

    Acceptance criteria

    • AC-1 manual Given the archive ref, when checked out, then the ADR-0001 and ADR-0005 spike commands in each spike README still run.
    • AC-2 unit Given main after the change, when git ls-files spikes/ runs, then it lists only spikes/README.md (or nothing).
    • AC-3 manual Given ADR-0001 and ADR-0005, when their evidence links are followed, then every link resolves on the archive ref.
    • AC-4 unit Given main after the change, when pnpm lint, typecheck, test:coverage and build run, then they pass with no coverage change.

    Waits on

    • mw-e11.2 Implement the deterministic behaviour runtime chosen by the ADR done
    area:infraepic:e00milestone:m0milestone:m1
E01Playable Vertical SliceA player can start the game from a title screen, pick a class, spawn into a grey-box room, walk a corridor, fight a skeleton, loot it, save, die, respawn and reload — end to end, in a browser, verified by an automated e2e test. At m2 a grey-box class gauntlet proves every class's core verbs in one course.16/21 done · 76%

M1 Grey-box slice 2

  • mw-e01.10Playtest the m1 slice flow and file follow-up beadsopenP1M1task

    Description

    Why

    Automated tests prove the loop works; only people prove it is understandable.

    What

    Five internal testers play the slice cold with no instructions beyond controls. Observe: time to first attack, whether they find the key, whether death/reload is understood, whether they save voluntarily. Produce docs/playtests/m1-slice.md and beads for every blocker.

    Scope

    • In: Session plan, observation notes, findings doc, follow-up beads
    • Out: Combat fun validation (e35-greybox-combat-test, e04-skeleton-fun-validation)

    Notes

    Run in the same sessions as e35-greybox-combat-test to save tester time.

    Acceptance criteria

    • AC-1 manual Given 5 testers, when they play, then >= 4 reach slice complete within 8 minutes without help.
    • AC-2 manual Given testers who die, when the death screen appears, then >= 4 of 5 return to play without asking what to do.
    • AC-3 content Given the findings doc, when complete, then every issue observed by >= 2 testers has a bead key listed next to it.

    Waits on

    • mw-e01.18 Show a slice-complete card and return to the title done
    • mw-e01.9 Prove the slice plays start-to-finish in a CI e2e test done
    area:qaepic:e01milestone:m1
  • mw-e01.20Playtest: 3 testers each name a skeleton attack by its telegraph (mw-e01.5 AC-4)openP1M1task

    Description

    Why

    Manual AC-4 of mw-e01.5 cannot be automated: readable telegraphs are a playfeel claim.

    What

    Run in the same sessions as mw-e01.10. Have 3 internal testers play the slice; record whether each can name at least one skeleton attack by its telegraph. Findings go in docs/playtests/m1-slice.md.

    Scope

    • In: session, per-tester result, follow-up beads for unreadable telegraphs
    • Out: automated telegraph tests (mw-e04.20, closed)

    Acceptance criteria

    • AC-1 manual Given 3 internal testers, when they play the slice, then each can name at least one skeleton attack by its telegraph.
    • AC-2 content Given the findings doc, when complete, then each tester's answer is recorded and any failure has a bead key next to it.
    area:gamearea:qaepic:e01milestone:m1needs-human

M2 Class fantasies 2

  • mw-e01.13Build the grey-box class gauntlet exercising every class verbblockedP1M2feature

    Description

    Why

    M2 must prove each class fantasy in grey-box: "a locked tower isn't simply requires level 8".

    What

    As a player of any class, I want a grey-box course whose every gate has a route for my class so that my class's core verbs are proven.

    Five chambers, each with one gate and four routes: (1) Parry gate: skeleton sentry — knight parry/riposte or smash a weak wall; archer headshot from a gallery; sorcerer Gust it off a ledge; thief sneak/backstab. (2) Rope bridge chasm: rope arrow anchor; Levitate/Blink; climb route; knight kicks a beam across. (3) Webbed door: Ember/fire arrow burns web; knight cuts; thief finds vent. (4) Water channel: Frostglass freeze; float crates; climb beams; blunt-arrow the sluice. (5) Guard room with locked chest and lever: lockpick; shoot the lever; Mage Hand it; shield-bash the lock.

    Scope

    • In: Scene data for 5 chambers, gate/route wiring, route declarations per class
    • Out: The verbs (E04/E05/E08/E10)
    • Out: Route audit for the real MVP (E16)

    Notes

    Each chamber is also a reusable e16 obstacle template. Every route must work via properties (flammable, climbable, shootable), never pairings.

    Acceptance criteria

    • AC-1 content Given the gauntlet scene, when validated, then every gate declares >= 3 class routes referencing existing capability ids.
    • AC-2 integration Given chamber 3's web, when any heat source above its ignition threshold touches it, then it burns away regardless of source (spell, arrow, torch).
    • AC-3 integration Given a player breaks the chamber 2 beam before crossing, when the chasm is re-evaluated, then at least one remaining route still exists for every class (no softlock, edge).
    • AC-4 perf Given the densest gauntlet chamber with 4 creatures and fire, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).

    Waits on

    • mw-e01.11 Connect scenes with area transitions and named spawn points done
    • mw-e03.13 Support hanging objects on ropes that burn, cut or snap done
    • mw-e04.12 Parry window and riposte critical attack done
    • mw-e04.17 Smash breakable walls and objects by impact force open
    • mw-e05.10 Rope arrows anchor into wood and create climbable ropes open
    • mw-e05.13 Shootable triggers and cuttable ropes activate mechanisms done
    • mw-e08.10 Add Mage Hand: grab, move and use distant objects done
    • mw-e08.13 Add Levitate: float the caster or an object upward slowly open
    • mw-e08.2 Add Ember: precise ignition of flammable things done
    • mw-e08.5 Add Frostglass: freeze targets and create temporary ice surfaces open
    • mw-e10.4 Backstabs and non-lethal takedowns on unaware targets open
    • mw-e10.7 Pick locks as an in-world, interruptible, noisy action open
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e13.1 Add the Forgotten skeleton with the e04 three-move set done
    area:contentepic:e01milestone:m2
  • mw-e01.14Replay the class gauntlet end to end for each of the four classesblockedP1M2task

    Description

    Why

    Class fantasies must stay proven as systems change; a regression in any class verb should fail CI.

    What

    Four recorded replays (knight, archer, sorcerer, thief) that complete the gauntlet using only class-granted capabilities, asserted headlessly in CI and via Playwright on Chromium nightly.

    Scope

    • In: 4 replays, headless CI job, nightly Playwright job, capability-use assertion
    • Out: Playtests of class feel (e35-class-fantasy-tests)

    Notes

    The capability-use assertion reads capability.used events and fails if a replay used a capability outside its class kit.

    Acceptance criteria

    • AC-1 integration Given each class replay, when run headless, then the gauntlet.complete fact is set and the final hash equals the golden hash.
    • AC-2 integration Given the thief replay, when capability.used events are inspected, then no event references a capability not granted by the thief class (edge).
    • AC-3 e2e Given the nightly Chromium run, when all four replays execute, then each finishes with zero console errors.

    Waits on

    • mw-e00.17 Record inputs and replay them to identical state hashes in tests done
    • mw-e01.13 Build the grey-box class gauntlet exercising every class verb open
    • mw-e19.4 Define the four classes as data: kit, capabilities, proficiencies done
    area:qaepic:e01milestone:m2

M3 MVP content 1

  • mw-e01.12Wake in context after death instead of reloadingblockedP1M3feature

    Description

    Why

    Bible §4.5: dying in the Knot wakes you in the Fold, dying in the Briarwood wakes you at the Sleeping Ox. Death must move the story sideways.

    What

    As a player, I want to wake somewhere meaningful after I die so that failure becomes part of the story.

    Extends the respawn resolver with mode wake-in-place: no reload; the world state is kept; the player is moved to the destination spawn with restored health, set facts (e.g. rescues.byHorn += 1), an optional cost (coin/trinket fee), and a wake text id. Death screen still offers "Load last save" as a secondary option. Rules for Knot → Fold, Knot (Horn dead) → goblin camp or Forgotten laying-out, Briarwood → Sleeping Ox are content in the respective area items.

    Scope

    • In: wake-in-place mode, fee/cost effects, counters, wake text hook, death-screen option ordering
    • Out: Rule content per area (e26-horns-hall-fold, e25-briarwood-greybox)
    • Out: Wake texts (e39-failure-narratives)

    Notes

    Creatures that killed the player return to routine; hostile creatures near the wake point are pushed to Searching elsewhere so the player never wakes into a lethal loop.

    Acceptance criteria

    • AC-1 unit Given a wake-in-place rule for region knot with fact horn.alive, when the player dies, then the player is placed at the Fold spawn at full health and rescues.byHorn increments by exactly 1.
    • AC-2 unit Given a rule with a fee of 20 coins and a player holding 5, when applied, then the fee takes 5 coins and sets fact debt.kettleback = 15 (edge: no negative gold).
    • AC-3 integration Given the player wakes in place, when inspected, then no world facts or entity deltas are rolled back other than those in factsToSet.
    • AC-4 integration Given a hostile creature within 15 m of the wake spawn, when the wake completes, then that creature is relocated or set to a non-combat state before input resumes (edge).
    • AC-5 e2e Given the death screen after a wake-eligible death, when shown, then "Wake" is the default focused option and "Load last save" is available.

    Waits on

    • mw-e01.11 Connect scenes with area transitions and named spawn points done
    • mw-e01.8 Run the player death and respawn loop done
    • mw-e23.4 Make quest failures continue the story instead of dead-ending open
    • mw-e27.5 Query world facts with a shared condition API for all systems done
    area:gameepic:e01milestone:m3
E02Core Character ControllerMovement, camera, jumping, climbing, stance, interaction, targeting and animation hooks feel excellent and responsive on keyboard + mouse (gamepad second). All movement rules live in src/sim as a deterministic kinematic controller driven by abstract input actions, so replays, AI and tests share the exact same rules the player feels.29/39 done · 74%

M1 Grey-box slice 9

  • mw-e02.25Fade the player and near occluders when the orbit camera is pulled in closeopenP2M1feature

    Description

    Why

    When collision pulls the orbit camera (mw-e02.4) in tight, for example behind a pillar in the testbed corridor or with the player backed against a wall, the placeholder capsule can fill half the screen and hide the path ahead. mw-e02.4 scoped a transparency fade of occluders near the camera, but it shipped without one.

    What

    As a player, I want the character and anything right in front of the camera to fade out when the camera is squeezed in close, so that I can still see where I am going.

    Scope

    • In: Fade the player's body by camera distance, and fade scene pieces that the camera's near sphere or the camera-to-player line passes through, with a smooth fade in and out.
    • Out: Camera placement and collision (done in mw-e02.4).

    Notes

    src/game/camera/orbit-camera.ts already publishes boom length and ideal distance each frame. The fade is presentation only and never touches the sim.

    Acceptance criteria

    • AC-1 unit Given the boom pulled in below the fade start distance, when a frame is drawn, then the player's opacity falls monotonically with distance and is fully opaque at or beyond it.
    • AC-2 unit Given a scene piece between the camera and the player, when a frame is drawn, then that piece fades out within 0.2 s and fades back in once it is clear.
    • AC-3 e2e Given the testbed corridor, when the bot walks past the pillars, then there are no console errors and the frame time stays within the perf budget.
    area:gamearea:renderarea:simclass:allepic:e02milestone:m1size:s
  • mw-e02.28Owner feel review of lock-on tuningopenP2M1task

    Description

    Why

    mw-e02.16 shipped lock-on with documented default numbers the bead did not specify (distance weighting, priority weight, turn rate, flick thresholds, camera framing). Feel is the owner's call.

    What

    As a designer, I want the lock-on feel reviewed in the testbed arena so that the defaults are confirmed or retuned.

    Scope

    • In: src/content/data/lock-on/player.json values (distanceWeight 0.5, priorityWeight 0.25, turnRate 720°/s, stick flick 0.7/0.3, mouse flick 40/5 counts, framing 0.2 s / 0.5 / −10°).
    • Out: rule changes (new beads).

    Notes

    Open the testbed, walk into the arena, lock on (Q / RS click), cycle (Tab, mouse swipe, RS flick), strafe with A/D.

    Acceptance criteria

    • AC-1 manual Given the testbed arena with three dummies, when the owner locks, cycles and strafes with keyboard+mouse and with a pad, then each tuning value is confirmed or a new value is recorded in the content file.
    area:designarea:gamearea:simepic:e02milestone:m1milestone:m2needs-human
  • mw-e02.39Pushables in content: surface friction lookup, class strength, authored push configopenP2M1task

    Description

    Follow-up from mw-e02.18 (PR #313). Push sim (src/sim/push) ships but: (1) friction comes from the object or an optional surface hook, not the surface under the object; (2) strength defaults to 100 for all classes (knight should be stronger, via class data); (3) push.config (axis, grid, rotateStep) cannot be authored in scene data; (4) prompt still reads Push while grabbing; (5) rotation is not swept and can clip walls; (6) PUSH_LOAD_FACTOR=4 was added to the bead formula so stone vs ice differ — confirm or retune. Place at least one pushable crate in the testbed.

    AC-1 unit A crate on an ice surface pushes faster than on stone using the surface under it.

    AC-2 unit Knight strength from class data exceeds the default and pushes faster.

    AC-3 unit Scene data can author axis, grid and rotateStep, validated by schema.

    AC-4 unit Rotation that would penetrate a wall is refused.

    AC-5 e2e The testbed has a pushable crate the player can grab, push and release.

    area:gamearea:simepic:e02milestone:m1
  • mw-e02.27Interpolate the lock point for moving targets in the lock marker and framingopenP3M1task

    Description

    Why

    The lock-on marker and camera framing (mw-e02.16) read the locked target's lock point from the sim's ViewAnchor as of the last tick. Training dummies stand still, but a moving creature would make the marker step at 60 Hz instead of gliding with the interpolated render.

    What

    As a player, I want the lock ring to stay glued to a moving target so that locked combat reads cleanly at any refresh rate.

    Scope

    • In: interpolate the target's lock point with RenderSync alpha (or read the drawn transform) for the HUD marker and LockFraming.
    • Out: lock-on rules (src/sim/targeting).

    Notes

    src/game/player/testbed-player.ts lockTarget(); src/game/player/lock-marker.ts.

    Acceptance criteria

    • AC-1 unit Given a target moving at 5 m/s and a 144 Hz display, when frames are drawn between ticks, then the marker position follows the interpolated lock point (error ≤ 1 px at 1080p).
    • AC-2 unit Given a stationary target, when frames are drawn, then the marker writes no DOM changes (idle HUD stays free).
    area:gamearea:simepic:e02milestone:m1milestone:m2
  • mw-e02.29Add InteractPrompt widget to the UI component galleryopenP3M1task

    Description

    From PR #100: InteractPrompt is not in src/ui/gallery.ts, so gallery axe and text-scale checks don't cover it. Add it.

    area:gamearea:simepic:e02milestone:m1
  • mw-e02.30Give NPC interactors their own interact inputopenP3M1task

    Description

    From PR #100: interaction system applies the Interact button to every interactor entity by default. Fine while only the player interacts; future NPC interactors must supply input via the system's input option.

    area:gamearea:simepic:e02milestone:m1
  • mw-e02.34Heavy encumbrance blocks the pull-up from a ledge hangopenP3M1feature

    Description

    Why

    mw-e02.12 notes that heavy encumbrance may block pull-up (data). Mantling and hangs shipped without it because the sim has no carried weight yet.

    What

    As a player carrying too much, I want pulling up from a hang to fail (with a cue), so that weight matters on climbs.

    Scope

    • In: an encumbrance threshold in the controller's ledge tuning (content); the ledge hook refuses the pull-up above it
    • Out: the inventory and weight model itself

    Acceptance criteria

    • AC-1 unit Given a hanging player above the pull-up weight threshold, when jump is pressed, then the player keeps hanging; below it, the pull-up runs.
    area:gamearea:simclass:allepic:e02milestone:m1
  • mw-e02.35FakeCollisionWorld: an airborne capsule pushing into a wall sticks at the wall's square top edgeopenP3M1bug

    Description

    Why

    Found while testing mw-e02.12: in the in-memory collision world, a falling capsule held against a wall whose top edge is within the capsule's height hangs in mid-air (velocity 0, not grounded) forever. The fake's square-edge Minkowski approximation reports the wall's top face (normal +y) for a diagonal down-and-in sweep beside the edge, and the controller's slide then cancels the fall. Rapier rounds edges, so the game is unaffected, but unit tests and goldens on the fake can hit it.

    What

    As a developer, I want the fake to behave like Rapier at wall top edges, so that controller tests never pin a test-double artifact.

    Scope

    • In: fix the fake's contact choice at edges (prefer the face the core is beside), plus a contract test run against both worlds
    • Out: changes to the Rapier port

    Acceptance criteria

    • AC-1 unit Given a capsule falling while pushing into a 2 m wall, beside its top edge, when stepped, then it slides down and lands, in both the fake and the Rapier collision world (contract suite).
    area:gamearea:simepic:e02milestone:m1
  • mw-e02.37Make bulky a world property per ADR-0003 (carry follow-up)openP3M1task

    Description

    Why

    mw-e02.17 (PR #301) marks shoulder-carried things with a carry.bulky marker component to avoid a property-schema version bump; ADR-0003 names bulky as a world property.

    What

    Add bulky to the property vocabulary (schema version bump + migration), switch src/sim/carry to read it, drop the marker component.

    Acceptance criteria

    AC-1 unit Given an entity with the bulky property, when carried, then the carry is a shoulder carry (x0.5 speed, no jump).

    area:gamearea:simepic:e02milestone:m1

M2 Class fantasies 1

  • mw-e02.19Run a controller feel review and retune against reference gamesopenP2M2spike

    Description

    Why

    Automated tests keep the controller correct; only humans can tell if it feels excellent. Numeric targets need validating against the tone references (Souls weight, Zelda responsiveness).

    What

    Time-boxed (1 day) playtest of the greybox traversal course with 3+ testers, comparing jump arc, acceleration, camera lag and mantle timing against reference feel notes. Output: tuning changes committed to controller data and a short findings doc.

    Scope

    • In: Playtest script, questionnaire, tuning deltas
    • In: docs/design/controller-feel.md with before/after values
    • Out: Combat feel — see mw-e04

    Notes

    Time-box: 1 day. Record sessions (e34 telemetry optional).

    Acceptance criteria

    • AC-1 manual Given 3 testers on the traversal course, when surveyed, then median "controls feel responsive" score is ≥ 4/5.
    • AC-2 content Given the review, when finished, then all tuning changes are committed to controller data and golden replays are re-blessed with diffs attached.
    • AC-3 manual Given any tester reports a specific frustration (e.g. missed mantle), when reviewed, then it is either fixed or filed as a bead with a failing test.

    Waits on

    • mw-e02.12 Mantle onto and grab ledges detected from world geometry done
    • mw-e02.3 Move controller tuning values into schema-validated content data done
    • mw-e02.4 Follow the player with a colliding, orbiting third-person camera done
    area:designepic:e02milestone:m2needs-humansize:s
E03Systemic Interaction EngineDoors, switches, movable objects, breakables, fire, water, ice, electricity, gas, light, physics and triggers form one reusable, property-based world simulation. Nothing is scripted pairwise: objects declare properties (flammable, wet, frozen, conductive, weight, fragile, climbable, liftable, hideable, reflective…) and elements propagate by rules over those properties, so a spell, an arrow, a torch, a creature and a puzzle all touch the same systems. This is the architectural heart of "Wait… I can do that?".37/58 done · 64%

M1 Grey-box slice 18

  • mw-e03.33Validate signal-graph entity bindings against level entity idsopenP1M1task

    Description

    Why

    mw-e03.21 signal graphs bind nodes to level entities by name ("entity": "lower-lock-gate"). Nothing checks those names at content load yet because levels are not content; a typo only fails when the graph is placed at runtime.

    What

    As a designer, I want the content loader to reject a graph whose bindings name entities missing from the level that places it, so that typos fail in CI rather than in play.

    Scope

    • In: cross-reference check from the level/placement data to signal-graph bindings, with file path and pointer
    • Out: the level format — see mw-e01.4 greybox level

    Notes

    The sim already throws on a missing binding when the graph is placed (addSignalGraph).

    Acceptance criteria

    • AC-1 content Given a level placing a graph whose node binds an entity id absent from the level, when validated, then validation fails naming the id and the level file.
    area:contentarea:simepic:e03milestone:m1size:s
  • mw-e03.36Save and load the sim's physics state in the world save sectionopenP1M1task

    Description

    Why

    Since mw-e03.35 a World with physics carries PhysicsState (engine id plus Rapier's snapshot as base64 and a handle table) in its WorldSnapshot, and restore() requires it. The save world section's schema (src/game/save/format/registry.ts) is a strictObject without a physics field, so saving a world that has physics would be rejected, and physics would be lost across save/load.

    What

    Add the optional physics field to the world section (a new section version with an identity migration, like facts in v2), with round-trip and fixture tests. Consider compressing the Rapier bytes (ADR-0001: about 350 KB per 200 bodies) and whether static level geometry should be rebuilt from the level rather than saved (mw-e27.3 baselines).

    Scope

    • In: world section schema/version, save fixtures, round-trip test with a physics world
    • Out: dynamic bodies (mw-e03.10)

    Acceptance criteria

    • AC-1 unit Given a World with Rapier physics and a loaded scene, when saved and loaded into a new World, then the state hash is identical and stepping on matches the uninterrupted run.
    • AC-2 unit Given a save from before this change (no physics), when loaded into a World without physics, then it loads unchanged.
    area:gamearea:simepic:e03milestone:m1
  • mw-e03.32Test trigger volumes for element presence in element-field cellsopenP2M1task

    Description

    Why

    mw-e03.21 filters volumes by element presence on entities (fire = burning, water = wetness > 0, ice = frozen, charge = charge > 0). A room flooding with gas or a patch of burning oil on the floor lives in the element grid (mw-e03.4), not on entities, so a volume cannot see it yet.

    What

    As a designer, I want a trigger volume filter that tests element-field cells inside the volume (fire, gas, water, charge above a threshold) so that burning oil or seeping gas can trip a mechanism.

    Scope

    • In: a field-presence predicate for volume nodes (element + min concentration), content schema + sim evaluation
    • Out: the element grid itself — see mw-e03.4

    Notes

    Reuse shapeBounds to find the cells; keep evaluation order canonical.

    Acceptance criteria

    • AC-1 unit Given a volume filtered to gas ≥ 0.3, when gas cells above that concentration overlap it, then active is true; below it, false.
    • AC-2 content Given a field predicate naming an unknown element, when validated, then validation fails naming the element.

    Waits on

    • mw-e03.4 Build a sparse spatial grid for temperature, moisture, gas and charge done
    area:simepic:e03milestone:m1milestone:m2size:s
  • mw-e03.34Attribute fire spread to whoever started it (instigator chains through fire)openP2M1task

    Description

    Follow-up from mw-e03.5 (PR #68). Fire rules currently write property changes with source null: a fire lit by the player's torch and spread through three crates carries no attribution, so quests, crime and AI blame (mw-e04.19, mw-e11) cannot tell who burned the barn. Record the heat source that ignited an entity (e.g. the attributed stimulus that raised its temperature, or the burning entity whose flames reached it) in a snapshotted component, and pass it as the source of ignition/burn/burnout property writes and fire events.

    AC-1 unit Given a player heat stimulus that ignites crate A whose flames ignite crate B, when both burn, then fireIgnited for B and B's burning propertyChanged carry the player as source.

    AC-2 unit Given the attribution state, when the world is snapshotted and restored mid-fire, then attribution survives and replays hash identically.

    area:simepic:e03milestone:m1
  • mw-e03.38Let light pass partially through foliage, cloth and glassopenP2M1feature

    Description

    Why

    Shadows under a hedge or behind a curtain should be dimmer, not pitch black or fully lit. Line of sight (mw-e09.1) already treats partial cover as transmittance; the light field (mw-e03.15) only knows opaque blockers.

    What

    As a thief, I want foliage and cloth to cast soft shadows so that partial cover hides me partly.

    Light paths through transparent (glass, water, ice) and partial-cover entities are attenuated by a transmittance factor, using the same occlusion vocabulary as line of sight (opaque | transparent | partial:<factor>), instead of only opaque entities blocking fully.

    Scope

    • In: transmittance for dynamic light occluders; sharing the occlusion factor source with mw-e09.1
    • Out: coloured light and caustics (render only)

    Notes

    Follow-up from mw-e03.15. Keep the sampling budget (AC-6 of mw-e03.15).

    Acceptance criteria

    • AC-1 unit Given a partial:0.5 bush between an emitter and a sample, when sampled, then the emitter's contribution is halved.
    • AC-2 unit Given a transparent pane between an emitter and a sample, when sampled, then the contribution is unchanged.
    • AC-3 perf Given the mw-e03.15 light benchmark, when partial occluders are added, then it stays within budget.

    Waits on

    • mw-e03.15 Query light level at any position from all light sources in sim done
    area:simclass:thiefepic:e03milestone:m1size:s
  • mw-e03.43Ledges on movable props and runtime-spawned geometryopenP2M1feature

    Description

    Why

    mw-e03.22 extracts ledges once at scene load from static greybox parts. Movable props (physics-object crates from testprops with bodies) and runtime-spawned geometry (propped ladders, debug-console spawns) have no ledges, so a player cannot mantle a pushed crate.

    What

    Ledges for physics-object boxes derived from their current pose (top edges of upright boxes), refreshed as they move/sleep, exposed through the same LedgeIndex query (LedgeHit) as scene ledges.

    Notes

    Build on src/sim/climb/ledges.ts (extractLedges, LedgeIndex). Only upright boxes need ledges; tilted ones can be skipped.

    Acceptance criteria

    • AC-1 unit Given a 1.4 m physics crate at rest, when ledges are queried near its top, then its four top edges are returned with its entity.
    • AC-2 unit Given the crate is pushed 2 m, when queried on the next tick, then the ledges follow its new pose.
    • AC-3 unit Given the crate is tipped over past 20°, when queried, then it has no ledges (edge).
    area:simepic:e03milestone:m1milestone:m2size:s
  • mw-e03.44Reconcile breakable profiles with the unused toughness and bashable world propertiesopenP2M1task

    Description

    Why

    PR #138 (mw-e03.11) added a breakable profile type with its own fragile threshold and resistances, but the existing world properties toughness (single-hit threshold per kind) and bashable remain unused. Two ways to express the same thing breaks the single property-based model (contract §2).

    What

    Either derive breakable thresholds from toughness/bashable or remove those properties; also decide whether physics impacts should wear down structural hp (today they only test fragility) and whether break loudness belongs on the material rather than the profile.

    Acceptance criteria

    • AC-1 unit Given a content entity, when it declares breakability, then exactly one property path determines its break thresholds and the validator rejects the other.
    area:simepic:e03milestone:m1
  • mw-e03.45Thrown liquid containers shatter and spill a property-carrying puddleopenP2M1feature

    Description

    Why

    mw-e17.6 shipped thrown oil flasks that land whole and burn where they lie. The bead's intent (a thrown flask shatters and leaves a flammable puddle) needs breakables that spill their liquid contents.

    What

    Fragile containers break on impact above a threshold and spawn a puddle entity inheriting the container's liquid worldProperties (flammable, wet, conductive...), with a data-driven radius. Purely property-based — no flask-specific code.

    Notes

    Follow-up from PR #154 (mw-e17.6).

    Acceptance criteria

    AC-1 unit A fragile container with liquid properties breaking emits a puddle spawn carrying exactly those properties.

    AC-2 integration In the greybox testbed a thrown oil flask shatters, leaves a puddle, and igniting it burns the area via e03 propagation.

    area:simepic:e03milestone:m1
  • mw-e03.46Check sustained fire next to wooden level geometry (floors, walls) can't soft-lock a sceneopenP2M1task

    Description

    PR #279 (mw-akb) gives every flammable thing, including wooden floors and walls, an ambient temperature, so Ember can now light level geometry. An idle probe showed no spread, but sustained fire beside wooden architecture is untested: decide whether structural pieces burn, char or are fireproof, and make sure burning one can't remove a required floor/door/path.

    Acceptance criteria

    • AC-1 integration: burn the wooden pieces in the Sleeping Ox and the slice; required paths stay traversable; result documented as a design rule
    area:simepic:e03milestone:m1
  • mw-e03.48Thrown items carry their own damage type for impactsopenP2M1task

    Description

    Follow-up from mw-e03.20 (PR #322). physicsImpact from thrown/dropped bodies is always blunt, so a thrown dagger cannot trip a pierce-only bullseye. Read a damage type (and optional element) from the thrown item's content data and carry it on the impact.

    AC-1 unit A thrown dagger (pierce) at >= 20 J activates a pierce-filtered bullseye.

    AC-2 unit A thrown crate (no damage type) stays blunt.

    AC-3 unit Hit-zone check optionally respects the switch's facing plane (front hits only) when configured.

    area:simepic:e03milestone:m1
  • mw-e03.50Element state SFX: crackle loop, sizzle, freeze crack, zapopenP2M1task

    Description

    mw-e03.28 maps burning/wet/frozen/charged to VFX and mesh looks, and the element-feedback table has an optional audioCue per state, but the sound manifest has no crackle loop, sizzle, freeze crack or zap cue. Add the cues (mw-e38 asset beads) and set audioCue in src/content/data/element-feedback/element-feedback.json. A looping cue (crackle while burning) needs a loop hook in ElementFeedbackBridge; today it plays one-shots on entering a state.

    area:simepic:e03milestone:m1
  • mw-e03.51Element states for entities that start a scene in a state (no propertyChanged)openP2M1task

    Description

    mw-e03.28's bridge reacts to propertyChanged, so an entity that loads burning, wet or frozen from scene data (addProperties fires no event) gets no VFX or look, e.g. lanterns and braziers in briar-glen-lane (their flame is the light rig's). Seed the bridge from a world scan at scene load, skipping entities whose flame the light rig already draws.

    area:simepic:e03milestone:m1
  • mw-e03.53Wet state legibility and colour-independent cuesopenP2M1task

    Description

    mw-e03.28 screenshot review: wet (darker bluish albedo + blue drips) is the weakest of the four states at game camera distance and is easily mistaken for a dark crate. Strengthen it (wet sheen, puddle decal vfx-decal-wet-01, larger drips) and give every state a non-colour cue (shape or motion), coordinated with mw-e31.8.

    area:simepic:e03milestone:m1
  • mw-e03.54Chaos room scene for element interaction e2e and playtest (AC-5)openP2M1task

    Description

    mw-e03.28 AC-3 and AC-5 refer to a chaos room that does not exist. The e2e uses crates spawned into the testbed. Add a purpose-built scene with spaced props for fire, freeze, wet and charge scenarios and the 6-object identification playtest.

    area:simepic:e03milestone:m1
  • mw-e03.55Light receivers only answer beams: a lit brazier, Ember's light or any field light cannot turn a beam sensor on; no light spell existsopenP3M1task

    Description

    Found in mw-e15.9: sunbeam-hall expresses 'light the sensor by igniting a brazier near it' in the puzzle goal (any of sensor lit, brazier lit) because lightReceiver reads beams only (lightActivated property is declared but unread), and the bead's 'light spell' has no spell content. Let receivers (or a sensor node) read light-field level, and add a light spell.

    area:simepic:e03milestone:m1
  • mw-e03.56Ceiling beams cannot be traversed: no hang-and-shimmy across overhead beams over a gapopenP3M1task

    Description

    Found in mw-e15.9: the frozen channel cannot declare 'climb the ceiling beams' because the climb system has ledge hang/shimmy and wall/rope climbing but no overhead traversal. Related open: mw-e10.9 (climb tagged surfaces), mw-e03.14 (buoyancy: crates sink, so 'float crates' is not declarable), mw-e08.5 (no cold source until Frostglass), mw-e08.13 (no self-levitation).

    area:simepic:e03milestone:m1
  • mw-e03.58No airflow or draft field: 'follow the drafts in the smoke' dark-crossing solution cannot be authoredopenP3M1task

    Description

    Found in mw-e15.10: the dark crossing was meant to be solvable by following drafts in smoke to the safe path. There is no smoke, draft or airflow field to read or render (wind only blows flames out as a force stimulus). Add an airflow source (vents, gaps) the stimulus API and renderer can read, then declare the route in src/content/data/puzzle/dark-crossing.json.

    area:simepic:e03milestone:m1milestone:m2
  • mw-e03.57Closing a trapdoor over a liquid volume is blocked by the water layer entity (drawbridge from trapdoors impossible)openP4M1task

    Description

    Found in mw-e15.9: four trapdoors (state open) in a flooded trench, wired to close from a lever, stay 'blocked' with door.blockedBy set to the liquid layer entity (placement radius 2 at the volume centre). A drawbridge over water would be a data-only second route for the frozen channel.

    area:simepic:e03milestone:m1

M2 Class fantasies 1

  • mw-e03.27Replay a library of emergent combo scenarios in a greybox chaos roomopenP1M2task

    Description

    Why

    We need living proof that "Wait… I can do that?" moments emerge from properties, and a regression net so they keep emerging as rules change.

    What

    As a designer, I want a catalogue of emergent combos, each a replayable greybox scenario, so that I can see and protect the game's surprising interactions.

    A chaos-room greybox level plus ≥ 12 scenario files, each with setup, input log and asserted outcome expressed via properties/facts. Initial catalogue: oil puddle ignition chain; burn rope → dropped chandelier; freeze river → walk across; soak enemies + charge in puddle; frozen actor shattered by blunt hit; levitated crate weighs 0 on plate; wedge portcullis with crate; gust extinguishes candles but not brazier; smoke blocks sight line; burning haystack ejects hider; focused beam ignites web barrier; ice block on pressure plate melts → plate releases (timer puzzle for free).

    Scope

    • In: Chaos room level, scenario schema, runner integrated with e00-replay-harness
    • In: 12+ scenarios with property-based outcome assertions
    • In: Catalogue doc docs/design/emergence-catalogue.md generated from scenario metadata
    • Out: Randomised coverage — see e03-interaction-matrix

    Notes

    Scenario outcomes are phrased as properties ("some entity with flammable ends burnt"), never "the rope entity". New combos discovered in playtests get added here.

    Acceptance criteria

    • AC-1 integration Given each scenario, when replayed in CI, then the asserted property outcome holds and the final state hash matches its golden.
    • AC-2 content Given the scenario directory, when validated, then there are ≥ 12 scenarios and each has setup, inputs, outcome and a player-facing description.
    • AC-3 integration Given a rule change breaks a scenario, when CI runs, then the failure names the scenario and its outcome description.
    • AC-4 integration Given the ice-on-plate scenario, when simulated, then the plate deactivates only after the ice melts below the weight threshold (edge: time-based emergent state).
    • AC-5 e2e Given the chaos room in the browser, when the Playwright bot runs the rope/chandelier scenario, then it completes with no console errors.

    Waits on

    • mw-e00.17 Record inputs and replay them to identical state hashes in tests done
    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e03.13 Support hanging objects on ropes that burn, cut or snap done
    • mw-e03.17 Redirect light beams with mirrors and lenses onto receivers done
    • mw-e03.19 Activate pressure plates by total weight of anything resting on them done
    • mw-e03.23 Hide in wardrobes, barrels and haystacks and search containers done
    • mw-e03.26 Property-test all element × property combinations in a matrix harness done
    area:designarea:qaclass:allepic:e03milestone:m2size:m

M3 MVP content 2

  • mw-e03.9Spread gas, smoke and steam clouds that react to fire and windopenP2M3feature

    Description

    Why

    Gust clearing poisonous gas, igniting swamp gas, smoke blocking sight lines for a thief escape — gas turns rooms into systemic spaces.

    What

    As a thief, I want smoke to block vision and flammable gas to explode when lit so that I can escape or set traps.

    Gas types in the element field (smoke: blocks vision; steam: obscures, scalds lightly; poison: damages actors; flammable/marsh gas: ignites with flash + force stimulus when concentration ≥ threshold). Gas diffuses, rises/sinks by type, is blocked by walls/doors, vents through openings, and is pushed by force stimuli (Gust).

    Scope

    • In: Gas species data (buoyancy, diffusion, decay, effects)
    • In: Ignition of flammable gas → explosion stimulus
    • In: Visibility occlusion query for stealth/AI (density along a ray)
    • Out: AI reaction to smoke — see mw-e11
    • Out: Gas VFX — see e29-vfx-framework

    Notes

    Closed doors block gas (door entities are field blockers) — opening a door lets smoke pour out.

    Acceptance criteria

    • AC-1 unit Given flammable gas at concentration ≥ threshold in a cell and a heat source ≥ ignition, when resolved, then the gas is consumed and a force + heat stimulus is applied with radius scaled by the consumed volume.
    • AC-2 unit Given smoke between an observer and a target, when densityAlongRay is queried, then it returns the integrated density and exceeds the vision-block threshold for a 2 m thick cloud.
    • AC-3 unit Given a closed door separating two rooms, when gas fills room A, then room B stays at 0 until the door opens, after which concentration equalises over time.
    • AC-4 unit Given a force stimulus through a gas cloud, when applied, then gas is displaced along the force direction by the documented amount.
    • AC-5 unit Given gas in a fully sealed room with no decay source, when simulated for 30 minutes, then total gas mass is conserved and no cell exceeds max concentration (edge).

    Waits on

    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e03.31 Consolidate world-property vocabulary assumed by other epics done
    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    area:simclass:allepic:e03milestone:m3size:m
  • mw-e03.14Float and sink objects in liquid volumes by densityopenP2M3feature

    Description

    Why

    Floating crates as stepping stones, sinking a heavy chest to trip a submerged plate, or ice slabs drifting are cheap emergent traversal once density is a property.

    What

    As a player, I want wooden objects to float and iron to sink so that I can improvise rafts and stepping stones.

    Buoyancy force from submerged volume × liquid density vs. object density, with drag; objects adjust to the liquid level; wet/soaked materials may change density (data).

    Scope

    • In: Buoyancy + drag forces for bodies in liquid volumes
    • In: Standing on floating bodies (moving platform)
    • In: Density changes from waterlogging (data)
    • Out: Currents / flowing rivers — out of scope for MVP

    Notes

    Ice (density 0.92) floats automatically once frozen slabs break free.

    Acceptance criteria

    • AC-1 unit Given an object with density 0.6 in water (1.0), when settled, then 60% ± 5% of its volume is submerged.
    • AC-2 unit Given an iron object (density 7.8), when placed in water, then it sinks to the bottom and can rest on a submerged pressure plate.
    • AC-3 unit Given a floating crate with a 20 kg load exceeding its buoyancy reserve, when loaded, then it sinks (edge).
    • AC-4 unit Given the water level drops (drain), when resolved, then floating objects descend with the surface and settle on the floor.

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e03.6 Simulate water volumes, splashes, wetness and drying done
    area:simclass:allepic:e03milestone:m3size:s
E04Knight CombatSword/shield gameplay supports attack chains, blocks, parries, dodges, stagger, heavy/charged attacks, shield bashes, weapon reach, armor trade-offs and satisfying hit reactions — and a greybox skeleton fight is fun with no rewards. The shared damage model underpins every class.26/39 done · 67%

M1 Grey-box slice 6

  • mw-e04.25Out-of-breath cues when the knight is ExhaustedopenP1M1feature

    Description

    Why

    mw-e04.5 AC-6: running out of stamina must be readable without the HUD (souls-like fairness). The sim now emits StaminaExhausted / StaminaRecovered (src/sim/combat/stamina.ts) but nothing presents them yet.

    What

    As a knight, I want to hear and see that I am out of breath so that I stop swinging before the HUD tells me.

    On StaminaExhausted: heavy-breathing loop on the player bus and a hunched/winded idle and slower recovery pose; on StaminaRecovered: breath settles and the loop stops. ActionRejected{reason:"stamina"} plays a short strained grunt (once per press). Placeholder assets via e28 cue sheets until final audio lands.

    Scope

    • In: cue-sheet entries and game-layer bindings for the three events, placeholder animation state, manual playtest
    • Out: HUD stamina bar (mw-e04.10), final SFX/animation assets (audio/art beads)

    Acceptance criteria

    • AC-1 unit Given a StaminaExhausted event, when the game layer processes it, then the breathing cue starts once and stops on StaminaRecovered.
    • AC-2 unit Given ActionRejected{reason:"stamina"}, when processed, then the strain cue plays once.
    • AC-3 manual (carried from mw-e04.5 AC-6) Given a 5-minute sandbox session, when a playtester fights the attacker dummy, then they can describe when they are "out of breath" without looking at the HUD.

    Waits on

    • mw-e04.5 Stamina pool governs attacks, blocks, dodges and sprint done
    • mw-e04.9 Combat sandbox scene with dummy creatures and frame-data overlay done
    area:audioarea:gameclass:allepic:e04milestone:m1
  • mw-e04.27Playtest dodge fairness in the combat sandbox (e04.8 AC-6)openP1M1task

    Description

    Why

    mw-e04.8 AC-6 is a manual feel check that needs the combat sandbox's attacker dummy (mw-e04.9), which did not exist when the dodge shipped.

    What

    As a player, I want dodges that feel fair so that timing, not luck, keeps me alive. Once the sandbox exists, three playtesters practise rolling through the attacker dummy's metronome swing for 3 minutes each.

    Scope

    • In: the playtest, logging counterexamples with replay files
    • Out: tuning changes (file separately with evidence)

    Notes

    Dodge rules: src/sim/combat/dodge; numbers in src/content/data/move/dodge-roll.json and backstep.json. Golden replays of an on-time vs one-tick-early roll: tests/replays/dodge-*.json.

    Acceptance criteria

    • AC-1 manual Given the sandbox attacker dummy, when three playtesters practise for 3 minutes, then each reports dodges "felt fair" (no hits they believed they had dodged); any counterexample is logged with a replay file.

    Waits on

    • mw-e04.9 Combat sandbox scene with dummy creatures and frame-data overlay done
    area:simclass:allclass:knightepic:e04milestone:m1milestone:m2
  • mw-e04.38Knight's light swing passes over short creatures like the 0.9 m fixture houndopenP1M1bug

    Description

    Why

    Found while wiring creature spawning (mw-e12.4): the knight's light attack, swung at a fixture-hound (0.9 m tall, hurtbox capsule 0–0.9 m) standing 1.2 m in front of him, never connects, while the same swing at the 1.8 m fixture-guard at the same distance does. Hounds, rats, goblins and other low creatures must be hittable with the knight's basic attack, or the player has no answer to them.

    What

    Decide (owner/design) how low creatures are hit: angle the light chain's socket track lower, add a downward/low attack, or auto-aim the swing's height at the locked target. Then make it so.

    Scope

    • In: knight melee reaching low targets; a test with a short creature.
    • Out: creature hurtbox regions per rig (asset beads).

    Acceptance criteria

    • AC-1 integration Given fixture-hound 1.2 m in front of the knight, when he performs the light attack (locked on or not), then it deals damage to the hound.
    • AC-2 integration Given fixture-guard at the same distance, the light attack still hits as today.
    area:contentarea:simclass:knightepic:e04milestone:m1milestone:m2
  • mw-e04.29Owner review: dodge feel defaults and controlsopenP2M1chore

    Description

    Why

    mw-e04.8 shipped numbers and controls the bead did not fix; they are documented defaults awaiting the owner's call.

    What

    Review and confirm or change: backstep travel 1.2 m (backstep.json); roll attack 10/4/20 ticks, 14 stamina, 16 slash, 12 poise (roll-attack.json); keyboard dodge on R (F stays the remap example; Ctrl/Alt trip browser shortcuts); pad dodge on B with crouch moved to D-pad Down and ability 3 on LB only; a swing dodged once cannot hit the dodger later in the same active window; a dodge and an attack pressed on the same tick start the attack; the roll moves only on its 13 active ticks and stands still in recovery.

    Scope

    • In: decisions, data edits, docs/design/controls.md
    • Out: new mechanics

    Acceptance criteria

    • AC-1 manual Given the list in the description, when the owner has reviewed it, then each item is confirmed or changed in content data/bindings with the decision noted in the move notes or controls doc.
    area:simclass:allclass:knightepic:e04milestone:m1milestone:m2
  • mw-e04.32Playtest the knight light chain for weight (mw-e04.6 AC-8)openP2M1task

    Description

    Why

    mw-e04.6 AC-8 is a manual playtest (three testers, median ≥ 4/5 for 'swings feel heavy and committed', none say floaty) that needs the combat sandbox (mw-e04.9).

    What

    Run the 5-minute sandbox session and record ratings.

    Scope

    • In: the playtest and its notes

    Notes

    Also review the defaults chosen in mw-e04.6: planted during attacks, facing locked through recovery, chain memory forgotten on interrupt, training dummy 200 hp.

    Acceptance criteria

    • AC-1 manual Given a 5-minute sandbox session, when three playtesters use the chain, then the median rating for 'swings feel heavy and committed' is ≥ 4/5 and none describe attacks as floaty.
    area:simclass:knightepic:e04milestone:m1milestone:m2
  • mw-e04.35Blind A/B playtest: hit-stop on vs off for impact (mw-e04.11 AC-5)openP2M1task

    Description

    mw-e04.11 AC-5 manual: given A/B builds with hit-stop on vs off, three playtesters try both blind; at least two of three prefer hit-stop on for impact. Hit-stop off = set every tier to 0 in src/content/data/hit-stop/hit-stop.json. Also a chance to tune the PLACEHOLDER tick values.

    area:simclass:knightepic:e04milestone:m1milestone:m2

M2 Class fantasies 6

  • mw-e04.17Smash breakable walls and objects by impact forceopenP1M2feature

    Description

    Why

    "The knight might discover that an old wall can simply be smashed apart." Force-based breaking turns the knight's strength into a world verb (Classes change possibilities).

    What

    As a knight, I want to smash cracked walls, barricades and crates with heavy blows so that brute force opens routes other classes find differently.

    Any object with world property breakable and a toughness breaks when a single hit's impactForce (J) reaches its toughness for that kind of hit (query breaksUnder(type, energy), e03 world properties). impactForce = move base × charge multiplier × weapon class (blunt ×1.5). Hits below toughness advance a visible crack stage (max 2) but never break it — a readable hint that more force is needed. Breaking spawns debris physics objects, emits a loud noise event for stealth, can reveal passages, and persists via e27-world-state-store. The rule is property-based: any source dealing impactForce (bash, blunt arrow, gust spell, rolling boulder) works.

    Scope

    • In: Toughness rule, crack stages, debris spawn, noise event, persistence
    • Out: Destruction visuals (e29-destruction-fx)
    • Out: Placing weak walls in levels (e26 dungeon)

    Notes

    Suggested toughness: crate 20, barricade 60, weak masonry wall 110 (charged heavy blunt or equivalent only).

    Acceptance criteria

    • AC-1 unit Given any breakable object with toughness 110, when a hit with impactForce 120 lands, then it breaks and ObjectBroken is emitted with the instigator.
    • AC-2 unit Given the same object, when a hit with impactForce 60 lands, then its crack stage increments (capped at 2) and it does not break.
    • AC-3 integration Given a weak wall hiding a passage, when broken, then debris physics objects spawn, the passage collider is traversable and a noise event of loudness ≥ 80 is emitted.
    • AC-4 integration Given a broken wall, when the game is saved and reloaded, then the wall remains broken.
    • AC-5 unit Given a non-knight source (e.g. a blunt projectile) producing impactForce ≥ toughness, when it hits, then the object breaks identically (no class check).
    • AC-6 manual Given a greybox room with one cracked wall, when three fresh playtesters play as knight, then at least two try hitting it within 2 minutes without being told.

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e03.11 Break fragile objects and smash weakened walls into debris done
    • mw-e04.13 Heavy and charged attacks with hyperarmor done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    area:simclass:knightepic:e04milestone:m2
  • mw-e04.22Golden replay suite for combat timing boundariesopenP1M2task

    Description

    Why

    Timing windows are the game; golden replays guarantee a refactor never silently shifts a parry by one tick.

    What

    A set of recorded input logs + expected state hashes in tests/replays/combat/: 3-hit chain; parry first/last/one-late tick; guard break; i-frame boundary (tick 14 vs 15); charged release at 11/12/60/90 ticks; hit-stop stacking; wall recoil. CI runs them on every PR; a failure prints the first divergent tick and the differing component.

    Scope

    • In: Fixtures, CI wiring, divergence reporter, fixture re-record script with review checklist
    • Out: Replay harness itself (e00-replay-harness)

    Notes

    Re-recording a fixture requires a PR note explaining the intended timing change.

    Acceptance criteria

    • AC-1 integration Given the combat fixtures, when run in CI, then all replays match their stored hashes.
    • AC-2 integration Given a deliberate 1-tick change to the parry window, when the suite runs, then the parry-last-tick fixture fails and reports the first divergent tick and component ParryState.
    • AC-3 unit Given src/sim/combat, when coverage runs, then it reports 100% on all metrics.
    • AC-4 integration Given a fixture recorded with an older move-data version, when run, then the harness fails with a clear "fixture data version mismatch" message rather than a hash diff.

    Waits on

    • mw-e00.17 Record inputs and replay them to identical state hashes in tests done
    • mw-e04.11 Hit-stop freezes attacker and victim briefly on impact done
    • mw-e04.12 Parry window and riposte critical attack done
    • mw-e04.13 Heavy and charged attacks with hyperarmor done
    • mw-e04.8 Dodge roll and backstep with invulnerability frames done
    area:qaclass:allepic:e04milestone:m2
  • mw-e04.24Validate a greybox skeleton fight is fun with no rewardsblockedP1M2spike

    Description

    Why

    Constitution: "Fighting a skeleton should be enjoyable even when the player doesn't need XP or loot." This spike proves or disproves that before content scales.

    What

    Question: with placeholder art/audio, is repeatedly fighting a greybox skeleton (3-move set from e04-creature-attack-hooks) intrinsically enjoyable for the knight with zero XP/loot? Time-box: 2 days. Protocol: ≥ 5 playtesters (internal acceptable), short tutorial, then an arena that spawns a new skeleton on demand; observe, record replays and telemetry (parries, dodges, voluntary re-fights, session length), short survey.

    Scope

    • In: Test protocol, arena variant of the sandbox, telemetry events, write-up with tuning recommendations
    • Out: Implementing the recommendations (follow-up beads)
    • Out: External m4 playtests (e35)

    Notes

    Pass bar: ≥ 4 of 5 testers voluntarily fight ≥ 3 skeletons beyond the required one and median "fun" ≥ 4/5. Failing is a valid outcome and must produce concrete tuning beads. Related: e13 bestiary skeleton, e35 fun validation.

    Acceptance criteria

    • AC-1 manual Given ≥ 5 playtest sessions, when completed, then docs/playtests/skeleton-fun-01.md records per-tester voluntary re-fight counts, fun rating (1–5) and quotes.
    • AC-2 integration Given the arena build, when a session runs, then telemetry events for parry attempts/successes, dodges, deaths and re-fights are exported via e34-telemetry-events.
    • AC-3 manual Given the results, when compared to the pass bar (≥ 4/5 testers fight ≥ 3 extra skeletons; median fun ≥ 4), then the write-up states PASS or FAIL explicitly.
    • AC-4 manual Given a FAIL or any rating ≤ 2, when the write-up is finished, then at least three tuning beads are proposed with the replay files that motivated them.

    Waits on

    • mw-e04.11 Hit-stop freezes attacker and victim briefly on impact done
    • mw-e04.12 Parry window and riposte critical attack done
    • mw-e04.20 Creatures attack via the move system with readable telegraphs done
    • mw-e04.9 Combat sandbox scene with dummy creatures and frame-data overlay done
    • mw-e28.4 Combat impact audio matrix: hits, blocks, parries, whiffs done
    • mw-e29.4 Impact VFX by material: sparks, splinters, bone dust, parry flash done
    • mw-e34.1 Define local-first telemetry event schema, store and export open
    area:qaclass:knightepic:e04milestone:m2
  • mw-e04.33Creatures standing in fire catch fire per creature burning rulesopenP2M2feature

    Description

    Why

    mw-e04.19 says fire volumes deal 8 fire/s *and apply burning per creature rules*. The hazard damage shipped (src/sim/combat/environment, 8 fire/s in 250 ms pulses through the damage model), but creatures have no burning status yet: fire rules (mw-e03.5) only ignite world objects with flammable/temperature properties.

    What

    Give creatures a burning state (duration, damage over time, extinguished by water/rolling) applied when a creature is hit by a hazard whose property is burning, respecting fire immunity (resistance 0 never ignites).

    Discovered from mw-e04.19.

    Acceptance criteria

    • AC-1 unit Given a creature with fire resistance 1 in a fire volume, when a pulse lands, then it gains the burning state per its creature data.
    • AC-2 unit Given a creature with fire resistance 0, when it stands in fire, then it never gains burning.
    • AC-3 unit Given a burning creature entering water, then burning ends.
    area:simclass:knightepic:e04milestone:m2
  • mw-e04.37Playtest: parry window is learnable against the sandbox metronomeopenP2M2task

    Description

    Why

    mw-e04.12 AC-8 is a manual playtest the agent cannot run: parrying must feel learnable (Knight fantasy: mastery).

    What

    As the owner, I want three playtesters to practise parrying the combat sandbox attacker dummy (?scene=combat-sandbox, 2 s metronome, parry on 3 / LB, F3 frame data shows the window, the Parried stun and 'riposte ready') so that the 10-tick window and the placeholder riposte tuning are validated.

    Also judge these placeholder decisions from mw-e04.12: (1) parry bound to ability 3 (LB / 3) while block holds LT / right click; (2) a successful parry still plays out its 30 ticks before the knight can riposte (no early exit); (3) the riposte's 8/4/24 frames, 2.0 m thrust and critical-tier hit-stop (src/content/data/move/sword-riposte.json).

    Scope

    • In: playtest, tuning notes back into move data
    • Out: creature attacks through the executor are not yet tagged parryable (they route through hit volumes in mw-e04.20)

    Acceptance criteria

    • AC-1 manual Given the sandbox attacker dummy with a 2 s metronome, when three playtesters practise for 5 minutes, then each lands >= 5 parries and rates the window 'learnable' >= 4/5 (carried over from mw-e04.12 AC-8).

    Waits on

    • mw-e04.12 Parry window and riposte critical attack done
    area:simclass:knightepic:e04milestone:m2
  • mw-e04.36Hit-stop freezes knockback travel and creature-executor attacks tooopenP3M2task

    Description

    mw-e04.11 freezes the action timeline, its hitbox sweeps and hit-reaction clocks. Not yet frozen: a knocked-back/launched victim keeps flying via the character controller during the freeze, and attacks run by the creature attack executor (src/sim/combat/attacks) have their own clock and ignore hit-stop. Decide whether they should follow local time (isHitStopped) and implement.

    area:simclass:knightepic:e04milestone:m2

M3 MVP content 1

  • mw-e04.23Combat assist settings: wider parry, extra i-frames, staminaopenP2M3feature

    Description

    Why

    Accessibility: more players should reach the joy of a parry without removing the skill ceiling for others.

    What

    As a player, I want optional combat assists so that timing-heavy combat is accessible to me.

    Options via e31-settings-framework: parry window ×1.0/×1.5/×2.0 (extends the end tick), i-frames +0/+3/+6 ticks, stamina costs ×1.0/×0.75, extended creature telegraph cue (+10 ticks warning). Values are injected into the sim at session start and recorded in the replay header for determinism.

    Scope

    • In: Assist options, sim injection, replay header recording, settings UI entries
    • Out: Difficulty levels / enemy damage scaling (later if needed)

    Notes

    Timing convention: sim runs at a fixed 60 Hz (1 tick = 16.67 ms, per e00-sim-core). All frame numbers are sim ticks; ms values are for readability only.

    Acceptance criteria

    • AC-1 unit Given parry assist ×2.0, when parry is pressed on tick 0, then hits on ticks 4–23 are parried (window 20 ticks).
    • AC-2 unit Given i-frame assist +3, when a medium-load roll executes, then i-frames cover ticks 2–17.
    • AC-3 integration Given a replay recorded with assists on, when replayed on a machine with assists off, then the header values are used and hashes match.
    • AC-4 unit Given assists changed mid-session, when applied, then they take effect at the next safe point (no action in progress) and an AssistsChanged event is logged.

    Waits on

    • mw-e04.12 Parry window and riposte critical attack done
    • mw-e04.8 Dodge roll and backstep with invulnerability frames done
    • mw-e31.1 Create typed settings store and options menu skeleton done
    • mw-e31.10 Provide difficulty presets and granular assists read by the sim done
    area:simclass:allepic:e04milestone:m3
E05ArcheryBows feel excellent; arrows have physical presence (gravity, drag, sticking, retrieval), weak points and elevation matter, and trick arrows (fire, water, rope, noise, blunt) solve problems through world properties rather than scripted pairings.7/21 done · 33%

M2 Class fantasies 13

  • mw-e05.3Bow draw, aim and release firing selected arrow typein progressP1M2feature

    Description

    Why

    Archery must feel excellent from the first shot: a satisfying draw, precise aim and immediate, physical release (Archer fantasy: precision).

    What

    As an archer, I want to draw, aim and release arrows so that I can hit precise targets at range.

    Hold fire to draw: full draw at 48 ticks (800 ms, shortbow). Launch speed lerps 30%→100% of 60 m/s by draw fraction. Releasing before 12 ticks cancels the shot and returns the arrow. Drawing costs 6 stamina; holding full draw beyond 120 ticks drains 8 stamina/s and at 0 the draw collapses (arrow returned). Aim mode uses the over-shoulder camera from e02-camera (FOV 70→55°), walk speed 50% while drawn. Consumes the selected arrow type from the quiver (e17-inventory-core); a cycle input switches type. Dodge or block cancels the draw and returns the arrow.

    Scope

    • In: Draw/release/cancel, launch speed curve, stamina, aim mode hookup, quiver selection, bow data (shortbow)
    • Out: Sweet-spot release (e05-draw-timing)
    • Out: Sway and reticle (e05-aim-sway)
    • Out: Ballistics (e05-arrow-projectile)

    Notes

    Anchor e05-bow-core: with e05-arrow-projectile (a dependency) this completes draw, aim, release and arrow physics.

    Timing convention: sim runs at a fixed 60 Hz (1 tick = 16.67 ms, per e00-sim-core). All frame numbers are sim ticks; ms values are for readability only.

    Acceptance criteria

    • AC-1 unit Given draw held for 24 ticks, when released, then an arrow spawns at 65% of full launch speed (30% + 0.5 × 70%).
    • AC-2 unit Given draw held for 8 ticks, when released, then no arrow spawns and the quiver count is unchanged.
    • AC-3 unit Given full draw held for 120 ticks, when held further, then stamina drains 8/s and at 0 the draw collapses with the arrow returned.
    • AC-4 unit Given an empty quiver for the selected type, when fire is pressed, then the draw does not start and ActionRejected{reason:"ammo"} is emitted.
    • AC-5 unit Given a drawn bow, when dodge is pressed, then the draw cancels, the arrow returns to the quiver and the dodge executes.
    • AC-6 manual Given a 5-minute archery range session, when three playtesters shoot, then median rating for "the bow feels satisfying" is ≥ 4/5.

    Waits on

    • mw-e02.1 Map remappable KB/M input to deterministic per-tick action frames done
    • mw-e02.4 Follow the player with a colliding, orbiting third-person camera done
    • mw-e04.5 Stamina pool governs attacks, blocks, dodges and sprint done
    • mw-e05.2 Deterministic arrow ballistics with gravity, drag and sticking done
    • mw-e17.3 Implement inventory model with stacks, keys, books and quest items done
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.4Focused release window and rhythm bonus for well-timed shotsblockedP1M2feature

    Description

    Why

    Draw timing gives archery a mastery curve comparable to the knight's parry (Archer fantasy: draw timing).

    What

    As an archer, I want a brief sweet spot at full draw so that well-timed releases are rewarded.

    Focused release: releasing within 6 ticks (100 ms) after reaching full draw → +25% damage, +15% launch speed, zero sway, FocusedShot event (reticle pulse + chime cue). Rhythm: consecutive focused releases reduce nock time from 20 to 14 ticks, stacking up to 3 times; any unfocused shot or 3 s idle resets stacks.

    Scope

    • In: Focused window, bonuses, rhythm stacks, events for presentation
    • Out: Reticle visuals (e05-aim-sway)
    • Out: Audio chime (e28-bow-audio)

    Notes

    Timing convention: sim runs at a fixed 60 Hz (1 tick = 16.67 ms, per e00-sim-core). All frame numbers are sim ticks; ms values are for readability only.

    Acceptance criteria

    • AC-1 unit Given full draw reached on tick 48, when released on tick 48 or tick 53, then the shot is focused; on tick 47 or tick 54, then it is not.
    • AC-2 unit Given a focused release, when the arrow spawns, then its damage template is ×1.25 and launch speed ×1.15.
    • AC-3 unit Given three consecutive focused shots, when the fourth arrow is nocked, then nock time is 14 ticks; after one unfocused shot, then it returns to 20.
    • AC-4 unit Given 2 rhythm stacks and 3 s without firing, when the next draw starts, then stacks are 0.
    • AC-5 manual Given the archery range, when three playtesters shoot for 5 minutes, then each can hit the focused window on ≥ 50% of shots by the end and describes it as "satisfying".

    Waits on

    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.5Deterministic aim sway, breath hold and bow reticleblockedP1M2feature

    Description

    Why

    Sway and breath control make long shots a skill and keep the arrow honest to what the reticle shows.

    What

    As an archer, I want my aim to steady or waver based on what I am doing so that long shots demand composure.

    Sway is simulated (seeded from sim RNG, so replays match): 0° for the first 60 ticks at full draw, then grows 0.1°/s up to 1.5°; walking adds 0.6°; being hit adds a 2° kick decaying over 300 ms; crouched & stationary ("braced") −40%. Hold-breath input at full draw zeroes sway for up to 3 s at 10 stamina/s. Launch direction = reticle direction + current sway offset. Reticle HUD shows draw progress and sway; optional trajectory arc preview (assist, off by default) via settings.

    Scope

    • In: Sway model, breath hold, braced modifier, reticle HUD, arc preview assist
    • Out: Camera aim mode (e02-camera)
    • Out: Lead indicator (e05-moving-targets)

    Notes

    Timing convention: sim runs at a fixed 60 Hz (1 tick = 16.67 ms, per e00-sim-core). All frame numbers are sim ticks; ms values are for readability only.

    Acceptance criteria

    • AC-1 unit Given full draw held for 60 ticks while stationary, when released, then sway offset is exactly 0°.
    • AC-2 unit Given full draw held 20 s, when sampled, then sway amplitude is capped at 1.5° (0.9° while braced).
    • AC-3 unit Given breath hold active with 25 stamina, when 3 s pass, then sway stays 0 for 2.5 s and resumes when stamina hits 0.
    • AC-4 integration Given the same seed and inputs, when two runs fire 10 swaying shots, then launch directions match bit-for-bit.
    • AC-5 unit Given the arc preview assist disabled (default), when drawing, then no arc renders; enabled, then the arc matches e05-arrow-projectile's prediction within 0.2 m at 30 m.

    Waits on

    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    • mw-e31.1 Create typed settings store and options menu skeleton done
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.8Fire arrows ignite flammable things; dip arrows in open flameblockedP1M2feature

    Description

    Why

    Setting a distant oil slick or rope alight is a classic archer "wait, I can do that?" — and must emerge from properties, not scripts.

    What

    As an archer, I want fire arrows and the ability to light any arrow in a flame so that I can ignite things at range.

    Fire arrows carry the burning property in flight; on impact they apply burning in a 0.3 m radius through e03-element-propagation — any flammable object or creature there reacts per its own rules. Dip to light: while drawing, if the arrow tip is within 0.8 m of any burning entity for 30 ticks, the nocked arrow becomes burning. Burning arrows passing through a water volume or heavy rain are extinguished.

    Scope

    • In: Fire payload behaviour, dip-to-light rule, extinguish in water
    • Out: Fire spread rules (e03-element-propagation)
    • Out: Fire visuals (e29-arrow-fx)

    Notes

    Timing convention: sim runs at a fixed 60 Hz (1 tick = 16.67 ms, per e00-sim-core). All frame numbers are sim ticks; ms values are for readability only.

    Acceptance criteria

    • AC-1 integration Given any flammable object, when a burning arrow impacts within 0.3 m, then the object gains burning via element propagation on that tick.
    • AC-2 integration Given a non-flammable stone wall, when a burning arrow impacts, then nothing ignites and the arrow burns out after 3 s.
    • AC-3 unit Given a drawn standard arrow held 0.6 m from a burning brazier for 30 ticks, when released, then the arrow carries burning; at 29 ticks, then it does not.
    • AC-4 integration Given a burning arrow that passes through a water volume, when it exits, then it no longer carries burning and ignites nothing on impact.
    • AC-5 manual Given a greybox room with a brazier and an oil-soaked rope bridge, when three fresh archer playtesters play, then at least one discovers dip-to-light unprompted within 5 minutes.

    Waits on

    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.9Water arrows douse fires, extinguish lights and wet surfacesblockedP1M2feature

    Description

    Why

    Dousing a torch from the shadows serves stealth, puzzles and fire-fighting through one property (multiple solutions).

    What

    As an archer, I want water arrows that shatter into a splash so that I can put out fires and lights and make surfaces wet.

    On impact the arrow shatters and applies wet in a 1.5 m radius and removes burning from anything inside it (torches, braziers, burning creatures). Extinguished light sources lower the local light level via e03-light-field. Wet surfaces then behave per element rules (e.g. conduct shock). Hitting extreme heat produces whatever e03 rules dictate (e.g. steam). Water arrows never stick.

    Scope

    • In: Water payload, extinguish, wet application
    • Out: Light-level recomputation (e03-light-field)
    • Out: Steam/conduction rules (e03-element-propagation)

    Notes

    Related: stealth group — dousing lights increases thief/archer concealment.

    Acceptance criteria

    • AC-1 integration Given any burning entity within 1.5 m of impact, when the water arrow shatters, then burning is removed from it that tick.
    • AC-2 integration Given a lit torch providing light, when extinguished by a water arrow, then the light level queried at the torch's position decreases.
    • AC-3 integration Given a wet floor and a shock source per e03 rules, when shock is applied, then conduction occurs across the wetted area (property-based, not arrow-specific).
    • AC-4 unit Given a water arrow, when it hits anything, then it never sticks and is not retrievable.

    Waits on

    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.10Rope arrows anchor into wood and create climbable ropesblockedP1M2feature

    Description

    Why

    Opening a vertical route with a rope arrow is the archer's answer to the locked tower (Classes change possibilities).

    What

    As an archer, I want to shoot a rope arrow into a wooden beam and climb it so that I can reach places others cannot.

    Rope arrows stick only into surfaces tagged softAnchor (the wood and earth material presets) whose normal is within 60° of horizontal or facing downward (beams, ceilings). On stone/metal they bounce off with sparks (readable hint). A hit spawns an 8 m rope entity hanging from the anchor, climbable via e02-player-controller climb hooks. Ropes are flammable (burning rope falls and drops climbers) and cuttable. Max 3 active ropes per area (oldest retracts).

    Scope

    • In: Anchor rule, rope spawn, climb hookup, rope properties, active cap, retrieval at anchor
    • Out: Climbing mechanics (e02-player-controller)
    • Out: Rope visuals (e29-arrow-fx)

    Notes

    Ropes persist while the area is loaded; persistence across saves is not required for MVP.

    Acceptance criteria

    • AC-1 integration Given a wooden beam overhead, when a rope arrow hits it, then an 8 m rope spawns and the player can climb to the beam.
    • AC-2 integration Given a stone wall, when a rope arrow hits it, then it bounces, no rope spawns and the arrow remains retrievable.
    • AC-3 integration Given a player climbing a rope, when the rope gains burning, then within 3 s it detaches and the player falls (environment fall rules apply).
    • AC-4 unit Given 3 active ropes, when a 4th is created, then the oldest retracts and returns a rope arrow at its anchor position.
    • AC-5 unit Given a wooden surface whose normal points 80° upward (a floor), when a rope arrow hits it, then no rope spawns.

    Waits on

    • mw-e02.2 Move the player with a deterministic third-person kinematic controller done
    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e03.22 Mark climbable surfaces and ledges from properties and geometry done
    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.11Noise arrows create sound events that lure creaturesblockedP1M2feature

    Description

    Why

    Luring a guard away with a rattling arrow is a clean, systemic distraction shared with the stealth model.

    What

    As an archer, I want a noise arrow that rattles where it lands so that I can pull creatures toward a spot.

    On impact it emits a noise event (loudness 70, duration 2 s) into e09-sound-propagation at the impact point; how creatures react is entirely their perception/AI. In water the loudness is ×0.3. Deals no damage (blunt head, 1 blunt).

    Scope

    • In: Noise payload emission, water muffling, positional cue event
    • Out: Noise propagation and creature reaction (stealth group)

    Notes

    Timing convention: sim runs at a fixed 60 Hz (1 tick = 16.67 ms, per e00-sim-core). All frame numbers are sim ticks; ms values are for readability only.

    Acceptance criteria

    • AC-1 integration Given a noise arrow impact, when resolved, then exactly one noise event of loudness 70 lasting 120 ticks is emitted at the impact position.
    • AC-2 integration Given impact inside a water volume, when resolved, then the noise event loudness is 21.
    • AC-3 integration Given a creature within hearing range per e09 rules, when the noise event propagates, then the creature receives it (reaction owned by AI; test asserts delivery only).
    • AC-4 unit Given a noise arrow hitting a creature, when resolved, then it deals ≤ 1 damage and causes no reaction beyond flinch rules.

    Waits on

    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.12Blunt arrows knock objects, press switches and stunblockedP1M2feature

    Description

    Why

    Non-lethal, physics-first arrows let the archer solve problems by shoving the world rather than killing it.

    What

    As an archer, I want blunt arrows that hit hard without sticking so that I can knock things over, press switches at range and stun unaware foes.

    Blunt damage, penetration 0, poise damage ×2.5, impactForceMul 2.5, never sticks (drops at impact; always retrievable unless it lands in a hazard). Applies impulse to physics objects (knock a bucket off a shelf). A head hit on an unaware creature whose schema allows knockout renders it unconscious for 60 s (non-lethal).

    Scope

    • In: Blunt behaviour, impulse, knockout rule
    • Out: Switch/mechanism triggering (e05-shoot-mechanisms)
    • Out: Unconscious state handling in AI (e11)

    Notes

    Timing convention: sim runs at a fixed 60 Hz (1 tick = 16.67 ms, per e00-sim-core). All frame numbers are sim ticks; ms values are for readability only.

    Acceptance criteria

    • AC-1 integration Given a 3 kg object on a shelf, when hit by a blunt arrow, then it receives an impulse and falls.
    • AC-2 unit Given an unaware creature with knockout: true, when hit in the head by a blunt arrow, then it becomes unconscious for 3600 ticks.
    • AC-3 unit Given an aware creature, when hit in the head by a blunt arrow, then it is not knocked out and takes blunt damage with ×2.5 poise damage.
    • AC-4 unit Given a blunt arrow impact on any surface, when resolved, then it does not stick and is retrievable at the impact point.

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    • mw-e05.6 Headshots, weak points and armored regions that deflect done
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.14Greybox archery range for tuning and e2e testsblockedP1M2feature

    Description

    Why

    Draw timing, drop and trick arrows need a fast, repeatable test space just as melee has the combat sandbox.

    What

    As a developer, I want an archery range scene so that I can tune ballistics and verify trick arrows quickly.

    Static targets at 10/20/40/60 m, targets on rails at 2/4/6 m/s, a 6 m elevated platform, an overhead wooden beam (rope anchor), a brazier, a shootable bell wired to a door, a cuttable rope holding a crate, a pool of water. Stats overlay: hit %, flight time, impact speed, focused-shot rate.

    Scope

    • In: Scene, fixtures, stats overlay, deterministic seed
    • Out: Final art for the range (none planned)

    Notes

    Lives alongside the combat sandbox under /dev/archery.

    Acceptance criteria

    • AC-1 e2e Given the range loaded in Chromium, when it boots, then all fixtures exist, no console errors occur and the overlay reads 0 shots.
    • AC-2 integration Given the rail targets, when 10 s elapse, then their positions match the deterministic schedule within 0.01 m.
    • AC-3 integration Given 10 scripted shots at the 20 m target, when complete, then the overlay hit % equals hits/shots from sim events.
    • AC-4 e2e Given the bell/door fixture, when an arrow hits the bell, then the door opens within 1 s.
    • AC-5 e2e Given the archery range in Chromium, when Playwright draws for 48 ticks and releases at the 20 m target, then the target registers a hit and no console errors occur. (Moved from mw-e05.3 AC-6 by owner decision 2026-10-02.)

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e04.9 Combat sandbox scene with dummy creatures and frame-data overlay done
    • mw-e05.21 Wire the bow and arrows into the game world with the aim camera done
    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    area:toolsclass:archerepic:e05milestone:m2
  • mw-e05.15Elevation grants archery damage and range advantageblockedP2M2feature

    Description

    Why

    High ground should matter to an archer: climbing a tower should change the fight (Archer fantasy: elevation).

    What

    As an archer, I want shooting from above to hit harder and reach farther so that seeking high ground is a real tactic.

    Range gain is natural from ballistics. Additionally: shooter at ≥ 3 m above target → +15% damage; ≥ 6 m → +25% (data-tunable). Implemented as an attacker-stage modifier in the damage pipeline tagged elevation.

    Scope

    • In: Elevation modifier, thresholds in data
    • Out: AI reaction to unreachable attackers (e11)

    Notes

    Related: AI group should give melee creatures a behaviour for unreachable archers (seek path, throw rocks, take cover).

    Acceptance criteria

    • AC-1 unit Given a shooter 4 m above the target, when a 20-pierce arrow hits, then 23 damage applies and the hit is tagged elevation.
    • AC-2 unit Given a shooter 2.9 m above, when an arrow hits, then no elevation bonus applies.
    • AC-3 unit Given a 30%-draw shot from 10 m height versus ground level, when simulated, then horizontal range increases by ≥ 20%.
    • AC-4 unit Given a shooter below the target, when an arrow hits, then no bonus or penalty applies.

    Waits on

    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.16Moving-target payoffs: leg stumbles, wing downs, lead assistblockedP2M2feature

    Description

    Why

    Hitting a running target should be hard and rewarding (Archer fantasy: moving targets).

    What

    As an archer, I want well-led shots on moving creatures to trip or ground them so that tracking a target is worth mastering.

    A limb (leg) hit on a creature moving > 3 m/s causes a stumble (60-tick knockdown for bipeds; quadrupeds slowed 50% for 3 s). A wing region hit on a flying creature grounds it for 4 s. Optional lead-indicator assist (off by default): shows the intercept point for the lock-on target from its velocity and arrow flight time (3-iteration solver).

    Scope

    • In: Moving-limb stumble rule, wing grounding, lead solver + indicator assist
    • Out: Flying locomotion (e12)

    Notes

    Timing convention: sim runs at a fixed 60 Hz (1 tick = 16.67 ms, per e00-sim-core). All frame numbers are sim ticks; ms values are for readability only.

    Acceptance criteria

    • AC-1 unit Given a biped moving at 4 m/s, when a leg region is hit, then it is knocked down for 60 ticks; moving at 2 m/s, then normal hit reactions apply.
    • AC-2 unit Given a flying creature, when its wing region is hit, then it is grounded for 240 ticks.
    • AC-3 unit Given a target moving at a constant 5 m/s at 30 m, when the lead solver runs, then its predicted intercept is within 0.3 m of the simulated arrow impact.
    • AC-4 unit Given the lead assist disabled (default), when locked on, then no indicator renders.

    Waits on

    • mw-e05.5 Deterministic aim sway, breath hold and bow reticle open
    • mw-e05.6 Headshots, weak points and armored regions that deflect done
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.17Archer mobility: quickstep while drawn and aerial shotsblockedP2M2feature

    Description

    Why

    The archer's fantasy is precision and movement; they should reposition without losing a draw.

    What

    As an archer, I want to sidestep while holding a draw and shoot mid-jump so that I can stay mobile under pressure.

    Quickstep: 12-tick sidestep with i-frames ticks 2–7, 15 stamina, retains up to 60% of current draw. Aerial shot: firing while airborne is allowed with +1.0° additional spread; draw progress continues in the air.

    Scope

    • In: Quickstep move, draw retention, aerial shot spread
    • Out: Knight roll (e04-dodge-iframes)

    Notes

    Timing convention: sim runs at a fixed 60 Hz (1 tick = 16.67 ms, per e00-sim-core). All frame numbers are sim ticks; ms values are for readability only.

    Acceptance criteria

    • AC-1 unit Given full draw, when quickstep executes, then draw fraction after it is 0.6 and i-frames cover ticks 2–7.
    • AC-2 unit Given 40% draw, when quickstep executes, then draw fraction remains 0.4 (retention caps at 60%, never increases).
    • AC-3 unit Given the player airborne, when an arrow is released, then its spread includes +1.0°.
    • AC-4 manual Given the range with rail targets, when three playtesters use quickstep, then median rating for "I feel mobile as an archer" is ≥ 4/5.

    Waits on

    • mw-e04.8 Dodge roll and backstep with invulnerability frames done
    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    area:simclass:archerepic:e05milestone:m2
  • mw-e05.20Creature projectile attacks fly as ballistic arrows and meet level geometryopenP2M2task

    Description

    Why

    Creature projectiles (mw-e12.5) fly in straight lines and pass through walls (the executor says level geometry does not stop them yet), while arrows (mw-e05.2) arc, collide with the level and use region-tagged hurtboxes. Two projectile models drift apart; a skeleton archer's arrow should behave like the player's.

    What

    Route projectile attacks through the arrow system: the attack's projectile data names an arrow content id (or a drag-free projectile body), runActive looses it with fireArrow (shooter = attacker), and hits go through the hurtbox query and CollisionWorld like any arrow. Keep AttackProjectileLaunched/AttackHit for AI and cues. Retire the straight-line projectileSystem once no content uses it.

    Scope

    • In: executor projectile launch via fireArrow, attack schema field, migration of shipped projectile attacks, tests.
    • Out: creature bow animation, AI aiming with lead.

    Discovered from mw-e05.2.

    Acceptance criteria

    • AC-1 unit Given a creature projectile attack at a target behind a wall, when fired, then the projectile stops at the wall and deals no damage.
    • AC-2 unit Given a projectile attack at a target in range, when it hits, then AttackHit is emitted with the damage results of the struck hurtbox's region.
    • AC-3 integration Given the creature attack replays, when re-recorded, then only content hashes change or the change is explained.

    Waits on

    • mw-e05.2 Deterministic arrow ballistics with gravity, drag and sticking done
    area:simclass:archerepic:e05milestone:m2

Post-MVP 1

  • mw-e05.18Extended trick arrows as pure data: frost, shock, smokeblockedP3post-MVPfeature

    Description

    Why

    Proves the systemic promise: new arrows need data, not code, and immediately interact with existing world properties.

    What

    As a designer, I want to add frost, shock and smoke arrows purely in data so that the arrow roster grows without engineering.

    Frost applies frozen (e.g. water surfaces become walkable ice per e03 rules); shock applies electrified (conducts through wet/conductive); smoke spawns a vision-blocking volume. No new sim code beyond what payload types already support.

    Scope

    • In: Three arrow data entries, tests exercising each
    • Out: New payload primitives (would need a separate engineering bead)

    Notes

    If any arrow needs code, split that capability into its own bead first.

    Acceptance criteria

    • AC-1 content Given the three new arrow entries, when validated, then they pass with no schema changes.
    • AC-2 integration Given a water surface, when a frost arrow impacts it, then it gains frozen per e03 rules.
    • AC-3 integration Given a smoke arrow impact, when resolved, then a vision-blocking volume exists for its declared duration and blocks sight queries through it.
    • AC-4 unit Given the change set for this bead, when reviewed, then no files under src/sim are modified (asserted by a CI path check on the PR).

    Waits on

    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e05.1 Data schema for arrow types and property-based payloads done
    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    area:contentclass:archerepic:e05milestone:post-mvp
E06Magic FrameworkA data-driven spell architecture where every spell is a content file composed of a delivery (self, projectile, AoE, beam, touch, summon point) and a list of effect operations (damage, world-property stimulus, force, status, summon, transform, displace). Spells never script pairwise interactions: they emit world stimuli (heat, cold, force, light, moisture, charge, life, decay, sound) into the systemic engine (E03), which resolves outcomes through object properties. Casting has a mana resource, cast times, channeling, interruption and botched casts that create new situations.14/25 done · 56%

M2 Class fantasies 11

  • mw-e06.7Deliver spells as AoE volumes, cones and reflecting beamsopenP1M2feature

    Description

    Why

    Battlefield manipulation needs areas, cones and beams, and beams that reflect enable light puzzles (puzzle constitution).

    What

    As a sorcerer, I want sphere, cone, line/wall and ground-decal volumes plus continuous beams so that shockwaves, fire walls and light rays are all data.

    Volumes: instant or persistent with tick rate, falloff curve, line-of-sight check option. Beams: raycast each tick, length, width, reflect off objects tagged reflective up to N bounces, blocked by opaque solids.

    Scope

    • In: volume shapes, persistence, tick, falloff, LOS option; beam raycast, reflection, max bounces
    • Out: stimulus semantics (e06-world-stimulus-emitters)
    • Out: specific spells (mw-e08)

    Notes

    Beam reflection uses the reflective property only — any mirror, polished shield or ice surface tagged reflective works.

    Acceptance criteria

    • AC-1 unit Given a 4 m sphere with linear falloff, when targets stand at 0, 2 and 4.1 m, then they receive 100%, 50% and 0% magnitude.
    • AC-2 unit Given a 60° cone of range 6 m, when a target is at 35° off-axis, then it is not affected; at 25°, it is.
    • AC-3 unit Given a persistent volume with tick 500 ms and duration 3 s, when it expires, then exactly 6 ticks were applied.
    • AC-4 unit Given a beam hitting an object tagged reflective, when maxBounces=2, then the beam reflects by the surface normal and stops after the second reflection.
    • AC-5 unit Given an AoE with requiresLOS, when a target is fully behind an opaque wall, then it receives no effect.
    • AC-6 perf Given 8 persistent volumes and 4 beams active in the stress scene, when simulated, then magic sim cost p95 ≤ 1.0 ms per tick on the reference machine.

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e06.2 Run data-driven spells through a cast→deliver→effect pipeline done
    area:simclass:sorcererepic:e06milestone:m2
  • mw-e06.10Summon temporary creatures and objects with allegiance and capsopenP1M2feature

    Description

    Why

    Summoning (Animate Bones, Mirror Self decoys, conjured objects) is a qualitatively different verb from damage.

    What

    As a sorcerer, I want summon ops that spawn a creature or object archetype for a duration, optionally consuming nearby world material, so that summons feel grounded in the world.

    Parameters: archetype id (from creature schema), duration, allegiance (caster/neutral), maxActive per caster, requiresMaterial {property tag, radius, count} (e.g. remains), on-expire ops, command hooks (follow/stay/attack).

    Scope

    • In: summon op, material consumption by property tag, lifetime, cap enforcement (oldest dismissed), allegiance faction assignment
    • Out: summon AI behaviours (E11/E12 — Related: follow/guard behaviours)
    • Out: specific summons (mw-e08)

    Notes

    Material requirement uses property tags such as remains, not specific corpse ids.

    Acceptance criteria

    • AC-1 unit Given maxActive=2 and two active summons, when a third is summoned, then the oldest is dismissed with its on-expire ops and the new one spawns.
    • AC-2 unit Given requiresMaterial {tag: remains, radius: 6, count: 1} and no remains within 6 m, when cast, then the cast fails with reason "no-material", emits a SpellFizzled event and refunds 100% mana.
    • AC-3 unit Given remains within range, when the summon succeeds, then the consumed remains entity is removed and the summon spawns at its position.
    • AC-4 unit Given duration 30 s, when 30 s pass, then the summon is removed and on-expire ops apply at its location.
    • AC-5 integration Given a summon with allegiance caster, when hostile creatures perceive it, then they treat it as hostile per faction rules.

    Waits on

    • mw-e06.2 Run data-driven spells through a cast→deliver→effect pipeline done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    area:simclass:sorcererepic:e06milestone:m2
  • mw-e06.11Temporarily transform creatures into other archetypes and backopenP1M2feature

    Description

    Why

    Polymorph-style effects are iconic "wait, I can do that?" magic and must restore state safely.

    What

    As a sorcerer, I want a transform op that swaps a creature's archetype (body, senses, attacks, properties) for a duration and restores it exactly so that turning a guard into a chicken is safe and systemic.

    Preserves identity, health ratio, inventory, quest/dialogue state, alert memory; the new form uses its own senses/locomotion/properties (a transformed creature that is now flammable burns).

    Scope

    • In: transform op, snapshot/restore, health ratio mapping, size-safe restore (find free space), resist rules via creature tags
    • Out: player self-transformation (post-MVP, Related: future spell)
    • Out: specific forms (mw-e08 Polymorph)

    Notes

    Restore must handle the form being killed (original dies? or reverts with 1 HP — configurable per spell) and not enough space to restore (push to nearest free space).

    Acceptance criteria

    • AC-1 unit Given a creature at 60% health transformed into a form with different max HP, when transformed and restored, then health ratio is 60% in both forms (minus damage taken).
    • AC-2 unit Given a transformed creature, when the duration ends, then inventory, faction, dialogue flags and identity id are byte-identical to the pre-transform snapshot.
    • AC-3 unit Given a creature tagged immune-transform, when targeted, then the op fails with reason "resisted" and emits SpellResisted.
    • AC-4 unit Given the transformed form is killed and the spell sets onFormDeath=revert, when killed, then the original reverts with 1 HP and a stagger status.
    • AC-5 unit Given insufficient space to restore a large creature, when reverting, then it is placed at the nearest free position within 3 m, or the revert is deferred until space exists.
    • AC-6 integration Given a save made while a creature is transformed, when loaded, then the transform remaining duration and snapshot restore correctly.

    Waits on

    • mw-e06.9 Apply buffs, debuffs and statuses with stacking and dispel done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e30.1 Define versioned save format with section registry and migrations done
    area:simclass:sorcererepic:e06milestone:m2
  • mw-e06.12Teleport and swap positions with collision-safe placementopenP1M2feature

    Description

    Why

    Teleportation opens traversal routes (classes change possibilities) and must never put the player inside walls.

    What

    As a sorcerer, I want displace ops (teleport-to-point, swap-with-target, short dash) with safe placement so that Blink-like spells are reliable and exploitable.

    Validates destination: capsule fits, not inside solid geometry, optional line-of-sight requirement, ledge/floor snapping, falls through if no floor (story!).

    Scope

    • In: displace op handler, capsule fit test, LOS option, nearest-valid fallback search, swap semantics
    • Out: specific spells (mw-e08 Blink)

    Notes

    Teleporting over a chasm with no floor intentionally drops the caster — failure creates stories.

    Acceptance criteria

    • AC-1 unit Given a teleport target inside a wall, when resolved, then the caster lands at the nearest valid point along the aim ray before the wall, never inside geometry (1000 seeded fuzz trials).
    • AC-2 unit Given requiresLOS and a target point behind a closed door, when cast, then it fails with reason "no-line-of-sight".
    • AC-3 unit Given a swap-with-target op on a creature too large to fit at the caster's position, when cast, then the swap is rejected with reason "no-space" and mana is refunded.
    • AC-4 unit Given a teleport destination with no floor within 1 m, when cast, then the caster arrives at the destination and begins falling.

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e06.2 Run data-driven spells through a cast→deliver→effect pipeline done
    area:simclass:sorcererepic:e06milestone:m2
  • mw-e06.13Resolve botched casts into data-driven miscast outcomesopenP1M2feature

    Description

    Why

    Failure creates stories: a botched spell should produce a new situation (smoke, a wild blink, a sudden frost) instead of a dull "fizzle".

    What

    As a sorcerer, I want interrupted, over-cast or poorly-understood spells to sometimes misfire in school-flavoured ways so that mistakes are memorable.

    Miscast triggers: over-cast (mana deficit), late interruption, low comprehension (from E07), casting while a status like drenched/charged conflicts. A weighted miscast table per school (and optional per spell) picks outcomes composed from existing ops: backfire on self at reduced magnitude, random-direction delivery, harmless cosmetic, loud noise event, stimulus burst at caster (e.g. frost puddle, smoke).

    Scope

    • In: miscast request handling, severity calculation, weighted tables in content, seeded selection, MiscastOccurred event
    • Out: comprehension model (e07-comprehension-study)
    • Out: VFX for miscasts (placeholder cue per school)

    Notes

    Miscast outcomes must never softlock or instakill: cap self-damage at 25% max HP. Every outcome reuses existing ops so miscasts interact with the world too (a fire miscast can ignite the bookshelf you are standing next to).

    Acceptance criteria

    • AC-1 unit Given a miscast request with severity 0.1, when resolved with a fixed seed, then the outcome is drawn from the table's low-severity band and is deterministic across runs.
    • AC-2 unit Given any miscast outcome, when applied to a caster at full HP, then self-damage never exceeds 25% max HP (property test over all tables).
    • AC-3 integration Given a Fire-school miscast producing a heat burst at the caster, when a flammable object is within the burst radius, then it ignites via E03 rules.
    • AC-4 content Given a miscast table whose weights sum to 0 or referencing an unknown op, when validated, then validation fails.
    • AC-5 unit Given a miscast outcome "loud", when applied, then a noise event of the configured loudness is emitted for stealth/AI.
    • AC-6 manual Given a playtest of 20 deliberate over-casts, when observed, then at least 3 distinct outcome types occur and testers describe them as funny or interesting rather than punishing.

    Waits on

    • mw-e06.3 Track mana pool, regeneration and spell costs done
    • mw-e06.4 Support cast times, channeling, cooldowns and interruption done
    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    area:simclass:sorcererepic:e06milestone:m2
  • mw-e06.17Bind spell events to placeholder VFX and SFX cuesopenP1M2feature

    Description

    Why

    Magic must look and sound magical even in grey-box; placeholders unblock gameplay until the art pass (gameplay is never blocked by final art).

    What

    As a developer, I want spell events (wind-up, release, travel, impact, persistent, miscast) to trigger named VFX and SFX cues so that swapping placeholders for final assets is a data change.

    Cue registry maps cue id → placeholder effect (coloured particles per school, primitive meshes) and placeholder sound; missing cue logs a warning and plays a school default.

    Scope

    • In: cue registry, event→cue binding in src/game, school-coloured placeholder particle presets, placeholder SFX hooks
    • Out: final VFX (E29 asset beads)
    • Out: final SFX (E28/E38 asset beads)

    Notes

    Cue naming follows asset ID convention: vfx-spell-<spell>-<phase>, sfx-spell-<spell>-<phase>.

    Acceptance criteria

    • AC-1 integration Given a spell impact event with vfxCue "vfx-spell-ember-impact", when emitted, then the VFX system receives a spawn request for that cue at the impact position.
    • AC-2 integration Given a cue id with no registered asset, when triggered, then the school default placeholder plays and one warning is logged per cue id (not per trigger).
    • AC-3 content Given every spell in the catalogue, when validated, then each referenced cue id matches the naming convention.
    • AC-4 e2e Given the greybox testbed, when every catalogue spell is cast in sequence, then no console errors occur and a screenshot sanity check detects non-background pixels at each impact.

    Waits on

    • mw-e06.2 Run data-driven spells through a cast→deliver→effect pipeline done
    • mw-e28.1 Web Audio engine: registry, buses, voice pool, positional audio done
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.10 Spell VFX slots and templates for the spell pipeline done
    area:gameclass:sorcererepic:e06milestone:m2
  • mw-e06.18Persist mana, cooldowns and active spell effects in savesblockedP1M2task

    Description

    Why

    Save-game stability is a technical pillar; a fire wall or summon must survive save/load exactly.

    What

    Serialize mana, cooldowns, in-progress channel state (cancelled on load), persistent volumes, summons and statuses into the versioned save format with round-trip and migration tests.

    Scope

    • In: magic save section, round-trip tests, migration test scaffold
    • Out: known spells and study progress (e07-learning-save-state)
    • Out: transform snapshots (e06-transformation-framework)

    Notes

    In-flight projectiles are dropped on save (documented) unless trivial to keep.

    Acceptance criteria

    • AC-1 unit Given a sim with 2 persistent volumes, 1 summon and 3 statuses, when saved and loaded, then state hashes of the magic subsystem match.
    • AC-2 unit Given a save while channeling, when loaded, then the channel is cancelled and no mana is lost beyond ticks already applied.
    • AC-3 unit Given a save from magic schema v1, when loaded by v2 code, then the migration test passes.

    Waits on

    • mw-e06.10 Summon temporary creatures and objects with allegiance and caps open
    • mw-e06.9 Apply buffs, debuffs and statuses with stacking and dispel done
    • mw-e30.1 Define versioned save format with section registry and migrations done
    area:simclass:sorcererepic:e06milestone:m2
  • mw-e06.22Prove spell cold freezes wet and waterSurface things (split from mw-e06.5 AC-2)openP1M2task

    Description

    Split from mw-e06.5 (its AC-2) because the freeze rule is mw-e03.7, not yet built. Once e03.7 lands, add the integration test through the spell pipeline.

    Acceptance criteria

    AC-1 integration Given any wet or waterSurface tile inside a spell cold stimulus >= its freeze threshold, when applied, then it gains the frozen property for the stimulus duration plus melt time. Generic property-tagged fixtures only (no named props).

    Waits on

    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    area:simclass:sorcererepic:e06milestone:m2
  • mw-e06.23Prove spell charge conducts through connected conductive and wet objects (split from mw-e06.5 AC-3)openP1M2task

    Description

    Split from mw-e06.5 (its AC-3) because conduction is mw-e03.8, not yet built. Once e03.8 lands, add the integration test through the spell pipeline.

    Acceptance criteria

    AC-1 integration Given a spell charge stimulus hitting a conductive object that touches other conductive or wet objects, when applied, then charge propagates to the connected objects per E03 rules. Generic property-tagged fixtures only.

    Waits on

    • mw-e03.8 Conduct electrical charge through conductive and wet objects done
    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    area:simclass:sorcererepic:e06milestone:m2
  • mw-e06.19Let creatures and NPCs cast catalogue spells through the same pipelineopenP2M2feature

    Description

    Why

    Enemy mages should obey the same rules as the player so that interrupts, miscasts and world interactions apply to them too.

    What

    As a designer, I want creature definitions to list spells with usage hints so that goblin shamans and liches cast via the standard pipeline.

    Exposes a cast-request API for AI; creature mana optional; AI can be interrupted and miscast.

    Scope

    • In: creature schema extension for spells (via E12 hooks), AI cast API, tests
    • Out: AI decision-making about when to cast (E11 — Related: combat behaviours)

    Notes

    Player-learnable spells dropped as books by enemy casters is handled in e07-book-acquisition-hooks.

    Acceptance criteria

    • AC-1 unit Given a creature with a fixture projectile spell, when AI requests a cast at a target, then the pipeline processes it identically to a player cast (same events).
    • AC-2 unit Given a creature caster hit hard during wind-up, when poise breaks, then its cast is interrupted.
    • AC-3 content Given a creature referencing an unknown spell id, when validated, then validation fails.

    Waits on

    • mw-e06.4 Support cast times, channeling, cooldowns and interruption done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    area:simclass:sorcererepic:e06milestone:m2
  • mw-e06.20Add magic debug commands and stimulus visualisationopenP2M2task

    Description

    Why

    Fast content creation needs designers to grant spells, ignore mana and see stimuli while testing combinations.

    What

    Debug console commands: spell.grant <id|all>, spell.infiniteMana, spell.noCooldown, spell.forceMiscast <table>, spell.reload (hot-reload spell JSON); overlay drawing active stimulus volumes, beams and summon lifetimes.

    Scope

    • In: console commands, hot reload of spell content in dev builds, debug overlay
    • Out: general console (e33-debug-console)

    Notes

    Hot reload re-validates; invalid file keeps the previous version and prints errors.

    Acceptance criteria

    • AC-1 integration Given the debug console, when "spell.grant all" runs, then every catalogue spell is known and assignable.
    • AC-2 integration Given a spell file edited with an invalid value, when hot-reloaded, then the previous definition remains active and the validation error is printed.
    • AC-3 integration Given spell.infiniteMana on, when casting 100 spells, then mana never decreases.

    Waits on

    • mw-e06.2 Run data-driven spells through a cast→deliver→effect pipeline done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsclass:sorcererepic:e06milestone:m2
E07Spellbook & Magical LearningSpells are discovered through books, shops, exploration, quests, secrets and experimentation rather than appearing on level-up. Books are inventory items with language, condition, comprehension difficulty and legality; reading and study teach spells; damaged, untranslated and forbidden books create side-goals; experimentation with the world reveals new verbs. Progression unlocks new verbs (Firebolt → Flame Jet → Fire Wall), never +% tiers.3/13 done · 23%

M2 Class fantasies 10

  • mw-e07.3Model comprehension so hard books teach unstable spells firstblockedP1M2feature

    Description

    Why

    Difficult books should be a challenge, not a lock; casting a half-understood spell is a botched-cast story generator.

    What

    As a sorcerer, I want difficult books to be learnable early at low comprehension so that I can cast advanced spells unreliably until I understand them.

    Comprehension = f(book difficulty, related known spells in same school, insights, reference books owned). Below threshold 1.0 the spell is "unstable": miscast chance scales with (1 − comprehension). Re-study or related learning raises comprehension.

    Scope

    • In: comprehension formula in data, unstable spell state, miscast chance hook into e06-botched-casts, UI-facing values
    • Out: miscast outcomes (e06-botched-casts)

    Notes

    Anti-grind: comprehension rises from knowledge (books, insights, related spells), not from casting count alone.

    Acceptance criteria

    • AC-1 unit Given difficulty 0.8 and no related knowledge, when learned, then comprehension is 0.2 and the spell is flagged unstable.
    • AC-2 unit Given comprehension 0.2, when cast 1000 times with a seeded RNG, then miscast rate is 80% ± 3%.
    • AC-3 unit Given the player learns two more spells of the same school, when comprehension is recomputed, then it increases by the configured per-related-spell bonus and caps at 1.0.
    • AC-4 unit Given comprehension reaches 1.0, when computed, then the unstable flag clears and no comprehension miscasts occur.
    • AC-5 content Given a comprehension config with negative bonuses, when validated, then validation fails.

    Waits on

    • mw-e06.13 Resolve botched casts into data-driven miscast outcomes open
    • mw-e07.2 Learn spells by reading and studying book items done
    area:simclass:sorcererepic:e07milestone:m2
  • mw-e07.6Give forbidden books social risk and whispering side effectsopenP1M2feature

    Description

    Why

    Forbidden knowledge is tempting; carrying or reading it should create risk and stories rather than a simple lock.

    What

    As a sorcerer, I want forbidden books to teach powerful spells at a social cost so that I decide whether to be seen with them.

    Forbidden books are contraband: guards/NPCs who perceive the player reading or openly casting forbidden-school spells react (disposition drop, confiscation attempt, alert). Some carry "whispers" side effects (noise events at night, attracting certain creatures).

    Scope

    • In: legality flag handling, witness detection via perception hooks, disposition/world-state consequences, whisper effect
    • Out: guard dialogue content (E22/E24)
    • Out: buying/selling forbidden stock (e21-stolen-forbidden-stock)

    Notes

    Necromancy school spells (e.g. Animate Bones) come from forbidden books in the MVP.

    Integration note: Promoted — Animate Bones (P1/m2) is taught by a forbidden book.

    Acceptance criteria

    • AC-1 integration Given an NPC with a lawful disposition that perceives the player reading a forbidden book, when perception succeeds, then a ContrabandWitnessed event fires and the NPC's disposition drops by the configured amount.
    • AC-2 integration Given no witness has line of sight, when the player reads a forbidden book, then no consequence fires.
    • AC-3 unit Given a book with whispers, when carried in inventory between 22:00 and 04:00 in-game, then a quiet noise event is emitted every 60 s at the player position.
    • AC-4 unit Given a book dropped or stashed, when whispers would emit, then they emit at the book's location instead.
    • AC-5 unit Given a forbidden spell learned, when cast unseen, then no ContrabandWitnessed event fires.

    Waits on

    • mw-e07.2 Learn spells by reading and studying book items done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    area:simclass:sorcererepic:e07milestone:m2
  • mw-e07.7Discover spell insights and variants through world experimentationopenP1M2feature

    Description

    Why

    "Wait… I can do that?" — some magic should be discovered by experimenting, not bought.

    What

    As a sorcerer, I want casting my spells in unusual world situations to occasionally reveal an insight so that experimentation teaches new verbs.

    Insight rules are data: trigger = (spell-sourced stimulus type, target property/state, optional second stimulus) observed by the sim; reward = new spell, spell variant, or comprehension boost. Example rules (property-based): cold stimulus on a water surface → insight "ice bridge" (unlocks Frostglass surface variant); force stimulus on a burning object → insight "flung flame".

    Scope

    • In: insight rule schema, observer on stimulus-resolution events, one-time unlocks, InsightDiscovered event + journal entry
    • Out: the unlocked spells themselves (mw-e08)

    Notes

    Rules may only reference stimulus types and property tags, never object or spell ids for triggers (validator enforces).

    Acceptance criteria

    • AC-1 unit Given an insight rule {stimulus: cold, targetProperty: waterSurface}, when a player-sourced cold stimulus freezes any water surface, then InsightDiscovered fires once and the reward is granted.
    • AC-2 unit Given the same condition caused by a non-player source (a frost trap), when resolved, then no insight fires.
    • AC-3 unit Given an insight already discovered, when its trigger recurs, then nothing is granted again.
    • AC-4 content Given an insight rule whose trigger references an object id, when validated, then validation fails ("triggers must use properties").
    • AC-5 integration Given a save after discovering an insight, when loaded, then the insight remains discovered.

    Waits on

    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    • mw-e07.2 Learn spells by reading and studying book items done
    area:simclass:sorcererepic:e07milestone:m2
  • mw-e07.8Unlock follow-on spell verbs through mastery and advanced booksblockedP1M2feature

    Description

    Why

    The anti-grind rule: progression unlocks new verbs (Firebolt → Flame Jet → Fire Wall), not +12% tiers.

    What

    As a sorcerer, I want mastering a spell to open its next verb, learnable by study, insight or advanced book, so that growth changes what I can do.

    Verb chain data: spell.next[] with unlock requirements (comprehension 1.0, N meaningful uses — e.g. hits on distinct target types, an insight, or owning an advanced book). A content validator rejects chain steps that differ only numerically from their predecessor (same delivery + same op types).

    Scope

    • In: verb chain data, unlock evaluation, integration with e19 progression model, anti-grind validator
    • Out: specific chains (mw-e08: Ember/Firebolt/Flame Jet/Fire Wall, Mage Hand → Telekinetic Throw & Catch)

    Notes

    "Meaningful uses" counts distinct contexts (distinct property tags affected), not raw cast count.

    Acceptance criteria

    • AC-1 unit Given Firebolt with next Flame Jet requiring comprehension 1.0 and 5 distinct affected property tags, when both are met, then Flame Jet becomes studyable and a VerbUnlocked event fires.
    • AC-2 unit Given 50 casts affecting only 1 property tag, when evaluated, then Flame Jet remains locked.
    • AC-3 content Given a chain step with the same delivery and op types as its predecessor differing only in magnitudes, when validated, then validation fails with "numeric-only progression".
    • AC-4 unit Given an advanced book that teaches a chain step directly, when studied before requirements are met, then the spell is learned but unstable (comprehension ≤ 0.5).
    • AC-5 integration Given the e19 progression model, when a verb unlocks, then it is recorded as a capability unlock.

    Waits on

    • mw-e07.3 Model comprehension so hard books teach unstable spells first open
    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    area:simclass:sorcererepic:e07milestone:m2
  • mw-e07.9Read books in a page-turning reader with a study actionopenP1M2feature

    Description

    Why

    Books are the sorcerer's core reward; reading one should feel like opening a treasure, not a tooltip.

    What

    As a sorcerer, I want to open a book into a two-page reader showing lore, diagrams and a Study button with time estimate so that reading is a moment.

    Shows garbled text for unknown language, torn-page placeholders for missing pages, forbidden warning, comprehension estimate, "already known" state.

    Scope

    • In: reader UI, study action with time estimate, placeholder parchment/page art, keyboard + gamepad navigation, text scaling via settings
    • Out: final book/parchment art (asset prompt beads)

    Notes

    Honour E31 text sizing and dyslexia-friendly font option if available.

    Acceptance criteria

    • AC-1 integration Given a book with 6 pages, when opened, then pages 1–2 show and next/prev keys navigate in pairs without going past the last page.
    • AC-2 integration Given a damaged book, when a missing page is shown, then a torn-page placeholder renders with the text "Pages missing".
    • AC-3 integration Given the Study button, when pressed, then the displayed estimate matches the sim's computed remaining study minutes.
    • AC-4 integration Given the player is in combat (Alerted/Combat nearby), when Study is pressed, then it is disabled with a tooltip reason.
    • AC-5 e2e Given the greybox testbed, when a fixture book is opened and closed with the keyboard, then no console errors occur.

    Waits on

    • mw-e00.23 Build HUD/menu UI layer, component kit, focus nav and UI test harness done
    • mw-e07.2 Learn spells by reading and studying book items done
    area:uiclass:sorcererepic:e07milestone:m2
  • mw-e07.10Browse known spells, insights and verb chains in the grimoireopenP1M2feature

    Description

    Why

    The grimoire is the sorcerer's trophy case and planning tool — seeing locked next verbs motivates exploration.

    What

    As a sorcerer, I want a grimoire listing known spells by school with description, cost, comprehension, world interactions discovered and next verbs (silhouetted if locked) so that I plan experiments and hotbar loadouts.

    Drag spell to hotbar; filter by school; insights journal page; "rumoured spells" section fed by NPC rumour hooks.

    Scope

    • In: grimoire UI, school tabs, drag-to-hotbar, insight journal page, locked-verb silhouettes, rumoured spells list
    • Out: hotbar (e06-spell-hotbar-ui)
    • Out: final grimoire art (asset prompt beads)

    Notes

    "World interactions discovered" lists property tags the player has personally affected with that spell — reinforcing the systemic model.

    Acceptance criteria

    • AC-1 integration Given 5 known spells across 3 schools, when the grimoire opens on the Fire tab, then only Fire spells are listed.
    • AC-2 integration Given a spell with a locked next verb, when viewed, then the next verb shows as a silhouette with its unlock requirement text.
    • AC-3 integration Given a spell dragged onto hotbar slot 4, when dropped, then slot 4 holds that spell.
    • AC-4 integration Given no known spells (non-sorcerer start), when opened, then an empty state is shown without errors.
    • AC-5 integration Given the player ignited 3 distinct property-tagged objects with Ember, when viewing Ember, then those 3 property tags are listed as discovered interactions.

    Waits on

    • mw-e06.16 Select spells from a hotbar and quick-select wheel with mana HUD done
    • mw-e07.2 Learn spells by reading and studying book items done
    area:uiclass:sorcererepic:e07milestone:m2
  • mw-e07.11Find books on bookshelves, enemies and as rewardsopenP1M2feature

    Description

    Why

    The world rewards curiosity: bookshelves can contain books, and casters carry the books they learned from.

    What

    As a sorcerer, I want to search bookshelves, loot books from enemy casters and receive books from quests or characters so that books come from everywhere, not just shops.

    Bookshelf-tagged objects have searchable loot tables (mostly mundane lore, occasional spell book); creature casters optionally drop a book for one of their spells; quest/dialogue reward actions can grant books.

    Scope

    • In: bookshelf search interaction, book entries in loot tables, caster book drop rule, grant-book action for quest/dialogue
    • Out: specific placements (E24–E26 world content)
    • Out: shops (mw-e21)

    Notes

    Searching a bookshelf takes 2 s and makes a quiet noise (thief interplay).

    Acceptance criteria

    • AC-1 integration Given a bookshelf-tagged object with a loot table containing a spell book, when searched with a fixed seed, then the book is added to inventory and the shelf becomes "searched" in world state.
    • AC-2 integration Given a searched bookshelf, when searched again, then nothing new is granted.
    • AC-3 unit Given a creature caster with dropsSpellBook=true, when killed, then its loot contains a book teaching one of its spells.
    • AC-4 integration Given a dialogue/quest action grantBook, when executed, then the book is added to inventory.
    • AC-5 unit Given a full inventory (if capacity limits exist), when a book is found, then it is placed on the ground at the player position rather than lost.

    Waits on

    • mw-e02.5 Focus and interact with world objects via contextual prompts done
    • mw-e07.1 Define book item schema: spell, language, condition, legality done
    • mw-e18.1 Implement loot table schema and deterministic seeded roller done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    area:simclass:sorcererepic:e07milestone:m2
  • mw-e07.12Persist known spells, study progress, languages and insightsopenP1M2task

    Description

    Why

    Losing a learned spell to a save bug would betray the core sorcerer reward loop.

    What

    Serialize known spells + comprehension, per-book study progress, known languages, discovered insights, verb unlock counters into the versioned save with round-trip and migration tests.

    Scope

    • In: learning save section, round-trip tests, migration scaffold
    • Out: inventory contents (E17/E30)

    Notes

    Unknown spell ids in a save (content removed) are dropped with a warning, not a crash.

    Acceptance criteria

    • AC-1 unit Given 4 known spells, 2 in-progress studies, 1 language and 2 insights, when saved and loaded, then all values are identical.
    • AC-2 unit Given a save referencing a spell id no longer in content, when loaded, then the spell is dropped, a warning is logged and load succeeds.
    • AC-3 unit Given a v1 learning save, when loaded by v2, then the migration test passes.

    Waits on

    • mw-e07.2 Learn spells by reading and studying book items done
    • mw-e30.1 Define versioned save format with section registry and migrations done
    area:simclass:sorcererepic:e07milestone:m2
  • mw-e07.4Restore damaged books by finding their missing pagesblockedP2M2feature

    Description

    Why

    Damaged books turn a spell into an exploration hook: the rest of the pages are somewhere in the monastery.

    What

    As a sorcerer, I want a damaged book to teach a partial version of its spell and point me towards missing pages so that finding pages completes it.

    Missing pages are separate page items (loot) linked by bookId; a damaged book teaches nothing, lore-only, or an unstable variant as configured; combining pages restores the book.

    Scope

    • In: page items, combine action, partial-teach behaviour, restoration event
    • Out: placement of pages in the world (E24–E26 content)

    Notes

    Missing page text may hint at location (Related: world-content group authors hints).

    Acceptance criteria

    • AC-1 unit Given a damaged book missing pages 3 and 7 configured partialTeach=unstable, when studied, then the spell is learned with comprehension capped at 0.5.
    • AC-2 unit Given the player holds both missing page items, when combining, then the book becomes intact, the page items are consumed and the comprehension cap lifts.
    • AC-3 unit Given the player holds only page 3, when combining, then the book remains damaged with only page 7 missing.
    • AC-4 content Given a page item referencing a book that is not damaged, when validated, then validation fails.

    Waits on

    • mw-e07.3 Model comprehension so hard books teach unstable spells first open
    area:simclass:sorcererepic:e07milestone:m2
  • mw-e07.5Translate books written in unknown languagesopenP2M2feature

    Description

    Why

    Untranslated books create quests and reasons to talk to scholars and find lexicons — curiosity rewarded.

    What

    As a sorcerer, I want books in unknown languages to be unreadable until I obtain a lexicon or a translation so that decoding knowledge feels earned.

    Languages are data; the player knows languages via lexicon items or NPC translation service (dialogue action); partially known languages show garbled text proportional to knowledge.

    Scope

    • In: language registry, known-language state, lexicon items, translate action hook for dialogue, garbled text renderer data
    • Out: NPC translator dialogue content (E22/E24)

    Notes

    Garbling is deterministic per book + knowledge level so the same text appears on re-read.

    Acceptance criteria

    • AC-1 unit Given a book in "Old Tessic" and no knowledge, when read, then study is disabled with reason "language" and pages render garbled.
    • AC-2 unit Given the player acquires the Old Tessic lexicon item, when reading, then the book is studyable.
    • AC-3 unit Given 50% language knowledge, when rendering page text, then the same deterministic ~50% of words are garbled on every read.
    • AC-4 integration Given a dialogue action "translate book X", when executed, then the book gains a translated flag and is studyable regardless of language knowledge.

    Waits on

    • mw-e07.2 Learn spells by reading and studying book items done
    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    area:simclass:sorcererepic:e07milestone:m2
E08Spell CatalogueAn MVP library of ~20 spells across Fire, Frost, Storm, Arcane, Illusion, Alteration, Conjuration, Necromancy, Nature, Light, Shadow, Gravity and Time, emphasising qualitatively different effects: ignition, freezing, force, telekinesis, teleportation, decoys, restraint, summoning, gravity, transformation, light, darkness, water and time. Every spell interacts with the world only through properties and stimuli, and ridiculous combinations are encouraged.3/25 done · 12%

M2 Class fantasies 22

  • mw-e08.1Document magic schools, spell data conventions and too-useful policyopenP1M2task

    Description

    Why

    Twenty spells authored by different people must feel like one coherent magic system.

    What

    docs/design/magic-schools.md: each school's fantasy, primary stimuli, colour tag for placeholder VFX, default loudness, miscast flavour; spell file template; naming for cue/icon/cover ids; testing template (effects + ≥2 property interactions); explicit "too useful is allowed" policy and the too-useful label.

    Scope

    • In: design doc
    • In: spell file template in src/content/spells/_template
    • In: test file template
    • Out: individual spells

    Notes

    Schools in MVP: Fire, Frost, Storm, Arcane, Illusion, Alteration, Conjuration, Necromancy, Nature, Light, Shadow, Gravity, Time.

    Acceptance criteria

    • AC-1 content Given the spell template file, when validated by the spell schema, then it passes.
    • AC-2 content Given the magic-schools doc, when checked by a docs test, then every school enum value in the schema has a section.
    • AC-3 manual Given a designer new to the project, when authoring a fixture spell from the template, then they finish in ≤ 30 minutes without code changes.

    Waits on

    • mw-e06.1 Define zod spell schema with delivery, effect ops and cue ids done
    area:designclass:sorcererepic:e08milestone:m2
  • mw-e08.3Add Firebolt and its Flame Jet follow-on verbblockedP1M2feature

    Description

    Why

    The canonical anti-grind chain starts here: Firebolt is a verb, Flame Jet is a new verb, not +12%.

    What

    As a sorcerer, I want Firebolt (fast damaging bolt that ignites on impact) and, once unlocked, Flame Jet (channeled short cone that sets everything in front ablaze and pushes gas) so that fire progression changes how I fight.

    Flame Jet is a chain step of Firebolt with a different delivery (cone channel).

    Scope

    • In: Firebolt spell
    • In: Flame Jet spell
    • In: verb chain link Firebolt → Flame Jet
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Fire. Placeholder cues: vfx-spell-firebolt-{cast,travel,impact}, vfx-spell-flame-jet-channel, sfx-spell-firebolt-{cast,impact}, sfx-spell-flame-jet-loop. Icon: icon-spell-firebolt. Book cover: ui-book-cover-firebolt.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given any flammable object hit by Firebolt, when resolved, then it ignites and a 1 m heat splash applies around the impact.
    • AC-3 integration Given Flame Jet channeled for 2 s at a group of objects, when resolved, then every flammable object in the cone ignites and non-flammable ones take no fire state.
    • AC-4 integration Given a gas volume tagged flammableGas in the Flame Jet cone, when channeled, then the gas ignites per E03 propagation (explosion allowed).
    • AC-5 content Given the Firebolt → Flame Jet chain, when checked by the anti-grind validator, then it passes (different delivery).
    • AC-6 unit Given Flame Jet channeled with mana running out mid-channel, when mana reaches 0, then channeling stops cleanly (over-cast disallowed).

    Waits on

    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    • mw-e06.6 Deliver spells as physical projectiles with collision and arcs done
    • mw-e06.7 Deliver spells as AoE volumes, cones and reflecting beams open
    • mw-e07.8 Unlock follow-on spell verbs through mastery and advanced books open
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.5Add Frostglass: freeze targets and create temporary ice surfacesblockedP1M2feature

    Description

    Why

    Constitution example; freezing water is a key puzzle verb and ice surfaces are traversal and combat tools.

    What

    As a sorcerer, I want a frost bolt that freezes what it hits and, aimed at water or ground, creates a temporary slick ice sheet so that I can freeze enemies, cross water and make foes slip.

    Cold stimulus at impact; creatures accumulate chill → slowed → frozen-solid (shatterable by force); water surfaces become walkable ice for 20 s; ground becomes slippery (low friction).

    Scope

    • In: Frostglass spell
    • In: ice sheet surface volume
    • In: frozen-solid shatter rule via force
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Frost. Placeholder cues: vfx-spell-frostglass-{cast,travel,impact}, vfx-spell-frostglass-ice-sheet, sfx-spell-frostglass-{cast,impact,shatter}. Icon: icon-spell-frostglass. Book cover: ui-book-cover-frostglass.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given any waterSurface area, when hit by Frostglass, then a walkable frozen patch of 3 m radius exists for 20 s then melts back to water.
    • AC-3 integration Given a creature hit 3 times within 4 s, when resolved, then it becomes frozen-solid for 3 s; a force ≥ threshold during that time shatters the ice and deals bonus damage.
    • AC-4 integration Given a creature walking onto an ice sheet, when moving, then its friction is reduced per E03 and it can slip (knockdown chance per creature balance data).
    • AC-5 integration Given a burning object hit by Frostglass, when resolved, then it is extinguished.
    • AC-6 unit Given a creature tagged cold-immune, when hit, then no chill accumulates.

    Waits on

    • mw-e06.22 Prove spell cold freezes wet and waterSurface things (split from mw-e06.5 AC-2) open
    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    • mw-e06.6 Deliver spells as physical projectiles with collision and arcs done
    • mw-e06.9 Apply buffs, debuffs and statuses with stacking and dispel done
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.6Add Wellspring: conjure a burst of water that soaks an areablockedP1M2feature

    Description

    Why

    Conjured water is the connective tissue for combinations: douse fires, fill basins, soak foes for frost and lightning.

    What

    As a sorcerer, I want to conjure a splash of water at a point so that I can extinguish fires, make things wet and fill containers.

    AoE moisture stimulus 3 m; creates a temporary puddle (waterSurface) for 15 s; fills container-tagged objects (basins, scales) with water weight.

    Scope

    • In: Wellspring spell
    • In: temporary puddle volume
    • In: container fill via moisture
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Conjuration. Placeholder cues: vfx-spell-wellspring-{cast,burst}, vfx-spell-wellspring-puddle, sfx-spell-wellspring-{cast,splash}. Icon: icon-spell-wellspring. Book cover: ui-book-cover-wellspring.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given burning objects inside the 3 m area, when Wellspring bursts, then they are extinguished and gain wet.
    • AC-3 integration Given a creature in the area, when hit, then it gains wet for 20 s, which E03 rules make conductive and freezable.
    • AC-4 integration Given an object tagged container under the burst, when filled, then its weight increases by the configured water mass (can trigger pressure plates).
    • AC-5 unit Given Wellspring cast in a space with no floor within 10 m, when resolved, then water falls and the puddle forms where it lands or nowhere if it falls out of world.

    Waits on

    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    • mw-e06.7 Deliver spells as AoE volumes, cones and reflecting beams open
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.7Add Gust: blast creatures back, clear gas and propel objectsblockedP1M2feature

    Description

    Why

    Constitution example; force + gas-clearing gives a cheap, flexible physics verb.

    What

    As a sorcerer, I want a cone of wind that pushes creatures and loose objects and disperses gas and smoke so that I can shove foes off ledges or clear poison.

    Cone force impulse scaled by weight; displaces gas volumes; fans existing fires (spreads heat downwind) and blows out small flames.

    Scope

    • In: Gust spell
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Storm. Placeholder cues: vfx-spell-gust-cone, sfx-spell-gust-whoosh. Icon: icon-spell-gust. Book cover: ui-book-cover-gust.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given loose objects of 5 kg and 80 kg in the cone, when Gust fires, then the 5 kg object is thrown ≥ 4 m and the 80 kg object moves ≤ 0.5 m.
    • AC-3 integration Given a poisonous gas volume in the cone, when Gust fires, then the gas concentration in the cone drops by ≥ 80% and relocates downwind.
    • AC-4 integration Given a small flame (candle-scale light source) in the cone, when Gust fires, then it is extinguished; a large fire instead spreads 1 m downwind.
    • AC-5 integration Given a creature near a ledge, when pushed past the edge, then it falls and takes fall damage per creature rules.
    • AC-6 unit Given a creature tagged anchored/heavy, when hit, then it staggers but is not displaced.

    Waits on

    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    • mw-e06.7 Deliver spells as AoE volumes, cones and reflecting beams open
    • mw-e06.8 Apply spell forces: impulse, knockback, pull and lift done
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.8Add Thunderclap: a violent shockwave that breaks and deafensblockedP1M2feature

    Description

    Why

    Constitution example: short-range shockwave with substantial environmental effects — and it is loud.

    What

    As a sorcerer, I want a point-blank radial shockwave that knocks creatures down, breaks fragile objects and shakes loose unstable things so that I can reshape a room in one cast.

    Radial force + fragile-break + "unstable" property trigger (loose rubble, chandeliers) + very loud noise event + short deafened status on creatures (reduced hearing).

    Scope

    • In: Thunderclap spell
    • In: deafened status
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Storm. Placeholder cues: vfx-spell-thunderclap-wave, sfx-spell-thunderclap-boom. Icon: icon-spell-thunderclap. Book cover: ui-book-cover-thunderclap.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given any object tagged fragile within 4 m, when Thunderclap fires, then it breaks.
    • AC-3 integration Given any object tagged unstable (hanging, precarious) within 6 m, when Thunderclap fires, then it detaches and falls under physics.
    • AC-4 integration Given creatures within 4 m, when hit, then they are knocked down if poise is exceeded and gain deafened for 5 s.
    • AC-5 integration Given sleeping or Unaware creatures within audible range of loudness 100, when Thunderclap fires, then they transition to at least Suspicious via the alert state machine.
    • AC-6 unit Given the caster standing on an ice sheet, when cast, then the caster is not displaced by their own shockwave (self-exempt) but the ice cracks if tagged fragile.

    Waits on

    • mw-e06.14 Make spells emit light and noise that stealth and AI perceive done
    • mw-e06.7 Deliver spells as AoE volumes, cones and reflecting beams open
    • mw-e06.8 Apply spell forces: impulse, knockback, pull and lift done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.9Add Arc Lash: lightning that chains through conductive and wetblockedP1M2feature

    Description

    Why

    Electricity rewards reading the environment: wet enemies, chains, puddles and metal armour become conductors.

    What

    As a sorcerer, I want a short beam of lightning that jumps between conductive or wet targets so that soaking enemies or luring them onto metal pays off.

    Beam with charge stimulus; E03 conduction propagates through connected conductive/wet objects and water surfaces; powers chargeActivated mechanisms.

    Scope

    • In: Arc Lash spell
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Storm. Placeholder cues: vfx-spell-arc-lash-beam, vfx-spell-arc-lash-chain, sfx-spell-arc-lash-crackle. Icon: icon-spell-arc-lash. Book cover: ui-book-cover-arc-lash.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given three wet creatures standing in a connected puddle, when one is hit, then all three receive charge damage via propagation.
    • AC-3 integration Given a dry creature not touching conductive objects, when hit, then only that creature is affected.
    • AC-4 integration Given any mechanism tagged chargeActivated, when hit by Arc Lash, then it activates.
    • AC-5 integration Given the caster standing in the same puddle as the target, when cast, then the caster also receives charge damage (failure creates stories).
    • AC-6 unit Given a creature tagged insulated, when in a conductive chain, then propagation stops at it.

    Waits on

    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e06.23 Prove spell charge conducts through connected conductive and wet objects (split from mw-e06.5 AC-3) open
    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    • mw-e06.7 Deliver spells as AoE volumes, cones and reflecting beams open
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.11Add Telekinetic Throw & Catch: hurl objects, creatures and arrowsblockedP1M2feature

    Description

    Why

    Anti-grind example from the constitution: telekinesis → throwing creatures → catching projectiles.

    What

    As a sorcerer, I want Mage Hand's follow-on verb to fling held objects (or small creatures) and snatch incoming projectiles from the air so that telekinesis becomes a combat tool.

    Throw applies a large impulse to the held entity; creatures under a size tag can be grabbed; catch window 0.4 s freezes an incoming projectile, which can then be thrown back.

    Scope

    • In: Telekinetic Throw spell (chain step of Mage Hand)
    • In: projectile catch
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Arcane. Placeholder cues: vfx-spell-telekinetic-throw-{launch,catch}, sfx-spell-telekinetic-throw-{launch,catch}. Icon: icon-spell-telekinetic-throw. Book cover: ui-book-cover-telekinetic-throw.

    TOO USEFUL — INTENTIONALLY ALLOWED (constitution §4). Do not nerf this spell to prevent sequence breaks or cheese; encounters and puzzles must tolerate it. Balance only via mana/cast time/cooldown, never by adding pairwise exceptions.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a held 10 kg object thrown at a creature, when it hits at ≥ 8 m/s, then collision damage and stagger apply per force rules.
    • AC-3 integration Given a small-tagged creature within range, when grabbed and thrown into any fragile object, then the object breaks and the creature takes collision damage.
    • AC-4 integration Given an incoming arrow or spell projectile, when catch is timed within the 0.4 s window, then the projectile stops and can be re-thrown with its on-hit ops intact.
    • AC-5 unit Given catch pressed outside the window, when the projectile arrives, then the catch fails and the projectile hits normally.
    • AC-6 content Given the Mage Hand → Telekinetic Throw chain, when checked by the anti-grind validator, then it passes.

    Waits on

    • mw-e07.8 Unlock follow-on spell verbs through mastery and advanced books open
    • mw-e08.10 Add Mage Hand: grab, move and use distant objects done
    area:contentclass:sorcererepic:e08milestone:m2too-useful
  • mw-e08.12Add Blink: teleport several metres through open spaceblockedP1M2feature

    Description

    Why

    Constitution example; opens balconies, gaps and escapes — a classic sequence-breaker we deliberately allow.

    What

    As a sorcerer, I want to teleport up to 8 m to an aimed point with line of sight so that I can cross gaps, escape grapples and reach ledges.

    Uses displacement op with LOS; breaks rooted/grappled statuses; leaves a brief light flash and a quiet noise at origin and destination.

    Scope

    • In: Blink spell
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Arcane. Placeholder cues: vfx-spell-blink-{depart,arrive}, sfx-spell-blink-{depart,arrive}. Icon: icon-spell-blink. Book cover: ui-book-cover-blink.

    TOO USEFUL — INTENTIONALLY ALLOWED (constitution §4). Do not nerf this spell to prevent sequence breaks or cheese; encounters and puzzles must tolerate it. Balance only via mana/cast time/cooldown, never by adding pairwise exceptions.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a ledge 7 m away and 3 m up with line of sight, when Blink is cast at it, then the caster stands on the ledge.
    • AC-3 integration Given a closed window or bars between caster and target, when cast, then Blink fails with reason "no-line-of-sight" and mana is refunded.
    • AC-4 integration Given the caster is rooted by any restraint status, when Blink succeeds, then the rooted status is removed.
    • AC-5 integration Given a guard watching the origin point, when the caster blinks out of sight, then the guard's last-known position is the origin (it did not see the destination).
    • AC-6 unit Given aim into a wall, when cast, then the caster lands at the nearest safe point before the wall.

    Waits on

    • mw-e06.12 Teleport and swap positions with collision-safe placement open
    • mw-e06.14 Make spells emit light and noise that stealth and AI perceive done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    area:contentclass:sorcererepic:e08milestone:m2too-useful
  • mw-e08.13Add Levitate: float the caster or an object upward slowlyopenP1M2feature

    Description

    Why

    Constitution: "the sorcerer might levitate onto a balcony" — vertical traversal as a class-specific solution.

    What

    As a sorcerer, I want to levitate myself (or a targeted object) upward at 1.5 m/s for up to 6 s so that I can reach balconies, cross pits slowly or lift a platform.

    Channeled lift status; drains mana per tick; ends gently (slow-fall for 2 s) when mana runs out or cancelled.

    Scope

    • In: Levitate spell
    • In: slow-fall ending
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Gravity. Placeholder cues: vfx-spell-levitate-loop, sfx-spell-levitate-loop. Icon: icon-spell-levitate. Book cover: ui-book-cover-levitate.

    TOO USEFUL — INTENTIONALLY ALLOWED (constitution §4). Do not nerf this spell to prevent sequence breaks or cheese; encounters and puzzles must tolerate it. Balance only via mana/cast time/cooldown, never by adding pairwise exceptions.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a balcony 6 m above, when Levitate is channeled for 4 s with lateral steering, then the caster reaches the balcony.
    • AC-3 integration Given mana runs out mid-levitation, when it ends, then the caster slow-falls for 2 s and takes no fall damage from ≤ 8 m.
    • AC-4 integration Given Levitate targeted at any object below the lift weight limit, when channeled, then it rises (e.g. lifting a platform or pressure-plate weight).
    • AC-5 unit Given the caster is hit and poise breaks while levitating, when interrupted, then levitation ends and slow-fall applies.

    Waits on

    • mw-e06.4 Support cast times, channeling, cooldowns and interruption done
    • mw-e06.8 Apply spell forces: impulse, knockback, pull and lift done
    • mw-e06.9 Apply buffs, debuffs and statuses with stacking and dispel done
    area:contentclass:sorcererepic:e08milestone:m2too-useful
  • mw-e08.14Add Gravity Well: pull creatures and loose objects to a pointblockedP1M2feature

    Description

    Why

    Constitution example; clumping enemies and debris sets up spectacular combinations.

    What

    As a sorcerer, I want to place a 5 s gravity point that drags creatures and loose objects inward so that I can group enemies, pull them off ledges or yank items from shelves.

    Persistent volume with damped point pull scaled by weight; objects pulled into each other collide (fragile breaks); combos with Thunderclap/Flame Jet.

    Scope

    • In: Gravity Well spell
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Gravity. Placeholder cues: vfx-spell-gravity-well-loop, vfx-spell-gravity-well-collapse, sfx-spell-gravity-well-{loop,collapse}. Icon: icon-spell-gravity-well. Book cover: ui-book-cover-gravity-well.

    TOO USEFUL — INTENTIONALLY ALLOWED (constitution §4). Do not nerf this spell to prevent sequence breaks or cheese; encounters and puzzles must tolerate it. Balance only via mana/cast time/cooldown, never by adding pairwise exceptions.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given 4 creatures within 6 m, when the well persists 5 s, then all creatures under the heavy tag end within 1.5 m of the centre.
    • AC-3 integration Given loose objects on a shelf within range, when the well activates, then they are pulled off and fly toward the centre, breaking if fragile on collision.
    • AC-4 integration Given the well placed beyond a ledge, when creatures are pulled, then they fall.
    • AC-5 unit Given the caster within the radius, when active, then the caster is also pulled (not exempt) — intentionally allowed hazard.
    • AC-6 perf Given 30 loose objects and 8 creatures in one well, when simulated, then magic + physics cost p95 ≤ 3 ms per tick on the reference machine.

    Waits on

    • mw-e06.7 Deliver spells as AoE volumes, cones and reflecting beams open
    • mw-e06.8 Apply spell forces: impulse, knockback, pull and lift done
    area:contentclass:sorcererepic:e08milestone:m2too-useful
  • mw-e08.15Add Mirror Self: an illusory double that draws attentionblockedP1M2feature

    Description

    Why

    Constitution example; deception that plugs into the stealth/AI simulation instead of damage.

    What

    As a sorcerer, I want to project an illusory copy of myself at a point so that enemies investigate or attack it while I slip away.

    Summons a decoy entity perceivable by sight and hearing (emits footsteps/noise), attracting perception priority; dispels when struck or on duration end; creatures tagged true-sight ignore it.

    Scope

    • In: Mirror Self spell
    • In: decoy entity archetype
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Illusion. Placeholder cues: vfx-spell-mirror-self-{spawn,shimmer,dispel}, sfx-spell-mirror-self-{spawn,dispel}. Icon: icon-spell-mirror-self. Book cover: ui-book-cover-mirror-self.

    TOO USEFUL — INTENTIONALLY ALLOWED (constitution §4). Do not nerf this spell to prevent sequence breaks or cheese; encounters and puzzles must tolerate it. Balance only via mana/cast time/cooldown, never by adding pairwise exceptions.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a guard in Unaware state with the decoy in view, when perceived, then the guard targets the decoy as the player-equivalent stimulus (Suspicious → Investigating toward decoy).
    • AC-3 integration Given the decoy is struck by any attack, when hit, then it dispels and the attacker enters Searching with last-known position at the decoy.
    • AC-4 integration Given a creature tagged true-sight, when the decoy is in view, then it is ignored.
    • AC-5 integration Given the decoy placed in darkness, when guards look, then its visibility uses the same light-field-based visibility model as the player.
    • AC-6 unit Given maxActive 1, when cast again, then the previous decoy dispels.

    Waits on

    • mw-e06.10 Summon temporary creatures and objects with allegiance and caps open
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    area:contentclass:sorcererepic:e08milestone:m2too-useful
  • mw-e08.17Add Wisp Light: a floating orb that lights darkness and repelsblockedP1M2feature

    Description

    Why

    Navigating darkness is a puzzle pillar; a light spell trades stealth for vision and scares light-averse creatures.

    What

    As a sorcerer, I want to summon a floating light orb that follows me or can be sent to a point so that I can explore dark places, light up puzzles and drive back light-averse creatures.

    Light op attached to a small summoned entity (follow or fixed); 90 s duration; sends creatures tagged light-averse into fear via their own properties.

    Scope

    • In: Wisp Light spell
    • In: wisp entity
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Light. Placeholder cues: vfx-spell-wisp-light-orb, sfx-spell-wisp-light-{spawn,hum-loop}. Icon: icon-spell-wisp-light. Book cover: ui-book-cover-wisp-light.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a dark room with light level 0.05, when the wisp is present, then the light field within 5 m of it is ≥ 0.5.
    • AC-3 integration Given any light-sensitive mechanism (tagged lightActivated) within the wisp's radius above its threshold, when the wisp arrives, then it activates.
    • AC-4 integration Given a creature tagged light-averse within 5 m, when the wisp approaches, then it retreats per its disposition rules.
    • AC-5 integration Given the player carries a follow-wisp while sneaking, when a guard evaluates visibility, then the player's visibility score increases per the visibility model (stealth trade-off).
    • AC-6 unit Given a Snuff/darkness effect overlapping the wisp, when resolved, then the wisp is extinguished early.

    Waits on

    • mw-e06.10 Summon temporary creatures and objects with allegiance and caps open
    • mw-e06.14 Make spells emit light and noise that stealth and AI perceive done
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.18Add Prism Ray: a light beam that reflects off reflective surfacesblockedP1M2feature

    Description

    Why

    Puzzle constitution: redirecting light. A reflecting beam turns mirrors and polished shields into puzzle pieces.

    What

    As a sorcerer, I want a channeled beam of focused light that bounces off reflective surfaces so that I can power light mechanisms around corners and dazzle creatures.

    Beam with light op and small heat; reflects up to 3 times off reflective-tagged objects; dazzles (blinded 2 s) creatures that look into it.

    Scope

    • In: Prism Ray spell
    • In: blinded status
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Light. Placeholder cues: vfx-spell-prism-ray-beam, vfx-spell-prism-ray-reflect, sfx-spell-prism-ray-loop. Icon: icon-spell-prism-ray. Book cover: ui-book-cover-prism-ray.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a reflective object angled at 45°, when the beam hits it, then the reflected beam continues at 90° and can activate a lightActivated mechanism on the reflected path.
    • AC-3 integration Given any object tagged reflective including a Frostglass ice sheet, when hit, then the beam reflects (property-based, not object-based).
    • AC-4 integration Given a creature facing the caster within the beam, when hit, then it gains blinded for 2 s and its sight perception is disabled for that time.
    • AC-5 unit Given more than 3 reflective surfaces in a row, when channeled, then the beam stops after the third reflection.

    Waits on

    • mw-e06.14 Make spells emit light and noise that stealth and AI perceive done
    • mw-e06.7 Deliver spells as AoE volumes, cones and reflecting beams open
    • mw-e06.9 Apply buffs, debuffs and statuses with stacking and dispel done
    • mw-e15.3 Run data-defined puzzles composed from reusable world objects done
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.20Add Grasping Vines: roots burst up and restrain creaturesblockedP1M2feature

    Description

    Why

    Constitution example; restraint as a verb — and vines are organic, so fire and frost interact naturally.

    What

    As a sorcerer, I want roots to erupt in a 3 m area and bind creatures for up to 6 s so that I can pin enemies, hold doors or stop a fleeing thief.

    Spawns vine entities (tagged organic, flammable) that apply rooted to creatures inside; rooted breaks when its vine entity is destroyed or burns; only works on soil/stone ground, not water or wood floors above empty space.

    Scope

    • In: Grasping Vines spell
    • In: vine entity archetype
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Nature. Placeholder cues: vfx-spell-grasping-vines-{erupt,hold,wither}, sfx-spell-grasping-vines-{erupt,creak}. Icon: icon-spell-grasping-vines. Book cover: ui-book-cover-grasping-vines.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given 3 creatures inside the area, when cast, then each is rooted for 6 s unless tagged too-large-to-root.
    • AC-3 integration Given the vines are hit by any heat stimulus above ignition threshold, when they burn, then they are destroyed within 2 s and rooted ends early.
    • AC-4 integration Given a strong creature with the break-free trait, when rooted, then it breaks free after 2 s.
    • AC-5 unit Given cast onto a water surface, when resolved, then the cast fails with reason "invalid-surface" and mana is refunded.
    • AC-6 integration Given a life stimulus source nearby (e.g. a second Vines cast), when overlapping, then vine duration refreshes (organic growth rule).

    Waits on

    • mw-e06.10 Summon temporary creatures and objects with allegiance and caps open
    • mw-e06.5 Emit world-property stimuli from spell effects into the world sim done
    • mw-e06.9 Apply buffs, debuffs and statuses with stacking and dispel done
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.21Add Animate Bones: raise nearby remains as a temporary servantblockedP1M2feature

    Description

    Why

    Constitution example; summoning grounded in the world — no bones nearby, no servant.

    What

    As a sorcerer, I want to assemble skeletal remains within 6 m into a temporary skeletal servant for 45 s so that the dungeon's dead fight for me.

    Summon op requiring remains-tagged material; servant follows/attacks; crumbles back into remains (reusable) on expiry; the spell comes from a forbidden book.

    Scope

    • In: Animate Bones spell
    • In: skeletal servant archetype (reuses bestiary skeleton data if available)
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Necromancy. Placeholder cues: vfx-spell-animate-bones-{assemble,crumble}, sfx-spell-animate-bones-{assemble,rattle,crumble}. Icon: icon-spell-animate-bones. Book cover: ui-book-cover-animate-bones.

    Related: bestiary skeleton archetype from the creatures group; use a fixture archetype until it exists. Book is forbidden (e07-forbidden-books).

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a remains-tagged object within 6 m, when cast, then a servant with caster allegiance spawns at the remains location and the remains are consumed.
    • AC-3 integration Given no remains in range, when cast, then the cast fizzles with a SpellFizzled event and full refund.
    • AC-4 integration Given the servant expires, when 45 s pass, then a remains-tagged object is left at its position (reusable).
    • AC-5 integration Given a hostile skeleton creature, when targeted with Animate Bones, then it is not converted (only inert remains qualify).
    • AC-6 integration Given a lawful NPC witness, when the player casts Animate Bones in view, then a ContrabandWitnessed event fires (forbidden school).

    Waits on

    • mw-e03.31 Consolidate world-property vocabulary assumed by other epics done
    • mw-e06.10 Summon temporary creatures and objects with allegiance and caps open
    • mw-e07.6 Give forbidden books social risk and whispering side effects open
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.22Add Polymorph: temporarily turn a creature into a harmless animalblockedP1M2feature

    Description

    Why

    Constitution example; transformation that solves fights, social problems and puzzles in unexpected ways.

    What

    As a sorcerer, I want to turn a creature into a small animal (e.g. a chicken-like critter) for 20 s so that I can neutralise threats, sneak past guards or make a heavy creature light enough to Mage Hand.

    Transform op to a small-creature archetype; large/boss creatures tagged immune-transform resist; the critter form has its own properties (small, light, flammable) that other spells interact with.

    Scope

    • In: Polymorph spell
    • In: critter archetype for the transformed form
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Alteration. Placeholder cues: vfx-spell-polymorph-{poof-in,poof-out}, sfx-spell-polymorph-{poof,critter-cluck}. Icon: icon-spell-polymorph. Book cover: ui-book-cover-polymorph.

    TOO USEFUL — INTENTIONALLY ALLOWED (constitution §4). Do not nerf this spell to prevent sequence breaks or cheese; encounters and puzzles must tolerate it. Balance only via mana/cast time/cooldown, never by adding pairwise exceptions.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a humanoid guard, when polymorphed, then it becomes the critter archetype for 20 s with its alert memory intact and restores exactly afterwards.
    • AC-3 integration Given a polymorphed creature now tagged small and light, when grabbed by Mage Hand/Telekinetic Throw, then it can be lifted (properties of the new form apply).
    • AC-4 integration Given a creature tagged immune-transform, when targeted, then it resists and emits SpellResisted.
    • AC-5 integration Given the critter is killed and Polymorph uses onFormDeath=revert, when killed, then the original reverts with 1 HP and a stagger status.
    • AC-6 unit Given Polymorph cast on the caster via a reflective surface bounce (if a beam reflection returns), when resolved, then the caster is transformed — intentionally allowed.

    Waits on

    • mw-e06.11 Temporarily transform creatures into other archetypes and back open
    • mw-e06.6 Deliver spells as physical projectiles with collision and arcs done
    area:contentclass:sorcererepic:e08milestone:m2too-useful
  • mw-e08.24Build the spell combination test suite and greybox spell galleryblockedP1M2task

    Description

    Why

    Emergent combinations are the point of magic; a suite proves they emerge from properties and catches regressions when E03 rules change.

    What

    A generated integration test matrix: for every pair of stimulus types emitted by catalogue spells (heat, cold, force, light, moisture, charge, life, decay) applied in both orders to a fixture set of property-tagged generic objects and creatures, assert deterministic, rule-consistent outcomes (golden snapshots). Plus curated scenario tests (Wellspring → Arc Lash chain, Wellspring → Frostglass bridge, Gravity Well → Thunderclap scatter, Gust → Fire spread, Polymorph → Telekinetic Throw) expressed via properties. Plus a greybox "spell gallery" room exhibiting every property for e2e/manual play.

    Scope

    • In: combination matrix generator, golden snapshots, curated scenario tests, greybox gallery scene, e2e smoke of the gallery
    • Out: E03 rule changes (Core group) — the suite reports, it does not fix

    Notes

    Golden updates require an explicit reviewed flag in the PR. Suite runs headless in < 60 s.

    Acceptance criteria

    • AC-1 integration Given every ordered pair of catalogue stimulus types and the fixture object set, when run, then outcomes match golden snapshots and two runs produce identical hashes.
    • AC-2 integration Given Wellspring then Arc Lash on 3 creatures in the puddle, when resolved, then all receive charge damage (conduction through wet).
    • AC-3 integration Given Wellspring then Frostglass on a pit filled with water, when resolved, then a walkable ice surface exists across the pit.
    • AC-4 unit Given a new spell added to the catalogue emitting an unseen stimulus type, when the suite runs, then it fails listing the missing pair coverage.
    • AC-5 perf Given the full suite, when run in CI, then it completes in ≤ 60 s.
    • AC-6 e2e Given the greybox spell gallery, when a scripted run casts every P1 spell at its gallery station, then no console errors occur and each station reports its expected property change.
    • AC-7 manual Given a 30-minute playtest in the gallery, when testers experiment freely, then they report at least 3 combinations nobody told them about.

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e08.11 Add Telekinetic Throw & Catch: hurl objects, creatures and arrows open
    • mw-e08.14 Add Gravity Well: pull creatures and loose objects to a point open
    • mw-e08.2 Add Ember: precise ignition of flammable things done
    • mw-e08.22 Add Polymorph: temporarily turn a creature into a harmless animal open
    • mw-e08.5 Add Frostglass: freeze targets and create temporary ice surfaces open
    • mw-e08.6 Add Wellspring: conjure a burst of water that soaks an area open
    • mw-e08.7 Add Gust: blast creatures back, clear gas and propel objects open
    • mw-e08.8 Add Thunderclap: a violent shockwave that breaks and deafens open
    • mw-e08.9 Add Arc Lash: lightning that chains through conductive and wet open
    area:qaclass:sorcererepic:e08milestone:m2
  • mw-e08.4Add Fire Wall: a persistent line of flame that blocks and burnsblockedP2M2feature

    Description

    Why

    Third step of the fire chain: area denial as a new verb — split a fight, block a corridor, burn a bridge.

    What

    As a sorcerer, I want to draw a 6 m line of fire on the ground that lasts 8 s so that I can block paths and ignite what crosses it.

    Persistent line volume with heat stimulus; creatures with fear-of-fire disposition refuse to cross; it emits strong light.

    Scope

    • In: Fire Wall spell
    • In: chain link Flame Jet → Fire Wall
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Fire. Placeholder cues: vfx-spell-fire-wall-{spawn,loop,end}, sfx-spell-fire-wall-{spawn,loop}. Icon: icon-spell-fire-wall. Book cover: ui-book-cover-fire-wall.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a Fire Wall placed across a corridor, when a creature whose disposition includes fears-fire paths to the player, then it routes around or waits rather than crossing.
    • AC-3 integration Given a wooden floor tagged flammable under the wall, when the wall persists 8 s, then the floor ignites and continues burning after the wall ends.
    • AC-4 integration Given a moisture stimulus (rain, Wellspring) applied to the wall, when resolved, then wall segments inside the moisture area are extinguished.
    • AC-5 unit Given a placement line crossing a wall, when cast, then the fire line is clipped at the geometry.

    Waits on

    • mw-e06.7 Deliver spells as AoE volumes, cones and reflecting beams open
    • mw-e08.3 Add Firebolt and its Flame Jet follow-on verb open
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.16Add Arcane Sight: reveal hidden mechanisms and magical propertiesopenP2M2feature

    Description

    Why

    Magic "can reveal secrets" — a sorcerer-flavoured alternative to the thief finding hidden passages.

    What

    As a sorcerer, I want a 15 s self buff that outlines objects tagged hidden, magical or trapped within 12 m so that I discover secret doors, traps and enchanted items.

    Revealed status applied to matching entities; revealed traps become visible to the player only.

    Scope

    • In: Arcane Sight spell
    • In: revealed status rendering hook (placeholder outline)
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Arcane. Placeholder cues: vfx-spell-arcane-sight-overlay, sfx-spell-arcane-sight-cast. Icon: icon-spell-arcane-sight. Book cover: ui-book-cover-arcane-sight.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given any object tagged hidden within 12 m, when Arcane Sight is active, then it gains revealed for the duration.
    • AC-3 integration Given a trap tagged trapped behind a wall with no line of sight, when active, then it is revealed (sight through walls up to 12 m).
    • AC-4 integration Given a hidden object at 13 m, when active, then it is not revealed until the player comes within 12 m.
    • AC-5 unit Given Arcane Sight ends, when duration expires, then all revealed statuses it applied are removed.

    Waits on

    • mw-e03.31 Consolidate world-property vocabulary assumed by other epics done
    • mw-e06.9 Apply buffs, debuffs and statuses with stacking and dispel done
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.19Add Snuff: extinguish all light sources in a radiusblockedP2M2feature

    Description

    Why

    Shadow magic that serves stealth: the sorcerer can create darkness like the thief extinguishing lights.

    What

    As a sorcerer, I want to snuff every flame and magical light within 6 m so that I can plunge a room into darkness and use it to hide or disorient.

    AoE that removes lit state from light-source objects and ends light ops; smothers small fires (not large blazes); quiet cast.

    Scope

    • In: Snuff spell
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Shadow. Placeholder cues: vfx-spell-snuff-pulse, sfx-spell-snuff-hush. Icon: icon-spell-snuff. Book cover: ui-book-cover-snuff.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given 5 lit candles and 1 torch within 6 m, when Snuff is cast, then all become unlit and the light field drops accordingly.
    • AC-3 integration Given a burning object larger than the small-fire threshold, when Snuff is cast, then it remains burning.
    • AC-4 integration Given guards in the darkened room, when they evaluate visibility of the player, then the reduced light level lowers the player's visibility score.
    • AC-5 unit Given Snuff noise loudness, when cast, then emitted loudness is ≤ 20 (quiet).

    Waits on

    • mw-e06.14 Make spells emit light and noise that stealth and AI perceive done
    • mw-e06.7 Deliver spells as AoE volumes, cones and reflecting beams open
    area:contentclass:sorcererepic:e08milestone:m2
  • mw-e08.23Add Stasis: freeze one object or creature in timeopenP2M2feature

    Description

    Why

    Time magic creates novel puzzle and combat verbs: hold a falling gate, stop a swinging blade, pause an enemy.

    What

    As a sorcerer, I want to lock a single target in time for 5 s so that I can freeze moving traps, suspend falling objects or stop an attacker mid-swing.

    Stasis status: zero velocity, immune to damage and forces, mechanisms paused; stored impulses from hits apply on release (capped).

    Scope

    • In: Stasis spell
    • In: stasis status with stored impulse
    • In: spell JSON + book item JSON, unit tests for effects, integration tests for world interactions, placeholder cue ids
    • Out: final VFX/SFX/icon/book cover (asset prompt beads)
    • Out: world placement of the book (E24–E26)

    Notes

    School: Time. Placeholder cues: vfx-spell-stasis-{lock,release}, sfx-spell-stasis-{lock,release}. Icon: icon-spell-stasis. Book cover: ui-book-cover-stasis.

    TOO USEFUL — INTENTIONALLY ALLOWED (constitution §4). Do not nerf this spell to prevent sequence breaks or cheese; encounters and puzzles must tolerate it. Balance only via mana/cast time/cooldown, never by adding pairwise exceptions.

    Acceptance criteria

    • AC-1 content Given the spell data file, when validated and loaded, then it has a school, book item, vfxCue and sfxCue and casts in the headless sim.
    • AC-2 integration Given a moving mechanism (swinging blade, falling portcullis), when stasis is applied, then it halts for 5 s and resumes its prior motion afterwards.
    • AC-3 integration Given a creature in stasis struck by forces totalling 300 N·s, when stasis ends, then the stored impulse (capped at 200 N·s) applies at once.
    • AC-4 unit Given a creature in stasis, when damage is applied, then health is unchanged during stasis.
    • AC-5 unit Given a creature tagged boss or immune-time, when targeted, then duration is reduced to 1 s.

    Waits on

    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e06.9 Apply buffs, debuffs and statuses with stacking and dispel done
    area:contentclass:sorcererepic:e08milestone:m2too-useful
E09Systemic StealthVisibility, lighting, sound, suspicion, searching, last-known-position and hiding work as coherent, deterministic systems. Stealth is not crouching + an eye icon: players read light exposure, noise and each enemy’s awareness, and failure escalates into new situations rather than a reload.6/23 done · 26%

M2 Class fantasies 15

  • mw-e09.6Author stealth tuning data: light weights, stance, noise, doorsopenP1M2task

    Description

    Why

    Stealth feel must be tunable by designers without code, and defaults pinned by tests.

    What

    A StealthTuning schema and default file: light-term curve, stance multipliers, motion bands, distance falloff, contrast bonus, gait base dB, surface table link, door-state and wall/floor transmission defaults, global audibility floor, hiding-place concealment defaults. Hot reload in dev; difficulty presets can override a whitelisted subset.

    Scope

    • In: Schema, defaults, hot reload, pinned default tests
    • In: Difficulty override whitelist (consumed by e09-stealth-assists)
    • Out: AI thresholds and timers (e11-ai-tuning-data)
    • Out: Sense ranges (e12-sense-profiles)

    Notes

    Curves are piecewise-linear point lists for easy editing.

    Acceptance criteria

    • AC-1 content Given the default file, when validated, then all curves are monotonic in the documented direction.
    • AC-2 unit Given a difficulty preset overriding a non-whitelisted key, when loaded, then loading fails naming the key.
    • AC-3 integration Given a dev build, when the stance multiplier is edited, then the visibility HUD reflects the change within 1 s.
    • AC-4 unit Given the shipped defaults, when the pinned-default test runs, then documented values match.

    Waits on

    • mw-e09.2 Compute player visibility from light, stance, motion and distance done
    • mw-e09.5 Emit footstep noise from speed, stance, surface and equipment weight done
    area:contentclass:thiefepic:e09milestone:m2
  • mw-e09.7Verticality rules: limited upward vision and height advantageblockedP1M2feature

    Description

    Why

    Verticality is a stealth input: rafters, balconies and rooftops should be real thief highways because guards rarely look up.

    What

    As a thief, I want to be harder to notice above or below a guard’s eye line so that rafters and ledges become routes. Vertical sight: per-profile vertical half-angles up/down (humanoids look up poorly by default, e.g. +20° up, −45° down) with an extra falloff; creatures with looks-up tag (e.g. spiders, fliers) ignore it; Searching agents perform occasional look-up scans. Height difference affects noise via floor transmission (already in propagation) and adds a visibility penalty when the target is above a lit area but itself in dark rafters.

    Scope

    • In: Vertical cone limits + falloff
    • In: Look-up scan in Searching/Investigating when LKP is elevated
    • In: Tuning data
    • Out: Climbing movement (e10-climbing)
    • Out: Flying creature navigation (post-MVP)

    Notes

    LKP elevation > 2 m above agent eye triggers look-up scan behaviour.

    Acceptance criteria

    • AC-1 unit Given a humanoid guard with vertical up half-angle 20°, when the target is 30° above horizontal at 8 m, then no sight stimulus is produced while the guard is Unaware.
    • AC-2 unit Given a creature tagged looks-up, when the same target is evaluated, then a sight stimulus is produced.
    • AC-3 unit Given a Searching guard whose LKP is 4 m above its eye height, when it reaches the LKP area, then it performs a look-up scan that widens its up half-angle to 60° for 3 s.
    • AC-4 integration Given a scenario where the player crosses rafters above 2 patrolling guards in a lit hall, when simulated, then neither guard exceeds Suspicious.
    • AC-5 unit Given the target directly overhead (90°), when evaluated, then no division-by-zero or NaN occurs and visibility follows the vertical rule.

    Waits on

    • mw-e09.2 Compute player visibility from light, stance, motion and distance done
    • mw-e11.11 Search patterns around last-known position, including hiding spots open
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    area:simclass:thiefepic:e09milestone:m2
  • mw-e09.8Hiding places: wardrobes, barrels, tall grass and shadowed alcovesblockedP1M2feature

    Description

    Why

    Hiding places are a constitution stealth input and give failed stealth a recovery move rather than a reload.

    What

    As a thief, I want to duck into a wardrobe, crouch in tall grass or press into an alcove so that I can break pursuit if I am quick and unseen. Two kinds: enter-able containers (wardrobe, barrel, under-bed — interact to enter/exit, player hidden, limited view) and concealment volumes (tall grass, curtains, alcoves — visibility multiplier while inside and stationary/crouched). Data: concealment factor, entry noise dB, entry time, capacity, searchable flag. AI that saw you enter knows; AI searching may check (e11-search-behaviour). Being found inside = instant Combat at close range with a brief stagger window to flee (failure creates a story).

    Scope

    • In: Hiding place component + data
    • In: Enter/exit via interaction with timing and noise
    • In: Concealment volumes feeding visibility model
    • In: Being-discovered outcome
    • Out: Hiding bodies in containers (e10-body-carry-hide)
    • Out: Hiding prop art (placeholder boxes)

    Notes

    Entering while observed must be tracked as a memory saw-enter:<hidingPlaceId>.

    Acceptance criteria

    • AC-1 unit Given the player inside a wardrobe, when any observer computes visibility, then the result is 0 unless the wardrobe is opened by that observer.
    • AC-2 unit Given the player crouched still in tall grass (concealment 0.3), when visibility is computed, then it is multiplied by 0.3; moving at run speed removes the bonus.
    • AC-3 unit Given a guard observes the player entering a barrel, when the guard searches, then the barrel is checked first (via memory saw-enter).
    • AC-4 unit Given an occupied single-capacity hiding place, when a second entity attempts to enter, then entry is refused with a prompt reason.
    • AC-5 integration Given a guard opens the wardrobe the player is in, when discovered, then the guard enters Combat and the player gets a 0.6 s stagger window during which exiting is possible.
    • AC-6 e2e Given the stealth grey-box course, when the player enters and exits a wardrobe via the interact action, then the camera switches to the hiding view and back without errors.

    Waits on

    • mw-e02.5 Focus and interact with world objects via contextual prompts done
    • mw-e03.23 Hide in wardrobes, barrels and haystacks and search containers done
    • mw-e09.2 Compute player visibility from light, stance, motion and distance done
    • mw-e11.11 Search patterns around last-known position, including hiding spots open
    • mw-e11.8 Target memory and last-known position without omniscience done
    area:gamearea:simclass:thiefepic:e09milestone:m2
  • mw-e09.9Guards notice world anomalies: bodies, open doors, dark torchesopenP1M2feature

    Description

    Why

    A thief’s actions leave traces; guards noticing a doused torch or a missing colleague creates tension and new situations.

    What

    As a thief, I want guards to notice what I changed so that covering my tracks is part of the craft. Anomalies are world facts compared against an agent’s expected state (routine knowledge): unconscious/dead bodies, doors open that are normally closed, lights extinguished that are normally lit, missing valuables from a watched spot, blood/broken objects, a colleague missing from post for > N s. Each anomaly type has data: detection via sight (uses visibility of the anomaly), suspicion weight, resulting state (Suspicious for an open door, Alerted for a body).

    Scope

    • In: Anomaly registry + expected-state baseline per area/agent
    • In: Perception integration (seen-anomaly stimulus)
    • In: Data-driven anomaly types + weights
    • Out: Relighting/closing on return (e11-return-to-routine)
    • Out: Body carrying (e10-body-carry-hide)

    Notes

    Expected state captured at level load and updated when guards themselves change things. Hidden bodies (in containers or darkness below visibility threshold) are not perceived.

    Acceptance criteria

    • AC-1 unit Given a door normally closed is open, when a guard perceives it, then it becomes Suspicious and investigates the door.
    • AC-2 unit Given a guard perceives an unconscious body, when evaluated, then it enters Alerted, investigates the body and may wake it (unconscious ally wakes after 3 s interaction).
    • AC-3 unit Given a body placed in a container or in light ≤ 0.1 beyond 6 m, when a guard walks its route, then the body is not perceived.
    • AC-4 unit Given a torch normally lit is extinguished, when a guard perceives the dark torch, then it becomes Suspicious (not Alerted) with cause light-out.
    • AC-5 unit Given a guard itself opened a door on its route, when it later perceives that door open, then no anomaly is raised.
    • AC-6 integration Given a scenario where the player knocks out guard A and leaves the body in a lit corridor on guard B’s route, when guard B passes, then guard B enters Alerted within 2 s of the body entering its view.

    Waits on

    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    area:simclass:thiefepic:e09milestone:m2
  • mw-e09.10Stealth HUD: light exposure, noise ring and stance readoutopenP1M2feature

    Description

    Why

    Stealth cannot be an eye icon: the player needs to read the inputs — how lit they are and how loud they are — to make decisions.

    What

    As a thief, I want to see how exposed and how loud I am so that I can make informed choices. Elements: light-exposure gem (continuous, 5 visual bands, driven by self-visibility), noise ring around the character footprint that pulses at each emitted noise scaled to its audible radius for a typical guard, stance/gait indicator, and optional diegetic cue (character material darkens in shadow). All toggleable and scalable via settings.

    Scope

    • In: HUD components in src/ui, data binding from sim
    • In: Placeholder art (CSS/SVG shapes)
    • In: Settings toggles
    • Out: Per-enemy awareness (e09-awareness-indicators)
    • Out: Final UI art (asset beads)

    Notes

    Noise ring radius = distance at which the emitted noise drops to the baseline humanoid hearing threshold in open space.

    Acceptance criteria

    • AC-1 unit Given self-visibility 0.05, when the HUD model is computed, then the gem shows band 1 of 5; at 0.95 band 5.
    • AC-2 unit Given a 40 dB footstep and a 30 dB baseline threshold, when the noise ring is computed, then its radius is ≈ 3.2 m (10^(10/20)).
    • AC-3 integration Given the settings toggle hud.stealth=false, when the HUD renders, then no stealth elements are present.
    • AC-4 e2e Given the stealth grey-box course, when the player walks from a lit area into shadow, then the gem band decreases within 250 ms.
    • AC-5 manual Given a playtest with 3 players, when asked to explain the gem and ring without instructions after 5 min, then at least 2 describe both correctly.

    Waits on

    • mw-e00.23 Build HUD/menu UI layer, component kit, focus nav and UI test harness done
    • mw-e09.2 Compute player visibility from light, stance, motion and distance done
    • mw-e09.5 Emit footstep noise from speed, stance, surface and equipment weight done
    • mw-e31.1 Create typed settings store and options menu skeleton done
    area:gamearea:uiclass:thiefepic:e09milestone:m2
  • mw-e09.11Directional awareness indicators showing each enemy’s alert stateopenP1M2feature

    Description

    Why

    Players must see who is noticing them, from where, how close to detection, and why — without the omniscient radar that kills tension.

    What

    As a thief, I want directional indicators for enemies becoming aware of me so that I can react before being caught. For each agent with awareness > 0 of the player: an indicator near the agent (on-screen) or screen-edge chevron (off-screen) that fills with awareness and changes shape per alert state (6 distinct shapes, not colour alone), plus a cause glyph (eye = saw, ear = heard, hand = anomaly). Indicators only appear for agents the player could plausibly perceive (on-screen or heard), preserving uncertainty.

    Scope

    • In: Indicator model from awareness + state + dominant cause
    • In: On-screen and off-screen rendering
    • In: Colour-blind-safe shapes
    • Out: Text barks (e09-alert-barks)
    • Out: Last-known-position ghost (e09-lkp-ghost)

    Notes

    Indicators for agents the player has not perceived (behind walls, silent) are hidden unless an accessibility assist enables them (e09-stealth-assists).

    Acceptance criteria

    • AC-1 unit Given an agent at awareness 0.45 in Suspicious caused by hearing, when the indicator model is built, then fill = 0.45, shape = suspicious, glyph = ear.
    • AC-2 unit Given an agent behind a wall that has not been seen or heard by the player, when the model is built with assists off, then no indicator is produced.
    • AC-3 unit Given each of the six states, when shapes are resolved, then six distinct shape ids are returned.
    • AC-4 e2e Given the stealth grey-box course, when a guard off-screen to the left becomes Suspicious from a noise, then a left-edge chevron appears within 1 frame of the state change.
    • AC-5 unit Given 12 aware agents, when the model is built, then at most 6 indicators are shown, prioritised by awareness × proximity.

    Waits on

    • mw-e00.23 Build HUD/menu UI layer, component kit, focus nav and UI test harness done
    • mw-e02.4 Follow the player with a colliding, orbiting third-person camera done
    • mw-e11.6 Accumulate and decay awareness from stimuli per perceived target done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    area:gamearea:uiclass:thiefepic:e09milestone:m2
  • mw-e09.13Text barks and audio stingers on alert state transitionsopenP1M2feature

    Description

    Why

    Players read enemy minds through barks ("Who’s there?", "Must be rats…"). With no voice in MVP, text barks plus audio stingers carry this.

    What

    As a thief, I want guards to mutter and call out as their state changes so that I understand what they think without a UI meter. Bark tables per behaviour profile map (transition, cause) → weighted lines, shown as floating subtitle text near the speaker within hearing range; audio stinger per escalation (placeholder tones) via the audio engine; cooldowns prevent spam. Barks also enable stealth-layer music hooks.

    Scope

    • In: Bark table schema + selection (seeded)
    • In: Floating text renderer with distance fade
    • In: Stinger cue ids + cooldowns
    • Out: Voice acting (no voice in MVP)
    • Out: Adaptive music system (Related: E28/E38 music layering)
    • Out: Final bark writing (narrative pass, Related: e39-story-bible tone)

    Notes

    Stingers: sfx-stealth-suspicious-01, sfx-stealth-alerted-01, sfx-stealth-combat-01, sfx-stealth-lost-01 — placeholder beeps until asset beads land.

    Acceptance criteria

    • AC-1 unit Given a Unaware→Suspicious transition with cause heard, when a bark is selected with a fixed seed, then it comes from the suspicious.heard table and is deterministic.
    • AC-2 unit Given the same agent barked 2 s ago with cooldown 5 s, when a new transition occurs, then no bark is shown.
    • AC-3 unit Given a speaker 40 m away beyond hearing range, when a bark would show, then it is suppressed for the player.
    • AC-4 integration Given an escalation to Alerted, when it occurs, then exactly one stinger cue is played via the audio engine.
    • AC-5 content Given a bark table referencing an unknown transition key, when validated, then validation fails.

    Waits on

    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e28.1 Web Audio engine: registry, buses, voice pool, positional audio done
    area:audioarea:gamearea:uiclass:thiefepic:e09milestone:m2
  • mw-e09.14Failed stealth escalates into new situations, not reload screensblockedP1M2feature

    Description

    Why

    Failure creates stories. Being spotted should cause lockdowns, reinforcements, changed patrols or a chase — situations the player can still play through.

    What

    As a thief, I want getting caught to change the level rather than end my run so that I can improvise an escape. Area alarm levels (0 calm, 1 wary, 2 alarm, 3 lockdown) per zone driven by alarms, bodies found and combat. Data-defined responses per zone and level: lock specified doors, light extra lights, reinforce posts from a reserve pool (pre-placed, activated — not spawned from nowhere), release hounds, shift patrols; decay back after N minutes of calm to a stable “wary” level, never fully reset. Responses recorded in world state.

    Scope

    • In: Zone alarm model + response data + decay
    • In: Integration with doors, lights, reserve creatures
    • In: World state persistence
    • Out: Crime/bounty system across settlements (Related: E22/E27 crime; not in this epic)
    • Out: Specific dungeon zone authoring (E26)

    Notes

    Reserve pool creatures are placed in level data with reserve: <zone>; activation paths them in from their barracks so the player can see them come.

    Acceptance criteria

    • AC-1 unit Given zone Z at level 0, when an alarm device activates in Z, then Z becomes level 2 and all level-2 responses fire once.
    • AC-2 unit Given a level-3 response lock-doors: [d1, d2], when triggered, then d1 and d2 are locked via the door system and pathfinding reflects it.
    • AC-3 unit Given no alarm triggers for 5 sim minutes at level 2, when the decay rule runs, then Z drops to level 1 (never to 0 once an alarm has occurred).
    • AC-4 unit Given a reserve creature already killed or knocked out by the player, when reinforcements are called, then it is not activated and no replacement is spawned.
    • AC-5 integration Given a save while Z is at level 2, when loaded, then Z is at level 2 with its responses applied.
    • AC-6 integration Given the stealth grey-box course, when the player is spotted and the alarm rung, then the course remains completable via at least one alternate route (scripted e2e path succeeds).

    Waits on

    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e11.12 Allies share alerts by shouts, sight signals and alarm devices open
    • mw-e12.4 Spawn data-defined creatures into the sim and grey-box scenes done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    area:contentarea:simclass:thiefepic:e09milestone:m2
  • mw-e09.15Build the stealth grey-box course covering every stealth inputopenP1M2task

    Description

    Why

    Stealth systems need one playable space that exercises light, sound, surfaces, doors, verticality and hiding for e2e tests and tuning playtests.

    What

    A grey-box level greybox/stealth-course with labelled stations: light/dark gradient hall, surface strip (carpet/stone/gravel/creaky wood/water), door maze (open/closed/locked), vertical hall with rafters and ledges, hiding place gallery, distraction room, patrol yard with 3 fixture guards, alarm bell zone with reserve guards. Includes a baked navmesh, room/portal graph and patrol routes.

    Scope

    • In: Level data, placeholder props, patrol routes, spawn points
    • In: Console tp station <n>
    • Out: Final dungeon content (E26)
    • Out: Art

    Notes

    Used by e09 e2e ACs, e09-infiltration-scenarios and e10 thief challenge.

    Acceptance criteria

    • AC-1 e2e Given the course, when loaded in the browser, then all 8 stations are reachable and no console errors appear.
    • AC-2 content Given the course data, when validated, then navmesh, portal graph and patrol routes pass validation.
    • AC-3 integration Given tp station 3, when entered, then the player is at the door maze start.
    • AC-4 perf Given the course with all guards active, when measured on the reference machine (High), then frame time p95 ≤ 16.7 ms.

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e09.4 Tag surfaces with acoustic materials that change footstep noise done
    • mw-e11.4 Navmesh generation and deterministic pathfinding for creatures done
    • mw-e11.9 Patrol routes, guard posts and idle routines authored as data done
    area:contentarea:qaclass:thiefepic:e09milestone:m2
  • mw-e09.16Deterministic infiltration replay scenarios with asserted guard statesblockedP1M2task

    Description

    Why

    Releases must be trusted without reading code. Scripted infiltrations with asserted guard states prove the stealth systems work together and stay working.

    What

    A suite of ≥ 10 headless scenarios using the AI scenario harness on the stealth course layouts, each with a scripted player path and asserted guard states over time. Scenarios: shadow sneak (never above Suspicious), sprint on gravel (Suspicious ≤ 1 s), closed-door muffling, thrown distraction lure, break LOS and hide (guard ends Searching then postAlert Unaware), body discovery → Alerted, alarm → zone level 2, rafters crossing, hiding-place seen-enter, ally communication chain. Each records a state-hash sequence as a regression baseline.

    Scope

    • In: Scenario files, baselines, CI job
    • In: Readable failure timelines
    • Out: Browser e2e (course e2e ACs)

    Notes

    Scenarios reference fixture creatures only so bestiary tuning never breaks them.

    Acceptance criteria

    • AC-1 integration Given the shadow-sneak scenario, when run, then no guard exceeds Suspicious for the full 60 s.
    • AC-2 integration Given the break-LOS scenario, when run, then the guard sequence is Combat → Searching → Unaware(postAlert) with the Searching phase starting within 5 s of LOS break.
    • AC-3 integration Given the closed-door scenario, when the same noise is made with the door open vs closed, then the guard enters Suspicious only in the open case.
    • AC-4 integration Given every scenario, when run twice, then state-hash sequences are identical to each other and to the committed baseline.
    • AC-5 integration Given a deliberately broken rule (test-only flag doubling light weight), when the suite runs, then at least 3 scenarios fail (the suite actually detects regressions).
    • AC-6 perf Given the full suite, when run in CI, then it completes in ≤ 30 s.

    Waits on

    • mw-e09.14 Failed stealth escalates into new situations, not reload screens open
    • mw-e09.7 Verticality rules: limited upward vision and height advantage open
    • mw-e09.8 Hiding places: wardrobes, barrels, tall grass and shadowed alcoves open
    • mw-e09.9 Guards notice world anomalies: bodies, open doors, dark torches open
    • mw-e10.2 Throw objects to create noise distractions guards investigate open
    • mw-e11.3 Scenario harness for scripted AI tests with asserted states over time done
    area:qaarea:simclass:thiefepic:e09milestone:m2
  • mw-e09.12Show a last-known-position ghost where enemies think you areopenP2M2feature

    Description

    Why

    Showing where guards believe you are turns last-known position into a tool — the player can see the gap between belief and reality and exploit it.

    What

    As a thief, I want to see a faint silhouette where the enemies last saw me so that I can plan to double back or set up an ambush. When at least one hunting agent (Searching/Alerted) holds a player LKP and the player is out of its perception, render a translucent silhouette at the LKP in the stance last observed. Disappears when all agents lose the memory or re-acquire. Toggleable.

    Scope

    • In: Ghost model from aggregated agent memories
    • In: Placeholder translucent capsule silhouette
    • In: Settings toggle
    • Out: Accurate player mesh silhouette (asset integration later)

    Notes

    Aggregate: show the most recent LKP among hunting agents; if two diverge by > 10 m, show both.

    Acceptance criteria

    • AC-1 unit Given one Searching agent with an LKP and no perception of the player, when the ghost model is built, then one ghost at that LKP is returned.
    • AC-2 unit Given the agent re-acquires the player, when the model is built, then no ghost is returned.
    • AC-3 unit Given two hunting agents with LKPs 15 m apart, when built, then two ghosts are returned; if 5 m apart, one.
    • AC-4 e2e Given the stealth grey-box course, when the player breaks LOS from an Alerted guard, then a ghost appears at the break point within 250 ms.

    Waits on

    • mw-e11.8 Target memory and last-known position without omniscience done
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e31.1 Create typed settings store and options menu skeleton done
    area:gamearea:renderarea:uiclass:thiefepic:e09milestone:m2
  • mw-e09.19Derive collider sight occlusion from world properties (opaque/transparent + partial factor)openP2M2task

    Description

    Why

    mw-e09.1 gives line of sight its own per-collider Occlusion (opaque | transparent | partial:<factor>) supplied through LineOfSight's occlusionOf callback; unregistered colliders are opaque. The world-property vocabulary (v2, mw-e03.31) has opaque/transparent flags but no partial-cover factor, and colliders do not yet map to entities.

    What

    Map physics colliders to their entities and derive occlusionOf from world properties: opaque -> opaque, transparent -> transparent, neither -> partial with a factor (add a sightTransmittance-style property or material default). Level geometry without properties stays opaque.

    Notes

    Adding a property is a schema change: bump WORLD_PROPERTIES_VERSION.

    area:simclass:thiefepic:e09milestone:m2
  • mw-e09.20Supply equipment brightness, cloak and disguise to the visibility profileopenP2M2task

    Description

    Why

    The visibility model (mw-e09.2) has a profile term (equipment brightness × cloak × disguise), and selfVisibilityOf reads a stealth.visibilityProfile component, but nothing writes it: items have no brightness and there is no cloak or disguise flag, so every character reads neutral.

    What

    Add an optional item stealth field (brightness 0–2, conceals: cloak) and have equipment derive each actor's VisibilityProfileComponent (product of worn brightness, cloaked when a concealing item is worn); disguise from the disguise system when it exists.

    Scope

    • In: Item schema field, equipment-derived profile, register the component in the game world

    • Out: Disguise gameplay (its own bead)

    Acceptance criteria

    • AC-1 unit Given polished plate (brightness 1.3) equipped, when the profile is derived, then brightness is 1.3 and self-visibility rises by that factor.

    • AC-2 unit Given a cloak equipped, when derived, then cloaked is true and the tuning's cloak modifier applies.

    • AC-3 content Given an item brightness outside 0–2, when validated, then loading fails.

    area:simclass:thiefepic:e09milestone:m2
  • mw-e09.21Reconcile controller stance×gait visibility with the stealth tuningopenP2M2task

    Description

    Why

    Two tables now describe how visible movement is: the controller's stealth.profiles[stance][gait].visibility (mw-e02.10, published on MovementProfile) and the stealth tuning's stance × motion bands (mw-e09.2), which the visibility model uses. The shipped values agree today (stance × motion reproduces the controller table) but can drift.

    What

    Pick one source: drop visibility from the controller profiles (MovementProfile.visibility derived from the stealth tuning) or document why both exist. Move the AI stand-in senses onto the visibility model.

    Scope

    • In: Remove or derive the duplicate, update the stand-in senses, docs

    • Out: New tuning values (mw-e09.6)

    Acceptance criteria

    • AC-1 unit Given the shipped content, when a movement profile and the visibility model are computed for every stance × gait, then they read from one table.

    • AC-2 content Given the controller file, when validated, then no second visibility table exists (or a check pins them equal).

    area:contentarea:simclass:thiefepic:e09milestone:m2
  • mw-e09.23Creature footsteps read the ground collider's material, not just tagged regionsopenP2M2task

    Description

    Why

    Creature footstep noise (mw-e09.5) has no collider to read, so it uses the scene's tagged surface regions and otherwise stone. A skeleton walking on untagged gravel steps as stone (0 dB instead of +8), so it is quieter than the player on the same ground.

    What

    Give creatures the ground probe the player has: a downward query (or the nav mesh's surface material) that yields the ground material, wet and frozen state for a creature's feet, fed to installFootstepNoise's creatureSurface in startSceneNoise (src/game/creatures/ai.ts).

    Acceptance criteria

    • AC-1 integration Given a creature walking on an untagged gravel collider, when it steps, then its footstep noise carries the gravel offset (+8 dB).
    • AC-2 unit Given a creature on a tagged carpet region over gravel, when it steps, then the region wins, as for the player.
    • AC-3 [bench] Per-tick cost with 100 walking creatures stays within the footstep-noise bench budget.
    area:simclass:thiefepic:e09milestone:m2

M3 MVP content 1

  • mw-e09.17Stealth accessibility assists: slower detection, stronger cuesblockedP2M3feature

    Description

    Why

    Stealth must be approachable for players with different reaction speeds, hearing or vision without removing its systemic nature.

    What

    As a player, I want stealth assist options so that I can enjoy infiltration at my own pace. Options: detection speed (50–150%), show indicators for unperceived agents, visual captions for noise events (“Footsteps — left”), stronger visibility gem contrast, extended hiding stagger window. Applied via the whitelisted stealth/AI tuning overrides.

    Scope

    • In: Settings entries, override application, captions for noise events
    • Out: Global accessibility framework (E31)

    Notes

    Assists alter tuning inputs only; rules stay identical so scenario tests still hold at 100%.

    Acceptance criteria

    • AC-1 unit Given detection speed 50%, when a constant stimulus accumulates, then time to Suspicious doubles versus 100%.
    • AC-2 integration Given noise captions on, when a 40 dB noise is perceived by the player from the left, then a caption with direction left appears within 100 ms.
    • AC-3 unit Given an assist value outside the allowed range in settings storage, when loaded, then it clamps to the nearest bound.
    • AC-4 integration Given all assists off, when the infiltration suite runs, then baselines are unchanged.

    Waits on

    • mw-e09.11 Directional awareness indicators showing each enemy’s alert state open
    • mw-e09.6 Author stealth tuning data: light weights, stance, noise, doors open
    • mw-e31.1 Create typed settings store and options menu skeleton done
    • mw-e31.10 Provide difficulty presets and granular assists read by the sim done
    area:simarea:uiclass:thiefepic:e09milestone:m3

M4 Fun validation 1

  • mw-e09.18Playtest and tune stealth feel on the grey-box courseblockedP2M4task

    Description

    Why

    A perfectly executed infiltration should feel as satisfying as a hard fight; only playtesting confirms that.

    What

    Run 5 playtest sessions on the stealth course and first dungeon grey-box, record telemetry (detections, causes, time in each state, restarts), adjust tuning data, document changes in docs/design/stealth-tuning-log.md.

    Scope

    • In: Sessions, telemetry capture, tuning edits, log
    • Out: New mechanics (file new beads)

    Notes

    Tuning changes that alter scenario baselines must update them in the same PR with rationale.

    Acceptance criteria

    • AC-1 manual Given 5 sessions, when players complete the course, then ≥ 4 of 5 rate stealth ≥ 4/5 for “I understood why I was seen”.
    • AC-2 integration Given telemetry events for alert transitions, when exported, then each includes cause, state, and time-in-state fields.
    • AC-3 manual Given the tuning log, when reviewed, then each change lists the metric that motivated it.

    Waits on

    • mw-e09.10 Stealth HUD: light exposure, noise ring and stance readout open
    • mw-e09.11 Directional awareness indicators showing each enemy’s alert state open
    • mw-e09.16 Deterministic infiltration replay scenarios with asserted guard states open
    • mw-e34.1 Define local-first telemetry event schema, store and export open
    area:designarea:qaclass:thiefepic:e09milestone:m4
E10Thief ToolkitLockpicking, pickpocketing, thrown distractions, extinguishing lights, climbing, hiding bodies, disguises, silent movement, takedowns, traps and escape tools produce a complete thief fantasy built on shared world systems (properties, light, sound, AI perception).1/17 done · 6%

M2 Class fantasies 15

  • mw-e10.1Define thief tool item data: lockpicks, throwables, smoke, trapsopenP1M2task

    Description

    Why

    Thief tools are data-driven items so shops, loot and progression can hand them out without code.

    What

    Item definitions (in the inventory schema) for: lockpick set (durability), coin/pebble/bottle throwables (impact noise, breakable), smoke bomb, flash powder, noisemaker trap, tripwire kit, caltrops, rope, water flask (extinguish), sap/blackjack (non-lethal), disguise items referencing faction. Each carries world properties (weight, fragile, noise) and tags consumed by E10 features.

    Scope

    • In: Item data files + tests
    • In: Tags: tool:lockpick, throwable, trap:*, disguise:<faction>
    • Out: Loot/shop placement (E18/E20)
    • Out: Icons (asset beads)

    Notes

    Placeholder icon ids: icon-tool-lockpick, icon-throw-coin, icon-throw-bottle, icon-smoke-bomb, icon-trap-noisemaker, icon-trap-tripwire, icon-caltrops, icon-water-flask, icon-sap.

    Acceptance criteria

    • AC-1 content Given each thief item file, when validated, then it passes the inventory item schema and carries its required tags.
    • AC-2 content Given a throwable without an impact noise value, when validated, then validation fails.
    • AC-3 unit Given a lockpick set with durability 10, when resolved, then durability is 10 and it stacks to max 5 sets.
    • AC-4 content Given every thief item, when the content harness runs, then each has at least one automated test (spawn into inventory + use).

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e17.3 Implement inventory model with stacks, keys, books and quest items done
    area:contentclass:thiefepic:e10milestone:m2
  • mw-e10.2Throw objects to create noise distractions guards investigateblockedP1M2feature

    Description

    Why

    Thrown distractions are the thief’s first verb in the progression ladder (Sneak → distractions → …) and a classic stealth tool.

    What

    As a thief, I want to throw a coin or bottle so that guards look away or walk over to investigate. Any throwable item or physics object can be aimed (trajectory preview arc) and thrown; on impact it emits a noise event = item impact dB + surface offset; fragile items shatter (louder, leave shards as glass-shards surface). Guards perceive the propagated noise and investigate the perceived position. Thrown object remains in the world (anomaly if found near a post repeatedly — hook).

    Scope

    • In: Throw aim + arc preview + release
    • In: Impact noise via sound propagation + surface
    • In: Pickup-able thrown objects (non-fragile)
    • Out: Combat throwing damage (E04)
    • Out: Arrows (E05)

    Notes

    Uses physics objects for the throw; the noise rule is property-based (throwable, fragile), never item-specific.

    Acceptance criteria

    • AC-1 unit Given a coin (impact 45 dB) landing on stone 10 m from a guard with threshold 30 dB, when propagated, then the guard receives a heard-noise stimulus and enters Suspicious.
    • AC-2 unit Given a bottle tagged fragile landing, when it hits any surface, then it shatters, emits the fragile-break loudness and adds a glass-shards surface patch.
    • AC-3 unit Given a coin landing on carpet, when propagated to the same guard, then perceived loudness is reduced by the carpet offset and the guard stays Unaware.
    • AC-4 integration Given the distraction-room scenario, when the player throws a bottle behind a guard, then the guard turns and investigates the impact location within 2 s.
    • AC-5 unit Given a throw into water, when it lands, then a splash noise kind is emitted and the object sinks (not retrievable unless shallow).
    • AC-6 e2e Given the stealth grey-box course, when the player aims, then a trajectory arc renders and the landing marker matches the actual landing point within 0.5 m.

    Waits on

    • mw-e02.1 Map remappable KB/M input to deterministic per-tick action frames done
    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e03.25 Emit noise events from world interactions with material loudness done
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e09.4 Tag surfaces with acoustic materials that change footstep noise done
    • mw-e10.1 Define thief tool item data: lockpicks, throwables, smoke, traps open
    • mw-e11.10 Guards investigate suspicious stimuli at their perceived location open
    area:gamearea:simclass:thiefepic:e10milestone:m2
  • mw-e10.3Extinguish and relight light sources to reshape the shadowsblockedP1M2feature

    Description

    Why

    Extinguishing lights lets thieves create their own darkness, and any system that affects light (water, wind, frost magic) should work too.

    What

    As a thief, I want to snuff candles and douse torches so that I can create shadows where I need them. Light sources with property extinguishable go out from: interact (pinch/snuff, quiet), any wet/water effect via element propagation (thrown water flask, rain), strong wind/gust effects, frost. ignitable light sources relight from any fire source. Light-field updates immediately; extinguishing emits a small noise and creates an anomaly (e09-anomaly-detection).

    Scope

    • In: Light source state + property-based rules
    • In: Interact snuff action
    • In: Light-field update + anomaly record
    • Out: Light-field implementation (e03-light-field)
    • Out: Water arrows (E05) — works automatically via property

    Notes

    Magical lights may be tagged non-extinguishable; that is data.

    Acceptance criteria

    • AC-1 unit Given any extinguishable light within a water/wet effect volume, when the effect applies, then the light turns off and the light-field level at 2 m drops to the ambient value within 1 tick.
    • AC-2 unit Given an ignitable unlit torch in contact with any fire source, when 0.5 s passes, then it relights.
    • AC-3 unit Given a light tagged non-extinguishable, when water hits it, then it stays lit.
    • AC-4 integration Given the player snuffs a candle via interact, when complete, then a ≤ 15 dB noise is emitted and an anomaly light-out is registered for that light.
    • AC-5 integration Given a guard walking past a torch the player extinguished, when perceived, then the guard enters Suspicious with cause light-out.

    Waits on

    • mw-e02.5 Focus and interact with world objects via contextual prompts done
    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e03.16 Extinguish and relight torches, candles and braziers systemically done
    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e09.9 Guards notice world anomalies: bodies, open doors, dark torches open
    area:gamearea:simclass:thiefepic:e10milestone:m2
  • mw-e10.4Backstabs and non-lethal takedowns on unaware targetsopenP1M2feature

    Description

    Why

    Opportunistic combat is the thief’s combat fantasy: ambushes and takedowns reward patience and positioning.

    What

    As a thief, I want to backstab or knock out an unaware enemy from behind so that a clean infiltration can thin the guard without a fight. Conditions: target alert state ∈ {Unaware, Suspicious}, player within rear arc (±60°) and 1.5 m, target does not perceive the player this think. Lethal backstab: damage multiplier from damage model (lethal on humanoids by default). Non-lethal (sap/choke): target becomes unconscious for a data-defined duration (default 10 min sim) unless woken. Creature schema flags (immune-to-knockout for undead/constructs, no-backstab for huge creatures) gate the verbs. Takedown emits noise (choke 20 dB, backstab 35 dB). Failed attempts (target turns) cause a scuffle: target enters Combat staggered.

    Scope

    • In: Prompt availability, execution, outcomes, noise
    • In: Creature flags gating
    • In: Failure scuffle outcome
    • Out: Environmental takedowns (e10-environmental-takedowns)
    • Out: Animations (placeholder snaps)

    Notes

    Unconscious bodies are carriable (e10-body-carry-hide) and anomalies (e09-anomaly-detection).

    Acceptance criteria

    • AC-1 unit Given an Unaware humanoid and the player 1 m behind within 60°, when takedown is evaluated, then both backstab and knockout verbs are available.
    • AC-2 unit Given the same target in Investigating or higher, when evaluated, then no takedown verb is available.
    • AC-3 unit Given a creature flagged immune-to-knockout, when evaluated, then only backstab is available.
    • AC-4 unit Given a knockout, when executed, then the target is unconscious for 600 s sim and a 20 dB noise is emitted at its position.
    • AC-5 unit Given the target perceives the player during the 0.5 s wind-up, when the takedown resolves, then it fails, the target enters Combat and is staggered for 0.8 s.
    • AC-6 integration Given the patrol-yard scenario, when the player knocks out a guard out of sight of others, then the other guards remain Unaware.

    Waits on

    • mw-e02.5 Focus and interact with world objects via contextual prompts done
    • mw-e04.1 Deterministic damage model: damage types, resistances, poise, death done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    area:gamearea:simclass:thiefepic:e10milestone:m2
  • mw-e10.5Carry and hide unconscious or dead bodiesblockedP1M2feature

    Description

    Why

    Hiding bodies is how thieves cover their tracks; a body left in the light should cause the alarm the player earned.

    What

    As a thief, I want to pick up and hide bodies so that patrols do not discover what I did. Pick up unconscious/dead humanoid-size creatures (size class limit), carry at reduced speed (−40%) and no sneak-sprint, higher visibility (+profile), drop or place into hiding places with body-capacity (chests, wardrobes, deep shadow, water). Placed bodies inside containers are invisible to anomaly detection; bodies in darkness depend on visibility. Unconscious creatures carried keep their wake timer.

    Scope

    • In: Carry state, movement modifiers, drop/place
    • In: Body containers
    • In: Integration with anomaly detection
    • Out: Ragdoll physics beyond placeholder (Related: physics/animation)
    • Out: Looting bodies (e17 / E18)

    Notes

    Dropping a body emits a thud noise scaled by surface (e.g. 35 dB on stone).

    Acceptance criteria

    • AC-1 unit Given an unconscious guard, when the player picks it up, then player speed is ×0.5 (ADR-0003, matches mw-e02.17) and the visibility profile term increases by the configured amount.
    • AC-2 unit Given the player carrying a body, when placed into a container with body capacity 1, then the body is hidden and the container is full.
    • AC-3 unit Given a body placed in a container, when a guard perceives the container, then no body anomaly is raised unless the guard opens it.
    • AC-4 unit Given a creature larger than the carry size limit, when pickup is attempted, then it is refused with reason too-heavy.
    • AC-5 unit Given the unconscious carried guard’s wake timer expires, when it wakes while carried, then it is dropped, enters Alerted and the player is staggered 0.5 s.

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e09.8 Hiding places: wardrobes, barrels, tall grass and shadowed alcoves open
    • mw-e09.9 Guards notice world anomalies: bodies, open doors, dark torches open
    • mw-e10.4 Backstabs and non-lethal takedowns on unaware targets open
    area:gamearea:simclass:thiefepic:e10milestone:m2
  • mw-e10.6Spike: systemic lockpicking design that stays in the worldopenP1M2spike

    Description

    Why

    The constitution prefers world systems over disconnected minigames. Lockpicking must keep the player in the world, exposed to guards and noise, while still involving skill.

    What

    Time-box 1 day. Question: how can lockpicking be an in-world, interruptible action with a light skill layer (e.g. timing tension clicks while the camera stays third-person) instead of a full-screen minigame? Prototype 2 variants in the grey-box (A: timed hold with pin-click timing windows; B: pure duration by lock quality vs tool/skill with noise risk), evaluate readability, tension with nearby guards, accessibility (a no-skill option), and progression hooks. ADR with recommendation.

    Scope

    • In: Two prototypes in spikes/lockpicking/
    • In: ADR with lock data shape (quality, pins, noise per failure, jam chance)
    • Out: Production lockpicking (e10-lockpicking)

    Notes

    Must remain compatible with sorcerer/knight alternatives (Unlock spell, bashing) via the same lock component from e03-doors-locks-switches.

    Acceptance criteria

    • AC-1 manual Given the ADR, when reviewed, then it records the choice, rejected alternatives, and a data shape for lock quality.
    • AC-2 manual Given 3 internal testers, when trying both prototypes near a patrolling guard, then preferences and time-to-open are recorded in the ADR.
    • AC-3 manual Given the ADR, when read, then it specifies an accessibility mode that removes timing requirements.

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    area:designarea:simclass:thiefepic:e10milestone:m2
  • mw-e10.7Pick locks as an in-world, interruptible, noisy actionblockedP1M2feature

    Description

    Why

    Locked doors and chests are the thief’s signature alternate routes; picking them in the world while guards patrol creates tension.

    What

    As a thief, I want to pick locks while staying aware of my surroundings so that opening a door is a tense, skilful choice rather than a menu. Implements the ADR: locks carry quality (1–5), pin count, jam chance; picking is an in-world action (player stays visible and hearable, camera third-person) consuming lockpick durability; skill layer per ADR with an accessibility no-timing mode. Failures emit small noises and may break a pick; jamming a lock makes it unpickable (bash/magic still work). Progression hooks raise max quality.

    Scope

    • In: Lock component extension, pick action, noise, durability, jam
    • In: In-world UI overlay (placeholder)
    • In: Accessibility mode
    • Out: Door/lock base mechanics (e03-doors-locks-switches)
    • Out: Unlock spells/bashing (E06/E04, same component)

    Notes

    Default noise per failed pin 18 dB; broken pick 25 dB.

    Acceptance criteria

    • AC-1 unit Given a quality-2 lock and one lockpick set, when the pick action completes successfully, then the lock is unlocked and durability decreases by 1.
    • AC-2 unit Given a failed pin attempt, when resolved, then an 18 dB noise event is emitted at the lock.
    • AC-3 unit Given a lock jams (seeded chance), when evaluated, then further pick attempts are refused with reason jammed while other unlock methods still work.
    • AC-4 unit Given the player is attacked or moves > 0.5 m while picking, when resolved, then the action is interrupted and progress is lost.
    • AC-5 unit Given lock quality above the player’s unlocked max, when the prompt is evaluated, then picking is not offered and the prompt says why.
    • AC-6 integration Given accessibility no-timing mode, when picking a quality-3 lock, then it completes after the documented duration without input timing.
    • AC-7 e2e Given the stealth grey-box door maze, when the player picks a locked door, then the door opens and the navmesh link becomes traversable.

    Waits on

    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e10.1 Define thief tool item data: lockpicks, throwables, smoke, traps open
    • mw-e10.6 Spike: systemic lockpicking design that stays in the world open
    • mw-e18.3 Add lootable containers that persist their contents done
    • mw-e19.10 Grant thief verbs from tools and tricks learned from contacts open
    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    area:gamearea:simarea:uiclass:thiefepic:e10milestone:m2
  • mw-e10.8Pickpocket and plant items on creatures from behindblockedP1M2feature

    Description

    Why

    Pickpocketing creates emergent solutions: steal a key instead of picking a lock, plant evidence, lift a guard’s disguise pass.

    What

    As a thief, I want to lift items from, or plant items on, unaware creatures so that I can solve problems without violence. Available when target is Unaware/Suspicious, not perceiving the player, within 1.2 m behind/side arc. Opens a compact in-world list of visible pockets (creature inventory items flagged pocketable). Each attempt takes time by item weight; success chance falls with target awareness and item weight; a failed attempt raises target awareness sharply (Alerted if it turns and sees you). Theft is recorded (disposition/faction events for witnesses).

    Scope

    • In: Pickpocket and plant actions, success model, witness events
    • In: Creature inventory integration
    • In: Compact UI (placeholder)
    • Out: Creature loot tables (e18-loot-tables)
    • Out: Crime/bounty (Related: crime system)

    Notes

    Success probability formula documented in tuning data; seeded RNG.

    Acceptance criteria

    • AC-1 unit Given an Unaware guard with a pocketable key, when the player attempts from behind at 1 m, then the item transfers on success and the attempt takes the weight-scaled duration.
    • AC-2 unit Given a failed attempt, when resolved, then the target’s awareness increases by the configured spike and it turns toward the player.
    • AC-3 unit Given a witness guard perceives the theft, when resolved, then a witnessed-theft event fires applying disposition and faction modifiers.
    • AC-4 unit Given a target with no pocketable items, when the prompt is evaluated, then the verb is offered but the list shows “Nothing to take” (still allows planting).
    • AC-5 unit Given the target walks out of range mid-attempt, when resolved, then the attempt cancels without a transfer or awareness spike.
    • AC-6 integration Given the player plants an item on a guard, when saved and loaded, then the guard’s inventory contains the planted item.

    Waits on

    • mw-e02.5 Focus and interact with world objects via contextual prompts done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e12.8 Faction table and relationship queries between creatures done
    • mw-e12.9 Per-creature disposition toward the player with event modifiers done
    • mw-e17.3 Implement inventory model with stacks, keys, books and quest items done
    • mw-e18.6 Track item ownership and flag stolen items on witnessed theft open
    • mw-e18.7 Drop what creatures actually carry, plus data-driven extras open
    • mw-e19.10 Grant thief verbs from tools and tricks learned from contacts open
    area:gamearea:simarea:uiclass:thiefepic:e10milestone:m2
  • mw-e10.12Detect and disarm world traps; failures trigger themblockedP1M2feature

    Description

    Why

    Triggered traps should create new situations rather than reloads; spotting and disarming them is thief expertise.

    What

    As a thief, I want to notice and disarm pressure plates, tripwires and dart traps so that I can open safe routes — and accept the chaos when I fail. Traps have a concealment value; the player perceives them via a proximity/light-based check (thieves have a bonus; sneaking slower improves it) which reveals a subtle highlight. Disarm is an in-world timed action (like lockpicking) with a failure chance by trap quality; failure triggers the trap. Disarmed traps can be picked up (become placeable items where data allows).

    Scope

    • In: Trap detection check, reveal highlight, disarm action, fail-trigger
    • In: Salvage to item
    • Out: Trap mechanics/effects themselves (e03-triggers / e03-doors-locks-switches)
    • Out: Dungeon trap placement (E26)

    Notes

    Detection uses light-field at trap position: dark traps are harder to spot.

    Acceptance criteria

    • AC-1 unit Given a trap with concealment 0.5 in light 0.8, when a thief sneaks within 3 m, then it is detected within 1 s.
    • AC-2 unit Given the same trap in light 0.1, when a knight walks within 3 m, then it is not detected.
    • AC-3 unit Given a disarm attempt that fails (seeded), when resolved, then the trap triggers its normal effect.
    • AC-4 unit Given a successfully disarmed pressure plate, when a creature steps on it, then nothing triggers.
    • AC-5 integration Given a disarmed tripwire, when salvaged, then a tripwire kit item is added to inventory.

    Waits on

    • mw-e02.5 Focus and interact with world objects via contextual prompts done
    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e03.21 Wire trigger volumes and mechanisms with data-defined signal graphs done
    • mw-e03.31 Consolidate world-property vocabulary assumed by other epics done
    • mw-e10.1 Define thief tool item data: lockpicks, throwables, smoke, traps open
    • mw-e18.3 Add lootable containers that persist their contents done
    • mw-e19.10 Grant thief verbs from tools and tricks learned from contacts open
    area:gamearea:simclass:thiefepic:e10milestone:m2
  • mw-e10.13Smoke bombs and flash powder break line of sight for escapesblockedP1M2feature

    Description

    Why

    Escape tools turn failed stealth into a chase instead of a death — the thief’s disengagement fantasy.

    What

    As a thief, I want to throw a smoke bomb so that I can break line of sight and slip away. Smoke bomb creates a gas volume (via element propagation, drifts and dissipates over 12 s) tagged occlusion: partial:0.1 for LOS; creatures inside have sight disabled and cough (noise). Flash powder: instant stun for creatures facing it within 5 m (sight-dependent — blind/life-sense creatures unaffected). Losing LOS feeds LKP rules, so guards search where you vanished.

    Scope

    • In: Smoke gas volume + LOS occlusion + dissipation
    • In: Flash stun rule by sense profile
    • In: Integration with memory/LKP
    • Out: Gas propagation engine (e03-element-propagation)
    • Out: VFX art (placeholders)

    Notes

    Smoke is a gas: a Gust effect should clear it via the same gas rules (property-based).

    Acceptance criteria

    • AC-1 unit Given a smoke volume between guard and player, when LOS is queried, then visible fraction ≤ 0.1.
    • AC-2 unit Given a smoke volume, when 12 s pass without wind, then it has dissipated and LOS is restored.
    • AC-3 unit Given flash powder within 5 m and a guard facing it, when detonated, then the guard is stunned 3 s; a creature without sight senses is not stunned.
    • AC-4 integration Given a Combat guard chasing the player, when the player throws smoke and runs 10 m sideways, then the guard enters Searching with LKP at the smoke cloud, not the player’s position.
    • AC-5 unit Given any gas-clearing wind effect through the smoke volume, when applied, then the volume moves/dissipates per gas rules.

    Waits on

    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e09.1 Multi-point line-of-sight queries with partial cover and see-through done
    • mw-e10.1 Define thief tool item data: lockpicks, throwables, smoke, traps open
    • mw-e11.8 Target memory and last-known position without omniscience done
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    area:gamearea:simclass:thiefepic:e10milestone:m2
  • mw-e10.17Grey-box thief infiltration challenge with multiple scripted routesblockedP1M2task

    Description

    Why

    Milestone m2 requires the thief fantasy proven in grey-box; a perfect infiltration must feel as good as a hard fight.

    What

    A grey-box vault infiltration greybox/thief-vault: guarded courtyard, lit halls, a locked vault with a key carried by a patrolling guard, climbable exterior wall, alarm bell, hiding places. At least 3 distinct solution routes (pickpocket key; climb + pick window lock; distraction + extinguish + takedown), each covered by a scripted e2e/scenario test. Records a “ghost” (never detected) flag on completion.

    Scope

    • In: Level data, routes, scripted solution tests, completion flag
    • Out: Final dungeon (E26)
    • Out: Art

    Notes

    Fixture creatures only.

    Acceptance criteria

    • AC-1 integration Given route A (pickpocket), when the scripted scenario runs, then the vault opens and no guard exceeds Suspicious.
    • AC-2 integration Given route B (climb + lockpick window), when run, then the vault is reached and the completion flag is set.
    • AC-3 integration Given route C (distract + extinguish + takedown), when run, then the vault opens with one unconscious guard hidden and no alarm.
    • AC-4 integration Given a scripted failure (player spotted in the courtyard), when run, then the alarm escalates the zone and the scripted escape via smoke + hiding place still completes the level.
    • AC-5 manual Given 3 playtesters, when completing the vault undetected, then ≥ 2 rate satisfaction ≥ 4/5.

    Waits on

    • mw-e09.14 Failed stealth escalates into new situations, not reload screens open
    • mw-e09.15 Build the stealth grey-box course covering every stealth input open
    • mw-e10.13 Smoke bombs and flash powder break line of sight for escapes open
    • mw-e10.3 Extinguish and relight light sources to reshape the shadows open
    • mw-e10.4 Backstabs and non-lethal takedowns on unaware targets open
    • mw-e10.7 Pick locks as an in-world, interruptible, noisy action open
    • mw-e10.8 Pickpocket and plant items on creatures from behind open
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    area:contentarea:qaclass:thiefepic:e10milestone:m2
  • mw-e10.10Disguises that fool factions until behaviour gives you awayblockedP2M2feature

    Description

    Why

    Disguises are a later thief verb in the progression ladder and create social infiltration moments.

    What

    As a thief, I want to wear a faction’s uniform so that I can walk among guards if I behave. Equipping a disguise:<faction> item makes that faction’s members treat the player as disguised instead of intruder: sight stimuli accumulate a separate suspicion meter driven by proximity (< 3 m), suspicious behaviour (running, crouching, climbing, being in restricted zones, being seen committing crimes, carrying bodies), and observer traits (officers and dogs see through faster; sees-through-disguise flag). Suspicion full → disguise blown for that zone (remembered).

    Scope

    • In: Disguise state, per-observer suspicion rules, restricted zone data, blown-state memory
    • Out: Dialogue with disguised player (E22)
    • Out: Uniform art (placeholder recolour)

    Notes

    Suspicion rules are tuning data; restricted zones are level regions.

    Acceptance criteria

    • AC-1 unit Given the player wears a disguise of faction A and walks at normal speed 8 m from an A guard in a public zone, when 30 s pass, then the guard remains Unaware.
    • AC-2 unit Given the same player sprints within 3 m, when evaluated, then disguise suspicion accumulates at the running rate and the guard enters Suspicious within 3 s.
    • AC-3 unit Given an observer flagged sees-through-disguise, when it perceives the player, then the disguise is ignored.
    • AC-4 unit Given the disguise is blown in zone Z, when the player re-enters Z still disguised, then Z’s guards treat the player as an intruder.
    • AC-5 unit Given a faction B guard, when perceiving the player in faction A disguise, then normal intruder rules apply.

    Waits on

    • mw-e10.1 Define thief tool item data: lockpicks, throwables, smoke, traps open
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e11.6 Accumulate and decay awareness from stimuli per perceived target done
    • mw-e12.8 Faction table and relationship queries between creatures done
    • mw-e17.3 Implement inventory model with stacks, keys, books and quest items done
    • mw-e22.1 Turn witnessed crimes into settlement bounties with pay/jail/flee open
    area:gamearea:simclass:thiefepic:e10milestone:m2
  • mw-e10.11Place traps: noisemakers, tripwires and caltropsblockedP2M2feature

    Description

    Why

    Traps let the thief shape the battlefield ahead of time — dirty tricks and disengagement are the thief combat fantasy.

    What

    As a thief, I want to place traps so that I can lure, slow or warn about enemies. Place trap items on valid surfaces with a placement preview: noisemaker (timed or triggered noise event), tripwire (trigger volume between two anchors → alarm noise for player, or trip/stagger), caltrops (slow + damage zone, noise when stepped). Traps are world objects with properties (flammable tripwire burns, etc.), perceivable by AI (visibility check); perceiving an armed trap makes AI avoid it and become Suspicious.

    Scope

    • In: Placement preview + validity, trap objects, trigger logic via e03-triggers
    • In: AI avoidance of perceived traps (nav cost)
    • Out: World/dungeon traps and disarming (e10-trap-disarm)
    • Out: Trap art (placeholders)

    Notes

    Creatures can trigger player traps; the player can too (friendly fire).

    Acceptance criteria

    • AC-1 unit Given a caltrops item and a flat valid surface, when placed, then a slow zone (×0.5 speed) with damage 2/s exists at the location.
    • AC-2 unit Given a placement on a slope > 30° or in water, when previewed, then placement is invalid with reason.
    • AC-3 unit Given a tripwire between two anchors, when any creature crosses it, then its trigger fires once and it becomes spent.
    • AC-4 unit Given a guard perceives an armed caltrops zone, when pathing, then its path avoids the zone if an alternative exists and it enters Suspicious.
    • AC-5 unit Given a tripwire tagged flammable in a fire volume, when 1 s passes, then it burns and is removed without triggering.

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e03.21 Wire trigger volumes and mechanisms with data-defined signal graphs done
    • mw-e10.1 Define thief tool item data: lockpicks, throwables, smoke, traps open
    • mw-e11.4 Navmesh generation and deterministic pathfinding for creatures done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    area:gamearea:simclass:thiefepic:e10milestone:m2
  • mw-e10.14Silent movement unlocks: soft steps, muffled gear, shadow dashopenP2M2feature

    Description

    Why

    Anti-grind rule: progression unlocks verbs, not +12%. Silent movement should grow into new capabilities.

    What

    As a thief, I want to unlock ways to move more silently so that I can take bolder routes. Capability unlocks via the progression model: soft-step (sneak gait ignores creaky-board creaks and gravel offset), muffled-gear (equipment noise halved while sneaking), shadow-dash (short burst of sneak-speed movement at walk noise while in light ≤ 0.2). Each is a data-defined modifier applied to the footstep/visibility rules.

    Scope

    • In: Three capability modifiers as data + rule hooks
    • Out: Progression UI and unlock sources (E19)

    Notes

    Modifiers alter inputs to e09-footstep-noise and e09-visibility-model only; rules stay pure.

    Acceptance criteria

    • AC-1 unit Given soft-step unlocked, when sneaking on wood-creaky, then no creak event is ever emitted over 1,000 seeded steps.
    • AC-2 unit Given muffled-gear and equipment noise +10 dB, when sneaking, then the footstep includes +5 dB equipment noise.
    • AC-3 unit Given shadow-dash in light 0.5, when activated, then it is refused because light exceeds 0.2.
    • AC-4 unit Given no unlocks, when evaluated, then footstep results equal the base rule exactly.

    Waits on

    • mw-e09.5 Emit footstep noise from speed, stance, surface and equipment weight done
    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    area:contentarea:simclass:thiefepic:e10milestone:m2
  • mw-e10.15Lean around corners and peek through keyholesopenP2M2feature

    Description

    Why

    Information is the thief’s currency; peeking lets players scout routines before committing.

    What

    As a thief, I want to lean around corners and peek through keyholes so that I can scout without exposing myself. Lean shifts camera and exposes only the head sample point to LOS (reduced visibility). Keyhole peek on doors with a keyhole flag gives a narrow view of the next room with the player fully hidden from that room.

    Scope

    • In: Lean input + camera offset + LOS sample override
    • In: Keyhole peek interaction
    • Out: Camera system (e02-camera)

    Notes

    During lean, only the head sample point counts for LOS (1 of 4).

    Acceptance criteria

    • AC-1 unit Given the player leaning, when LOS is queried by an observer, then only the head sample point is considered.
    • AC-2 unit Given a door without a keyhole, when interaction options are built, then peek is not offered.
    • AC-3 integration Given a keyhole peek, when active, then the camera renders from the keyhole position and visibility to observers in the other room is 0.
    • AC-4 unit Given the player is attacked while peeking, when damage applies, then peek ends immediately.

    Waits on

    • mw-e02.1 Map remappable KB/M input to deterministic per-tick action frames done
    • mw-e02.4 Follow the player with a colliding, orbiting third-person camera done
    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e09.1 Multi-point line-of-sight queries with partial cover and see-through done
    area:gamearea:simclass:thiefepic:e10milestone:m2

M3 MVP content 1

  • mw-e10.16Environmental takedowns: drop, push and douse via world propertiesblockedP2M3feature

    Description

    Why

    The progression ladder ends at environmental takedowns; the world itself becomes the thief’s weapon, and it must be systemic.

    What

    As a thief, I want to drop a chandelier, cut a hanging load or push a crate from a ledge onto an enemy so that the world does my work. Any object with suspended property released (cut rope, shot chain, lever) falls under physics; impact damage = f(mass, fall height) via the damage model. Deaths/knockouts caused by environment are tagged accident so witnesses raise lower suspicion (Suspicious/Investigating instead of Alerted) unless they perceived the player causing it.

    Scope

    • In: Falling-object damage rule by mass/height
    • In: Accident attribution + AI response weights
    • Out: Specific set-pieces (E26 content)
    • Out: Rope cutting by arrows (E05, works via property)

    Notes

    Property-based: never "chandelier" in rules.

    Acceptance criteria

    • AC-1 unit Given any object tagged suspended with mass 80 kg released from 5 m onto a creature, when impact resolves, then damage equals the documented mass×height curve.
    • AC-2 unit Given a creature killed by a falling object with no witness perceiving the player within 3 s, when attributed, then the event is tagged accident.
    • AC-3 unit Given a witness to an accident, when evaluated, then it enters Investigating (not Alerted).
    • AC-4 unit Given a witness perceived the player releasing the object, when evaluated, then it enters Alerted with the player LKP.

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e04.1 Deterministic damage model: damage types, resistances, poise, death done
    • mw-e09.9 Guards notice world anomalies: bodies, open doors, dark torches open
    • mw-e10.4 Backstabs and non-lethal takedowns on unaware targets open
    area:simclass:thiefepic:e10milestone:m3
E11Enemy AIEnemies patrol, perceive, investigate, communicate, fight, retreat, search and return to believable routines through a deterministic, data-driven behaviour runtime and the six-state alert machine (Unaware → Suspicious → Investigating → Searching → Alerted → Combat). Enemies never know the player position except through their senses.14/26 done · 54%

M1 Grey-box slice 5

  • mw-e11.22Owner review: accept or reject ADR-0006 (pure-TS navmesh vs recast-navigation-js)openP1M1task

    Description

    Why

    mw-e11.4 (PR #162) shipped a pure-TypeScript navmesh bake and A* and recorded the choice as ADR-0006, status Proposed.

    What

    Owner reads docs/adr/0006-navmesh-and-pathfinding.md and accepts (flip status to Accepted) or rejects (file a migration bead to recast-navigation-js).

    Acceptance criteria

    AC-1 manual ADR-0006 status is Accepted or Rejected with the owner's decision recorded.

    area:designarea:simepic:e11milestone:m1needs-human
  • mw-e11.20Bake one navmesh per agent size class (small, humanoid, large)openP2M1task

    Description

    Why

    Briar Wolves (0.4 m) and Brother Horn are wider than the humanoid radius (0.35 m) every scene is baked for (mw-e11.4, ADR-0006), so they can clip corners and squeeze through gaps they should not fit; goblins (0.3 m) path more conservatively than they need to.

    What

    Bake each navigated scene for a small set of agent size classes (e.g. 0.3 / 0.35 / 0.6 m radius, matching heights) and pick the navmesh by a creature's NavAgent radius at query time.

    Scope

    • In: bake settings per size class in the navmesh data or a sibling file, query-time selection, pnpm nav:check coverage
    • Out: crowd simulation

    Notes

    Related: src/sim/nav/bake.ts, src/tools/navmesh/bake.ts, ADR-0006 consequence 'One agent size per navmesh'.

    Acceptance criteria

    • AC-1 unit Given a 0.6 m gap, when a 0.35 m agent and a 0.8 m-radius agent request a path through it, then only the smaller one's path uses the gap.
    • AC-2 integration Given the testbed, when the bake runs for every size class, then all navmeshes are produced in <= 10 s and content validation passes.
    area:simepic:e11milestone:m1milestone:m2
  • mw-e11.24Smell and magic-sense channel handlers for perceptionopenP2M1task

    Description

    Why

    Sense profiles can give creatures smell and a magic-sense channel, but perception (mw-e11.5) has no handler for either, so a wolf cannot smell the thief and a warded creature cannot feel a spell: those senses silently perceive nothing.

    What

    Register a smell handler (range, wind sensitivity, scent trails from the smell profile) and a magic-sense handler (active spells and enchanted items as sources) in the special-sense channel registry, producing typed percepts. Needs scent sources and magic sources in the sim.

    Scope

    • In: Smell and magic-sense handlers; their percept kinds or reuse of sensed-life

    • Out: Wind simulation; scent trail simulation beyond a hook

    Notes

    Channel registry is src/sim/perception/channels.ts; content channels are SPECIAL_SENSE_CHANNELS.

    Acceptance criteria

    • AC-1 unit Given a creature with smell range 10 m downwind of the player 8 m away, when evaluated, then a percept from smell is produced; upwind it is not.

    • AC-2 unit Given a creature with magic-sense and a lit spell 5 m away behind a wall, when evaluated, then a percept is produced when requiresLineOfSight is false.

    Waits on

    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    area:simepic:e11milestone:m1milestone:m2
  • mw-e11.25Draw claimed search points in the AI debug overlayblockedP2M1task

    Description

    Why

    mw-e11.17's AI debug overlay lists claimed search points per agent, but no search system claims points yet (search patterns are mw-e11.11), so the snapshot has nothing to draw.

    What

    When mw-e11.11 lands, add each agent's claimed search points to the AI introspection snapshot (src/sim/debug/ai-snapshot.ts) and draw them in src/render/debug/ai-overlay.ts (markers tinted by alert state, with the claiming agent in the label).

    Acceptance criteria

    • AC-1 unit Given an agent searching with claimed points, when the snapshot is built, then it lists those points.
    • AC-2 e2e Given a searching guard and ai.debug on, then its claimed points render with no console errors.

    Waits on

    • mw-e11.11 Search patterns around last-known position, including hiding spots open
    area:renderarea:simarea:toolsepic:e11milestone:m1
  • mw-e11.26Persist the nav path queue so a save mid-request resumes identicallyopenP2M1task

    Description

    Why

    mw-e12.14 made a loaded world continue exactly as one never saved (creature components, brains and perception bookkeeping are all saved). One gap remains, accepted in mw-e11.4: the navmesh path request queue (src/sim/nav/queue.ts) lives in the navigation port, not the world. A save taken while an agent's path request waits or is half-searched loads with its nav.route 'lost': the agent resubmits it (same start and goal), under a new request id, and the search starts over, so the resumed run's state hash differs from the uninterrupted run's for a few ticks onward. Nothing breaks for the player, but the resume-determinism property (and any golden that saves mid-chase) does not hold with navmesh travel.

    What

    Make the queue's state part of the world so saves carry it: its next request id, the waiting requests in order (request + the budgets each search step was given, so a search can be rebuilt by replaying its steps) and finished results not yet taken. Load rebuilds the queue from that state, and the 'lost route resubmits' path stays only for saves from before.

    Acceptance criteria

    • AC-1 integration Given navmesh AI travel with a tight per-tick budget and a save taken while a request is half-searched, when loaded into a fresh world and run on, then the state hash at the end equals the uninterrupted run's.
    • AC-2 unit Given a save from before this change with a pending route, when loaded, then the agent resubmits and reaches its goal (no regression).
    area:simepic:e11milestone:m1milestone:m2

M2 Class fantasies 7

  • mw-e11.10Guards investigate suspicious stimuli at their perceived locationopenP1M2feature

    Description

    Why

    Distractions only work if guards go and look. Investigation is the core lever for thrown objects, noises and glimpses.

    What

    As a thief, I want a guard to walk over and check a noise or glimpse so that I can lure him away from his post. In Suspicious: stop, turn toward stimulus, text bark cue. In Investigating: path to stimulus position at walk (or cautious) gait, look around on arrival with a scan pattern, inspect the source object if perceived (e.g. a thrown bottle), then decide: nothing found → de-escalate; more stimuli → escalate. Multiple stimuli: most recent strong one wins; weaker stimuli queue up to 3.

    Scope

    • In: Investigate behaviour, scan pattern, source inspection, stimulus queue
    • In: Cautious gait when postAlert
    • Out: Group investigation roles (e11-communication)
    • Out: Search around LKP (e11-search-behaviour)

    Notes

    Investigation position is the perceived position (may be offset by sound routing), not the true source.

    Acceptance criteria

    • AC-1 unit Given an Investigating guard with target position 12 m away, when simulated, then it arrives within (12 / walkSpeed + 1) s and performs a scan of ≥ 3 look directions.
    • AC-2 unit Given a second, louder stimulus while investigating, when perceived, then the guard retargets to the new position and the first is queued.
    • AC-3 unit Given an unreachable stimulus position (on a roof), when investigating, then the guard moves to the closest reachable point, looks toward the position for the scan duration, then de-escalates.
    • AC-4 integration Given a scenario where a noise occurs behind a closed door, when the guard investigates, then it opens the door (if unlocked) before scanning the room.
    • AC-5 unit Given a queue already holding 3 stimuli, when a 4th weaker stimulus arrives, then the weakest is dropped.

    Waits on

    • mw-e11.4 Navmesh generation and deterministic pathfinding for creatures done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e11.8 Target memory and last-known position without omniscience done
    area:simepic:e11milestone:m2
  • mw-e11.11Search patterns around last-known position, including hiding spotsblockedP1M2feature

    Description

    Why

    A convincing search — fanning out, checking corners and wardrobes — makes escaping feel earned, and gives up plausibly so failure does not force a reload.

    What

    As a thief, I want searching guards to check plausible places near where they lost me so that hiding well matters and hiding badly gets me caught. Searching generates candidate points around LKP (+ bounded prediction): nav-reachable points ranked by distance, cover/darkness, and whether the point is out of sight from LKP; plus hiding spots within radius. Agents claim points (no two agents search the same point), check hiding spots with a probability based on whether they saw the target enter it, expand radius over time, then give up.

    Scope

    • In: Candidate generation, ranking, claiming, radius expansion
    • In: Hiding-spot checks with probability rules
    • In: Diligence trait scaling of duration
    • Out: Hiding place mechanics (e09-hiding-places)
    • Out: Alarm raising (e11-communication)

    Notes

    Probability of checking a hiding spot: 1.0 if target was seen entering; otherwise base 0.25 scaled by proximity to LKP. Seeded RNG.

    Acceptance criteria

    • AC-1 unit Given a Searching guard with LKP L, when candidates are generated, then all lie within the current radius, are nav-reachable and the first 3 are sorted by the ranking function.
    • AC-2 unit Given two guards searching the same LKP, when they claim points, then no point is claimed by both.
    • AC-3 unit Given the guard saw the target enter a hiding spot, when searching, then it checks that spot first with probability 1.0.
    • AC-4 unit Given a hiding spot not seen being entered, 10 m from LKP, when evaluated with a fixed seed, then the check decision matches the documented probability formula.
    • AC-5 unit Given no reachable candidates (LKP on an isolated ledge), when searching, then the guard looks toward LKP from the nearest point, then de-escalates at the search timeout without error.
    • AC-6 integration Given a scenario where the player hides in darkness 8 m from LKP and stays still, when a single guard searches for 60 s, then the guard ends Searching without entering Combat in the scripted seed.

    Waits on

    • mw-e03.23 Hide in wardrobes, barrels and haystacks and search containers done
    • mw-e11.10 Guards investigate suspicious stimuli at their perceived location open
    • mw-e11.4 Navmesh generation and deterministic pathfinding for creatures done
    • mw-e11.8 Target memory and last-known position without omniscience done
    area:simepic:e11milestone:m2
  • mw-e11.12Allies share alerts by shouts, sight signals and alarm devicesopenP1M2feature

    Description

    Why

    Enemies that communicate make a single mistake escalate believably, and give players targets — silence the shouter, cut the bell rope.

    What

    As a thief, I want guards to call for help through the world rather than telepathy so that I can prevent or exploit alarms. Channels: shout (emits a loud noise event via sound propagation carrying a report: LKP, state), visual signal (allies in LOS within 25 m receive the report), alarm device (agents path to a nearest alarm object and activate it via the interaction/mechanism system, broadcasting Alerted to a faction zone). Only allies (faction relation ally/friendly) accept reports. Group roles in Alerted/Searching: one caller, others flank/search.

    Scope

    • In: Report message type, shout/visual/alarm channels
    • In: Faction filtering
    • In: Basic role assignment (caller, searcher, guard-post-holder)
    • Out: Reinforcement spawning (e09-failed-stealth-outcomes)
    • Out: Speech/voice (text barks only — e09-alert-barks)

    Notes

    Alarm objects are world mechanisms with an alarm property; if destroyed or jammed, the AI must fall back to shouting. Related: alarm bell mechanism may be authored with E03 switches.

    Acceptance criteria

    • AC-1 unit Given a guard entering Alerted, when it shouts, then a noise event of the configured loudness is emitted and allies whose perceived level exceeds their hearing threshold receive the report.
    • AC-2 unit Given a guard behind 2 closed doors whose shout is attenuated below an ally’s threshold, when shouting, then that ally receives nothing.
    • AC-3 unit Given a creature of a hostile faction within hearing, when a shout occurs, then it does not receive the report (it may still perceive the noise as a stimulus).
    • AC-4 unit Given an alarm object that has been disabled (jammed or destroyed), when a guard attempts to use it, then it falls back to shouting within 2 s.
    • AC-5 integration Given a scenario with 3 guards and one alarm bell, when the first guard spots the player and reaches the bell, then all guards in the bell’s zone enter Alerted within 1 tick of activation.
    • AC-6 unit Given a guard is knocked out mid-path to the alarm, when the tick runs, then no alarm activation occurs.

    Waits on

    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e11.8 Target memory and last-known position without omniscience done
    • mw-e12.8 Faction table and relationship queries between creatures done
    area:simepic:e11milestone:m2
  • mw-e11.14Creatures retreat, flee to allies and cower based on moraleblockedP1M2feature

    Description

    Why

    Enemies that retreat, regroup or flee make fights and scares feel alive and allow non-lethal victories.

    What

    As a player, I want frightened or wounded creatures to disengage so that encounters end in more ways than death. Consumes Flee/Cower intents from e12-fears-morale and health thresholds: flee away from the fear source toward allies, safe zones or a lair point; cower when cornered; regroup and re-enter Alerted/Searching when morale recovers. Fleeing creatures may shout (communication) and drop carried items (hook).

    Scope

    • In: Flee destination scoring, cower, regroup
    • In: Surrender intent event (hook for E14 dialogue)
    • Out: Morale model (e12-fears-morale)
    • Out: Surrender dialogue (E14/E22)

    Notes

    Flee destination scoring: distance from threat, ally proximity, darkness preference per creature.

    Acceptance criteria

    • AC-1 unit Given a creature with a Flee intent and threat at T, when fleeing, then after 3 s its distance from T has increased and its path does not pass within 2 m of T.
    • AC-2 unit Given a fleeing creature with no escape path (dead end), when cornered, then it enters Cower within 1 s.
    • AC-3 unit Given morale recovers above the regroup threshold, when the intent clears, then the creature enters Searching with the threat’s last-known position.
    • AC-4 unit Given a creature tagged fearless (morale disabled), when at 1 health, then it never flees.

    Waits on

    • mw-e11.12 Allies share alerts by shouts, sight signals and alarm devices open
    • mw-e11.13 Combat behaviour: engage, space, select attacks and share targets done
    • mw-e12.10 Creature fears and morale that trigger fleeing and cowering open
    area:simepic:e11milestone:m2
  • mw-e11.15Guards return to routines, visibly changed by what happenedopenP1M2feature

    Description

    Why

    Failure creates stories: after an alert guards should go back to work, but the world should remember — lit torches, doubled posts, grumbling barks.

    What

    As a thief, I want guards to settle back down after an alert but stay changed so that my mistakes reshape the level instead of resetting it. On de-escalation: path back to routine, apply post-alert adjustments from data (e.g. relight extinguished lights on route, close opened doors, patrol in pairs, add a checkpoint post, carry a torch), keep heightened awareness for a duration. Adjustments are data-driven per behaviour profile and recorded as world facts.

    Scope

    • In: Return behaviour, post-alert adjustment list, persistence via world state
    • In: Barks cue on return
    • Out: Level lockdowns/reinforcements (e09-failed-stealth-outcomes)

    Notes

    Adjustments list example: relight-seen-extinguished-lights, close-seen-open-doors, pair-up, carry-torch.

    Acceptance criteria

    • AC-1 unit Given a guard de-escalates with postAlert=true, when simulated, then it resumes its route within 5 s and awareness rate multiplier is 1.5 for 300 s, then 1.0.
    • AC-2 unit Given a guard with the relight-seen-extinguished-lights adjustment that perceived an extinguished torch during the alert, when returning, then it paths to the torch and relights it before resuming.
    • AC-3 unit Given the torch was destroyed (not merely extinguished), when the adjustment runs, then the guard skips it and switches to carry-torch if declared.
    • AC-4 integration Given a save after an alert with pair-up applied, when loaded, then the paired patrol persists.

    Waits on

    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e11.9 Patrol routes, guard posts and idle routines authored as data done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    area:simepic:e11milestone:m2
  • mw-e11.16Author AI tuning data: thresholds, decay timers, search durationsopenP1M2task

    Description

    Why

    Stealth feel is tuned constantly; all numbers must be data so designers can iterate without code and tests can pin defaults.

    What

    A AiTuning schema and default files per behaviour profile: awareness thresholds per state, accumulation rates per sense, grace and decay timers, state timeouts (Suspicious 6 s, Investigating 20 s, Searching 60 s, Alerted 120 s defaults), post-alert multiplier and duration, search radius growth, token budgets, think rates. Profiles inherit (guard-default → guard-lazy). Hot-reload in dev.

    Scope

    • In: Schema, inheritance, defaults, hot reload in dev builds
    • In: Pinned default-value tests
    • Out: Sense ranges (e12-sense-profiles)
    • Out: Stealth emitter tuning (e09-stealth-tuning-data)

    Notes

    Changing defaults requires updating pinned tests deliberately — that is the point.

    Acceptance criteria

    • AC-1 content Given the default tuning files, when validated, then every state has a positive timeout and thresholds are strictly increasing Suspicious < Investigating < Detected.
    • AC-2 unit Given guard-lazy inheriting from guard-default overriding only Searching timeout 30 s, when resolved, then all other values equal the parent.
    • AC-3 unit Given an inheritance cycle, when loaded, then loading fails naming the cycle.
    • AC-4 integration Given a dev build, when a tuning file is edited, then running agents use the new values within 1 s without reload.
    • AC-5 unit Given the shipped defaults, when the pinned-default test runs, then each documented default matches.

    Waits on

    • mw-e00.18 Load schema-validated content with a per-entry test harness done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    area:contentarea:simepic:e11milestone:m2
  • mw-e11.18Perf budget: 24 active AI agents within sim frame budgetblockedP1M2task

    Description

    Why

    The hardware baseline requires steady 60 fps; AI perception, pathing and sound propagation are the likeliest sim hot spots.

    What

    Add an AI stress scene and budget tests: 24 agents (mixed fixtures) in Alerted/Searching with continuous noise events and a moving target. Budgets: total AI+perception+sound sim cost p95 ≤ 3 ms per tick on the reference machine; ≤ 5 ms on the Low-preset class machine. Includes LOS cache and level-of-detail think rates (agents > 40 m from player think at 2 Hz).

    Scope

    • In: Stress scene, budget assertions, AI LOD think rates, LOS result caching
    • Out: Render perf (E32)

    Notes

    Numbers cite the contract hardware baseline.

    Acceptance criteria

    • AC-1 perf Given the AI stress scene with 24 agents, when run for 60 s headless on the reference machine, then AI+perception+sound cost p95 ≤ 3 ms per tick.
    • AC-2 unit Given an agent 50 m from the player with LOD enabled, when 60 ticks run, then it thinks 2 times; within 40 m it thinks 10 times.
    • AC-3 unit Given AI LOD, when an out-of-range agent receives a noise stimulus above threshold, then it is promoted to full think rate on the next tick (no missed alerts).
    • AC-4 perf Given the stress scene in the browser (High), when measured, then frame time p95 ≤ 16.7 ms.

    Waits on

    • mw-e11.11 Search patterns around last-known position, including hiding spots open
    • mw-e11.13 Combat behaviour: engage, space, select attacks and share targets done
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    area:perfarea:simepic:e11milestone:m2
E12Creature FrameworkCreatures are data: unique senses, locomotion, attacks, property-driven vulnerabilities, factions/relationships, dispositions, fears/morale, personalities, needs and non-hostile interaction affordances are all declared in validated content and consumed by AI and stealth systems — ready for the bestiary (E13) and social creatures (E14).10/20 done · 50%

M1 Grey-box slice 4

  • mw-e12.18Creatures stand on the ground and get knocked back through a character controlleropenP1M1feature

    Description

    Why

    Spawned creatures (mw-e12.4) are placed entities: they have no body in the controller or physics world, so they do not fall to the ground from a raised spawn, and hit reactions compute knockbacks and launches for them that nothing applies (the pushers act on the player's CharacterController and physics objects only). The constitution wants creatures that are creatures, not target dummies.

    What

    Give each spawned creature a kinematic character body sized from its nav agent (radius, height, step height, max slope) so it stands on and collides with the level, and apply hit-reaction pushes to it like the player's. Locomotion speeds stay AI's (e11) business.

    Scope

    • In: per-creature controller capsule from its locomotion; gravity; knockback/launch pushes.
    • Out: pathfinding (mw-e11.4), AI steering.

    Acceptance criteria

    • AC-1 integration Given fixture-hound spawned 2 m above the floor, when 60 ticks pass, then it stands on the floor.
    • AC-2 integration Given a knockback-tier hit on fixture-guard, when the reaction plays, then the guard moves away from the attacker and never through a wall.
    • AC-3 unit Given the same seed and inputs, two runs hash identically.
    area:contentarea:simepic:e12milestone:m1
  • mw-e12.17Creature projectiles collide with level geometryopenP2M1task

    Description

    The mw-e12.5 projectile executor flies straight and only tests living hurtboxes (placement + health); walls and props do not stop it. Once the physics layer (e03.10) exposes sim-side raycasts/sweeps, stop projectiles at geometry and emit an impact event.

    area:contentepic:e12milestone:m1
  • mw-e12.19Creatures name their own lock-on targetable profile in dataopenP2M1task

    Description

    Why

    Spawned creatures are lock-on targets (mw-e12.4), but their lock points are derived from their nav agent height (chest 60 %, head 90 %, base 25 %) because the creature schema has no way to name a targetable profile, though src/content/types/targetable.ts says creatures will. A spider's weak point or a wraith's head should be data, not a formula.

    What

    Add an optional targetable ref to CreatureDef; the spawner uses it when present and keeps the derived profile as the default.

    Scope

    • In: schema field, docs regen, spawner use, fixture untouched (default).
    • Out: bow weak-point targeting (e05).

    Acceptance criteria

    • AC-1 unit Given a creature naming a targetable profile, when spawned in a world with lock-on, then its Targetable points equal the profile's.
    • AC-2 unit Given a creature naming none, then its points are the derived chest/head/base profile.
    area:contentarea:simepic:e12milestone:m1
  • mw-e12.20Spawn creature hurtboxes from content regions and toggle weak points by stateopenP2M1task

    Description

    Follow-up from mw-e05.6 (PR #327). The creature schema now has a regions array (region, multiplier, armor, enabledIn, underlying) and the sim resolves weakpoints via setRegionState/effectiveHurtbox, but the spawner does not build hurtboxes from regions and no creature AI/state calls setRegionState. No shipped creature declares regions yet.

    AC-1 unit A creature with authored regions spawns hurtboxes carrying those multipliers, armor and enabledIn.

    AC-2 unit A creature entering a state listed in a weakpoint's enabledIn (e.g. roaring) enables it via setRegionState; leaving disables it.

    AC-3 content At least one slice creature (e.g. the forgotten shield) declares an armored region so deflection can be seen in play.

    area:contentepic:e12milestone:m1

M2 Class fantasies 6

  • mw-e12.7Drive creature vulnerabilities from world properties, not pairingsopenP1M2feature

    Description

    Why

    The constitution requires systemic interactions: a creature tagged flammable should burn from any fire source, and undead should respond to any light effect, without scripted spell/creature pairs.

    What

    As a player, I want creatures to react to the same world properties as objects so that my experiments transfer. Creatures carry world-property tags (from e03-world-properties) plus vulnerabilities/resistances keyed by damage type or property effect (e.g. heat: x2, frozen: immune, light: stagger). A sim rule applies element-propagation effects to creatures exactly as to objects, then applies the creature multiplier.

    Scope

    • In: Property tags on creatures participate in element propagation
    • In: Multiplier + immunity + special reaction (stagger, flee trigger) data
    • In: Resolution order documented
    • Out: New element types (E03)
    • Out: Specific creature weaknesses (E13)

    Notes

    Express everything as properties; tests must use property names, never spell names. Reactions can emit a FearStimulus consumed by e12-fears-morale.

    Acceptance criteria

    • AC-1 unit Given any creature tagged flammable inside an active fire volume, when 1 s of sim time passes, then it gains the burning state.
    • AC-2 unit Given a creature with resistances.heat: immune, when inside a fire volume, then it takes 0 heat damage and does not gain burning.
    • AC-3 unit Given a creature with vulnerabilities.cold: 2.0, when it receives a 10-point cold packet, then it loses 20 health.
    • AC-4 unit Given a creature with reaction light: stagger and light level at its position rising above the configured threshold within 1 tick, then it enters stagger once and not again until light falls below the threshold (no re-trigger spam).
    • AC-5 content Given a vulnerability keyed by an unknown property or damage type, when validated, then validation fails listing known keys.

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e04.1 Deterministic damage model: damage types, resistances, poise, death done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    area:contentarea:simepic:e12milestone:m2
  • mw-e12.10Creature fears and morale that trigger fleeing and coweringopenP1M2feature

    Description

    Why

    Creatures have fears. Frightening a wolf pack with fire or breaking goblin morale by felling their leader are non-lethal solutions the constitution wants.

    What

    As a player, I want to exploit what creatures fear so that I can win encounters without killing everything. fears: list of {stimulus property or faction or event, intensity}. Morale 0–100 per creature, reduced by fear stimuli, ally deaths, low health, leader death; restored over time and near allies. Below thresholds the creature emits Cower or Flee intents for the AI.

    Scope

    • In: Fear stimulus matching via properties (e.g. anything burning or light level > X)
    • In: Morale model + thresholds + recovery
    • In: Group morale shock when a leader-tagged ally dies
    • Out: Flee movement behaviour (e11-retreat-flee)
    • Out: Intimidation dialogue (E14)

    Notes

    Fear stimuli are perceived — the creature must sense the burning object (via e11-perception) for it to count.

    Acceptance criteria

    • AC-1 unit Given a creature with fear {property burning, intensity 30} and morale 50, when it perceives a burning object within 5 m, then morale drops to 20 and a Flee intent is emitted (flee threshold 25).
    • AC-2 unit Given a fear stimulus the creature cannot perceive (behind a wall), when evaluated, then morale is unchanged.
    • AC-3 unit Given a leader-tagged creature dies, when allies within 20 m perceive it, then each ally loses the configured leader-shock morale once.
    • AC-4 unit Given morale 10 and no stimuli, when 30 s pass near 2 allies, then morale recovers by the configured rate and the Flee intent clears once above 35 (hysteresis).
    • AC-5 content Given a fear with intensity outside 0–100, when validated, then validation fails.

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    area:contentarea:simepic:e12milestone:m2
  • mw-e12.13Declare non-hostile creature interactions (feed, talk, calm) in dataopenP1M2feature

    Description

    Why

    Not everything exists solely to be killed. Social creatures (E14) need a framework hook: feeding, talking, intimidating, petting or trading must be declarable per creature.

    What

    As a designer, I want to declare which non-hostile verbs a creature accepts and under what conditions so that E14 can build social creatures without new engine code. interactions: list of {verb (talk, feed, intimidate, calm, pet, trade, give), conditions (disposition range, alert state ∈ {Unaware, Suspicious}, item tag required), outcome event id}. Available verbs surface as contextual prompts via the interaction system; executing emits a typed sim event consumed by dialogue/disposition rules.

    Scope

    • In: Schema, condition evaluation, prompt surfacing, outcome events
    • In: Alert-state gating (cannot pet a creature in Combat)
    • Out: Dialogue trees (e22-dialogue-runtime)
    • Out: Specific social creatures and their outcomes (E14)

    Notes

    Outcome events feed e12-dispositions modifier rules, e.g. feed with any edible item applies the fed modifier.

    Integration note: Promoted to P1 — befriending/helping creatures (Brother Horn, the goblins, Clatter) is an MVP constitution pillar and depends on this.

    Acceptance criteria

    • AC-1 unit Given a creature declaring feed requiring item tag edible:meat, when the player holds no such item, then the feed verb is not offered.
    • AC-2 unit Given the same creature in Combat state, when the player holds meat, then feed is not offered.
    • AC-3 integration Given the grey-box testbed and a fixture creature declaring feed, when the player feeds it, then the item is removed from inventory, a CreatureInteracted{verb: feed} event fires and disposition rises by the fed modifier.
    • AC-4 content Given an interaction with an unknown verb, when validated, then validation fails listing allowed verbs.
    • AC-5 unit Given two verbs with overlapping conditions, when prompts are built, then both are offered in declared order.

    Waits on

    • mw-e02.5 Focus and interact with world objects via contextual prompts done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e12.9 Per-creature disposition toward the player with event modifiers done
    • mw-e17.3 Implement inventory model with stacks, keys, books and quest items done
    area:contentarea:gamearea:simepic:e12milestone:m2
  • mw-e12.11Personality traits that weight AI decisions per individualopenP2M2task

    Description

    Why

    Personalities make creatures memorable: a lazy guard who gives up searching early, a curious goblin who investigates every noise.

    What

    Trait vector (bravery, curiosity, aggression, diligence, sociability, greed) 0–1 per creature, def default plus seeded per-spawn jitter within a declared range. Traits are exposed as inputs to the behaviour runtime (utility weights or BT conditions) and to tuning curves (e.g. diligence scales search duration).

    Scope

    • In: Schema, deterministic jitter, accessor API
    • In: Documented list of which AI behaviours read which trait
    • Out: Dialogue personality/voice (E22)
    • Out: Named-character authored personalities (E13/E14 content)

    Notes

    Jitter must come from the seeded sim RNG keyed by entity id so replays match.

    Acceptance criteria

    • AC-1 unit Given a def with curiosity 0.5 ± 0.2, when 1,000 spawns are sampled with a fixed seed, then all values lie within 0.3–0.7 and the sequence is identical across runs.
    • AC-2 unit Given diligence 1.0 vs 0.0 with base search duration 60 s and diligence scale 0.5–1.5, then search durations are 90 s and 30 s respectively.
    • AC-3 content Given a trait outside 0–1, when validated, then validation fails.
    • AC-4 unit Given a creature with no personality section, when resolved, then all traits default to 0.5 with zero jitter.

    Waits on

    • mw-e11.2 Implement the deterministic behaviour runtime chosen by the ADR done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    area:contentarea:simepic:e12milestone:m2
  • mw-e12.12Creature needs (hunger, sleep, fatigue) with behaviour hooksopenP2M2feature

    Description

    Why

    A hungry beast that can be lured with meat or a guard who dozes at 3am turns creatures into systems the player can read and exploit.

    What

    As a thief, I want creatures to eat, sleep and tire so that I can time or engineer my approach. Needs (hunger, sleep, fatigue, plus extensible custom needs) rise over sim time at data-defined rates; satisfiers are world objects tagged with properties (edible:meat, bed) or schedule windows. Crossing thresholds emits intents (SeekFood, Sleep) the behaviour runtime may choose. Sleeping creatures use a reduced sense profile.

    Scope

    • In: Need decay/satisfaction model
    • In: Property-based satisfier discovery via perception
    • In: Sleep modifies senses (e.g. sight off, hearing −20 dB)
    • Out: Day/night world clock (owned by world/time systems — Related: world clock)
    • Out: Poisoned bait (e10 / alchemy post-MVP)

    Notes

    Needs must be cheap: update at 1 Hz, not per tick. Related: a world time-of-day clock is needed for schedule windows; if none exists use sim time with a configurable day length.

    Acceptance criteria

    • AC-1 unit Given hunger rate 10/min and threshold 70, when 7 sim minutes pass from 0, then a SeekFood intent is emitted exactly once.
    • AC-2 unit Given a hungry creature that perceives any object tagged edible:meat within 15 m, when it chooses SeekFood, then its target is the nearest perceived edible object.
    • AC-3 unit Given a sleeping creature, when a 30 dB noise occurs 5 m away and its awake threshold is 25 dB with sleep penalty 20 dB, then it does not wake; a 50 dB noise wakes it into Suspicious.
    • AC-4 unit Given an edible object that is removed while a creature walks to it, when it arrives, then the intent fails gracefully and the creature returns to its routine within 3 s.
    • AC-5 unit Given 200 creatures with needs, when 1 sim hour elapses, then needs update 3,600 times per creature (1 Hz) and never per tick.

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e11.2 Implement the deterministic behaviour runtime chosen by the ADR done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    area:contentarea:simepic:e12milestone:m2
  • mw-e12.16Write the creature authoring guide with a worked exampleblockedP2M2task

    Description

    Why

    The world-content group will author the bestiary in parallel; a single guide keeps creatures consistent and systemic.

    What

    A designer guide docs/content/creatures.md: every schema section explained, how senses/fears/needs/personality affect AI, property-based vulnerability rules, a worked example built from fixtures (not a real bestiary creature), checklist for a new creature (data, smoke test, placeholder asset ids, prompt bead).

    Scope

    • In: Guide + checklist + links to generated schema reference
    • Out: Bestiary entries (E13)

    Notes

    Link from docs/backlog-contract.md is out of scope for this bead; content group will reference the guide.

    Acceptance criteria

    • AC-1 content Given the guide, when its worked-example JSON is extracted by a doc test, then it validates against CreatureDef.
    • AC-2 manual Given a designer unfamiliar with the code, when following the checklist, then they can add a new creature that passes the smoke harness in ≤ 30 min.
    • AC-3 unit Given the generated schema reference, when a schema field is added without documentation, then the doc-coverage check fails.

    Waits on

    • mw-e12.13 Declare non-hostile creature interactions (feed, talk, calm) in data open
    • mw-e12.15 Auto-generate smoke tests for every creature data file done
    area:contentarea:designepic:e12milestone:m2
E13BestiaryThe ten MVP creature types from the story bible (the Forgotten, Rootcellar Goblins, Brother Horn, Loom Spiders, Briar Wolves, Hushlings, Tallow Ooze, Mimics, Hollow Sentinels, the Sleepless Abbot) exist as data on e12-creature-schema with behaviours, property-driven vulnerabilities, readable telegraphed attacks and at least one avoid/trick option each. Horn and the Abbot have authored boss encounters.1/19 done · 5%

M2 Class fantasies 2

  • mw-e13.2Write the MVP bestiary design sheet for all ten creaturesopenP1M2task

    Description

    Why

    Creatures are creatures, not target dummies; each needs behaviours, fears and non-combat options designed before data is authored.

    What

    docs/design/bestiary.md: for each of the ten MVP creatures — role, senses, locomotion, faction, move list with telegraph type and timings, vulnerabilities as world properties (never pairings), fears, avoid/trick/social options, placement areas, song-intensity behaviour, and asset needs pointer.

    Scope

    • In: Design sheet for all ten creatures
    • In: Telegraph table
    • In: Property-vulnerability table
    • Out: Creature data (per-creature items)
    • Out: Creature lore text (e39-item-creature-text)

    Notes

    Names and lore must match docs/narrative/story-bible.md §8 exactly.

    Acceptance criteria

    • AC-1 content Given the sheet, when reviewed, then every creature lists >= 1 avoid option and >= 1 trick or social option.
    • AC-2 content Given the sheet, when reviewed, then every vulnerability is expressed as a property or stimulus (e.g. "frozen and fragile shatters"), with zero spell- or item-name pairings.
    • AC-3 content Given the telegraph table, when reviewed, then every unblockable or grab move lists windup >= 500 ms and a distinct audio+VFX cue id.

    Waits on

    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:designepic:e13milestone:m2
  • mw-e13.3Forgotten crumble and reassemble unless bones are scattered or burnedblockedP1M2feature

    Description

    Why

    Bible §8: the Forgotten crumble and reassemble — understanding that rule, and breaking it systemically, is the fight.

    What

    As a player, I want downed skeletons to rise again unless I deal with their bones so that I learn to fight smart (scatter, burn, smash).

    On Died, the skeleton becomes a bone-pile entity (physics, flammable after oil, fragile). After 8 s it reassembles if >= 60% of bones remain within 2 m. Blocked by: bones scattered by force/impulse, bones burning or burnt, crushing blunt hit on the pile, or holy water (tag consecrated). Animate Bones may claim a pile.

    Scope

    • In: Bone-pile entity, reassembly timer and rules, property hooks
    • Out: Animate Bones spell (e08-spell-animate-bones)

    Notes

    Rules via properties only: impulse, burning, blunt impact, consecrated. Reassembly emits a telegraph (bones rattle, 1 s) so players can react.

    Acceptance criteria

    • AC-1 unit Given a bone pile untouched, when 8 s pass, then the skeleton reassembles at 50% health with a 1 s telegraph beforehand.
    • AC-2 unit Given a bone pile hit by an impulse that moves > 40% of bones beyond 2 m, when 8 s pass, then it does not reassemble and becomes inert.
    • AC-3 unit Given a bone pile with burning = true for >= 2 s, when evaluated, then it becomes burnt and never reassembles, regardless of the heat source.
    • AC-4 integration Given a pile reassembles while the player stands on it, when it completes, then the player is displaced safely with no clipping (edge).

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e12.7 Drive creature vulnerabilities from world properties, not pairings open
    • mw-e13.1 Add the Forgotten skeleton with the e04 three-move set done
    area:contentepic:e13milestone:m2

M3 MVP content 15

  • mw-e13.4Add monk Forgotten and habit routines that ignore quiet playersblockedP1M3feature

    Description

    Why

    The Forgotten are people who forgot themselves; they sweep, pray and haul — and can be avoided.

    What

    As a thief, I want skeletons absorbed in old habits so that I can slip past, and as a player I want the monk variant to fight differently.

    forgotten-monk (staff sweep, censer swing that carries live embers) plus habit routines as patrol data: sweeping, praying at altars, hauling buckets/stone. Habit trance: perception reduced 50% while performing a habit; noise above a threshold breaks it. Calmed by hymn-tagged noise (see e14-hum-vesper-hymn); hostile regardless at song intensity 3.

    Scope

    • In: Monk variant data and moves, habit routine library, trance perception modifier, calm rule
    • Out: Song-intensity state (e13-song-intensity)
    • Out: Placement (E26)

    Notes

    The censer is a heat source: it ignites flammable things it touches, including the monk's own oil-soaked surroundings. Related: e03-gas-clouds (P2) — if it lands, the censer may also leave a smoke cloud.

    Acceptance criteria

    • AC-1 content Given forgotten-monk.json, when validated, then its moves pass readability and its censer move declares a heat stimulus via the stimulus API.
    • AC-2 integration Given a sweeping Forgotten and a crouched player moving at walk speed 4 m behind it in dim light, when 10 s pass, then it stays Unaware.
    • AC-3 integration Given a Forgotten in Combat, when a hymn-tagged noise reaches it at song intensity <= 2, then it drops to Unaware and resumes its habit within 3 s.
    • AC-4 integration Given song intensity 3, when the hymn is heard, then the Forgotten ignores it and stays hostile (edge).

    Waits on

    • mw-e03.3 Inject heat, cold, water, charge, force and gas via one stimulus API done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e11.9 Patrol routes, guard posts and idle routines authored as data done
    • mw-e13.1 Add the Forgotten skeleton with the e04 three-move set done
    • mw-e14.1 Let the player hum the Vesper hymn after reading the Vesperine Hours open
    area:contentepic:e13milestone:m3
  • mw-e13.5Drive creature behaviour from a global song-intensity world stateopenP1M3feature

    Description

    Why

    The Nightjar's song is the dungeon's weather: when it swells, the Forgotten turn, Hushlings multiply and Clatter forgets.

    What

    As a designer, I want one world fact song.intensity (0–3) that creature data can react to so that story beats reshape encounters without scripts.

    Fact set by quest effects (e39-main-quest-data) and by events (sour bell ring = +1 for 5 minutes; Horn dead = +1 permanent). Creature data declares modifiers per intensity: aggression, perception, spawn weights, calm immunity.

    Scope

    • In: Fact registration, timed modifiers, creature-data modifier hook, debug command
    • Out: Which quest beats set it (E39)

    Notes

    Also read by audio (music tension layer) — Related: e28-adaptive-music.

    Acceptance criteria

    • AC-1 unit Given intensity 1 and a +1 timed modifier for 300 s, when 300 s elapse, then intensity returns to 1 exactly once.
    • AC-2 unit Given modifiers pushing intensity above 3, when evaluated, then it clamps to 3 (edge).
    • AC-3 integration Given a Hushling spawner with weights per intensity, when intensity rises from 1 to 2, then spawn weights switch on the next spawner evaluation.

    Waits on

    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    • mw-e27.5 Query world facts with a shared condition API for all systems done
    area:simepic:e13milestone:m3
  • mw-e13.6Add Rootcellar goblin combatants: slings, nets and loud alarmsblockedP1M3feature

    Description

    Why

    Goblins are clever scavengers, not fodder: they call for help, flee when outnumbered and can be talked to.

    What

    As a player, I want goblins that fight like a clan (slings, nets, alarms, retreat) so that fighting them feels different from undead.

    goblin-scavenger and goblin-slinger data: sling stone (ranged, 300 ms windup), net throw (grab-class, 500 ms, entangles 2 s, flammable), kettle-helm (head region blunt resistance 0.5, pierce deflect). Alarm pots and shouts via e11-communication. Morale: flee when allies are outnumbered 2:1. Immune to song and Hushling mimicry (they do not dream).

    Scope

    • In: Two goblin variants, moves, head region armour, morale thresholds, alarm device entity
    • Out: Talking, trade, capture-negotiation (E14)
    • Out: Camp placement (e26-deepworks-encounters)

    Notes

    Surrender intent (e11-retreat-flee) opens E14 negotiation.

    Acceptance criteria

    • AC-1 content Given both goblin files, when validated, then the net throw declares a grab telegraph >= 30 ticks with distinct cue ids.
    • AC-2 integration Given a goblin netted player, when any heat source touches the net, then the net burns off and the player is freed.
    • AC-3 integration Given 3 goblins facing a player plus 2 allied creatures, when one goblin falls, then the rest flee toward the nearest alarm device.
    • AC-4 unit Given song intensity 3, when goblin perception and aggression are evaluated, then they are unchanged (edge: goblins immune).

    Waits on

    • mw-e04.20 Creatures attack via the move system with readable telegraphs done
    • mw-e05.6 Headshots, weak points and armored regions that deflect done
    • mw-e11.12 Allies share alerts by shouts, sight signals and alarm devices open
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e12.10 Creature fears and morale that trigger fleeing and cowering open
    area:contentepic:e13milestone:m3
  • mw-e13.7Add Loom Spiders that weave readable webs and fear bright lightblockedP1M3feature

    Description

    Why

    Loom spiders make the Outer Ring feel alive and teach "light and fire change the fight".

    What

    As a player, I want pale dog-sized spiders that climb walls, web routes and flee bright light so that I can drive them off instead of fighting.

    loom-spider: climber locomotion (walls/ceilings), bite (poison), web spit (slows 40% for 3 s, 300 ms windup). Places web entities (flammable, blocks passage, can carry copied rune text). Fear: light level >= 0.7 at its position triggers flee. Fire: burning = flee + damage.

    Scope

    • In: Creature data, web entity prefab with readable text slot, fear-of-light rule
    • Out: Web rune-clue puzzle placement (e26-knot-rune-navigation)

    Notes

    Webs readable by any class with a light source; sorcerers with Hornfolk fragments read more (content in E26/E39).

    Acceptance criteria

    • AC-1 content Given loom-spider.json, when validated, then it declares climber locomotion and a light-level fear threshold.
    • AC-2 integration Given a spider in Combat, when the light level at its position rises to >= 0.7 from any source, then it flees to the darkest reachable point within 20 m.
    • AC-3 integration Given a web in a doorway, when it ignites, then it burns away within 3 s and the doorway navmesh link opens.
    • AC-4 integration Given no dark point is reachable, when fear triggers, then the spider cowers in place and its defence drops (edge).

    Waits on

    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e12.10 Creature fears and morale that trigger fleeing and cowering open
    • mw-e12.6 Support walker, climber, flier, swimmer and burrower locomotion data done
    area:contentepic:e13milestone:m3
  • mw-e13.8Add silent Briar Wolf packs that can be fed, scared or rememberedblockedP1M3feature

    Description

    Why

    The wolves' silence is the first uncanny sign; a pack not fought should remember the player.

    What

    As a player, I want a wolf pack that circles, flanks and can be fed or frightened so that the Briarwood has a living threat with options.

    briar-wolf: fast walker, smell + hearing; bite, lunge (300 ms), flank coordination. Fear of fire (burning within 4 m). Feeding: meat items (edible:meat) thrown near the pack pacify for 120 s and raise pack disposition. Pack memory world fact (wolves.fed, wolves.harmed) persists and changes greeting behaviour. Sleepwalkers are ignored (song stills animals).

    Scope

    • In: Wolf data, pack coordination tags, feeding rule, fear rule, pack-memory facts
    • Out: Den placement (e25-wolf-den)

    Notes

    Silent: wolves have no howl cue while the breach is open; add a howl variant for the "Vespers Rung" ending state.

    Acceptance criteria

    • AC-1 integration Given a pack Suspicious of the player, when an edible:meat item lands within 5 m, then the pack eats and stays non-hostile for 120 s.
    • AC-2 integration Given a burning object within 4 m of a wolf, when evaluated, then the wolf backs away and will not path through the fire.
    • AC-3 integration Given fact wolves.fed >= 2, when the player next enters the den, then the pack starts at disposition Wary instead of Hostile.
    • AC-4 integration Given a sleepwalking NPC passes through the pack, when perceived, then no wolf targets the NPC (edge).

    Waits on

    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e12.10 Creature fears and morale that trigger fleeing and cowering open
    • mw-e12.13 Declare non-hostile creature interactions (feed, talk, calm) in data open
    • mw-e12.9 Per-creature disposition toward the player with event modifiers done
    area:contentepic:e13milestone:m3
  • mw-e13.9Add blind Hushlings that hunt by sound and break at loud noisesblockedP1M3feature

    Description

    Why

    Hushlings are the thief's nightmare and playground: silence is survival, loudness is a weapon.

    What

    As a thief, I want blind fog-children that hunt purely by sound so that silence and distraction are my tools; as a knight, I want to learn that my clanking draws them.

    hushling: sight disabled, hearing only, drifts; grasp attack (500 ms, unblockable, distinct whisper cue). Mimic barks using the names of the missing ("Da? I'm cold"). Any noise event with loudness >= 0.85 within 6 m tears them apart (dissipate). Ignore goblins.

    Scope

    • In: Creature data with hearing-only senses, loud-noise dissipation rule, mimic bark set ids
    • Out: Bark text (e39-item-creature-text)
    • Out: Placement (E25/E26)

    Notes

    Loud sources include bells, Thunderclap, shattered glass, shield bash on metal — all via noise loudness, never pairings.

    Acceptance criteria

    • AC-1 integration Given a crouched player moving silently in full light within 3 m, when 10 s pass, then the Hushling does not detect them (sight disabled).
    • AC-2 integration Given a noise event of loudness >= 0.85 within 6 m, when propagated, then every Hushling in range dissipates.
    • AC-3 integration Given a thrown distraction at 8 m, when heard, then the Hushling investigates the noise location, not the player.
    • AC-4 content Given the grasp attack, when validated, then it is unblockable with windup >= 30 ticks and a unique audio cue (edge: readability for a blind hunter).

    Waits on

    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e11.10 Guards investigate suspicious stimuli at their perceived location open
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e12.2 Add sense profile data: sight cones, hearing, smell, special senses done
    area:contentclass:thiefepic:e13milestone:m3
  • mw-e13.10Add Tallow Ooze that melts into fire puddles and shatters when frozenblockedP1M3feature

    Description

    Why

    The ooze is a systemic toy: the best way to fight it is with the world's properties.

    What

    As a sorcerer, I want a slow wax slime that reacts to heat and cold so that experimenting pays off.

    tallow-ooze: slow, sticky engulf (slows 50%), splits into two small oozes on heavy blunt hits. Heat: melts into a spreading flammable puddle (flammable liquid volume) that can then be ignited. Cold: frozen + fragile → shatters on impact.

    Scope

    • In: Creature data, split rule, melt-to-puddle and freeze-to-brittle property rules
    • Out: Scriptorium placement (e26-priory-scriptorium)

    Notes

    Puddle cap: max 6 active puddles per room to protect the element-field budget.

    Acceptance criteria

    • AC-1 integration Given an ooze exposed to heat above its melt threshold for 2 s, when evaluated, then it becomes a flammable puddle entity covering >= 2 m².
    • AC-2 integration Given an ooze with frozen = true, when any impact >= its fragile threshold hits it, then it shatters and dies.
    • AC-3 integration Given a heavy blunt hit on a full-size ooze, when resolved, then two half-size oozes spawn; half-size oozes do not split again (edge).

    Waits on

    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e03.6 Simulate water volumes, splashes, wetness and drying done
    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e12.7 Drive creature vulnerabilities from world properties, not pairings open
    area:contentepic:e13milestone:m3
  • mw-e13.11Add book, lectern and chest mimics with tells and feedingblockedP1M3feature

    Description

    Why

    Mimics reward curiosity and observation: a careful player spots the tell; a clever one feeds them.

    What

    As a player, I want mimics disguised as books, lecterns and chests that I can spot, feed, avoid or wake so that containers stay exciting.

    Three variants (book-mimic, lectern-mimic, chest-mimic) presenting as interactables. Tell: subtle breathing motion + faint paper-rustle noise audible within 3 m. Bite on interact (500 ms, grab-class). Feeding: any item tagged edible:paper placed on/near it pacifies and yields a treat item.

    Scope

    • In: Three variants, disguise-as-interactable hook, tell cues, feed rule, drop tables
    • Out: Mortimer the tame mimic (e14-mortimer)

    Notes

    Waking on purpose (strike first) is valid; mimic then fights normally but flees at 30% health.

    Acceptance criteria

    • AC-1 integration Given a disguised chest-mimic, when the player interacts, then a 500 ms telegraph plays before the bite and a dodge in that window avoids it.
    • AC-2 integration Given an edible:paper item placed within 1 m, when 3 s pass, then the mimic eats it, becomes pacified and drops its treat.
    • AC-3 integration Given the player listens within 3 m, when the tell noise plays, then it is captioned by the sound-caption system when captions are enabled (edge).

    Waits on

    • mw-e04.20 Creatures attack via the move system with readable telegraphs done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e12.13 Declare non-hostile creature interactions (feed, talk, calm) in data open
    • mw-e18.3 Add lootable containers that persist their contents done
    area:contentepic:e13milestone:m3
  • mw-e13.12Add Hollow Sentinels bound to hold the tower until relievedblockedP1M3feature

    Description

    Why

    The Sentinels embody "keeping watch": honour-bound, relentless inside the tower, and able to be relieved rather than destroyed.

    What

    As a knight, I want armour that obeys a forty-year-old order so that speaking the old words ends the fight honourably.

    hollow-sentinel: slow walker, sight + life-sense, never sleeps; halberd sweep, shield charge (500 ms, unblockable). Leash: never leaves the tower volume. Resistances pierce 0.3, blunt 1.5, conductive. Stand-down conditions (facts): watchword spoken, knight formal relief, "watch ended" bell rung, binding dispelled. Stood-down sentinels salute and fall still permanently.

    Scope

    • In: Creature data, leash volume, stand-down fact conditions, salute state
    • Out: Dialogue lines for watchword and relief (e39-side-quests-wilds)
    • Out: Tower placement (e25-mooring-watch-encounters)

    Notes

    Smashing them is valid but slow (high poise). Dispel uses a generic magic-binding property so any dispel-capable effect works.

    Acceptance criteria

    • AC-1 integration Given a sentinel in Combat, when the player leaves the tower volume, then it returns to its stand and does not path outside.
    • AC-2 integration Given fact watch.ended is set, when evaluated, then all sentinels salute and become inert within 3 s and stay inert after save/reload.
    • AC-3 unit Given a pierce hit of 40, when resolved, then 12 damage applies; given a blunt 40, then 60 (edge: armour identity).
    • AC-4 integration Given a sentinel standing in water and a shock stimulus, when propagated, then it is staggered via conductivity.

    Waits on

    • mw-e03.8 Conduct electrical charge through conductive and wet objects done
    • mw-e04.20 Creatures attack via the move system with readable telegraphs done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e12.7 Drive creature vulnerabilities from world properties, not pairings open
    • mw-e27.5 Query world facts with a shared condition API for all systems done
    area:contentepic:e13milestone:m3
  • mw-e13.13Add Brother Horn's creature data: charges, grabs and throws to stopblockedP1M3feature

    Description

    Why

    Horn fights to stop, not to kill — his combat must say so.

    What

    As a player, I want the minotaur to fight like a warden restraining an intruder so that the fight hints he is not a monster.

    npc-horn creature: 9 ft, walker; moves: axe sweep (parryable), charge (unblockable, 600 ms, bellow cue), grab-and-throw (grab-class, 500 ms), stomp (ground AoE). Non-lethal rule: damage from Horn cannot reduce the player below 1 HP; at <= 15% HP his next hit subdues (player.subdued event, not Died), routed to the Fold via e01-contextual-respawn.

    Scope

    • In: Creature data, move set, non-lethal clamp, subdue event
    • Out: Encounter phases, yield and trial (e13-horn-encounter)
    • Out: Befriend/help (e14-horn-befriend-help)

    Notes

    Horn is also a social creature — the same entity is shared with E14.

    Acceptance criteria

    • AC-1 content Given npc-horn.json, when validated, then the charge and grab moves are unblockable/grab with windups >= 30 ticks and distinct cues.
    • AC-2 unit Given the player at 10 HP, when a Horn hit of 50 resolves, then the player ends at 1 HP and no Died event fires.
    • AC-3 integration Given the player at <= 15% HP, when Horn's next hit lands, then player.subdued fires and the respawn resolver routes to the Fold.
    • AC-4 integration Given environmental damage (a fall) while fighting Horn, when it would kill the player, then normal death applies (edge: clamp only on Horn's own hits).

    Waits on

    • mw-e01.12 Wake in context after death instead of reloading open
    • mw-e04.1 Deterministic damage model: damage types, resistances, poise, death done
    • mw-e04.20 Creatures attack via the move system with readable telegraphs done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    area:contentepic:e13milestone:m3
  • mw-e13.14Build the Warden boss encounter with yield, spare and Trial of HornsblockedP1M3feature

    Description

    Why

    The Warden encounter is the pivotal moment of the game (bible §4.2); combat must feed every resolution.

    What

    As a player, I want the Horn fight to end in a choice so that combat becomes a story decision.

    Phases: guarding (circles, warns), fighting, yielding at 20% HP ("Enough. Hear me, or finish it.") — combat pauses; the player must explicitly attack again to kill (fact horn.killed) or lower weapon/interact to spare (horn.spared, wounded). Trial of Horns mode (knight capability): no-kill honour duel; first to three clean parries/blocks wins (horn.befriended via trial). Portcullis-trapped state and "rests one eye" state as encounter states for trick resolutions.

    Scope

    • In: Encounter state machine, yield/kill/spare gating, trial rules and counter, trick states exposed as facts
    • Out: Horn's Hall level (e26-horns-hall-fold)
    • Out: Dialogue (e39-dialogue-horn)

    Notes

    Killing requires an explicit second action after the yield (e39-main-quest-data note).

    Acceptance criteria

    • AC-1 integration Given Horn at 20% HP, when the threshold is crossed, then he yields, all his attacks stop and horn.yielded is set.
    • AC-2 integration Given a yielded Horn, when the player lands a deliberate attack, then horn.killed is set and his horn item drops; when the player interacts instead, then horn.spared is set.
    • AC-3 integration Given the Trial of Horns, when the knight lands 3 clean parries/blocks before taking 3 clean hits, then the trial is won, horn.befriended is set and no damage below 1 HP ever applies.
    • AC-4 integration Given the player loses the trial, when resolved, then Horn offers a rematch and the encounter does not become lethal (edge).

    Waits on

    • mw-e04.12 Parry window and riposte critical attack done
    • mw-e13.13 Add Brother Horn's creature data: charges, grabs and throws to stop open
    • mw-e27.5 Query world facts with a shared condition API for all systems done
    area:contentepic:e13milestone:m3
  • mw-e13.15Add the Sleepless Abbot wraith: solid only while singingblockedP1M3feature

    Description

    Why

    The abbot must be beatable by understanding him — sound and light break his concentration — not by damage race.

    What

    As a player, I want a wraith who is only vulnerable while singing and whose form is anchored to lanterns so that I defeat him with observation.

    npc-abbot creature: fog body; states singing (solid, damageable, commands Hushlings) and drifting (immune). Loud noise (>= 0.85) or bright light (>= 0.9) within 5 m interrupts singing and staggers. Anchor lanterns: 4 linked lantern entities; each destroyed/extinguished removes 25% of his max health. Summons Hushlings while singing (cap 4).

    Scope

    • In: Creature data, sing/drift state rules, anchor link component, summon cap
    • Out: Cradle encounter and resolutions (e13-abbot-encounter)

    Notes

    Interrupt rules by stimulus threshold only — bell, Thunderclap, shattered glass, Wisp Light all qualify systemically.

    Acceptance criteria

    • AC-1 integration Given the abbot drifting, when any damage packet hits, then 0 damage applies and immune feedback shows.
    • AC-2 integration Given the abbot singing, when a noise >= 0.85 occurs within 5 m, then singing is interrupted, he is staggered for 2 s and becomes damageable during it.
    • AC-3 integration Given two of four anchor lanterns extinguished, when his max health is read, then it is 50% of base.
    • AC-4 integration Given the Hushling cap of 4 is reached, when he sings again, then no further Hushlings spawn (edge).

    Waits on

    • mw-e03.16 Extinguish and relight torches, candles and braziers systemically done
    • mw-e06.10 Summon temporary creatures and objects with allegiance and caps open
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e13.9 Add blind Hushlings that hunt by sound and break at loud noises open
    area:contentepic:e13milestone:m3
  • mw-e13.16Build the Cradle encounter with fight, trick, persuade and join pathsblockedP1M3feature

    Description

    Why

    The final confrontation must honour every class and the persuade path earned through Clatter.

    What

    As a player, I want to end the abbot by fighting, tricking, persuading or joining him so that my choices and class matter at the climax.

    Fight: via e13-abbot-wraith rules. Trick: pickpocket the tongue from his belt while singing (thief; sets tongue.recovered); a Mirror Self decoy emitting hymn-tagged noise turns nearby Forgotten on him; shooting anchor lanterns. Persuade: available only if clatter.restored and Clatter present. Join: dialogue choice → ending 4 state. Tansy-hostage variant if tansy.reachedCradle.

    Scope

    • In: Encounter state machine, trick hooks (pickpocket target, faction flip on hymn), hostage variant, outcome facts
    • Out: Cradle level (e26-cradle-arena)
    • Out: Abbot dialogue (e39-dialogue-abbot)

    Notes

    Pickpocketing the tongue is "the single most satisfying theft in the game" — give it a 1.5 s pickpocket window during each sing phase.

    Acceptance criteria

    • AC-1 integration Given the abbot singing and the thief behind him, when pickpocket succeeds, then tongue.recovered is set and the abbot enters a fury phase.
    • AC-2 integration Given a hymn-tagged noise from any source during the fight, when Forgotten are within 10 m, then they switch faction target to the abbot for 20 s.
    • AC-3 integration Given clatter.restored is false, when the persuade option is evaluated, then it is not offered; given true with Clatter present, then it is.
    • AC-4 integration Given the Tansy-hostage variant, when an area attack would hit Tansy, then she is protected (no damage) and the abbot moves her (edge).

    Waits on

    • mw-e08.15 Add Mirror Self: an illusory double that draws attention open
    • mw-e10.8 Pickpocket and plant items on creatures from behind open
    • mw-e12.8 Faction table and relationship queries between creatures done
    • mw-e13.15 Add the Sleepless Abbot wraith: solid only while singing open
    • mw-e14.5 Build Clatter: the apologetic skeleton who can remember his name open
    area:contentepic:e13milestone:m3
  • mw-e13.17Author the MVP creature faction and relationship tableblockedP1M3feature

    Description

    Why

    Creatures have relationships; setting them against each other is a valid solution.

    What

    As a designer, I want a faction table for the MVP roster so that goblins fight spiders, Hushlings ignore goblins and players can exploit it.

    Factions: forgotten, rootcellar, warden, loom, briar-pack, dream (Hushlings + abbot), sentinels, mimic, ooze. Relationships: rootcellar ↔ loom hostile; dream ignores rootcellar; briar-pack avoids mine volumes; forgotten neutral to dream until intensity 3; warden protective of sleepers.

    Scope

    • In: Faction data, relationship matrix, content tests
    • Out: Faction runtime (e12-factions-relationships)

    Notes

    Player standing with factions is disposition (E14/E22), not this table.

    Acceptance criteria

    • AC-1 content Given the faction table, when validated, then every MVP creature references exactly one existing faction.
    • AC-2 integration Given a goblin and a loom spider in mutual sight, when perceived, then they enter Combat with each other.
    • AC-3 integration Given a Hushling and a goblin within 2 m, when evaluated, then neither targets the other (edge).

    Waits on

    • mw-e12.8 Faction table and relationship queries between creatures done
    • mw-e13.6 Add Rootcellar goblin combatants: slings, nets and loud alarms open
    • mw-e13.7 Add Loom Spiders that weave readable webs and fear bright light open
    • mw-e13.9 Add blind Hushlings that hunt by sound and break at loud noises open
    area:contentepic:e13milestone:m3
  • mw-e13.18Gate CI on creature readability, avoidability and arena smoke testsblockedP1M3task

    Description

    Why

    Readable telegraphs and non-combat options are constitutional; they must not rot as creatures are tuned.

    What

    A CI audit over all shipping creature data: every attack passes the readability rule; every creature declares >= 1 avoid option and has a scenario test proving it; every declared vulnerability has a property-based test; a 12-creature mixed Ossuary scene runs in the perf suite.

    Scope

    • In: Audit script and report (docs/design/bestiary-audit.md), scenario tests, perf scene
    • Out: Framework-level harness (e12-creature-content-harness)

    Notes

    Reuse e32-combat-stress-scene infrastructure for the perf scene.

    Acceptance criteria

    • AC-1 integration Given a creature move with a 12-tick windup, when the audit runs, then CI fails naming the creature and move.
    • AC-2 integration Given a creature with no avoid-option scenario test, when the audit runs, then CI fails (edge).
    • AC-3 perf Given 8 Forgotten, 2 Hushlings and 2 loom spiders active with fire, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent) and p95 <= 16.7 ms at 1080p on the Low preset on an Intel Iris Xe / base M1 8 GB class machine, with p99 <= 33.3 ms (30 fps floor) during worst-case combat.

    Waits on

    • mw-e12.15 Auto-generate smoke tests for every creature data file done
    • mw-e13.4 Add monk Forgotten and habit routines that ignore quiet players open
    • mw-e13.7 Add Loom Spiders that weave readable webs and fear bright light open
    • mw-e13.9 Add blind Hushlings that hunt by sound and break at loud noises open
    • mw-e32.13 Add combat stress scene with 12 creatures and heavy VFX open
    area:qaepic:e13milestone:m3

M4 Fun validation 1

  • mw-e13.19Tune the bestiary from creature-arena sessions and playtest telemetryblockedP1M4task

    Description

    Why

    Creatures should be memorable for behaviour; tuning must be evidence-led.

    What

    Run creature-arena sessions per class against every MVP creature and read playtest telemetry (deaths, abandon points). Adjust timings, health, perception within design bounds; record changes in docs/design/bestiary-tuning.md.

    Scope

    • In: Arena sessions, telemetry review, data tuning PR, tuning log
    • Out: Framework changes (file beads in E11/E12)

    Notes

    Related: e34-analysis-scripts, e35-external-round-1.

    Acceptance criteria

    • AC-1 manual Given one tester per class, when each fights every creature once, then median time-to-kill for regular creatures is between 15 s and 60 s.
    • AC-2 integration Given the tuned data, when the bestiary audit runs, then it still passes (tuning never breaks readability).
    • AC-3 content Given the tuning log, when reviewed, then each change cites the observation or telemetry metric that motivated it.

    Waits on

    • mw-e13.18 Gate CI on creature readability, avoidability and arena smoke tests open
    • mw-e33.12 Create a creature arena to spawn and pit creatures open
    • mw-e34.3 Emit core gameplay events: deaths, encounters, spells, puzzles open
    area:qaepic:e13milestone:m4
E14Social CreaturesThe Rootcellar goblins (Mother Kettleback, Snig), Clatter the skeleton who remembers, Brother Horn and Mortimer the book mimic can be talked to, fed, gifted, calmed, befriended and helped — not only fought — using e22 dialogue/disposition/gifts and e12 dispositions/affordances, with outcomes persisted as world facts.0/8 done · 0%

M3 MVP content 8

  • mw-e14.1Let the player hum the Vesper hymn after reading the Vesperine HoursblockedP1M3feature

    Description

    Why

    Humming the hymn calms the Forgotten, befriends Horn and rewards reading — a verb every class can learn from a book.

    What

    As a player of any class, I want to learn the Vesper hymn from The Vesperine Hours and hum it so that I can calm the dead and speak to the warden.

    Reading the hymn page grants capability verb.hum.vesper-hymn. Hum is a held action: emits a noise event every 0.5 s tagged hymn (loudness 0.3), movement slowed to walk. Creatures declare responses in data (calmedBy: hymn).

    Scope

    • In: Capability grant on read, hum action and animation hook, hymn-tagged noise emission
    • Out: The book item and shop placement (e24-lamplit-stacks)
    • Out: Creature responses (E13/E14 creature items)

    Notes

    Mirror Self can emit hymn-tagged noise via the same tag (Cradle trick). Humming while sneaking still makes noise — a real trade-off.

    Acceptance criteria

    • AC-1 integration Given the player reads the hymn page, when complete, then verb.hum.vesper-hymn is granted with source book:vesperine-hours.
    • AC-2 unit Given the player humming for 2 s, when noise events are inspected, then 4 events tagged hymn with loudness 0.3 are emitted.
    • AC-3 integration Given the player without the capability, when the hum action is pressed, then nothing is emitted and no prompt shows (edge).

    Waits on

    • mw-e07.9 Read books in a page-turning reader with a study action open
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e12.13 Declare non-hostile creature interactions (feed, talk, calm) in data open
    • mw-e19.2 Create capability registry with source-tracked grants done
    area:gameclass:allepic:e14milestone:m3
  • mw-e14.2Make the Rootcellar clan talkable, bribable and forgiving of captureblockedP1M3feature

    Description

    Why

    "A goblin camp might actually have people to talk to." Getting caught should open negotiation, not end the game.

    What

    As a player, I want to approach the goblin camp as a guest, a trader or a trespasser so that my approach changes how the clan treats me.

    Clan disposition (faction-level) with modifiers: gifts of shiny/kettle items, returning salvage, harming goblins, freeing Duggan by force. Guests: goblins stay Wary, trade allowed. Capture: when the player is netted/subdued in the camp, they are dragged to Kettleback (fact goblins.capturedPlayer) and dialogue opens regardless of prior hostility. Thieves get a kin bonus.

    Scope

    • In: Clan disposition rules, gift preferences, capture-to-negotiation flow, kin bonus
    • Out: Kettleback and Snig specifics (e14-mother-kettleback, e14-snig)
    • Out: Dialogue text (e39-dialogue-labyrinth-folk)

    Notes

    Clan standing is one of the ending facts (goblin standing).

    Acceptance criteria

    • AC-1 unit Given clan disposition Neutral and a gift tagged kettle, when given, then disposition rises by the gift preference value and a goblins.gifted fact increments.
    • AC-2 integration Given the player is subdued inside the camp volume, when the subdue resolves, then the player wakes in front of Kettleback and her dialogue starts.
    • AC-3 integration Given the player killed >= 3 goblins, when entering the camp, then goblins start Alerted but capture still leads to negotiation (edge).
    • AC-4 unit Given the thief class, when clan disposition is initialised, then it starts one band higher than for other classes.

    Waits on

    • mw-e12.9 Per-creature disposition toward the player with event modifiers done
    • mw-e13.6 Add Rootcellar goblin combatants: slings, nets and loud alarms open
    • mw-e22.12 Let players give gifts and bribes that shift disposition open
    • mw-e22.4 Track NPC disposition with bands, event modifiers and factions done
    • mw-e22.9 Start conversations with NPCs in-world and handle interruptions done
    area:contentepic:e14milestone:m3
  • mw-e14.3Bring Mother Kettleback to life: trade, Duggan crate and carrying feesblockedP1M3feature

    Description

    Why

    Kettleback is a memorable monster-character: pragmatic, sarcastic and useful.

    What

    As a player, I want to bargain with the goblin matriarch so that I can trade, free Duggan Marl and hire her clan.

    npc-kettleback: creature + merchant (goblin salvage stock), gift likes (kettles, brass, shiny), Duggan crate interaction states (trade for Dot's kettle, persuade to release, force), clan hire effects (wall the breach, hold the shaft), and the carrying-fee rule when she retrieves a dead player (post-Horn-death).

    Scope

    • In: Creature/merchant data, gift table, Duggan crate state entity, hire effects as facts, carrying fee rule
    • Out: Framed in Brass quest graph (e39-side-quests-wilds)

    Notes

    Kettleback never fights unless the camp is attacked; she flees to the back tunnel at 50% health.

    Acceptance criteria

    • AC-1 content Given npc-kettleback.json and her merchant data, when validated, then both pass and stock references existing items.
    • AC-2 integration Given the player gives Dot's kettle, when accepted, then duggan.released is set and the crate opens.
    • AC-3 integration Given clan disposition Friendly and a hire request, when accepted, then goblins.hired.breach is set for the breach-sealing option.
    • AC-4 integration Given the player attacks Kettleback, when her health reaches 50%, then she flees via the back tunnel and the clan becomes Hostile (edge).

    Waits on

    • mw-e14.2 Make the Rootcellar clan talkable, bribable and forgiving of capture open
    • mw-e20.2 Define merchant schema with identity, specialty and stock rules done
    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    • mw-e39.8 Write dialogue for Clatter, Mother Kettleback and Snig done
    area:contentepic:e14milestone:m3
  • mw-e14.5Build Clatter: the apologetic skeleton who can remember his nameblockedP1M3feature

    Description

    Why

    "A skeleton might remember fragments of its previous life." Clatter is the warmest quest in the game.

    What

    As a player, I want a skeleton that apologises while fighting, calms to the hymn and regains memories so that helping him feels like the heart of the story.

    npc-clatter: Forgotten variant; hostile-apologetic (reduced aggression, apology barks) unless hymn heard; tends mushroom garden idle. Memory pieces as facts (psalter, pear-bloom, sister's letter); song intensity 3 removes the most recent unanchored memory. Sorcerer memory-reading: success skips a piece; failure removes one permanently. Outcomes: clatter.restored → follower to Cradle; or rest (knight rites / psalter on priory altar).

    Scope

    • In: Creature data, memory facts and loss rule, reading attempt check, follower/rest outcomes
    • Out: Name on the Bones quest graph (e39-side-quests-wilds)
    • Out: Clatter dialogue (e39-dialogue-labyrinth-folk)

    Notes

    Clatter must never be killable by accident while calm: friendly-fire off when disposition >= Friendly.

    Acceptance criteria

    • AC-1 integration Given Clatter hostile, when a hymn-tagged noise reaches him, then he stops attacking and opens dialogue.
    • AC-2 unit Given 2 memories recovered and song intensity rising to 3, when evaluated, then the most recent memory not yet anchored is removed and the fact is cleared.
    • AC-3 unit Given a failed memory-reading attempt, when resolved, then one memory is permanently lost and cannot be recovered by its piece (edge).
    • AC-4 integration Given clatter.restored, when the player enters the Cradle, then Clatter follows and is present for the persuade option.

    Waits on

    • mw-e12.9 Per-creature disposition toward the player with event modifiers done
    • mw-e13.4 Add monk Forgotten and habit routines that ignore quiet players open
    • mw-e13.5 Drive creature behaviour from a global song-intensity world state open
    • mw-e14.1 Let the player hum the Vesper hymn after reading the Vesperine Hours open
    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    area:contentepic:e14milestone:m3
  • mw-e14.6Befriend and help Brother Horn without fightingblockedP1M3feature

    Description

    Why

    "A minotaur guarding an ancient labyrinth might be fought, tricked, befriended or helped."

    What

    As a player, I want to lower my weapon, hum, return his mother's horn-ring or have friends vouch so that Horn becomes my ally.

    Befriend triggers: player sheathed and stationary for 6 s in Horn's sight (he circles three times, then speaks); hymn heard; horn-ring or the Hornfolk name-stone (from The Crate for Mr. S—, e40-crate-heist) given; vouch (snig.lessons or clatter present). Help steps: bread for sleepers, healing (salve, Nature spell, rest in Fold), breach sealed. Ally mode: follows to key points, opens the crypt shortcut, holds the shaft foot in the climb.

    Scope

    • In: Befriend trigger rules, help-step facts, ally behaviours (open crypt, hold shaft)
    • Out: Horn dialogue (e39-dialogue-horn)
    • Out: Combat encounter (e13-horn-encounter)

    Notes

    Befriend is combinable with spared/tricked outcomes (bible §4.2).

    Acceptance criteria

    • AC-1 integration Given the player sheathed and stationary for 6 s in Horn's sight, when evaluated, then Horn circles the player 3 times and opens dialogue instead of attacking.
    • AC-2 integration Given the player draws a weapon during the circling, when detected, then the befriend attempt aborts and Horn resumes guarding (edge).
    • AC-3 integration Given horn.befriended and the player at the crypt door, when Horn is asked, then the crypt shortcut opens and shortcut.crypt is set permanently.
    • AC-4 integration Given horn.befriended and horn.healed, when the climb begins, then Horn holds the shaft foot and Hushlings target him first.

    Waits on

    • mw-e12.9 Per-creature disposition toward the player with event modifiers done
    • mw-e13.13 Add Brother Horn's creature data: charges, grabs and throws to stop open
    • mw-e14.1 Let the player hum the Vesper hymn after reading the Vesperine Hours open
    • mw-e22.12 Let players give gifts and bribes that shift disposition open
    • mw-e39.7 Write Brother Horn's dialogue across all Warden resolutions done
    area:contentepic:e14milestone:m3
  • mw-e14.8Prove every social creature path in an automated scenario suiteblockedP1M3task

    Description

    Why

    Social paths are easy to break silently; every one must stay reachable.

    What

    Scenario tests (e11-ai-scenario-harness + quest/dialogue test runners) for each P1 path: goblins guest/trade/capture; Kettleback Duggan trade/persuade/force; Clatter hymn/memories/loss/restore/rest; Horn wait/hymn/ring/vouch/trial/help. The suite is a registry: Snig and Mortimer (P2) register their own scenarios in their items.

    Scope

    • In: Scenario suite, CI job, coverage report of social paths
    • Out: Quest-level validation (e23-quest-validator)

    Notes

    Report lists each path id and its outcome fact. Related: e14-snig, e14-mortimer add scenarios to this registry when they land.

    Acceptance criteria

    • AC-1 integration Given the suite, when run in CI, then every path listed in docs/design/bestiary.md social options reaches its outcome fact.
    • AC-2 integration Given a path whose outcome fact is never set, when the suite runs, then CI fails naming the path (edge).
    • AC-3 integration Given each social failure path (capture, ban, lost memory), when run, then the resulting state offers at least one further action (no dead end).

    Waits on

    • mw-e11.3 Scenario harness for scripted AI tests with asserted states over time done
    • mw-e14.3 Bring Mother Kettleback to life: trade, Duggan crate and carrying fees open
    • mw-e14.5 Build Clatter: the apologetic skeleton who can remember his name open
    • mw-e14.6 Befriend and help Brother Horn without fighting open
    area:qaepic:e14milestone:m3
  • mw-e14.4Bring Snig to life: pocket-picking, reading lessons and vouchingblockedP2M3feature

    Description

    Why

    Snig is the game's comic heart and the goblin who wants to read.

    What

    As a player, I want Snig to steal from me, follow me and vouch for me so that he becomes a recurring ally.

    npc-snig: attempts to pickpocket the player (thief can notice and allow — snig.trusted); Bookshop Burglar outcomes as facts (jailed, lessons, scared of the reading one); follower mode in town and mine; vouch flag used by Horn befriend; fear of Mortimer (flees if within 5 m).

    Scope

    • In: Creature data, pickpocket-the-player behaviour, follower mode, outcome facts
    • Out: Bookshop Burglar quest graph (e39-side-quests-town)

    Notes

    If jailed, the thief can bust him out through the jail drain (e24-watch-house-jail).

    Acceptance criteria

    • AC-1 integration Given Snig adjacent and the player idle, when his pickpocket attempt succeeds, then one low-value item moves to his inventory and the thief class receives a notice prompt.
    • AC-2 integration Given snig.lessons is set, when Horn's befriend conditions are evaluated, then the vouch option is available.
    • AC-3 integration Given Mortimer within 5 m of Snig, when evaluated, then Snig flees and follower mode pauses until distance > 10 m (edge).

    Waits on

    • mw-e10.8 Pickpocket and plant items on creatures from behind open
    • mw-e14.2 Make the Rootcellar clan talkable, bribable and forgiving of capture open
    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    area:contentclass:thiefepic:e14milestone:m3
  • mw-e14.7Add Mortimer, the tame book mimic who guards the rare shelfblockedP2M3feature

    Description

    Why

    Mortimer makes the bookshop memorable and makes shoplifting a story rather than a menu.

    What

    As a player, I want Mirela's tame mimic to bite shoplifters and be won over with paper so that the bookshop has a guardian with personality.

    npc-mortimer: stationary mimic on the rare shelf; detects witnessed theft from the shop (e27-ownership-theft) within 6 m and bites (non-lethal); sets mirela.banned for 1 in-game day; bringing biscuits to Mirela lifts it early; can be fed paper for a treat (Mortimer's tooth rare drop if provoked).

    Scope

    • In: Creature data, theft-detect-and-bite rule, ban fact with timeout, feed rule
    • Out: Bookshop stock (e24-lamplit-stacks)
    • Out: Snig-meets-Mortimer beat (e39-side-quests-town)

    Notes

    Mortimer never leaves his shelf; theft from other shelves out of his view is not detected by him.

    Acceptance criteria

    • AC-1 integration Given the player takes an owned book within Mortimer's view, when theft is recorded, then Mortimer bites for non-lethal damage and mirela.banned is set.
    • AC-2 unit Given mirela.banned set at day 3 08:00, when world time reaches day 4 08:00, then the ban clears.
    • AC-3 integration Given a theft outside Mortimer's view, when recorded, then Mortimer does not react (edge).

    Waits on

    • mw-e13.11 Add book, lectern and chest mimics with tells and feeding open
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e27.9 Track object ownership and record thefts as world facts done
    area:contentepic:e14milestone:m3
E15Puzzle FrameworkDesigners compose systemic puzzles from reusable world objects and data — not custom code. A puzzle is a data file naming world entities, a goal condition over live properties and world facts, declared solutions per capability set, and reset/hint policies. Tooling proves each declared solution is reachable, detects softlocks, and reports which classes can solve each puzzle, so "several solutions" is verified rather than hoped for.12/33 done · 36%

M2 Class fantasies 19

  • mw-e15.14Let solved puzzles grant item and loot rewardsopenP2M2task

    Description

    Why

    mw-e15.1 puzzle outputs can only write facts (solvedFact, set). Rewards such as an item or a loot table on solve have no field yet because items are not content.

    What

    As a designer, I want to declare a puzzle's item or loot reward in its file so that solving it grants the reward exactly once without a quest wrapper.

    Scope

    • In: outputs.rewards referencing item/loot content ids, checked at load; runtime grant once on solve
    • Out: item schema (mw-e17.2), puzzle runtime (mw-e15.3)

    Acceptance criteria

    • AC-1 content Given a puzzle reward naming an unknown item id, when validated, then validation fails naming the id.
    • AC-2 unit Given a one-shot puzzle with an item reward, when solved, saved and reloaded, then the item was granted exactly once.

    Waits on

    • mw-e15.3 Run data-defined puzzles composed from reusable world objects done
    • mw-e17.2 Define item definition schema and content validator done
    area:contentarea:simarea:toolsepic:e15milestone:m2size:s
  • mw-e15.18Model signal graphs, plates and facts in the puzzle solver's abstract stateopenP2M2task

    Description

    mw-e15.6 left goals that read a signal, fact or count of facts (and the cold, water and charge elements) inconclusive in the abstract layer (src/tools/puzzle/abstract.ts, unmodelled()). Add switch, plate and door state and signal-graph propagation so those goals are searched, and add rules for cold/water/charge so fewer solutions rely on the concrete run alone (abstraction gaps). Acceptance: a puzzle whose goal is a signal/door driven by a plate and crate is proven reachable abstractly with its minimum action count; unit tests for each new rule.

    area:simarea:toolsepic:e15milestone:m2size:m
  • mw-e15.21Puzzle reset volume and reset lever prefabopenP2M2task

    Description

    mw-e15.7 shipped reset recovery triggered by using a listed entity (lever). Add the reset volume trigger (walking into a volume resets, as the bead's 'reset lever/volume' says) and a reset lever prefab composed from existing components, plus a demo in prefab-gallery. Reset currently restores listed doors and switches only; consider signal-graph latches, plates and liquid drains.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.22Softlock search: model stuck mechanisms and alternate routesopenP2M2task

    Description

    mw-e15.7 softlock search covers irreversible losses of listed entities (burn, break, fall, melt) in the abstract lit/place state. Extend it to mechanism states (a door jammed or a latch thrown that cannot be undone, signal-graph latches) and honour a declared alternate route or a reversible-only flag as a covering recovery. Also: a critical object that falls while its puzzle is still dormant is not returned (the runtime only marks critical entities once a puzzle is in play, to keep dormant worlds hashing as before); revisit if designers hit it.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.26Timed door: decide whether the window includes the door's close timeopenP2M2task

    Description

    mw-e15.5 (#396) AC-3: with an 8 s window the door's signal goes off at 8 s, but the sliding door takes 1.5 s to close, so a player passing at 8.1 s can still slip through. Owner decision: should a timed window mean 'shut by N s' (start closing at N minus close time, or close faster), or is 'starts closing at N s' fine? Adjust plate-timed-door prefab and its test accordingly.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.33Draw puzzle hint barks and highlight pulses in the HUDopenP2M2task

    Description

    The sim now emits puzzleHint (mw-e15.11) with a class-aware bark, the spawn ids and entities to pulse, and a rumour fact. Today the game only publishes it as #app[data-puzzle-hint] (hintReadout in src/game/puzzles/index.ts, wired in src/main.ts onHint). Needs: a bark line (subtitle style, accessible, respects text size) and a glint/outline pulse on the highlighted entities. Styling is mw-e31 scope. AC: firing a hint shows its bark for a few seconds and pulses each entity; hints off shows nothing.

    area:simarea:toolsarea:uiepic:e15epic:e31milestone:m2milestone:m3
  • mw-e15.15Liquid layer entities outlive a scene unloadopenP3M2bug

    Description

    Scene spawns can now be liquid volumes (mw-e15.4). A volume's layer entities are separate entities from the spawn, so unloading the scene (unloadScene destroys the spawn entity) leaves its liquid layers behind in the world. Destroy a volume's layers when its LiquidVolume component is removed (world.onRemove in installLiquids), with a test that unloads a scene with a basin.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.16Puzzle prefab e2e and gallery screenshotopenP3M2task

    Description

    mw-e15.4 shipped 15 prefabs and ?scene=prefab-gallery with integration tests only. Add a Playwright smoke that loads the gallery (CI software GL ~1 fps: pace on state, 30 s polls) and a screenshot for the docs; add a measured weight to e2e/shards.json.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.17Prefab goals: let puzzle goals read a prefab's outputs by nameopenP3M2task

    Description

    A puzzle goal reads a prefab output today as signal "<instance>/<node>" or the entity <instance>-<local>. Consider a checked reference ("prefab:<instance>.<output>") so a renamed instance or output fails at load, and the solver (mw-e15.6) can list them.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.19Give the testbed-room-lever puzzle a live goal the solver can confirmopenP3M2task

    Description

    pnpm puzzle:validate reports all three solutions of testbed-room-lever as diverged in the concrete run: its goal reads a stand-in fact (testbed.room-lever.thrown) that nothing sets (the lever prop has no live switch state). It is not mvp so CI passes, but the report is noisy. Make the goal read the lever's live state (mw-e15.2 leaves) or give it a real switch, then confirm by-hand, mage-hand and crate-shove with the solver. Acceptance: pnpm puzzle:validate testbed-room-lever exits 0 with every solution OK.

    area:simarea:toolsepic:e15milestone:m2size:s
  • mw-e15.20Path-aware concrete steps for the puzzle solver (walk, push and carry instead of teleport)openP3M2task

    Description

    mw-e15.6's concrete layer (src/tools/puzzle/concrete.ts) teleports the player beside a reach target and a moved thing beside its destination, so it cannot catch a puzzle whose route is blocked in the real level. Drive the player controller along the navmesh and push/carry through the interaction path, with timeouts reported as the step index that stalled. Acceptance: a fixture level with a wall across the route makes the solution diverge at the reach step; brazier-hall still passes.

    area:simarea:toolsepic:e15milestone:m2size:m
  • mw-e15.23Respawn chute: visible and audible replacementopenP3M2task

    Description

    mw-e15.7 respawner drops a copy at the spawn point when due; there is no chute prop, drop animation or sound, and the player is not told a copy is coming. Add a chute prefab and cue (puzzleRecovered kind respawn) so recovery is diegetic and legible, and a telemetry sink for puzzleRecovered.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.24Sequence validator tolerance: timing window and near-miss leniency for the sequence nodeopenP3M2feature

    Description

    mw-e15.5 shipped the ordered mechanism with the existing strict sequence node (any out-of-order edge fails and restarts). The bead text also says sequence validators 'with tolerance': add an optional per-node tolerance (for example a maximum gap between steps after which the run restarts, and/or a number of forgiven wrong steps) as a general signal-node option, plus prefab parameters on bell-sequence and rune-tile-sequence.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.25Wire the book reader to readClue so reading a bound tome records its puzzle clueopenP3M2task

    Description

    mw-e15.5 added item book.clueFor, the clueRead event and readClue(world, actor, item, puzzles) in src/game/puzzles/clues.ts (attachBookClues returns read(actor,item)); scroll reads are already wired. When the book reader UI (mw-e07.9) opens a page, call BookClues.read so tomes and notes count too. Also consider emitting it on StudyEnded completed.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.27Scene inventory tests hard-code every scene id (scene-loader.test.ts, scene.test.ts), so any new scene edits src/*.test.tsopenP3M2task

    Description

    Found building mw-e15.9 (data-only reference puzzles): src/game/scene/scene-loader.test.ts and src/content/types/scene.test.ts list every scene by name, so adding a scene file forces edits to TypeScript under src/. Derive the expectation from the content directory (or assert membership) so content-only PRs touch no src/*.ts.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.28Concrete puzzle solver teleports the player (reach, move player), so traversal puzzles such as the frozen channel validate without proving the crossingopenP3M2task

    Description

    Found in mw-e15.9: src/tools/puzzle/concrete.ts reach/move put the player beside the target without pathing, and a cold stimulus step on a liquid volume spawn (no placement) is not checked for effect. The frozen-channel freeze solution is therefore 'confirmed' even if nothing froze; the real proof is tests/integration/reference-puzzles.test.ts, which walks the player over the ice. Add walking/pathing or an expected-effect check for cold (ice thickness) and weight steps.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.30Puzzle validator abstraction does not model the facing predicate: Watchers reports abstract and softlock inconclusiveopenP3M2task

    Description

    Found in mw-e15.10: the Watchers goal reads 'facing north' on rotatable statues, which the abstract search does not model, so every solution is abstract-inconclusive and the softlock search cannot prove a destroyed statue leaves the puzzle solvable (only the concrete run and an integration test do). Add facing (quarter-turn state per rotatable entity, rotate and break actions) to the abstraction and softlock search.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.31Puzzle solver cannot strike impact switches: bells cannot be rung by an arrow or spell step, so a balcony-arrow solution cannot be declaredopenP3M2task

    Description

    Found in mw-e15.10: concrete.ts applies stimuli by contact, and a contact stimulus is never an impact (src/sim/mechanisms/impacts.ts), so a 'shoot the bells in order' step diverges. Chimes declares crate-lob and Mage Hand routes instead and tests the arrow feed with deliverImpact. Let a stimulus/strike step deliver an impact (damage type and energy) at the target, and let the abstraction ring bells in sequence.

    area:simarea:toolsepic:e15milestone:m2
  • mw-e15.32Chimes: author the keeper's ledger readable (book.clueFor chimes) so the find-it-in-a-book solution reads the clueopenP3M2task

    Description

    Found in mw-e15.10: the Chimes by-the-book solution is modelled as skipping the button because no lore book item exists (a book needs cover art ui-book-cover-<id>, legality and rarity data, which that data-only bead could not add) and the reader is not wired (mw-e15.25). Add the ledger item with clueFor ['chimes'], place it in the scene, and change the solution to read it so clue.<item> lands on the trail.

    area:contentarea:simarea:toolsepic:e15milestone:m2

M3 MVP content 2

  • mw-e15.12Inspect puzzle goals, wiring and solver results in an in-game toolopenP2M3task

    Description

    Why

    Designers iterate fastest when they can see why a puzzle is not solving (developer tooling pillar).

    What

    Debug panel listing puzzles in the level with lifecycle state, live goal explain() tree, wiring graph highlight, attribution trail, and buttons to reset, force-solve, and run the solver for the current capability set.

    Scope

    • In: Panel in e33 debug console; goal tree view; reset/force-solve/solve commands
    • Out: Standalone level editor — out of scope

    Notes

    Force-solve must set facts exactly as a real solve would (for save testing).

    Acceptance criteria

    • AC-1 integration Given a level with a puzzle, when the inspector opens, then it lists the puzzle with current state and goal explain tree.
    • AC-2 integration Given force-solve, when executed, then the solved fact and outputs match a real solve (compared via fact store diff).
    • AC-3 integration Given the solver button on a puzzle whose search is inconclusive, when run, then the panel shows inconclusive without freezing the game for > 100 ms (runs in a worker) (edge).

    Waits on

    • mw-e15.3 Run data-defined puzzles composed from reusable world objects done
    • mw-e15.6 Prove declared puzzle solutions reachable with a headless solver done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e15milestone:m3size:s
  • mw-e15.13Emit puzzle discovery, attempt, solve and abandon telemetry eventsblockedP2M3task

    Description

    Why

    E34 wants puzzle completion signals; undeclared solutions are gold for designers.

    What

    Emit e34 telemetry events: puzzleDiscovered, puzzleAttemptFailed, puzzleHintShown{tier}, puzzleSolved{solutionId|undeclared, durationS, class}, puzzleAbandoned (left region > 10 min unsolved after discovery).

    Scope

    • In: Event schema entries + emission from runtime
    • Out: Dashboards/export — see e34-telemetry-events

    Notes

    Local-first; no network by default.

    Acceptance criteria

    • AC-1 unit Given a puzzle solved via an undeclared route, when solved, then puzzleSolved carries solutionId=undeclared and the capability trail.
    • AC-2 unit Given discovery then leaving the region for 10 min unsolved, when the tick runs, then puzzleAbandoned fires once.
    • AC-3 unit Given telemetry disabled, when events occur, then nothing is recorded (edge).

    Waits on

    • mw-e15.3 Run data-defined puzzles composed from reusable world objects done
    • mw-e34.1 Define local-first telemetry event schema, store and export open
    area:gameepic:e15milestone:m3size:s
E16Class-Specific SolutionsEvery mandatory obstacle in the MVP has deliberate routes for knight, archer, sorcerer and thief (at least three of four, target four), documented in a route matrix, declared as data, proved by replays and enforced by a CI audit.1/7 done · 14%

M3 MVP content 5

  • mw-e16.2Declare obstacles and class routes as validated content dataopenP1M3task

    Description

    Why

    Routes must be data so they can be audited and replayed, not tribal knowledge.

    What

    Schema content/obstacles/*.json: {id, scene, mandatory, routes: [{id, classes, requiredCapabilities, entities (ids of the anchor points, weak walls, vents…), replay?}]} with a validator that checks scene/entity/capability references.

    Scope

    • In: Zod schema, validator, entries for every matrix obstacle
    • Out: Audit gate (e16-route-audit)

    Notes

    Entities referenced must carry the property that makes the route work (e.g. climbable, weakened, shootable) — the validator checks the property exists.

    Acceptance criteria

    • AC-1 content Given an obstacle entry, when validated, then every referenced scene, entity and capability id exists.
    • AC-2 content Given a route referencing a weak wall entity lacking the weakened property, when validated, then validation fails (edge).
    • AC-3 content Given the registry, when compared to the route matrix, then every matrix obstacle id has an entry.

    Waits on

    • mw-e00.18 Load schema-validated content with a per-entry test harness done
    • mw-e15.1 Define the puzzle data schema with goals, solutions and policies done
    • mw-e16.1 Write the MVP obstacle × class route matrix done
    • mw-e19.2 Create capability registry with source-tracked grants done
    area:contentepic:e16milestone:m3
  • mw-e16.3Fail CI when a mandatory obstacle lacks three class routesblockedP1M3task

    Description

    Why

    "Problems support multiple solutions" must be enforced, not hoped for.

    What

    CI audit reusing e15-solution-audit class capability profiles: for each obstacle, evaluate each route against each class's MVP capability profile; fail if a mandatory obstacle has < 3 classes with a valid route. Generates docs/design/route-coverage.md and a PR diff summary.

    Scope

    • In: Audit script, CI gate, generated report
    • Out: Puzzle audits (e15-solution-audit)

    Notes

    Shares profile data with e15; do not duplicate profiles.

    Acceptance criteria

    • AC-1 integration Given a mandatory obstacle with valid routes for only knight and thief, when CI runs, then it fails naming the obstacle and the missing classes.
    • AC-2 integration Given a route requiring a capability absent from every class profile, when audited, then the route is reported invalid (edge).
    • AC-3 integration Given all obstacles pass, when CI runs, then the report is regenerated and the PR summary lists coverage deltas versus main.

    Waits on

    • mw-e15.8 Report and enforce per-class solution coverage for puzzles in CI done
    • mw-e16.2 Declare obstacles and class routes as validated content data open
    area:qaepic:e16milestone:m3
  • mw-e16.4Replay every declared class route to prove it is traversableblockedP1M3task

    Description

    Why

    A declared route that does not actually work is worse than none.

    What

    Each route in the registry gets a short recorded replay (from a start marker to the obstacle's exit fact) run headlessly in CI; failing replays mark the route invalid in the audit.

    Scope

    • In: Replays per route, runner, audit integration
    • Out: Full critical-path replays (e26-dungeon-playtest)

    Notes

    Replays start from committed save fixtures near each obstacle to stay short. Related: e33-teleport-bookmarks (P2) can generate those fixtures faster if it lands.

    Acceptance criteria

    • AC-1 integration Given each declared route, when its replay runs, then the obstacle exit fact is set.
    • AC-2 integration Given a replay that fails, when the audit runs, then that route no longer counts toward coverage.
    • AC-3 integration Given level geometry changes that break a replay, when CI runs, then the failure names the obstacle, route and first diverging checkpoint (edge).

    Waits on

    • mw-e00.17 Record inputs and replay them to identical state hashes in tests done
    • mw-e16.3 Fail CI when a mandatory obstacle lacks three class routes open
    • mw-e30.1 Define versioned save format with section registry and migrations done
    area:qaepic:e16milestone:m3
  • mw-e16.5Close class-route gaps in Briar Glen, the wilds and WendmouthblockedP1M3feature

    Description

    Why

    The audit will find gaps; closing them is authoring work with a clear owner.

    What

    As a player of any class, I want every surface obstacle to have my class's route so that I never feel my class was forgotten.

    For every E24/E25/E40 obstacle flagged by the audit: add anchor points, weak walls, climbable ivy, vents, shootable counterweights or spell affordances until >= 3 (target 4) classes pass.

    Scope

    • In: Level data edits in town and wilderness scenes, registry updates, replays
    • Out: Dungeon gaps (e16-gap-pass-dungeon)

    Notes

    Prefer adding a route over widening an existing one.

    Acceptance criteria

    • AC-1 integration Given the audit after this pass, when run, then every E24/E25/E40 mandatory obstacle passes with >= 3 classes.
    • AC-2 integration Given each newly added route, when replayed, then it passes.
    • AC-3 perf Given the added props, when the town and Briarwood perf scenes run, then budgets from the hardware baseline still hold (edge: no perf regression).

    Waits on

    • mw-e16.4 Replay every declared class route to prove it is traversable open
    • mw-e24.17 Author class routes for Briar Glen's obstacles open
    • mw-e25.17 Author class routes and ability-gated shortcuts across the wilderness open
    • mw-e40.21 Declare Wendmouth obstacles and class routes in the registry open
    area:contentclass:allepic:e16milestone:m3
  • mw-e16.6Close class-route gaps in the Deepworks, priory and the KnotblockedP1M3feature

    Description

    Why

    The dungeon is the constitution's showcase: "the knight forces, the thief infiltrates, the archer manipulates, the sorcerer alters."

    What

    As a player of any class, I want every dungeon obstacle to have my class's route so that the Labyrinth plays differently for me.

    For every E26 obstacle flagged by the audit: add routes until >= 3 (target 4) classes pass, preferring routes that express the class fantasy lines in the constitution MVP scenario.

    Scope

    • In: Dungeon level data edits, registry updates, replays
    • Out: Puzzle solutions (E15 audit)

    Notes

    Target: all 4 classes for the mine gate, Horn's Hall and the Cradle.

    Acceptance criteria

    • AC-1 integration Given the audit after this pass, when run, then every E26 mandatory obstacle passes with >= 3 classes and the mine gate, Horn's Hall and Cradle pass with 4.
    • AC-2 integration Given each newly added route, when replayed, then it passes.
    • AC-3 integration Given a route that consumes a one-shot resource (e.g. breaking the only weak wall), when used, then the obstacle stays passable for the remaining classes (edge).

    Waits on

    • mw-e16.4 Replay every declared class route to prove it is traversable open
    • mw-e26.21 Author first-pass class routes through every dungeon area open
    area:contentclass:allepic:e16milestone:m3

M4 Fun validation 1

  • mw-e16.7Playtest the MVP critical path once per class for route fantasyblockedP1M4task

    Description

    Why

    Only players can tell whether a route feels like their class or like a checkbox.

    What

    One tester per class plays the MVP critical path; observers log each obstacle, the route taken and whether the tester found their class route unprompted. Findings to docs/playtests/class-routes.md with beads.

    Scope

    • In: 4 sessions, observation sheet, findings, beads
    • Out: External playtests (e35-external-round-1)

    Notes

    Run with builds from e35-playtest-builds.

    Acceptance criteria

    • AC-1 manual Given each class tester, when they finish, then they found their class route unprompted at >= 60% of mandatory obstacles.
    • AC-2 manual Given each tester, when surveyed, then they name >= 3 "wait, I can do that?" moments.
    • AC-3 content Given the findings doc, when complete, then every obstacle where the class route was missed has a bead or an explicit "accepted" note (edge).

    Waits on

    • mw-e16.5 Close class-route gaps in Briar Glen, the wilds and Wendmouth open
    • mw-e16.6 Close class-route gaps in the Deepworks, priory and the Knot open
    • mw-e35.3 Deploy playtest builds to GitHub Pages with build IDs open
    area:qaclass:allepic:e16milestone:m4
E17Inventory & EquipmentWeapons, armor, books, keys, consumables, quest objects and unusual artifacts are manageable without inventory busywork. Equipment changes what the player can *do* (new verbs, altered stealth/noise, light, traversal), not only numbers. All rules live in `src/sim` with data in `src/content`.13/19 done · 68%

M1 Grey-box slice 3

  • mw-e17.16Grant item capabilities while carried through the capability registryopenP1M1feature

    Description

    Why

    Tools such as the climbing hook declare grants with while: carried (ADR-0004), but nothing grants them yet: mw-e17.3's inventory model holds items without touching capabilities (discovered while implementing mw-e17.3).

    What

    When the first unit of a definition with while: carried grants enters an actor's inventory, grant each capability through CapabilityRegistry (src/sim/progression/capabilities.ts) with source tool:<defId>; revoke when its last unit leaves. Driven by item.added / item.removed or inside InventoryRules.

    Acceptance criteria

    • AC-1 unit Given an actor without verb.climb.rough, when a climbing hook is added, then the actor has it from source tool:<id> and capability.gained is emitted once.
    • AC-2 unit Given two hooks carried, when one is removed, then the capability stays; when the second is removed, capability.lost is emitted.
    • AC-3 unit Given an inventory with carried grants, when saved and loaded, then capability sources and inventory agree and the state hash matches.

    Waits on

    • mw-e17.3 Implement inventory model with stacks, keys, books and quest items done
    area:simepic:e17milestone:m1
  • mw-e17.17Bind the four quick slots to default keys and pad buttonsopenP1M1task

    Description

    Why

    mw-e17.6 shipped four quick slots (sim: Consumables.useSlot, useQuickSlotCommand) but no buttons use them: keys 1-4 and the d-pad are already ability1-4 (docs/design/controls.md), so binding them needs an owner layout decision.

    What

    Pick the default keyboard and pad bindings for quick slots 1-4 (e.g. a modifier + 1-4, F1-F4, or d-pad with abilities moved), add quickSlot1-4 actions to the ActionFrame registry, and have the consumables system read them (consumablesSystem input option).

    Scope

    • In: actions, default bindings, remapping conflicts, controls doc
    • Out: quick-slot HUD (mw-e17.10)

    Acceptance criteria

    • AC-1 unit Pressing the quick slot 1 binding uses quick slot 1 (item.used with slot 0).
    • AC-2 unit The default bindings have no conflicts in the gameplay context.
    area:gamearea:simepic:e17milestone:m1
  • mw-e17.19Bind render models for objects spawned after scene load (recovered quest objects)openP3M1task

    Description

    Why

    mw-e17.18 (PR #308) respawns a destroyed quest-critical object as an intact copy at its anchor, but the game's render binding is made only at scene load, so the copy exists in the sim with no visible model.

    What

    Have the render layer bind models for physics/world objects created after scene load (listen for spawns or object.recovered), reusing the original's model id.

    Acceptance criteria

    AC-1 e2e Given an anchored quest-critical breakable in a test scene, when it is broken, then a visible model appears at the anchor.

    area:simepic:e17milestone:m1

M2 Class fantasies 3

  • mw-e17.9Let equipment grant verbs and systemic propertiesopenP1M2feature

    Description

    Why

    Zelda-style meaningful items: equipment should unlock verbs (a lantern makes light, a grappling hook enables anchors, soft boots quiet footsteps), not just add stats.

    What

    As a player, I want gear that changes what I can do so that finding a new item feels like finding a new ability.

    Equipped items with grants register capabilities as source equipment:<instanceId> in the capability registry; unequipping revokes them. Items may also emit properties: lightRadius (feeds e03-light-field), noiseModifier, carriesFire, etc. Interaction prompts query capabilities so new options appear on world objects.

    Scope

    • In: Grant/revoke on equip change, property emitters, prompt refresh event
    • In: Three grey-box sample items: lantern (light), soft boots (noise), climbing hook (anchor verb)
    • Out: The verbs' mechanics themselves (owned by their epics, e.g. climbing in mw-e10)

    Notes

    Same registry as progression so dialogue/quests/puzzles check "can the player do X" regardless of source.

    Acceptance criteria

    • AC-1 unit Given an item granting verb.anchor-climb, when equipped, then hasCapability("verb.anchor-climb") is true; when unequipped, it is false.
    • AC-2 unit Given the player already has a capability from progression and equips an item granting the same one, when the item is unequipped, then the capability remains (source-counted).
    • AC-3 integration Given an equipped lantern, when the light field is sampled at the player position, then light level increases by the item's lightRadius contribution.
    • AC-4 integration Given soft boots equipped, when the player walks on stone, then emitted footstep noise is reduced by the item's noiseModifier.
    • AC-5 unit Given an item granting an unknown capability at runtime (content bypass), when equipped, then equip succeeds, the grant is skipped and an error event is logged.

    Waits on

    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e17.4 Add equipment slots with class proficiencies and equip events done
    • mw-e19.2 Create capability registry with source-tracked grants done
    area:simepic:e17milestone:m2
  • mw-e17.11Add equipment paper-doll view with verb and stealth comparisonblockedP1M2feature

    Description

    Why

    Equipment choices should be legible as trade-offs in verbs, noise and light, not just damage numbers.

    What

    As a player, I want to see what I'm wearing and how swapping gear changes my noise, light and available verbs so that I can dress for the job (stealthy thief vs. armored knight).

    Paper-doll with slot silhouettes, compare panel showing deltas for noise, weight class, light, granted/lost verbs, and key combat values. Non-proficiency penalties shown clearly.

    Scope

    • In: Equipment view, compare panel, slot filters, gamepad support
    • Out: 3D character preview rendering (optional, render group later)

    Notes

    UI assets assumed: slot silhouette icons (head, body, hands, feet, main, off, trinket, ammo, tool), comparison up/down indicators.

    Acceptance criteria

    • AC-1 integration Given heavy armor equipped and soft leather hovered, when comparing, then the panel shows noise decrease and weight class change using derived EquipmentState values.
    • AC-2 integration Given an item that grants a verb, when hovered, then the compare panel lists the verb under "Gains"; unequipping an item lists its verbs under "Loses".
    • AC-3 integration Given a sorcerer hovering plate armor, when compared, then the non-proficiency penalty is shown with a warning style.
    • AC-4 unit Given an empty slot, when rendered, then its silhouette placeholder is displayed and is focusable for gamepad navigation.

    Waits on

    • mw-e17.10 Build inventory screen with category tabs, inspect and actions done
    • mw-e17.9 Let equipment grant verbs and systemic properties open
    area:uiepic:e17milestone:m2
  • mw-e17.13Apply armor load class to speed, sprint, jump, climbing and armor swapsopenP1M2feature

    Description

    Why

    ADR-0003 makes armor the only weight in the game: the heavy knight should be slower, tire sooner and lose rope and ivy routes, while the thief in leather keeps every verb. mw-e04.16 covers rolls, regen, poise and noise; nothing yet applies the load class to running, sprinting, jumping, climbing or armor swaps.

    What

    As a knight, I want my armor's load class to change how I move and climb so that putting on plate is a real choice, not a bigger number.

    From the derived EquipmentState.loadClass (mw-e17.4), apply the ADR-0003 table: run/sprint/crouch speed multipliers (Medium ×0.95, Heavy ×0.9, Overloaded walk only ≤ 2.4 m/s), sprint drain (×1.15 / ×1.3 / no sprint), climb drain (×1.25 / ×1.5 / ×2.0), jump height (×0.95 / ×0.85 / ×0.7), climbing allowed surfaces (Heavy and Overloaded: ladders only, others refused "Too heavy to climb"). Armor and shield equip changes are refused while in Combat (reason in-combat) or while climbing, hanging or carrying (reason busy); weapons, ammo and tools still swap.

    Scope

    • In: Load class multipliers in controller, stamina and climb tuning as content data; climb surface gate; armor-swap refusal rules
    • Out: Roll profiles, regen, poise and noise (mw-e04.16); pull-up refusal (mw-e02.34); footstep noise (mw-e09.5)

    Notes

    Numbers and the table live in docs/adr/0003-encumbrance-model.md. Load ratio = equipped armor kg / class armor capacity (knight 30, others 23).

    Acceptance criteria

    • AC-1 unit Given a Heavy load class, when the player runs and sprints, then horizontal speed is 4.5 m/s and 6.75 m/s ± 0.01 and sprint drains stamina at 13/s.
    • AC-2 unit Given an Overloaded load class, when sprint is held, then the player stays at walk speed ≤ 2.4 m/s and no stamina is drained for sprinting.
    • AC-3 unit Given a Heavy load class, when the player walks into ivy or a rope, then the grab is refused with reason too-heavy; a ladder grab succeeds and drains climb stamina at 7.5/s.
    • AC-4 unit Given a Medium load class, when the player jumps, then apex height is 0.95 × the Light apex height ± 1%.
    • AC-5 unit Given a creature in Combat with the player, when body armor is equipped, then it fails with reason in-combat and equipment is unchanged; a weapon swap in the same state succeeds.
    • AC-6 unit Given the player is climbing, when a shield is unequipped, then it fails with reason busy (edge).
    • AC-7 content Given the load class tuning data, when validated, then every load class defines every multiplier and all multipliers are in (0, 1].

    Waits on

    • mw-e17.4 Add equipment slots with class proficiencies and equip events done
    area:simclass:allepic:e17milestone:m2
E18Loot & TreasureExploration produces interesting, handcrafted discoveries rather than endless statistically interchangeable equipment. Loot is data (tables + placements), deterministic under seeded RNG, persistent in world state, and aware of ownership so theft is a real, systemic act.4/10 done · 40%

M2 Class fantasies 5

  • mw-e18.5Support designer-placed and hidden treasure with discovery rulesopenP1M2feature

    Description

    Why

    The world rewards curiosity: wells hide tunnels, loose bricks hide stashes. Handcrafted placement beats random drops.

    What

    As a designer, I want to place specific items in the level and optionally hide them behind discovery conditions so that curious players find hand-authored rewards.

    Placement data: {id, itemOrTable, transform, hidden?: {revealWhen: property-based conditions}}. Reveal conditions are systemic: light level above threshold (e03-light-field), capability present (e.g. sense.detect-magic), object moved/broken (e03 events). Looted placements persist.

    Scope

    • In: Placement schema, reveal condition evaluation, persistence, greybox examples: stash under a movable crate, item only visible in light
    • Out: Hidden passages / secret doors (mw-e03 / mw-e15)

    Acceptance criteria

    • AC-1 unit Given a hidden placement with revealWhen: lightLevel >= 0.6, when light at its position rises to 0.7, then it becomes interactable and a treasure.revealed event fires once.
    • AC-2 unit Given a placement hidden under a movable object, when the object is moved off its footprint, then the placement is revealed.
    • AC-3 unit Given a looted placement, when the level reloads, then the placement does not respawn.
    • AC-4 unit Given a reveal condition referencing an unknown capability, when content is validated, then validation fails.

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e03.31 Consolidate world-property vocabulary assumed by other epics done
    • mw-e18.3 Add lootable containers that persist their contents done
    • mw-e19.2 Create capability registry with source-tracked grants done
    area:simepic:e18milestone:m2
  • mw-e18.6Track item ownership and flag stolen items on witnessed theftopenP1M2feature

    Description

    Why

    Stealing must be a real systemic act with consequences (thief fantasy, Elder Scrolls living world) and feed shops, disposition and AI.

    What

    As a thief, I want taking things that belong to others to be tracked and only punished when someone notices so that careful theft pays off and sloppy theft creates stories.

    Ownership on containers, placements and world items (ownerId NPC or faction). Taking an owned item marks the instance stolen with owner. At the moment of taking, witnesses are evaluated via e11 perception/e09 visibility: witnessed theft emits crime.theft (value, owner, witnesses) consumed by e11-alert-states and disposition; unwitnessed theft emits nothing but the item remains flagged. Owner discovers missing high-value items later (optional fact owner.noticedMissing).

    Scope

    • In: Ownership data, stolen flag assignment, witness check, crime event, returning stolen items clears the flag
    • Out: Guard responses/bounty (mw-e11)
    • Out: Fence pricing (e20-fences-stolen-goods)
    • Out: Pickpocket minigame (mw-e10)

    Acceptance criteria

    • AC-1 unit Given an owned item in a container and no witness able to see the player, when taken, then the instance is stolen with the ownerId and no crime.theft event is emitted.
    • AC-2 unit Given an NPC with the player in sight cone and visibility ≥ its threshold, when an owned item is taken, then crime.theft is emitted listing that NPC as witness.
    • AC-3 unit Given a stolen item given back to its owner (via dialogue effect or putting it back in the owner's container), when returned, then the stolen flag clears.
    • AC-4 unit Given an unowned item, when taken in full view, then no stolen flag or crime event occurs.
    • AC-5 integration Given the greybox guard watching a chest, when the player takes an item, then the guard enters at least the Suspicious alert state.

    Waits on

    • mw-e09.2 Compute player visibility from light, stance, motion and distance done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e17.7 Pick up, drop and throw items as physical world objects done
    • mw-e18.3 Add lootable containers that persist their contents done
    • mw-e27.9 Track object ownership and record thefts as world facts done
    area:simclass:thiefepic:e18milestone:m2
  • mw-e18.7Drop what creatures actually carry, plus data-driven extrasopenP1M2feature

    Description

    Why

    Creatures are not target dummies or loot piñatas; what they carry should be visible and plausible (the goblin with the lantern drops the lantern).

    What

    As a player, I want defeated or robbed creatures to hold the gear I saw them using so that loot feels grounded.

    Creature schema extension: carried inventory (equipped items shown on the creature) + optional dropTable for pouch contents. On death the corpse becomes a container; on pickpocket (mw-e10) the carried inventory is the source. Wolves drop nothing but pelts-as-quest-materials only if data says so.

    Scope

    • In: Carried inventory on creatures, corpse-as-container, owned-by-creature flags (robbing a living goblin is theft)
    • Out: Pickpocket mechanics (mw-e10)
    • Out: Harvesting/crafting (not planned for MVP)

    Acceptance criteria

    • AC-1 unit Given a creature with carried [rusty-sword, lantern], when killed, then its corpse container holds exactly those plus the rolled drop table results.
    • AC-2 unit Given a creature with no carried items and no drop table, when killed, then no corpse container is created (no empty loot prompt).
    • AC-3 unit Given a living intelligent creature, when an item is taken from it, then the item is flagged stolen with the creature as owner.
    • AC-4 content Given every creature data file, when validated, then all carried/dropTable references resolve.

    Waits on

    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e18.3 Add lootable containers that persist their contents done
    area:simepic:e18milestone:m2
  • mw-e18.8Add unique artifacts with active verbs and loreblockedP1M2feature

    Description

    Why

    Handcrafted discoveries with verbs are the reward that replaces stat-sticks; artifacts should make players say "wait, I can do that?"

    What

    As a player, I want rare artifacts that do strange, useful things so that finding one changes how I play.

    Artifact = item with flags.unique and either passive grants or an activate block (cooldown/charges, effects via the shared effect vocabulary and world properties). Examples for grey-box tests only: a compass that points to the nearest hidden placement, a bell that emits a loud noise event at a distance, a cold stone that gives frozen to touched water. Uniqueness enforced world-wide.

    Scope

    • In: Activate verb, charges/cooldown, uniqueness guarantee, lore text field, 3 grey-box test artifacts
    • Out: The MVP artifact roster (world-content group)

    Notes

    Artifacts must express effects via properties (e03) — never artifact-specific code paths.

    Acceptance criteria

    • AC-1 unit Given an artifact with 3 charges and recharge-on-rest, when activated 4 times without rest, then the 4th activation fails with reason no-charges.
    • AC-2 unit Given a unique artifact already obtained, when any table or placement tries to grant another, then no second instance is created.
    • AC-3 integration Given the bell test artifact activated, when resolved, then a noise event with the configured loudness is emitted at the target point and nearby guards react via e11.
    • AC-4 integration Given the cold-stone test artifact touching a wet/water volume, when resolved, then the volume gains frozen via e03 propagation.
    • AC-5 content Given all artifact data, when validated, then each has a non-empty lore text key and at least one grant or activate effect.

    Waits on

    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e17.9 Let equipment grant verbs and systemic properties open
    • mw-e18.1 Implement loot table schema and deterministic seeded roller done
    • mw-e27.13 Rest at inns, campfires and shrines to reset facts and pass time open
    area:simepic:e18milestone:m2
  • mw-e18.9Write treasure design guide for handcrafted lootopenP1M2task

    Description

    Why

    World-content authors need a shared rule set so loot stays meaningful across the town, wilderness and labyrinth.

    What

    docs/design/treasure.md: treasure tiers (junk-with-jokes, useful consumables, tools, books, artifacts), placement density guidelines ("interesting-looking places usually contain something"), ratio of handcrafted vs table-rolled, gold budget per area (links to economy doc), ownership conventions, humour guidelines for flavour text.

    Scope

    • In: Guide doc with examples and anti-patterns
    • Out: Actual placements (world-content group)

    Acceptance criteria

    • AC-1 manual Given the guide, when reviewed, then it defines each treasure tier with one example and an anti-pattern.
    • AC-2 manual Given the guide, when reviewed, then it states numeric density targets (e.g. discoveries per room/area) and the handcrafted:rolled ratio.
    • AC-3 manual Given the guide, when reviewed, then it references the economy gold budget from e20-economy-design.

    Waits on

    • mw-e20.1 Write economy design: gold income, meaningful sinks, price bands done
    area:designepic:e18milestone:m2

M3 MVP content 1

  • mw-e18.10Build treasure audit and loot distribution report toolblockedP2M3task

    Description

    Why

    Designers need to see what a region yields before playtesting it, and to catch gold inflation or missing books.

    What

    CLI pnpm content:loot-report [region]: enumerates placements, containers and creature drops; simulates each table N times (seeded) and outputs expected gold, item counts by category, unique artifact locations, and per-class availability of progression items (books, tools, schematics). Debug console command loot.roll <table> [n].

    Scope

    • In: CLI report (markdown + JSON), console command
    • Out: Economy balance CI gate (e20-economy-balance-tool)

    Acceptance criteria

    • AC-1 unit Given a fixture region with 2 containers and known tables, when the report runs with seed 1 and N=1000, then expected gold equals the analytic expectation within ±1%.
    • AC-2 unit Given a region where a class-gated progression item has no source, when the report runs, then it lists that item under "Unobtainable".
    • AC-3 unit Given loot.roll unknown-table, when executed in the console, then it reports an error and suggests close matches.

    Waits on

    • mw-e18.2 Validate loot tables: references, uniques, cycles, weights done
    • mw-e18.7 Drop what creatures actually carry, plus data-driven extras open
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e18milestone:m3
E19ProgressionCharacter advancement primarily unlocks capabilities (verbs), specialization and new play styles — never Firebolt I → II (+12%). The player picks a class at the start; each class earns new verbs through its own fiction: books (sorcerer), techniques from trainers (knight), arrows and trick-shot techniques (archer), tools and tricks (thief). Supporting stats are minimal and subordinate.6/19 done · 32%

M1 Grey-box slice 1

  • mw-e19.6Implement minimal supporting stats and rare stat growth sourcesopenP1M1feature

    Description

    Why

    Stats can exist but must support rather than define progression (constitution §3); keep them few and legible.

    What

    As a player, I want a small set of stats (e.g. health, stamina, focus) that grow from rare discoveries so that finding a heart-container-like relic feels special without turning into grind.

    Stats per ADR (≤ 5), with base from class, modifiers from equipment and temporary effects, and permanent increments from data-defined sources (relic items, shrines, deeds). Hard caps. No per-kill XP.

    Scope

    • In: Stat model with base/modifier/permanent layers, caps, sources, events, save section
    • Out: Combat consumption of stamina/poise (mw-e04)
    • Out: Mana/focus spending (mw-e06)

    Acceptance criteria

    • AC-1 unit Given base health 100 and a relic granting +10 permanent max health, when consumed, then max health is 110 and current health increases by 10.
    • AC-2 unit Given max health at its cap, when another permanent increment is applied, then it is clamped and the source is not consumed (returns at-cap).
    • AC-3 unit Given an equipment modifier of -10 stamina, when unequipped, then stamina max returns to its prior value.
    • AC-4 unit Given a creature is killed, when resolved, then no stat changes occur (no per-kill XP).

    Waits on

    • mw-e17.4 Add equipment slots with class proficiencies and equip events done
    • mw-e19.4 Define the four classes as data: kit, capabilities, proficiencies done
    area:simepic:e19milestone:m1

M2 Class fantasies 12

  • mw-e19.7Wire spellbook learning into progression prerequisitesopenP1M2feature

    Description

    Why

    Magic is learned primarily from books (constitution §4). Book learning must respect progression prerequisites and class rules defined in the ADR.

    What

    As a sorcerer, I want reading a spellbook to teach me its spell when I understand the prerequisites so that books become exciting and school knowledge matters.

    Adapter from e07-spellbook-learning to progression.learn(spell, channel: book). Handles: missing prerequisite (book stays readable, shows what knowledge is missing), non-sorcerer readers per ADR cross-learning rule, damaged/untranslated books gated by conditions.

    Scope

    • In: Adapter, failure explanations, cross-class rule enforcement
    • Out: Book reading UI and spell data (mw-e07, mw-e08)
    • Out: Bookshop inventories (e21-bookshop-system)

    Acceptance criteria

    • AC-1 unit Given a sorcerer reading a book for a spell whose prerequisites are met, when read, then the spell capability is granted with source learned and channel book.
    • AC-2 unit Given a knight reading a sorcerer-only spellbook, when read, then no capability is granted and the result explains per ADR (e.g. "The runes swim before your eyes.").
    • AC-3 unit Given a book whose spell is already known, when read, then no duplicate grant occurs and the book is flagged read.
    • AC-4 integration Given the greybox testbed, when a sorcerer picks up and reads a test spellbook, then the new spell appears in the capabilities list and can be cast.

    Waits on

    • mw-e07.2 Learn spells by reading and studying book items done
    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    area:simclass:sorcererepic:e19milestone:m2
  • mw-e19.8Let trainers teach knight techniques through dialogue servicesopenP1M2feature

    Description

    Why

    Knights master techniques; learning them from a character (for gold, a deed, or a duel) is more memorable than a skill point.

    What

    As a knight, I want to learn new techniques from trainers who demand payment, proof or a test so that each new move has a story.

    Trainer = NPC with teaches: [{capability, price?, requires: conditions, test?: questId}]. Dialogue effect learnCapability (via e22 DSL) and a service listing in the trainer's dialogue. Supports technique chains (shield bash → shield charge → shield vault) and non-gold prices (a favour quest).

    Scope

    • In: Trainer data schema, dialogue effect binding, gold deduction via shop transactions, test-quest gating
    • Out: Technique mechanics (mw-e04)
    • Out: Specific trainer NPCs (world-content group)

    Acceptance criteria

    • AC-1 unit Given a trainer teaching technique.shield-charge for 50 gold and a knight with 60 gold and the prerequisite, when learned, then gold is 10 and the capability is granted with channel trainer.
    • AC-2 unit Given insufficient gold, when the learn effect runs, then it fails atomically (no gold removed, no capability).
    • AC-3 unit Given a technique gated by a test quest not yet resolved, when offered in dialogue, then the option is shown as locked with its requirement text.
    • AC-4 content Given all trainer data, when validated, then every taught capability exists and every test quest id resolves.

    Waits on

    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    • mw-e20.4 Implement merchant buy/sell transactions with persistent stock done
    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    area:simclass:knightepic:e19milestone:m2
  • mw-e19.9Unlock archer trick arrows via schematics and trick-shot techniquesblockedP1M2feature

    Description

    Why

    Archers control space through specialized arrows and trick shots; new arrow types are new verbs.

    What

    As an archer, I want to find fletching schematics and learn trick shots so that my quiver gains new ways to solve problems (rope arrows, water arrows, noise arrows).

    Fletching schematic item → learn(arrow.<type>, channel: schematic); once known, arrows of that type can be assembled at rest points from simple materials (count-limited, no crafting tree). Trick-shot techniques (e.g. ricochet, pinning) learned from deeds or trainers via the shared channels.

    Scope

    • In: Schematic item handling, simple arrow assembly (materials → arrows), trick-shot unlock via deed/trainer
    • Out: Arrow physics and effects (mw-e05)
    • Out: General crafting system (not MVP)

    Acceptance criteria

    • AC-1 unit Given an archer reading a rope-arrow schematic, when read, then arrow.rope is learned with channel schematic and the schematic is consumed.
    • AC-2 unit Given arrow.rope known and 2 rope + 2 shafts, when assembling at a rest point, then 2 rope arrows are added and materials removed.
    • AC-3 unit Given arrow.rope not known, when assembling, then the recipe is unavailable even with materials.
    • AC-4 unit Given a non-archer reading a schematic, when read, then behaviour follows the ADR cross-learning rule and is covered by a test.

    Waits on

    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    • mw-e17.3 Implement inventory model with stacks, keys, books and quest items done
    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    • mw-e27.13 Rest at inns, campfires and shrines to reset facts and pass time open
    area:simclass:archerepic:e19milestone:m2
  • mw-e19.10Grant thief verbs from tools and tricks learned from contactsblockedP1M2feature

    Description

    Why

    Thief growth is about tools and tricks (lockpicks, grapples, smoke, disguises); owning a tool is owning a verb.

    What

    As a thief, I want new tools and tricks to open new routes so that my arsenal grows in options, not numbers.

    Tools are items with grants (via e17-equipment-verbs on the toolBelt, or passive when carried per ADR). Tricks (e.g. trick.feign-death, trick.shadow-step) are learned from notes/contacts via the shared learn API with channel trick. Tool degradation per ADR (e.g. lockpicks can break — failure creates stories).

    Scope

    • In: Tool-carried capability grants, trick learning channel, optional breakage rule hook
    • Out: Tool mechanics (mw-e10)

    Acceptance criteria

    • AC-1 unit Given lockpicks on the tool belt, when checked, then tool.lockpick is granted; removing the lockpicks revokes it.
    • AC-2 unit Given a trick note read by a thief, when read, then the trick is learned with channel trick.
    • AC-3 unit Given a breakable tool with 1 durability, when a breaking event occurs, then the tool is removed and its capability revoked with a tool.broke event.
    • AC-4 unit Given two lockpick stacks, when one breaks, then the capability remains while any stack remains.

    Waits on

    • mw-e17.9 Let equipment grant verbs and systemic properties open
    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    area:simclass:thiefepic:e19milestone:m2
  • mw-e19.12Build capabilities screen and "new verb learned" feedbackblockedP1M2feature

    Description

    Why

    Players must notice and remember new verbs, otherwise capability progression is invisible.

    What

    As a player, I want a screen listing what I can do, grouped by source, with hints about what I might learn next, and a clear moment when I learn something new so that I try my new verbs.

    Screen: capabilities grouped (Class, Learned, From Gear, Temporary), each with icon, description and input hint. "Rumoured" section shows known-but-unlearned capabilities from rumors/books glimpsed. Learn moment: banner with verb name, one-line usage hint, and input glyph; optional short practice prompt.

    Scope

    • In: Capabilities screen, learn banner, input glyph binding, rumoured hints
    • Out: Spellbook-specific UI (mw-e07)

    Notes

    UI assets assumed: capability/verb icons per class (placeholder shapes first), learn banner frame, input glyph set (KB/M + gamepad).

    Acceptance criteria

    • AC-1 integration Given capabilities from class, learning and an equipped lantern, when the screen opens, then each appears under the correct group with its icon.
    • AC-2 integration Given capability.gained from a learn action, when fired, then the learn banner appears within 1 frame and shows the currently bound input glyph for that verb.
    • AC-3 integration Given the player remaps the verb's input, when the screen reopens, then the new glyph is shown.
    • AC-4 unit Given a temporary capability expires while the screen is open, when it expires, then it is removed from the list without closing the screen.

    Waits on

    • mw-e00.23 Build HUD/menu UI layer, component kit, focus nav and UI test harness done
    • mw-e02.1 Map remappable KB/M input to deterministic per-tick action frames done
    • mw-e17.9 Let equipment grant verbs and systemic properties open
    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    area:uiepic:e19milestone:m2
  • mw-e19.15Validate progression content against the ADR-0004 anti-grind rulesopenP1M2task

    Description

    Why

    ADR-0004 defines eight content rules (P1–P8) that keep progression about verbs. mw-e19.3 AC-6 covers numeric-only unlocks and cycles and mw-e07.8 covers spell chains; the rest (narrow supporting, one-time stat sources, cross-class bounds, no exclusive unlocks, reachability, no XP fields) have no validator yet, so content could quietly reintroduce grind.

    What

    As a designer, I want pnpm content:check to reject progression data that breaks the anti-grind rule so that a bad unlock fails in CI with the rule id, entry and file.

    Implement rules P2 and P4–P8 from docs/adr/0004-progression-model.md and generalize P3 (each chain step is a new verb) from spells to techniques, arrows, tools and tricks. Every message names the rule id, the entry id and the file.

    Scope

    • In: Validator rules over capability, unlock, trainer, schematic, tool, trick, deed, stat-source and class data; fixtures for each rule
    • Out: The P1 numeric-only rule and cycle check already in mw-e19.3; spell chain check in mw-e07.8; runtime learn API (mw-e19.16)

    Notes

    MVP stat budget is 8 shrines and 6 boon items; stat steps are exactly +10; caps 200 (ADR-0004 stats table).

    Acceptance criteria

    • AC-1 content Given a stat source entry granting +15 max health, when validated, then validation fails with rule P5 naming the entry and file.
    • AC-2 content Given an unlock flagged supporting: true that targets spell.firebolt, when validated, then validation fails with rule P2.
    • AC-3 content Given a technique chain step whose move, ops and stimuli equal its predecessor's and differ only in damage, when validated, then validation fails with rule P3.
    • AC-4 content Given a crossClass: true unlock with a prerequisite, or one listed in its class's signature capabilities, when validated, then validation fails with rule P6.
    • AC-5 content Given an unlock declaring excludes, or a replacing unlock with no subsumes, when validated, then validation fails with rule P7.
    • AC-6 content Given a capability that no book, trainer, schematic, tool, trick, deed, item or class grants, when validated, then validation fails with rule P8 naming the capability.
    • AC-7 content Given any content entry with an xp, level or skillPoints field, when validated, then validation fails with rule P4.

    Waits on

    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    area:contentepic:e19milestone:m2
  • mw-e19.16Enforce the cross-class simple-capability rule in the learn APIopenP1M2feature

    Description

    Why

    ADR-0004 allows a knight to read an easy spellbook and a sorcerer to learn a basic shield bash, but only for *simple* capabilities. The rule must live once in the shared learn API, not be re-implemented in each channel (mw-e19.7–mw-e19.10 each say "per the ADR cross-learning rule").

    What

    As a knight, I want to learn an easy spell from a book I found so that my curiosity is rewarded, while the sorcerer's deeper chains stay hers.

    learn(capId, channel) checks, for a learner whose class differs from the capability's affinity: the capability is a chain root, its unlock sets crossClass: true, it is within the channel bound (book: difficulty ≤ 0.3, mana cost ≤ 20, licensed school; trainer: stamina cost ≤ 25, no proficiency; schematic: shop-sold materials, any bow; trick: no tool or trick required; tool: grant flagged crossClass) and it is not in the home class's signature list. A refusal returns reason off-class with an in-fiction explanation key, and the source (book, schematic, note) is not consumed.

    Scope

    • In: Cross-class check in the learn API, refusal reasons and text keys, class signature list in class data
    • Out: Content validation of crossClass flags (mw-e19.15); channel adapters' own tests (mw-e19.7–mw-e19.10)

    Notes

    See docs/adr/0004-progression-model.md, "Cross-class learning: the simple rule".

    Acceptance criteria

    • AC-1 unit Given a knight and a crossClass root spell with difficulty 0.2 and mana cost 15, when learned from a book, then the capability is granted with channel book.
    • AC-2 unit Given a knight and spell.flame-jet (has prerequisites), when learned from a book, then learning fails with reason off-class and the book is not consumed.
    • AC-3 unit Given a sorcerer and the knight's signature technique.parry, when offered by a trainer, then learning fails with reason off-class and no gold is deducted.
    • AC-4 unit Given a thief and a crossClass schematic whose arrow needs shop-sold materials, when read, then the arrow is learned with channel schematic.
    • AC-5 unit Given an off-class learner and an unlock without crossClass: true that otherwise meets every bound, when learned, then it fails with reason off-class (edge).

    Waits on

    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    • mw-e19.4 Define the four classes as data: kit, capabilities, proficiencies done
    area:simclass:allepic:e19milestone:m2
  • mw-e19.17Offer a one-time health, stamina or mana boon choice at shrinesblockedP1M2feature

    Description

    Why

    ADR-0004 grows health, stamina and mana only from one-time shrines and found boon items. mw-e19.6 implements the stat layers and fixed-stat sources; nothing yet offers the shrine's choice, which is the player's only say in how their supporting stats grow.

    What

    As a player, I want to find a shrine and choose whether it strengthens my health, stamina or mana so that a rare discovery fits how I play.

    A shrine is a world entity with once: true. Interacting opens a choice of +10 health, +10 stamina or +10 mana; a stat at cap is shown but unavailable. Choosing applies the step through mw-e19.6, records a world-state fact so the shrine stays spent across save and load, and emits stat.boon. A shrine is a discovery, not a rest point.

    Scope

    • In: Shrine component and schema, choice flow on the minimal UI, spent fact, events, a grey-box shrine in the testbed
    • Out: Stat model and boon items (mw-e19.6); shrine art and story names (mw-e37, mw-e39); world placement (content epics)

    Notes

    MVP budget: 8 shrines. Story names must not reuse "relic" (Vane's shipments).

    Acceptance criteria

    • AC-1 unit Given an unspent shrine and max stamina 100, when the player chooses stamina, then max stamina is 110, current stamina rises by 10 and stat.boon is emitted once.
    • AC-2 unit Given a spent shrine, when the player interacts, then no choice is offered and stats are unchanged.
    • AC-3 unit Given max health at its cap of 200, when the shrine choice opens, then health is listed as unavailable and cannot be chosen (edge).
    • AC-4 unit Given all three stats at cap, when the player interacts, then the shrine is not spent and reports at-cap.
    • AC-5 integration Given a spent shrine, when the game is saved and loaded, then the shrine is still spent.
    • AC-6 e2e Given the grey-box testbed shrine, when the player chooses mana, then the mana HUD maximum increases by 10 with no console errors.

    Waits on

    • mw-e19.6 Implement minimal supporting stats and rare stat growth sources open
    area:simclass:allepic:e19milestone:m2
  • mw-e19.18hasCapability must honour replacing unlocks (subsumed capabilities stay usable)openP1M2task

    Description

    Why

    ADR-0004 says a replacing unlock must subsume the capability it replaces (Telekinesis still pulls levers like Mage Hand). PR #143 (mw-e19.3) revokes the replaced capability's learned source and only UnlockBook.knows follows the replacement chain; hasCapability used by puzzles, traversal and other checks does not. Authoring any replacement chain today would break checks on the replaced id.

    What

    Make the registry's capability query treat a capability as held when a held capability replaces it (transitively), or keep the replaced grant; one source of truth for every caller.

    Acceptance criteria

    • AC-1 unit Given spell.telekinesis learned as a replacement of spell.mage-hand, when a puzzle checks hasCapability(actor, spell.mage-hand), then it returns true.
    • AC-2 unit Given a replacement chain A→B→C with only C held, when any caller queries A, then it is held.
    area:simepic:e19milestone:m2
  • mw-e19.11Unlock capabilities from notable deeds via data-driven rulesopenP2M2feature

    Description

    Why

    Some verbs are best earned by doing something memorable (befriending the minotaur, surviving a fall into the mine), rewarding curiosity instead of repetition.

    What

    As a player, I want remarkable actions to teach me something so that the world itself trains me.

    Deed rules: {when: event/fact conditions, grants: capability, once: true, message} evaluated on world-state changes. Explicitly not repetition counters (anti-grind): validator rejects deed rules whose condition is a count > 3 of the same event unless flagged.

    Scope

    • In: Deed rule schema, evaluator on world-state/event bus, validator anti-grind rule, notification event
    • Out: Specific deeds (world-content group)

    Acceptance criteria

    • AC-1 unit Given a deed rule on fact minotaur.befriended, when the fact becomes true, then the capability is learned with channel deed exactly once.
    • AC-2 unit Given the fact toggles false then true again, when evaluated, then the deed does not grant twice.
    • AC-3 unit Given a deed rule requiring 20 kills of the same creature type without allowRepetition, when validated, then validation fails citing the anti-grind rule.

    Waits on

    • mw-e19.3 Implement capability-unlock progression with prerequisite chains done
    • mw-e22.2 Create shared typed condition/effect DSL for dialogue, quests, shops done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    area:simepic:e19milestone:m2
  • mw-e19.14Check interaction affordance capability requirements against the capability registryopenP2M2task

    Description

    Why

    Scene affordances (src/content/types/interaction.ts) declare requires: [{ capability }] as a plain kebab content id, while puzzles (mw-e15.1) name capabilities by registry id (spell.mage-hand) checked against src/content/data/capability/. Two spellings of the same idea means a gated lever can name a capability nothing grants.

    What

    As a designer, I want affordance capability requirements to use the capability id format and be checked against the registry at load so that a typo fails in CI rather than greying out a prompt forever.

    Scope

    • In: interaction requirement uses capabilityId; load check against the capability registry with file and pointer
    • Out: the runtime capability registry (mw-e19.2)

    Acceptance criteria

    • AC-1 content Given a scene spawn whose affordance requires an undeclared capability id, when validated, then validation fails naming the id, file and pointer.
    • AC-2 content Given an affordance requirement that is not in capability id format, when validated, then validation fails.

    Waits on

    • mw-e19.2 Create capability registry with source-tracked grants done
    area:contentarea:simepic:e19milestone:m2size:s
  • mw-e19.19Let shrines and boons raise max mana (mana profile.max growth API)openP2M2task

    Description

    From PR #267 (mw-e06.3): mana profile.max is fixed at install; ADR-0004 stat growth (shrines, mw-e19.17 boons) needs an API to raise it deterministically and persist it.

    Acceptance criteria

    • AC-1 a shrine/boon raises max mana; current mana handling documented; survives save/load
    area:simepic:e19milestone:m2
E20Economy & ShopsGold has meaningful uses and merchants have identities, inventories and specialties (Quest for Glory merchants with personality; Elder Scrolls living shops). Players can buy, sell, haggle and steal, and prices respond to disposition, specialty and stolen goods.6/12 done · 50%

M2 Class fantasies 2

  • mw-e20.6Support fences and merchant reactions to stolen goodsblockedP1M2feature

    Description

    Why

    Stolen goods need an outlet and consequences; offering a merchant their own stolen silver should be memorable (and funny).

    What

    As a thief, I want to sell stolen goods to a fence at a discount, and face consequences if I try to sell them to their owner so that theft is a complete loop.

    Fences buy stolen items at the economy-doc discount. Non-fences refuse stolen items; if the merchant (or their faction) is the owner, emit crime.theft.recognized → disposition drop and optional guard alert. Fences can "launder" at a fee (clear stolen flag) if the design doc enables it.

    Scope

    • In: Fence rules, owner recognition, disposition/crime events, optional laundering
    • Out: Guard arrest/bounty behaviour (mw-e11)

    Acceptance criteria

    • AC-1 unit Given a stolen item worth 100 and a fence with discount 0.4, when sold, then the player receives the price model result for a fence (breakdown includes stolen discount).
    • AC-2 unit Given a merchant who owns a stolen item the player tries to sell, when attempted, then the sale is refused, disposition drops by the configured amount and crime.theft.recognized is emitted.
    • AC-3 unit Given a stolen item owned by someone else, when offered to a non-fence, then the sale is refused with no crime event.
    • AC-4 unit Given laundering enabled, when paid, then the stolen flag clears and gold is deducted atomically.

    Waits on

    • mw-e18.6 Track item ownership and flag stolen items on witnessed theft open
    • mw-e20.4 Implement merchant buy/sell transactions with persistent stock done
    • mw-e22.4 Track NPC disposition with bands, event modifiers and factions done
    area:simclass:thiefepic:e20milestone:m2
  • mw-e20.7Allow stealing shop stock with witness-based consequencesblockedP2M2feature

    Description

    Why

    Shops are prime thief targets; lifting an item from a counter while the merchant is distracted is a classic thief moment.

    What

    As a thief, I want to steal displayed wares or from the merchant's stock when unobserved so that distractions and timing pay off.

    Shop display items are world items owned by the merchant; taking them uses e18 ownership + witness checks. Witnessed shoplifting: merchant disposition drop, prices up, possible ban (merchant.banned fact) and guard alert. Stolen shop stock decrements merchant stock.

    Scope

    • In: Display items bound to merchant stock, consequences ladder (warning → price hike → ban), ban lifting via fine/quest effect
    • Out: Pickpocketing the merchant (mw-e10)

    Acceptance criteria

    • AC-1 unit Given an unwitnessed theft of a displayed item, when taken, then merchant stock decrements and the instance is stolen with owner = merchant.
    • AC-2 unit Given a first witnessed theft, when detected, then the consequence ladder moves to "warning" and disposition drops per data.
    • AC-3 unit Given a banned merchant, when the player opens the shop, then trade is refused with a ban dialogue line until a fine.paid effect lifts the ban.
    • AC-4 integration Given the greybox shop with a merchant facing away, when the thief takes a displayed item, then no crime event fires; facing toward, then one fires.

    Waits on

    • mw-e18.6 Track item ownership and flag stolen items on witnessed theft open
    • mw-e20.4 Implement merchant buy/sell transactions with persistent stock done
    • mw-e22.1 Turn witnessed crimes into settlement bounties with pay/jail/flee open
    area:simclass:thiefepic:e20milestone:m2

M3 MVP content 4

  • mw-e20.9Add purchasable services as meaningful gold sinksblockedP1M3feature

    Description

    Why

    Gold has meaningful uses beyond items: healing, lodging, translation of books, bribes and donations create choices and stories.

    What

    As a player, I want to pay for services (heal, rest at the inn, translate an untranslated book, bribe a guard, donate to the shrine) so that gold opens doors, not just inventory slots.

    Service schema: {id, providerNpcId, price or priceFormula, conditions, effects} reusing the effect DSL; invoked from dialogue. Bribes/donations can change disposition or facts.

    Scope

    • In: Service schema + validator, purchase via dialogue effect, atomic gold deduction
    • Out: Trainer techniques (e19-knight-trainer-channel uses this)

    Acceptance criteria

    • AC-1 unit Given a translate-book service costing 40 and an untranslated book in inventory, when purchased, then 40 gold is removed and the book instance gains translated.
    • AC-2 unit Given insufficient gold, when purchasing, then nothing changes and the dialogue receives insufficient-gold.
    • AC-3 unit Given a service whose conditions are unmet (e.g. no untranslated book), when listed, then it is hidden or shown locked per its showWhenLocked flag.
    • AC-4 content Given service data, when validated, then every provider NPC and effect reference resolves.

    Waits on

    • mw-e20.4 Implement merchant buy/sell transactions with persistent stock done
    • mw-e22.2 Create shared typed condition/effect DSL for dialogue, quests, shops done
    • mw-e27.13 Rest at inns, campfires and shrines to reset facts and pass time open
    area:simepic:e20milestone:m3
  • mw-e20.8Add haggling with class options and disposition riskopenP2M3feature

    Description

    Why

    QfG-style merchant banter and DOS2 persuasion make trading a social encounter rather than a spreadsheet.

    What

    As a player, I want to haggle a price using my class's strengths (knight's reputation, thief's bluff, sorcerer's impressive trick, archer's trade in pelts) so that talking well saves gold.

    Haggle is a short dialogue sub-flow: choose an approach, deterministic check (disposition + class/capability modifiers + merchant personality), success grants a haggle modifier (bounded by the economy doc), failure worsens price or disposition; limited to 2 attempts per item per day.

    Scope

    • In: Haggle flow via dialogue runtime, deterministic check formula, attempt limits, personality modifiers
    • Out: General persuasion checks (e22-persuasion-checks is reused)

    Acceptance criteria

    • AC-1 unit Given a greedy merchant and a thief bluff approach with modifiers summing above threshold, when haggling, then the price improves by the data-defined amount and never beyond the doc cap.
    • AC-2 unit Given a failed haggle, when resolved, then disposition drops per personality data and the next haggle on that item has a penalty.
    • AC-3 unit Given 2 attempts already made on an item today, when a third is requested, then the option is unavailable with the merchant's refusal line.
    • AC-4 unit Given identical state, when the same haggle is attempted twice from the same save, then the outcome is identical (no hidden randomness).

    Waits on

    • mw-e20.4 Implement merchant buy/sell transactions with persistent stock done
    • mw-e22.7 Add deterministic persuasion checks with fail branches done
    area:simepic:e20milestone:m3
  • mw-e20.11Add data-driven merchant barks for shop eventsblockedP2M3task

    Description

    Why

    Merchants with personality (QfG5) react to what you do — browsing forever, haggling badly, offering them their own candlestick.

    What

    Bark sets keyed by shop event (greet, browseLong, buyExpensive, sellJunk, haggleWin, haggleFail, stolenRecognized, banned, farewell) with condition filters and anti-repetition (no same line twice within 5 uses). Uses e22 bark system for display.

    Scope

    • In: Bark set schema for shop events, selection logic, 1 grey-box bark set
    • Out: Actual merchant writing (world-content group)

    Acceptance criteria

    • AC-1 unit Given a bark set with 3 greet lines, when greet fires 3 times, then 3 distinct lines are chosen before any repeats.
    • AC-2 unit Given a browseLong threshold of 60 s in the shop UI, when exceeded, then exactly one browseLong bark is emitted.
    • AC-3 content Given a bark set missing the greet event, when validated, then validation fails.

    Waits on

    • mw-e20.4 Implement merchant buy/sell transactions with persistent stock done
    • mw-e22.13 Show ambient NPC barks as accessible positional subtitles open
    area:contentepic:e20milestone:m3
  • mw-e20.12Add economy balance report and CI gateblockedP2M3task

    Description

    Why

    Balance drifts as content grows; a CI gate keeps gold meaningful without playtesting every change.

    What

    CLI pnpm content:economy-report: sums expected obtainable gold (loot report + quest rewards + sellable items at average buy rates) vs total cost of meaningful sinks (books, techniques, tools, services) for the MVP region; fails CI if the ratio leaves the band in docs/design/economy.md. Outputs markdown report artifact.

    Scope

    • In: Report CLI, CI step, markdown output
    • Out: Loot distribution details (e18-treasure-audit-tool, reused)

    Acceptance criteria

    • AC-1 unit Given fixture content with known totals, when the report runs, then the computed ratio matches the analytic value.
    • AC-2 unit Given a ratio outside the configured band, when run in CI mode, then the process exits non-zero naming the direction (too rich/too poor).
    • AC-3 unit Given a quest with a gold reward effect, when the report runs, then it is included in obtainable gold.

    Waits on

    • mw-e18.10 Build treasure audit and loot distribution report tool open
    • mw-e20.9 Add purchasable services as meaningful gold sinks open
    • mw-e23.2 Implement quest state machine with branching and multi-resolution done
    area:toolsepic:e20milestone:m3
E21BookshopsMagical bookshops are exciting progression and exploration destinations. A data-authored bookshop definition combines regional stock pools, school specialties, deterministic rotation, rare one-off books, secret back-room stock, stolen and forbidden books, book-specific pricing and a bookseller identity that hooks into dialogue and rumours. Any settlement's bookshop can be authored purely as data.0/9 done · 0%

M3 MVP content 9

  • mw-e21.1Generate bookshop stock from regional pools and school specialtiesopenP1M3feature

    Description

    Why

    Bookshops should be genuinely exciting destinations with different inventories per settlement (constitution §4).

    What

    As a designer, I want to author a bookshop as data (region, specialties, pools, rules) on top of the generic shop system so that each settlement's bookshop feels distinct without code.

    BookshopDefinition: shopId (E20), region, specialtySchools[] with weight multipliers, staplePool (always stocked), regionalPool, rarePool, secretPool, rotation rules, bookseller profile id. Stock generation is deterministic from world seed + shop id + rotation period.

    Scope

    • In: bookshop schema, stock generator for staples/regional/specialty, integration with e20 shop buy/sell
    • Out: rotation (e21-rotating-stock)
    • Out: rare/secret (own beads)
    • Out: Briar Glen shop content (world-content group, E24)

    Notes

    The same book may appear in multiple regional pools; uniques are tracked globally so a unique book only ever exists once.

    Acceptance criteria

    • AC-1 unit Given a bookshop with 3 staple books and a regional pool of 10, when stock is generated, then all 3 staples plus N regional books (per rule) are present.
    • AC-2 unit Given specialty Fire with weight 3×, when stock is generated over 1000 seeds, then Fire books are selected ≈3× as often as unweighted books (±10%).
    • AC-3 unit Given the same world seed, shop id and period, when generated twice, then stock is identical.
    • AC-4 integration Given the player buys a book, when the transaction completes via the e20 shop system, then the book is in inventory and removed from stock.
    • AC-5 content Given a bookshop referencing a non-book item in a book pool, when validated, then validation fails.

    Waits on

    • mw-e00.15 Build deterministic fixed-step sim loop, entity store and event bus done
    • mw-e07.1 Define book item schema: spell, language, condition, legality done
    • mw-e20.2 Define merchant schema with identity, specialty and stock rules done
    • mw-e20.4 Implement merchant buy/sell transactions with persistent stock done
    area:simclass:sorcererepic:e21milestone:m3
  • mw-e21.2Rotate bookshop stock on an in-game scheduleblockedP1M3feature

    Description

    Why

    Rotating inventory gives a reason to return to the bookshop after each expedition.

    What

    As a sorcerer, I want the bookshop's non-staple shelves to change every few in-game days so that revisiting is worthwhile.

    Rotation period in in-game days; rotating slots re-roll from pools excluding books the player already owns or knows (configurable); sold-out items restock only at rotation; state persists.

    Scope

    • In: rotation scheduler, exclusion rules, persistence of current stock and last rotation
    • Out: rare/unique books (e21-rare-stock)

    Notes

    Rotation triggers on in-game time crossing the boundary, including while the player is away (lazy evaluation on shop open).

    Acceptance criteria

    • AC-1 unit Given a rotation period of 3 days, when in-game time advances 3 days and the shop opens, then rotating slots re-roll exactly once.
    • AC-2 unit Given in-game time advances 9 days while away, when the shop opens, then stock equals what 3 sequential rotations would produce (deterministic).
    • AC-3 unit Given excludeKnown=true, when rotating, then no book teaching an already-known spell appears in rotating slots.
    • AC-4 unit Given a pool smaller than the slot count after exclusions, when rotating, then remaining slots are filled with lore books or left empty — never duplicates.
    • AC-5 integration Given a save mid-period, when reloaded, then stock and next rotation time are unchanged.

    Waits on

    • mw-e20.5 Restock merchant inventories on world-time ticks deterministically done
    • mw-e21.1 Generate bookshop stock from regional pools and school specialties open
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e30.1 Define versioned save format with section registry and migrations done
    area:simclass:sorcererepic:e21milestone:m3
  • mw-e21.3Stock rare and unique books gated by world state conditionsblockedP1M3feature

    Description

    Why

    Rare books are the thrill of a bookshop: the one copy of a legendary grimoire appearing after you help the bookseller.

    What

    As a sorcerer, I want rare books that appear only under conditions (quest completed, disposition level, day of week, region event) and unique books that exist once in the world so that bookshop visits can surprise me.

    Conditions evaluated against the world state store and dialogue disposition; unique books tracked globally; a rare book may be "reserved" for the player for N days.

    Scope

    • In: condition evaluation, unique registry, reservation window
    • Out: secret back-room stock (e21-secret-stock)

    Notes

    Conditions reuse the shared condition language from E22/E23 if available; otherwise a minimal condition set with a migration note.

    Acceptance criteria

    • AC-1 unit Given a rare book conditioned on world fact "helped_bookseller", when the fact is false, then the book is not stocked; when true, it appears at next shop open.
    • AC-2 unit Given a unique book already looted from a dungeon, when a shop would stock it, then it is skipped.
    • AC-3 unit Given a reserved rare book with a 5-day window, when 5 days pass without purchase, then it leaves stock and returns to the rare pool.
    • AC-4 content Given a rare entry with an unknown condition key, when validated, then validation fails.

    Waits on

    • mw-e21.1 Generate bookshop stock from regional pools and school specialties open
    • mw-e22.2 Create shared typed condition/effect DSL for dialogue, quests, shops done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    area:simclass:sorcererepic:e21milestone:m3
  • mw-e21.5Price books by rarity, condition, legality, region and dispositionblockedP1M3feature

    Description

    Why

    Gold should have meaningful uses (E20); expensive books are aspirational goals.

    What

    As a sorcerer, I want book prices that reflect rarity, condition, forbidden premium, regional demand and my relationship with the bookseller so that saving up for a grimoire matters.

    price = base(rarity, tier) × condition × legality premium × region demand(school) × disposition modifier; sell-back price for books the player sells (booksellers pay more for books in their specialty).

    Scope

    • In: pricing function (pure, data-configured), sell-back pricing, integer rounding rules
    • Out: generic currency/transactions (e20-shop-system)

    Notes

    All arithmetic in integer copper to avoid float drift; 100% coverage as an economy rule.

    Acceptance criteria

    • AC-1 unit Given base 200, damaged ×0.5, forbidden ×1.8, region ×1.0 and neutral disposition, when priced, then the price is 180.
    • AC-2 unit Given friendly disposition −10% modifier, when priced, then the price is reduced by 10% (rounded to nearest copper).
    • AC-3 unit Given the player sells a book in the shop's specialty school, when priced, then sell-back is the specialty rate (e.g. 40% of buy) instead of the default (25%).
    • AC-4 unit Given any combination of modifiers, when priced, then the result is an integer ≥ 1 (property test).
    • AC-5 content Given a pricing config with a negative multiplier, when validated, then validation fails.

    Waits on

    • mw-e20.3 Implement pure price model with disposition and stolen modifiers done
    • mw-e21.1 Generate bookshop stock from regional pools and school specialties open
    area:simclass:sorcererepic:e21milestone:m3
  • mw-e21.7Give booksellers identity profiles, wants and rumour hooksblockedP1M3feature

    Description

    Why

    Merchants have identities (E20); a bookseller who wants a specific tome or gossips about a rare book elsewhere drives exploration.

    What

    As a designer, I want a bookseller profile (personality tags, favoured/disliked schools, wanted books list, rumours about books elsewhere, greeting variants keyed on player class and known spells) so that the dialogue group can make each bookseller memorable.

    Exposes conditions/variables to the dialogue runtime: bookseller.wants(bookId), bookseller.rumour(), player.knowsSchool(school). Wanted books pay a bonus or unlock rare stock.

    Scope

    • In: profile schema, dialogue variables/conditions, wanted-book bonus, rumour selection rule (points to books in other shops or dungeons)
    • Out: actual dialogue writing and NPC characters (world-content/narrative groups)

    Notes

    Rumours reference book ids + a location hint string authored in content; they add entries to the grimoire "rumoured spells" section (e07-grimoire-ui).

    Acceptance criteria

    • AC-1 integration Given a profile with wantedBooks [X], when the player sells book X, then the bonus price applies and world fact "delivered_X" is set.
    • AC-2 integration Given the dialogue runtime queries bookseller.rumour(), when the player already owns the rumoured book, then a different rumour is chosen or none.
    • AC-3 integration Given a rumour is heard, when resolved, then the rumoured spell appears in the grimoire rumoured list with its location hint.
    • AC-4 content Given a profile referencing an unknown book id in wantedBooks, when validated, then validation fails.

    Waits on

    • mw-e21.1 Generate bookshop stock from regional pools and school specialties open
    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    area:simclass:sorcererepic:e21milestone:m3
  • mw-e21.8Browse bookshop shelves with covers, previews and known markersblockedP1M3feature

    Description

    Why

    The bookshop should feel like browsing a magical shop, not a spreadsheet.

    What

    As a sorcerer, I want to browse books by shelf/school with cover art, price, a first-page preview, comprehension estimate and "already known"/"stolen"/"forbidden" markers so that choosing a book is exciting and informed.

    Extends the generic shop UI with book-specific panels; sell tab shows sell-back prices and wanted-book highlights.

    Scope

    • In: bookshop UI panels, preview (reuses reader component), markers, sell tab highlights, keyboard/gamepad navigation
    • Out: generic shop UI (E20)
    • Out: final cover art (asset prompt beads per book)

    Notes

    Placeholder covers: school-coloured leather with title text until art arrives.

    Acceptance criteria

    • AC-1 integration Given a stocked shop, when the UI opens, then books are grouped by school shelf with price and cover (placeholder if no art).
    • AC-2 integration Given a book teaching a known spell, when listed, then it shows an "Already known" marker.
    • AC-3 integration Given the preview action, when used, then the first page renders via the reader component (garbled if language unknown).
    • AC-4 integration Given insufficient gold, when attempting to buy, then the buy button is disabled with a reason and no transaction occurs.
    • AC-5 e2e Given the greybox testbed fixture shop, when a scripted player buys a book, then it appears in inventory and gold decreases by the listed price.

    Waits on

    • mw-e00.23 Build HUD/menu UI layer, component kit, focus nav and UI test harness done
    • mw-e07.9 Read books in a page-turning reader with a study action open
    • mw-e21.5 Price books by rarity, condition, legality, region and disposition open
    area:uiclass:sorcererepic:e21milestone:m3
  • mw-e21.9Provide a bookshop authoring template, validator and fixture shopblockedP1M3task

    Description

    Why

    The world-content group must author the Briar Glen bookshop (and future ones) purely as data.

    What

    Template src/content/bookshops/_template.json with every field documented, a CLI/dev validator (pnpm validate:bookshops) reporting stock simulation over 10 rotations, and a non-Briar-Glen fixture shop ("Testbed Tomes") in the greybox testbed exercising every rule.

    Scope

    • In: template, validator CLI with stock simulation report, fixture shop, authoring notes in docs/design/bookshops.md
    • Out: Briar Glen bookshop content (world-content group, E24)

    Notes

    Report flags pools that can never appear (all conditions unsatisfiable) and uniques duplicated across shops.

    Acceptance criteria

    • AC-1 content Given the template, when validated, then it passes the bookshop schema.
    • AC-2 integration Given the fixture shop, when the validator simulates 10 rotations, then it prints stock per period and exits 0.
    • AC-3 integration Given a shop whose rare book condition references a fact no content ever sets, when validated, then the validator warns "unreachable stock".
    • AC-4 content Given two shops listing the same unique book, when validated, then validation fails.

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e21.1 Generate bookshop stock from regional pools and school specialties open
    • mw-e21.2 Rotate bookshop stock on an in-game schedule open
    • mw-e21.3 Stock rare and unique books gated by world state conditions open
    area:toolsclass:sorcererepic:e21milestone:m3
  • mw-e21.4Reveal secret back-room stock through dialogue, trust or discoveryblockedP2M3feature

    Description

    Why

    Secret inventory rewards curiosity and relationships — the "do you have anything… special?" moment.

    What

    As a sorcerer, I want some bookshops to have hidden stock unlocked by a password, high disposition, a quest, or physically finding the back room so that secrets exist even in shops.

    Secret pool gated by unlock method; can be accessed by a thief breaking in (stolen goods flagged on removal).

    Scope

    • In: secret pool unlock via dialogue action/disposition/world fact, physical back-room container hook
    • Out: dialogue content and passwords (world-content group)

    Notes

    Taking from the back room without buying marks books stolen (e21-stolen-forbidden-stock).

    Acceptance criteria

    • AC-1 integration Given a dialogue action unlockSecretStock, when executed, then the secret pool becomes purchasable for this shop.
    • AC-2 unit Given disposition below the threshold and no other unlock, when the shop opens, then secret items are not listed.
    • AC-3 integration Given the player takes a secret-stock book from the back-room container without buying, when removed, then the book is flagged stolen with owner = the shop.
    • AC-4 unit Given secret stock unlocked, when saved and reloaded, then it remains unlocked.

    Waits on

    • mw-e21.3 Stock rare and unique books gated by world state conditions open
    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    area:simclass:sorcererepic:e21milestone:m3
  • mw-e21.6Handle stolen and forbidden books in bookshop tradeblockedP2M3feature

    Description

    Why

    Some books are stolen or forbidden (constitution §4) — trading them should carry risk and create thief/sorcerer crossover.

    What

    As a sorcerer or thief, I want booksellers to react to stolen and forbidden books — refusing, fencing at a discount, or selling forbidden stock under the counter — so that illicit books have a market with consequences.

    Bookseller profile flags: buysStolen, sellsForbidden, reportsContraband. Selling a book stolen from this very shop triggers recognition. Forbidden stock is only shown when no lawful witnesses are nearby.

    Scope

    • In: stolen-owner tracking in trade, bookseller legality flags, witness check for forbidden sales, recognition consequence
    • Out: guard response behaviour (E11)
    • Out: forbidden reading consequences (e07-forbidden-books)

    Notes

    Stolen flag comes from the E17/E10 ownership model — Related: thief group stealing/ownership bead.

    Acceptance criteria

    • AC-1 unit Given a bookseller with buysStolen=false, when offered a stolen book, then the sale is refused with reason "stolen".
    • AC-2 unit Given buysStolen=true, when buying a stolen book, then price is the fence rate (default 50% of normal sell-back).
    • AC-3 integration Given the player tries to sell a book stolen from this same shop, when offered, then the bookseller recognises it: disposition drops and a world fact "caught_selling_back" is recorded.
    • AC-4 integration Given sellsForbidden=true and a lawful NPC within perception range, when the shop opens, then forbidden stock is hidden until the witness leaves.
    • AC-5 integration Given reportsContraband=true, when the player sells a forbidden book, then a ContrabandReported event fires.

    Waits on

    • mw-e07.6 Give forbidden books social risk and whispering side effects open
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e18.6 Track item ownership and flag stolen items on witnessed theft open
    • mw-e21.5 Price books by rarity, condition, legality, region and disposition open
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    area:simclass:sorcererepic:e21milestone:m3
E22NPC & Dialogue SystemCharacters support conversations with conditions and effects, disposition, meaningful choices, class-specific options, persuasion (Divinity: Original Sin 2 style), rumors that lead to places, and lightweight state tracking. Text only for MVP (no voice), with subtitle/text-size accessibility hooks. Dialogue is authored as validated data, never bespoke code.13/19 done · 68%

M2 Class fantasies 4

  • mw-e22.1Turn witnessed crimes into settlement bounties with pay/jail/fleeblockedP1M2feature

    Description

    Why

    Thief play needs stakes: getting caught should create a new situation (a fine, a night in the Watch House cell, a chase out of town), not an instant reload. Theft, fence recognition, shoplifting, disguises and failure narratives all emit or expect crime consequences, but no item owned bounty or guard outcomes.

    What

    As a thief, I want crimes that are actually witnessed to raise a bounty in that settlement and lead to a confrontation I can pay, serve or flee so that failure changes the story instead of ending it.

    • Crime types (data): theft (from crime.theft / crime.theft.recognized), trespass (entering a restricted trigger volume owned by a settlement/faction while seen, after one warning bark), assault (damage to a non-hostile NPC via damage events), disguise exposure (crime.disguise.exposed from e10-disguises), murder. Each has severity, report delay and consequence effects written in the condition/effect DSL.
    • Witnesses: a crime counts only if a witness perceives it (e11 perception). A witness must *report* — survive and stay conscious for the report delay or reach a guard — before bounty is added. Silencing a witness is a (risky) choice.
    • Bounty & reputation: bounty per settlement stored as world facts (crime.bounty.<settlement>), crime records with witness and game time; disposition/faction effects via e22-disposition.
    • Guard response hook: when a guard of that settlement perceives a player whose bounty ≥ threshold, emit one crime.confront{guard, settlement, bounty}; e11 behaviour and dialogue consume it.
    • Outcomes that continue the story: *pay* (gold ≥ bounty → cleared; stolen items confiscated), *jail* (advanceTime by sentence, stolen items to the settlement evidence container, player.jailed.count++, player placed at the jail spawn — world content may offer an escape), *resist/flee* (settlement guards go to Combat toward the player, bounty += resist severity, DSL-gated services refuse while bounty > 0). A clearBounty DSL effect lets quests pardon.

    Scope

    • In: Crime definitions schema, witness/report pipeline, bounty facts per settlement, trespass and assault detection, confront event, pay/jail/resist outcome effects, save via world facts, debug commands
    • Out: Theft detection and stolen flag — see e18-ownership-stolen
    • Out: Guard movement/arrest behaviour and barks — mw-e11 (consume crime.confront)
    • Out: Jail geometry and escape route — world content (Related: E24/E26)
    • Out: Failure-narrative text — see e39-failure-narratives

    Notes

    Canon (docs/narrative/story-bible.md): Briar Glen's Watch House has a one-cell jail; the failure-narrative fact is player.jailed.count. The story's "bounty: 500 crowns, raised to 800" is the missing-persons reward on the notice board, not a crime bounty — keep the terms distinct in UI text ("fine"/"wanted" vs "reward").

    Integration note: Emits crime.confront; guard arrest/confront behaviour in E11 consumes it (E11 guard behaviour items should subscribe when this lands).

    Acceptance criteria

    • AC-1 unit Given a crime.theft event with one witness who reports, when processed, then the bounty for that witness's settlement increases by the theft severity scaled by item value tier and one crime record (type, witness, game time) is stored as a fact.
    • AC-2 unit Given a witnessed theft where the witness is knocked out before the report delay (default 20 s) expires, when the delay passes, then no bounty is added (edge: silenced witness).
    • AC-3 unit Given a player with bounty ≥ the confront threshold perceived by a guard of that settlement, when perception fires repeatedly, then exactly one crime.confront event is emitted per encounter and the pay option is disabled when gold < bounty.
    • AC-4 unit Given the jail outcome with a 2-day sentence, when applied, then the world clock advances 2 days, stolen items move to the evidence container, the bounty clears, player.jailed.count increments and the player is placed at the jail spawn without a reload.
    • AC-5 unit Given the resist outcome, when chosen, then every guard of that settlement within alert radius enters the Combat alert state toward the player and the bounty increases by the resist severity.
    • AC-6 unit Given crimes in two settlements, when one bounty is paid, then the other settlement's bounty is unchanged.
    • AC-7 content Given the crime definitions, when validated, then every crime type has severity, report delay and DSL-valid consequences, and an unknown settlement id fails validation naming the file.

    Waits on

    • mw-e03.21 Wire trigger volumes and mechanisms with data-defined signal graphs done
    • mw-e04.1 Deterministic damage model: damage types, resistances, poise, death done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e18.6 Track item ownership and flag stolen items on witnessed theft open
    • mw-e22.2 Create shared typed condition/effect DSL for dialogue, quests, shops done
    • mw-e22.4 Track NPC disposition with bands, event modifiers and factions done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    area:simclass:thiefepic:e22milestone:m2size:m
  • mw-e22.14Add dialogue preview runner and debug console commandsopenP2M2task

    Description

    Why

    Fast content creation (constitution §10): writers need to play a conversation in seconds with any state.

    What

    CLI pnpm dialogue:play <id> --class thief --fact x=true --item y running the real runtime in the terminal; pnpm dialogue:graph <id> exporting Mermaid for docs/review. Debug console: dlg.start <id>, disp.set <npc> <n>, fact.set, rumor.list.

    Scope

    • In: Terminal runner, Mermaid export, console commands
    • Out: A visual dialogue editor (post-MVP)

    Acceptance criteria

    • AC-1 unit Given a fixture dialogue and --class thief, when run with scripted choice input, then the transcript matches the snapshot including the thief option.
    • AC-2 unit Given dialogue:graph, when run on a fixture, then the output is valid Mermaid containing every node id.
    • AC-3 unit Given disp.set unknown-npc 50, when executed, then the console reports an unknown NPC and changes nothing.

    Waits on

    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e22milestone:m2
  • mw-e22.17Dialogue validator: cross-dialogue jump loops, rumor ids, check nodes with no reachable successopenP3M2task

    Description

    Follow-ups from PR #420 (mw-e22.8): analyse loops that pass through jump nodes across dialogues; check rumor ids once a rumor content type exists (mw-e22.11); flag a check node whose success score is unreachable given the persuasion table maxima.

    area:simepic:e22milestone:m2
  • mw-e22.18Conversation robustness: body-height talk focus, endConversing on NPC death/despawnopenP3M2task

    Description

    From PR #421: Talk focus uses the creature's feet (use a body-height anchor); call endConversing when an NPC dies or despawns mid-talk from the owning modules, not only from the controller's per-step check.

    area:simepic:e22milestone:m2

M3 MVP content 2

  • mw-e22.12Let players give gifts and bribes that shift dispositionblockedP1M3feature

    Description

    Why

    Giving the right thing to the right person is a classic QfG-style solution and a gold/item sink.

    What

    As a player, I want to offer items or gold to characters, with their tastes deciding the effect, so that knowing people pays off.

    NPC likes/dislikes item tags; a generic "Offer…" dialogue option opens an item picker; effect = disposition delta by taste × value tier; bribes can satisfy dialogue conditions (bribed fact). Offering a stolen item to its owner returns it (clears flag) and triggers the owner's stolenReturned line.

    Scope

    • In: Taste data, offer flow, disposition effect, bribe facts, stolen-return path
    • Out: Creature feeding/befriending (mw-e14)

    Integration note: Promoted to P1 — befriending/helping creatures (Brother Horn, the goblins, Clatter) is an MVP constitution pillar and depends on this.

    Acceptance criteria

    • AC-1 unit Given an NPC who likes flower and a flower offered, when resolved, then disposition increases by the liked amount for its value tier.
    • AC-2 unit Given a disliked item offered, when resolved, then disposition decreases and the item is returned to the player.
    • AC-3 unit Given a stolen item offered to its owner, when resolved, then the item is removed, the stolen flag cleared and the owner's stolenReturned node is entered.
    • AC-4 unit Given a quest item offered to a non-target NPC, when attempted, then the offer is refused and the item stays.

    Waits on

    • mw-e18.6 Track item ownership and flag stolen items on witnessed theft open
    • mw-e22.4 Track NPC disposition with bands, event modifiers and factions done
    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    area:simepic:e22milestone:m3
  • mw-e22.13Show ambient NPC barks as accessible positional subtitlesopenP2M3feature

    Description

    Why

    Overheard lines make the world feel alive and deliver rumors and stealth feedback; without voice they must be readable subtitles.

    What

    As a player, I want to read what nearby characters say (guards muttering, merchants calling out) with speaker names and direction so that I overhear the world.

    Bark runtime: condition-filtered lines triggered by events (alert state changes, proximity, time), priority + cooldown + anti-repetition. Subtitle display: speaker name, direction indicator for off-screen speakers, max 3 concurrent, respects text size, background opacity and "show speaker names" settings; can be toggled.

    Scope

    • In: Bark schema + selector, subtitle HUD, settings hooks
    • Out: Merchant bark content (e20-merchant-barks)
    • Out: AI state bark triggers wiring (mw-e11 emits events)

    Notes

    UI assets assumed: subtitle background plate, off-screen direction chevron.

    Acceptance criteria

    • AC-1 unit Given 5 barks triggered in the same second, when displayed, then at most 3 are visible, ordered by priority.
    • AC-2 unit Given a bark line used once with cooldown 30 s, when triggered again at 10 s, then a different line or no line is chosen.
    • AC-3 integration Given a speaker behind the camera, when a bark shows, then a direction indicator points toward the speaker.
    • AC-4 integration Given subtitles disabled for barks in settings, when a bark triggers, then nothing is shown but the bark event is still emitted for telemetry/tests.

    Waits on

    • mw-e00.23 Build HUD/menu UI layer, component kit, focus nav and UI test harness done
    • mw-e22.2 Create shared typed condition/effect DSL for dialogue, quests, shops done
    • mw-e31.1 Create typed settings store and options menu skeleton done
    area:uiepic:e22milestone:m3
E23Quest FrameworkQuests support branching objectives and multiple resolutions (including non-combat) authored as data without bespoke scripting. Quest state lives in the world-state store and persists; failure transitions continue the story instead of dead-ending it. Players track progress in an in-character journal.6/13 done · 46%

M2 Class fantasies 6

  • mw-e23.4Make quest failures continue the story instead of dead-endingopenP1M2feature

    Description

    Why

    Failure creates stories (constitution §2): if the key NPC dies or the thief is caught, the world should adapt.

    What

    As a player, I want the story to continue when I fail — a new lead, a harder path, a changed ending — so that I rarely feel the need to reload.

    Failure continuation types: start a successor quest, move to an alternate stage, or resolve with a "bittersweet" resolution. Common auto-failure triggers: essential NPC removed, item destroyed, time window elapsed. Runtime guarantees a continuation is applied atomically with the failure. Journal records the failure narratively.

    Scope

    • In: Continuation application, built-in failure triggers (npc removed, item destroyed, deadline), journal hook
    • Out: Timed world events beyond quest deadlines (mw-e27)

    Acceptance criteria

    • AC-1 unit Given a quest whose giver dies with continuation startQuest(avenge-giver), when the giver is removed, then the original fails and the successor starts in the same tick.
    • AC-2 unit Given a quest item destroyed (e.g. burned via e03), when item.destroyed fires for it, then the configured failure applies.
    • AC-3 unit Given a deadline of 3 in-game days, when day 4 begins without resolution, then the failure fires once.
    • AC-4 unit Given a failure continuation referencing a successor that fails to start (conditions false), when applied, then the runtime falls back to the quest's defaultContinuation and logs a content error.

    Waits on

    • mw-e23.2 Implement quest state machine with branching and multi-resolution done
    • mw-e23.3 Bind quest objective kinds to sim events done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    area:simepic:e23milestone:m2
  • mw-e23.5Validate quests are resolvable and failures have continuationsblockedP1M2task

    Description

    Why

    An unresolvable quest is the worst kind of bug; CI must prove every quest can be finished and every failure continues.

    What

    Static + symbolic validator: all references resolve (items, npcs, facts, areas, dialogues); every resolution's conditions are satisfiable given the set of known fact/item producers (placements, loot, shops, dialogue effects, other quests); every required item is obtainable somewhere; at least one non-combat resolution exists unless combatOnly: true with justification; every failure has a continuation that is itself valid; no quest start depends on its own resolution (cycle).

    Scope

    • In: Producer index across content, satisfiability check, cycle detection, CLI + CI hook
    • Out: Runtime simulation of full playthroughs (e23-quest-debug-tools)

    Acceptance criteria

    • AC-1 unit Given a resolution requiring item x that no placement, loot table, shop or effect produces, when validated, then validation fails naming the quest, resolution and item.
    • AC-2 unit Given a quest whose only resolution requires entityState(... dead) and no combatOnly flag, when validated, then a non-combat warning is reported.
    • AC-3 unit Given quest A starting on B resolved and B starting on A resolved, when validated, then a cycle error is reported.
    • AC-4 unit Given a fact required by a resolution with no producer, when validated, then validation fails naming the fact.
    • AC-5 content Given all repository quests, when CI runs the validator, then it exits 0.

    Waits on

    • mw-e18.2 Validate loot tables: references, uniques, cycles, weights done
    • mw-e22.8 Validate dialogues: reachability, exits, references, text limits done
    • mw-e23.1 Define quest authoring format with objectives and resolutions done
    • mw-e23.4 Make quest failures continue the story instead of dead-ending open
    area:contentepic:e23milestone:m2
  • mw-e23.7Build grey-box reference quest with three resolutions and a failureblockedP1M2feature

    Description

    Why

    An end-to-end fixture proves dialogue, quests, inventory, loot and AI integrate, and gives world-content authors a working template.

    What

    As a designer, I want a small grey-box quest demonstrating the full framework so that I can copy it and so CI proves the systems work together.

    Testbed-only content (not Briar Glen): an NPC asks the player to recover a stolen item from a guarded room. Resolutions: combat (remove guard), stealth (take item unseen via e18 ownership), diplomacy (persuasion check with the guard), plus a failure (item destroyed → successor quest). Uses a rumor, a class-gated option and a loot container.

    Scope

    • In: Fixture content under content/fixtures/, Playwright e2e scripts for each path
    • Out: Real game quests (world-content group)

    Acceptance criteria

    • AC-1 e2e Given the greybox reference quest, when the combat path is played via scripted input, then the quest resolves as combat and the journal shows the resolution entry.
    • AC-2 e2e Given the reference quest, when the stealth path is played (item taken unseen), then it resolves as stealth and no crime event was emitted.
    • AC-3 e2e Given the reference quest, when the diplomacy path passes the persuasion check, then it resolves as diplomacy without the guard entering Combat state.
    • AC-4 e2e Given the reference quest, when the item is destroyed by fire, then the quest fails and the successor quest becomes active.
    • AC-5 content Given the fixture, when the quest and dialogue validators run, then both pass.

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e18.6 Track item ownership and flag stolen items on witnessed theft open
    • mw-e22.7 Add deterministic persuasion checks with fail branches done
    • mw-e22.9 Start conversations with NPCs in-world and handle interruptions done
    • mw-e23.4 Make quest failures continue the story instead of dead-ending open
    • mw-e23.6 Build in-character journal for quests, rumors and notes done
    area:qaclass:allepic:e23milestone:m2
  • mw-e23.10Write dialogue and quest authoring guide with templatesblockedP1M2task

    Description

    Why

    The world-content group will author Briar Glen NPCs and quests; a clear guide and templates make that fast and consistent.

    What

    docs/content/dialogue-and-quests.md: format reference, DSL condition/effect catalogue (generated from the registry), patterns (multiple resolutions, class-gated options, persuasion with fail branches, rumors that lead to places, failure continuations), humour/tone guidance aligned to the tone row in the contract, validator error glossary, copyable templates in content/_templates/.

    Scope

    • In: Guide, generated DSL catalogue section, templates for NPC dialogue, merchant, trainer, quest, rumor
    • Out: Story bible (e39-story-bible)

    Acceptance criteria

    • AC-1 unit Given the DSL registry, when the catalogue generator runs, then every registered condition and effect kind appears in the guide section (test compares lists).
    • AC-2 content Given the templates in content/_templates/, when validated, then each passes its schema.
    • AC-3 manual Given the guide, when reviewed, then it includes a worked example of a quest with combat, stealth and diplomacy resolutions and a failure continuation.

    Waits on

    • mw-e19.8 Let trainers teach knight techniques through dialogue services open
    • mw-e20.2 Define merchant schema with identity, specialty and stock rules done
    • mw-e22.11 Add rumor system that points players to places and secrets done
    • mw-e23.7 Build grey-box reference quest with three resolutions and a failure open
    area:designepic:e23milestone:m2
  • mw-e23.8Add quest debug commands and "why is this stuck" explaineropenP2M2task

    Description

    Why

    Diagnosing stuck quests must be fast for designers and playtest bug reports.

    What

    Debug console: quest.list, quest.start <id>, quest.objective <id> <obj> complete, quest.resolve <id> <res>, quest.why <id> (prints each resolution/objective condition with describe() and current truth values). CLI pnpm quest:sim <id> --script path to run a quest against scripted fact/item changes headlessly.

    Scope

    • In: Console commands, explainer, headless quest simulator
    • Out: Visual quest editor (post-MVP)

    Acceptance criteria

    • AC-1 unit Given an active quest with an unmet resolution condition, when quest.why runs, then output lists that condition as false with its describe() text.
    • AC-2 unit Given quest.resolve q1 bogus, when executed, then the console lists valid resolution ids and changes nothing.
    • AC-3 unit Given a scripted sim of the reference quest stealth path, when run headlessly, then it ends with resolution stealth.

    Waits on

    • mw-e23.2 Implement quest state machine with branching and multi-resolution done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e23milestone:m2
  • mw-e23.13Remember quest-relevant events from before a quest startsopenP2M2task

    Description

    Follow-up to mw-e23.12 (PR #446): seen-facts are only written for active quests, so side quests that start later (e.g. kill the chief before being asked) never credit earlier deeds. Consider durable world facts (entity state, area visits) for ids referenced by any quest objective so a newly started quest catches up. Mind the e2e golden save hashes and the new-game-facts rule.

    area:simepic:e23milestone:m2

M3 MVP content 1

  • mw-e23.9Add optional quest wayfinding hints as an accessibility settingopenP2M3feature

    Description

    Why

    Default play favours discovery (no waypoints), but some players need help navigating; an opt-in hint respects both.

    What

    As a player who gets lost, I want to enable subtle hints toward my pinned objective so that I can keep playing without a guide.

    Objectives may author hintTarget (entity/area). Setting "Quest hints": Off (default) / Subtle (compass nudge when facing direction) / Clear (on-screen marker). Hints never reveal hidden/secret objectives.

    Scope

    • In: Hint target data, three-level setting, compass nudge + marker rendering hook
    • Out: Full world map (not planned for MVP)

    Notes

    UI assets assumed: compass nudge glyph, objective marker icon.

    Acceptance criteria

    • AC-1 unit Given setting Off, when a pinned objective has a hintTarget, then no hint renders.
    • AC-2 integration Given setting Clear, when the target is on-screen, then a marker renders at its projected position; off-screen, an edge arrow renders.
    • AC-3 unit Given a hidden objective with a hintTarget, when any setting is active, then no hint renders for it.

    Waits on

    • mw-e23.6 Build in-character journal for quests, rumors and notes done
    • mw-e31.1 Create typed settings store and options menu skeleton done
    area:uiepic:e23milestone:m3
E24Briar GlenBriar Glen is a dense, lived-in settlement: every named building from the story bible exists and is enterable, merchants and the Lamplit Stacks have authored stock, named NPCs keep day/night schedules, rumours point at real places, rooftops and secrets reward thieves and the curious, and the first-night sleepwalk plays out through its streets.4/22 done · 18%

M3 MVP content 17

  • mw-e24.13Place Briar Glen's NPCs on day/night schedulesin progressP1M3feature

    Description

    Why

    A lived-in town: people open shops, go to the inn, sleep — and some walk in their sleep.

    What

    As a player, I want townsfolk to keep daily routines so that the town feels alive and so that timing matters for thieves.

    Schedule data (consumer of e27-world-clock, which leaves NPC routines to consumers) per named NPC (Mirela, Hale, Vane, Dot, Hollis, Juniper, Oswin, Duggan pre-capture) and 8–12 generic townsfolk: windows (time range → location/activity) built on e11-patrol-routines posts and the world clock. Shop hours bound to merchant hours. Hale sleepwalks toward the Bell Line stones on unlocked nights (Captain's Boots).

    Scope

    • In: Schedule schema (thin layer on patrol routines + clock windows), schedule data for all town NPCs, shop hours
    • Out: Off-screen catch-up engine (Related: e27-offscreen-catchup, P2 — not needed: positions are resolved directly from the schedule at load)
    • Out: Dialogue (E39)

    Notes

    The clock and scheduler are e27-world-clock; this item adds only the thin schedule-window schema and all Briar Glen routine data.

    Acceptance criteria

    • AC-1 unit Given Mirela's schedule and time 08:00, when resolved, then her target is the Stacks counter; at 22:00, her upstairs room.
    • AC-2 integration Given the player enters town at 14:00 after being away, when loaded, then every NPC is placed at their scheduled location for 14:00.
    • AC-3 integration Given an NPC is in dialogue when their window ends, when the dialogue closes, then they walk to the next location (edge: never teleport in view).
    • AC-4 perf Given all scheduled NPCs present at Market Green midday, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).

    Waits on

    • mw-8551 Walk scheduled NPCs between locations instead of popping at window edges done
    • mw-8stk Measure Market Green midday frame time with all scheduled townsfolk (mw-e24.13 AC-4) open
    • mw-e11.9 Patrol routes, guard posts and idle routines authored as data done
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    area:contentepic:e24milestone:m3
  • mw-e24.3Place systemic objects and hiding spots throughout Briar GlenblockedP1M3feature

    Description

    Why

    The town must be a toybox too: lanterns to snuff, hay to hide in, troughs to freeze, washing lines to burn.

    What

    As a player, I want the town full of things that react to fire, water, light and force so that I can improvise.

    Lamp posts and window lights (extinguishable, relit by the lamplighter on schedule), water troughs, hay carts and barrels (hiding places), washing lines (flammable ropes), stacked crates, market stalls (breakable), shadowed alleys, loose cobbles for throwing.

    Scope

    • In: Prop placement with material presets, hiding-place volumes, light sources, throwables
    • Out: Interiors' props (per-building items)

    Notes

    Fire in town is a real risk: flammable density near the Ox and stalls must be capped so fires burn out, not destroy the town (bible tone).

    Acceptance criteria

    • AC-1 content Given the town scene, when validated, then every placed prop uses an e03 material preset and no ad-hoc properties.
    • AC-2 integration Given a fire started at a market stall, when simulated 120 s, then it burns out without spreading to building shells flagged non-flammable (edge).
    • AC-3 integration Given a hay cart hiding place at night, when a guard passes at 3 m, then the hidden player remains undetected.

    Waits on

    • mw-e03.13 Support hanging objects on ropes that burn, cut or snap done
    • mw-e03.16 Extinguish and relight torches, candles and braziers systemically done
    • mw-e03.2 Provide data-defined material presets for common world objects done
    • mw-e09.8 Hiding places: wardrobes, barrels, tall grass and shadowed alcoves open
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    area:contentepic:e24milestone:m3
  • mw-e24.4Build the Sleeping Ox inn: common room, rooms, cellar and restblockedP1M3feature

    Description

    Why

    The inn is the story's first night, the rumour hub and the Briarwood wake point.

    What

    As a player, I want a warm inn where I can rest, hear rumours and sell hot goods so that town has a home base.

    Interior: common room with hearth (Dot's Ember request can fail and scorch), bar, lending shelf, stairs to the player's room (the first-night window), Dot's back room (thief), cellar with fencing stock and the goblin kettle for Framed in Brass. Rest via an inn-kind rest point. Respawn rule: Briarwood deaths wake here.

    Scope

    • In: Interior scene, inn-kind rest point (e27-rest-points) paid via e20-services, lending shelf books, cellar with fence merchant data, kettle item, respawn rule entry
    • Out: Dot's dialogue (e39-dialogue-town-core)
    • Out: Fence runtime (e20-fences-stolen-goods)

    Notes

    Lending shelf books from e39-books-lore (A Traveller's Account of the Glen, The Ox Beneath the Hill copy).

    Acceptance criteria

    • AC-1 integration Given the player rents the room, when resting until dawn, then rest.completed fires, the clock reads 06:00 and rest-reset facts reset.
    • AC-2 integration Given the player dies in the Briarwood, when the respawn rule resolves, then the player wakes in the Ox room.
    • AC-3 content Given Dot's fence merchant, when validated, then isFence is true and the goblin kettle is present in the cellar.
    • AC-4 integration Given a botched Ember at the hearth, when fire spreads to the rug, then it is extinguishable and sets fact ox.scorched which Dot remarks on (edge).

    Waits on

    • mw-e01.12 Wake in context after death instead of reloading open
    • mw-e20.6 Support fences and merchant reactions to stolen goods open
    • mw-e20.9 Add purchasable services as meaningful gold sinks open
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e27.13 Rest at inns, campfires and shrines to reset facts and pass time open
    area:contentepic:e24milestone:m3
  • mw-e24.5Author the Lamplit Stacks bookshop on the e21 authoring templateblockedP1M3feature

    Description

    Why

    The constitution makes bookshops "genuinely exciting destinations"; this is the MVP's one excellent bookshop.

    What

    As a sorcerer, I want a crooked three-storey bookshop with rotating stock, a restricted shelf and a back room so that visiting Mirela is a highlight.

    src/content/bookshops/lamplit-stacks.json from the e21 template: regional pool (licensed schools), rotating shelf, rare conditional stock (e.g. restored after dungeon finds), buyback counter, The Vesperine Hours (sale or loan). Interior: three floors, red shelf, reading nook, Mortimer's rare shelf, the curtain and back-room door (content behind them is e24-stacks-back-room).

    Scope

    • In: Bookshop data (public stock), interior scene, shelf placements, Vesperine Hours item placement
    • Out: Restricted shelf and back room (e24-stacks-back-room)
    • Out: Bookshop runtime/UI (E21)
    • Out: Mortimer behaviour (e14-mortimer)
    • Out: Spellbook flavour text (e39-spellbook-flavor)

    Notes

    Follow the bible's legality: Illusion/Conjuration/Gravity/Shadow restricted; Necromancy/Time/Somnomancy forbidden.

    Acceptance criteria

    • AC-1 content Given lamplit-stacks.json, when pnpm validate:bookshops runs, then it passes and the 10-rotation simulation shows every pooled book appearing at least once.
    • AC-2 integration Given the shop at closing hour, when the player is inside, then Mirela asks them to leave and the stock UI closes (edge).
    • AC-3 integration Given a book sold to the buyback counter, when the stock rotates, then it may appear in public stock per the e21 rules.
    • AC-4 content Given the shop, when validated, then The Vesperine Hours is obtainable by purchase or loan on day 1.

    Waits on

    • mw-e21.3 Stock rare and unique books gated by world state conditions open
    • mw-e21.7 Give booksellers identity profiles, wants and rumour hooks open
    • mw-e21.9 Provide a bookshop authoring template, validator and fixture shop open
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    area:contentclass:sorcererepic:e24milestone:m3
  • mw-e24.7Build the Forge, Fletchery & Simples and Bakery with merchant stockblockedP1M3feature

    Description

    Why

    Merchants have identities, inventories and specialties; each shop should serve a class fantasy.

    What

    As a player, I want Oswin's forge, Juniper's fletchery and Hollis's bakery to feel like places with people so that shopping is part of the world.

    Interiors and merchant data: Brand's Forge (weapons, armour repair service, lockpicks "for miners", Ember-heats-forge discount, bell mould for recasting the tongue), Fenn's Fletchery & Simples (arrows, trick-arrow schematics, snares, salves, wakeful tea vs sleep-draught), Pell's Bakery (bread — also feed for the sleepers, Pell family Bible in the back room).

    Scope

    • In: Three interiors, three merchant files, services, key story items placement
    • Out: Dialogue (e39-dialogue-town-secondary)
    • Out: Economy balancing (e20-economy-balance-tool)

    Notes

    Juniper sells poisons to thieves only after a favour (condition on fact).

    Acceptance criteria

    • AC-1 content Given the three merchant files, when validated, then they pass e20 schema checks and price bands.
    • AC-2 integration Given the sorcerer casts any heat stimulus on the forge hearth, when Oswin is next spoken to, then a discount effect applies once.
    • AC-3 integration Given Juniper's stock, when the player has no favour fact, then poisons are hidden (edge); with it, they appear.
    • AC-4 integration Given the tongue is lost or destroyed, when asked, then Oswin offers the recast service using the bell mould.

    Waits on

    • mw-e20.2 Define merchant schema with identity, specialty and stock rules done
    • mw-e20.4 Implement merchant buy/sell transactions with persistent stock done
    • mw-e20.9 Add purchasable services as meaningful gold sinks open
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    area:contentepic:e24milestone:m3
  • mw-e24.8Build the Watch House and a jail cell whose drain leads outblockedP1M3feature

    Description

    Why

    "Caught stealing in town — Hale jails you. The cell has a loose stone." Jail is a secret entrance, not a game over.

    What

    As a thief, I want getting caught to put me in a cell with a way out so that failure opens a new route.

    Watch House interior (Hale's desk with the missing-persons list and footprint map, boots by the door), one cell. Jail outcome of e22-crime-bounty places the player at this cell's jail spawn and confiscates stolen goods into this settlement's evidence chest. Loose stone (interactable, or found by searching) → Vesperine drain → cistern node.

    Scope

    • In: Interior, cell with jail spawn, settlement evidence container, drain passage to cistern
    • Out: Crime, bounty and jail outcome logic (e22-crime-bounty)
    • Out: Guard arrest AI (E11)
    • Out: Cistern (e24-glen-well-cistern)

    Notes

    Snig can be jailed here too; busting him out uses the same drain.

    Acceptance criteria

    • AC-1 integration Given the e22-crime-bounty jail outcome for Briar Glen, when applied, then the player stands in this cell and stolen items are in the Watch House evidence chest.
    • AC-2 integration Given the player in the cell, when the loose stone is interacted with, then the drain opens and leads to the cistern node.
    • AC-3 integration Given the player escapes, when Hale next sees them, then fact jail.escaped is set and his greeting changes (edge: no instant re-arrest loop).

    Waits on

    • mw-e18.3 Add lootable containers that persist their contents done
    • mw-e22.1 Turn witnessed crimes into settlement bounties with pay/jail/flee open
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    area:contentclass:thiefepic:e24milestone:m3
  • mw-e24.9Build Vane House as an infiltration target with strongbox and ledgerblockedP1M3feature

    Description

    Why

    The thief can have proof of Vane's lie before Act II; the house is the town's infiltration set piece.

    What

    As a thief, I want to break into the mine owner's house by rooftop or cellar so that I can steal the horn-coin sample and his secrets.

    Two-storey house on the rise: servants and a house guard on schedules, study with the strongbox (horn-coin samples, letter from "Mr. S—"), Vane's mine key (for the mine gate), dogs-free garden with hedges, balcony window, coal-chute cellar. Day: Vane receives visitors; night: guard patrol.

    Scope

    • In: Interior and grounds, patrols, strongbox and contents, mine key placement, three entry points
    • Out: Vane dialogue (e39-dialogue-town-secondary)
    • Out: Strongbox lock mechanics (e10-lockpicking)

    Notes

    Entry points: balcony window (climb/levitate/rope arrow), coal chute (thief/any), front door (persuade, or bribe the servant).

    Acceptance criteria

    • AC-1 integration Given night patrols, when the stealth scenario replay enters via the balcony, then the strongbox can be opened with no guard reaching Alerted.
    • AC-2 content Given the house, when validated, then at least three entry points are declared as obstacle routes for >= 3 classes.
    • AC-3 integration Given the player is detected, when the guard raises the alarm, then a crime is reported via e22-crime-bounty and the jail outcome remains available (edge: failure lands in jail).
    • AC-4 integration Given the mine key is taken, when the mine gate is approached, then the key opens the padlock via the keyring.

    Waits on

    • mw-e10.7 Pick locks as an in-world, interruptible, noisy action open
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e11.9 Patrol routes, guard posts and idle routines authored as data done
    • mw-e17.5 Auto-use keys from the keyring on matching locks done
    • mw-e22.1 Turn witnessed crimes into settlement bounties with pay/jail/flee open
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    area:contentclass:thiefepic:e24milestone:m3
  • mw-e24.10Hide the cistern route under the Glen WellopenP1M3feature

    Description

    Why

    "Wells can conceal tunnels." The rumour "drop a stone and you hear it land twice" should pay off.

    What

    As a curious player, I want to find a loose ladder rung in the Glen Well that leads to an old cistern so that the town connects to the priory.

    Well shaft with a loose rung (climb down, or drop down and take fall damage), echo behaviour (a dropped object produces two landing sounds via a ledge), flooded cistern chambers (wade, freeze to cross, or swim), Snig's goblin tunnels branch, jail drain junction, and a gate to the priory end (E26).

    Scope

    • In: Well and cistern scene, echo ledge, water volumes, junctions to jail drain, goblin tunnels and priory
    • Out: Priory side of the cistern (e26-priory-greybox)

    Notes

    Sets fact well.tunnel.found (resolves rumour 4).

    Acceptance criteria

    • AC-1 integration Given any object dropped into the well, when it lands, then two landing noise events fire about 0.4 s apart.
    • AC-2 integration Given the player reaches the cistern, when entered, then well.tunnel.found is set and rumour 4 resolves.
    • AC-3 integration Given the player drops down the shaft instead of climbing, when landing, then fall damage applies but never kills from full health (edge).
    • AC-4 integration Given the flooded chamber, when frozen by any cold stimulus, then it becomes walkable ice.

    Waits on

    • mw-e02.14 Wade and swim in water and slide on frozen surfaces done
    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e04.19 Fall, crush and hazard damage through the damage model done
    • mw-e22.11 Add rumor system that points players to places and secrets done
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    area:contentepic:e24milestone:m3
  • mw-e24.12Build a rooftop network across Briar Glen for thieves and climbersopenP1M3feature

    Description

    Why

    Town infiltration and verticality: the thief should be able to cross town without touching the street.

    What

    As a thief, I want climbable drainpipes, ivy and connected roofs so that I can move above the watch.

    Roof paths linking the Ox, the Stacks (third-floor window), the Forge chimney, the Watch House, and the rise to Vane House. Gaps jumpable, some requiring a plank (movable) or rope arrow. Archer overlooks; sorcerer Levitate/Blink shortcuts.

    Scope

    • In: Climbable surfaces, roof walk surfaces with acoustic tags, window entries, gap props
    • Out: Climbing mechanics (e10-climbing, e02-climb-surfaces)

    Notes

    Roof tiles are noisy (acoustic tag loose-tile) in places — a deliberate risk.

    Acceptance criteria

    • AC-1 integration Given the rooftop replay, when a thief crosses from the Ox to Vane House, then they never touch street navmesh.
    • AC-2 integration Given a loose-tile roof section, when walked at run speed, then footstep noise loudness exceeds that of slates by >= 50%.
    • AC-3 integration Given a player falls from a roof, when landing on the street, then fall damage is applied and the watch reacts only if in sight (edge).

    Waits on

    • mw-e02.12 Mantle onto and grab ledges detected from world geometry done
    • mw-e09.4 Tag surfaces with acoustic materials that change footstep noise done
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    area:contentclass:thiefepic:e24milestone:m3
  • mw-e24.14Stage the first-night sleepwalk from the Ox to the mine gateblockedP1M3feature

    Description

    Why

    The first night is the tutorial and the hook: follow Tansy, fail gracefully, see the horned shadow.

    What

    As a player, I want to follow a sleepwalking child through the silent town so that I learn to move, sneak and interact while the mystery lands.

    Night 1 is held: a rest veto (e27-rest-points veto registry) blocks resting until the beat resolves. Tansy's path: bakery → Market Green → mine road → Briarwood edge → mine gate. She cannot be woken (shaking raises her hum). Wolves let her pass. Tutorial prompts along the path. The beat always ends with the horned shape lifting her at the gate — even if the player falls behind (fallback trigger), gets lost, or is blocked.

    Scope

    • In: Tansy sleepwalk path, rest veto while night 1 is active, tutorial prompt markers, gate cinematic trigger, fallback triggers
    • Out: Text (e39-intro-endings-text)
    • Out: Quest graph (e39-main-quest-data)

    Notes

    Spans town and Briarwood edge; the gate exterior itself is e25-mine-gate-approach.

    Acceptance criteria

    • AC-1 integration Given the player follows Tansy, when she reaches the gate, then the horned-shape beat plays and fact night1.shadowSeen is set.
    • AC-2 integration Given the player loses Tansy for 60 s, when the fallback fires, then the beat still resolves with the shadow seen from the nearest vantage (edge).
    • AC-3 integration Given the player shakes Tansy, when interacted, then her hum loudness rises and she does not wake.
    • AC-4 e2e Given a new game, when the first-night replay runs, then morning begins at the Ox with night1.shadowSeen set.

    Waits on

    • mw-e13.8 Add silent Briar Wolf packs that can be fed, scared or remembered open
    • mw-e24.4 Build the Sleeping Ox inn: common room, rooms, cellar and rest open
    • mw-e25.10 Build the boarded mine gate with every class's way in open
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e27.13 Rest at inns, campfires and shrines to reset facts and pass time open
    area:contentepic:e24milestone:m3
  • mw-e24.17Author class routes for Briar Glen's obstaclesblockedP1M3feature

    Description

    Why

    Town obstacles (Vane House, restricted shelf, jail, Watch House records) should open differently per class.

    What

    As a player of any class, I want my class to open town obstacles its own way so that town reflects my fantasy.

    First-pass routes from the route matrix: knight (persuade via rank, force the coal-chute grate), archer (rope arrow to balcony, shoot the gate latch), sorcerer (Mage Hand the study key, Levitate to window, trade favours with Mirela), thief (lockpick, rooftops, pickpocket keys). Declared in the obstacle registry.

    Scope

    • In: Route affordances in town scenes, registry entries, replays for each route
    • Out: Gap closing after audit (e16-gap-pass-surface)

    Notes

    Uses the route matrix ids verbatim.

    Acceptance criteria

    • AC-1 content Given the registry, when validated, then every E24 obstacle has >= 3 class routes declared.
    • AC-2 integration Given each declared route, when replayed, then the obstacle exit fact is set.
    • AC-3 integration Given a route that relies on an NPC schedule window, when attempted outside the window, then an alternative route for that class still exists (edge).

    Waits on

    • mw-e16.2 Declare obstacles and class routes as validated content data open
    • mw-e24.12 Build a rooftop network across Briar Glen for thieves and climbers open
    • mw-e24.5 Author the Lamplit Stacks bookshop on the e21 authoring template open
    • mw-e24.8 Build the Watch House and a jail cell whose drain leads out open
    • mw-e24.9 Build Vane House as an infiltration target with strongbox and ledger open
    area:contentclass:allepic:e24milestone:m3
  • mw-e24.18Art-dress Briar Glen with final environment assetsblockedP1M3feature

    Description

    Why

    The lights are on in town: warmth and hedgerow charm must read at a glance.

    What

    As a player, I want Briar Glen to look like a crooked, bookish mining town so that it feels like a place worth saving.

    Replace grey-box with approved modular town kit, props and textures; keep collision, navmesh and gameplay entity ids unchanged.

    Scope

    • In: Swap grey-box to final meshes/materials, prop dressing, signage, decals
    • Out: Asset creation (E37 prompt/generate/integrate beads)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item.

    Acceptance criteria

    • AC-1 integration Given the dressed town, when the e2e town tour and all town route replays run, then they pass unchanged.
    • AC-2 perf Given the dressed town at Market Green, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent) and draw calls <= 1500.
    • AC-3 manual Given the art review, when compared to the style bible, then no building uses colours outside the palette (edge: consistency).

    Waits on

    • mw-e24.13 Place Briar Glen's NPCs on day/night schedules in progress
    • mw-e24.17 Author class routes for Briar Glen's obstacles open
    • mw-e24.3 Place systemic objects and hiding spots throughout Briar Glen open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.14 Legibility kit: visual cues for every exploitable world property open
    • mw-e37.15 Build the style-target diorama as the visual and performance benchmark open
    • mw-e37.246 Integrate approved Briar Glen environment concepts open
    • mw-e37.266 Integrate approved Briar Glen tileables and trims open
    • mw-e37.298 Integrate approved Briar Glen exterior props open
    • mw-e37.302 Integrate approved Briar Glen interior props open
    • mw-e37.328 Integrate approved Briar Glen story props open
    • mw-e37.352 Integrate approved world prop gap-fill open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artepic:e24milestone:m3
  • mw-e24.19Light and score Briar Glen for day, dusk and nightblockedP1M3feature

    Description

    Why

    Every warm room has one thing that makes you uneasy; lighting and ambience carry that.

    What

    As a player, I want town days to sound busy and nights to go quiet so that the sleepwalking dread lands.

    Lighting presets per phase, lit windows by schedule, lamplighter relighting; ambience beds (market day, night crickets, forge hammering near the forge, inn murmur); music cues for town day/night/first night; reverb zones for interiors.

    Scope

    • In: Lighting setup, ambience zones, music cue bindings, reverb zones
    • Out: Audio assets (E38)
    • Out: Adaptive music engine (e28-adaptive-music)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item. Related: e28-ambience, e28-reverb-zones and e29-environment-fx are P2 in the combat plan; bind ambience beds, reverb zones and fog/firefly FX here when they land, otherwise ship lighting + music only.

    Acceptance criteria

    • AC-1 integration Given the clock crosses dusk, when the phase event fires, then the lighting preset blends to night within 5 s and music switches from the day to the night cue.
    • AC-2 integration Given night, when sampling light at Market Green away from lamps, then the level is dark enough for thief visibility < 0.3 while crouched (edge: stealth must remain viable).
    • AC-3 perf Given night with all lamps lit, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).

    Waits on

    • mw-e24.18 Art-dress Briar Glen with final environment assets open
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e37.282 Integrate approved location skies and backdrops open
    • mw-e38.108 Integrate approved Briar Glen music family into adaptive music open
    • mw-e38.136 Integrate approved Briar Glen and wilderness ambience open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:audioepic:e24milestone:m3
  • mw-e24.6Author the Stacks' restricted shelf and forbidden back roomblockedP2M3feature

    Description

    Why

    Some books are expensive, forbidden, hidden or stolen; Mirela's curtain and back room are where the sorcerer's best finds live.

    What

    As a sorcerer, I want a restricted shelf that opens when Mirela trusts me and a back room holding a book she will never sell so that trust and theft both matter.

    Restricted shelf (Mirror Self, Gravity Well and other restricted schools — writ or Trusted disposition), back room with Nine Sleeps on a locked lectern (never for sale; readable; stealable, teaching Lull), Court-seal markings, and Mirela's reaction facts.

    Scope

    • In: Secret/restricted stock data, back-room scene dressing, Nine Sleeps placement, reaction facts
    • Out: Public stock (e24-lamplit-stacks)
    • Out: Forbidden-book side effects (e07-forbidden-books)

    Notes

    Legality per story bible §3.3. Rumour 7 resolves on first restricted-shelf reveal.

    Acceptance criteria

    • AC-1 integration Given disposition below Trusted and no writ, when viewing the restricted shelf, then its stock is hidden; at Trusted it appears and rumour 7 resolves.
    • AC-2 integration Given Nine Sleeps, when the player attempts to buy it, then it is not for sale; when stolen, then theft is recorded and Mirela reacts on the next visit (edge).
    • AC-3 content Given the secret stock data, when pnpm validate:bookshops runs, then every restricted book carries the restricted legality tag and no forbidden book is purchasable.

    Waits on

    • mw-e21.4 Reveal secret back-room stock through dialogue, trust or discovery open
    • mw-e21.6 Handle stolen and forbidden books in bookshop trade open
    • mw-e24.5 Author the Lamplit Stacks bookshop on the e21 authoring template open
    area:contentclass:sorcererepic:e24milestone:m3
  • mw-e24.11Build the lychgate cemetery and the empty schoolhouseopenP2M3feature

    Description

    Why

    Quiet places carry the story: Vesperine graves and a teacher's empty desk.

    What

    As a player, I want to find lore in the cemetery and schoolhouse so that the town's history and its missing people feel real.

    Cemetery: lychgate, Vesperine graves with epitaphs (Hornfolk ear-covering motif on the oldest), Mooring family plot, a fresh unmarked grave (false alarm, humour beat). Schoolhouse: Mina Coles' desk, the skipping rhyme on the slate, Tansy's reading corner, a torn page from The Ox Beneath the Hill.

    Scope

    • In: Two small scenes/areas, readable epitaphs and slate, lore item placements
    • Out: Text content (e39-books-lore)

    Notes

    The torn last page links to Tansy's copy of the book (lore payoff).

    Acceptance criteria

    • AC-1 content Given both areas, when validated, then every readable references an existing text id.
    • AC-2 integration Given the player reads the slate rhyme, when complete, then fact lore.rhyme.read is set (used by Mirela dialogue).
    • AC-3 integration Given night, when the player enters the cemetery, then no hostile creature spawns there (tone rule: the lights are on in town, edge).

    Waits on

    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e39.13 Write in-game books, notes and inscriptions done
    area:contentepic:e24milestone:m3
  • mw-e24.15Place the rumour set on sources and wire targets to real factsblockedP2M3feature

    Description

    Why

    "NPC rumors can lead somewhere." Each of the twelve rumours must point at something placed.

    What

    As a player, I want rumours from Dot, townsfolk and goblins to lead to real places so that talking becomes exploring.

    Bind e39 rumour data to sources (Dot, townsfolk tags, goblins) and ensure each rumour's resolvesWhen fact is produced by placed content (well echo, Mooring armour, stamped trinkets, cracked bell, ledger, restricted shelf, Hale's boots, millpond lantern, the Fold, Clatter, the Standing Horn).

    Scope

    • In: Source bindings, fact producers placed where missing, validation run
    • Out: Rumour text (e39-rumor-set)
    • Out: Rumour runtime (e22-rumors)

    Notes

    Rumours 10–11 come from goblins (E26 camp).

    Acceptance criteria

    • AC-1 content Given the rumour set, when validated, then all 12 rumours have >= 1 source and a produced resolvesWhen fact (no warnings).
    • AC-2 integration Given rumour 4 heard and the cistern entered, when evaluated, then it resolves as Investigated.
    • AC-3 integration Given the false rumour 3 (goblins took them), when the Framed in Brass proof is found, then it resolves with a "false" journal note (edge).

    Waits on

    • mw-e22.11 Add rumor system that points players to places and secrets done
    • mw-e24.10 Hide the cistern route under the Glen Well open
    • mw-e39.12 Write the rumour set with sources, truth values and targets done
    area:contentepic:e24milestone:m3
  • mw-e24.16Place Briar Glen's secrets, lore books and hidden treasureblockedP2M3feature

    Description

    Why

    Interesting-looking places should usually contain something interesting; every bookshelf has a book.

    What

    As a curious player, I want secrets in town — stashes, notes, books — so that exploring town pays off.

    Placement: every bookshelf gets a book, Dot's stamped trinket in the cellar, Hale's dusty boots (Captain's Boots clue), the Pell family Bible, the "friend below" note under the player's door, a thief stash on the Forge roof, a chimney cache, and 6–10 small treasures per the e18 treasure guide.

    Scope

    • In: Lore/treasure placements, discovery rules, fact ids
    • Out: Text (e39-books-lore)
    • Out: Loot tables design (e18-treasure-design-guide)

    Notes

    Density target from e18-treasure-design-guide.

    Acceptance criteria

    • AC-1 content Given the town scenes, when audited, then every bookshelf entity has >= 1 book placed.
    • AC-2 integration Given the player morning 1, when they leave the room, then the "friend below" note is at the door and readable.
    • AC-3 integration Given a hidden stash taken, when saved and reloaded, then it stays empty (edge).

    Waits on

    • mw-e18.5 Support designer-placed and hidden treasure with discovery rules open
    • mw-e18.9 Write treasure design guide for handcrafted loot open
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e39.13 Write in-game books, notes and inscriptions done
    area:contentepic:e24milestone:m3

M4 Fun validation 1

  • mw-e24.20Perf-pass and playtest Briar Glen on both presetsblockedP1M4task

    Description

    Why

    The town is the densest scene (NPCs, lights, props); it is the likeliest perf failure.

    What

    Run the perf suite on the town (day/night, full schedules, a street fire) on reference and low-tier machines; run a 5-tester town playtest (can they find the Stacks, the well, Vane House entries unprompted?). Record in docs/playtests/briar-glen.md; file beads.

    Scope

    • In: Perf captures, fixes within budget, playtest session and findings
    • Out: Global perf work (E32)

    Notes

    Related: e32-reference-runbook.

    Acceptance criteria

    • AC-1 perf Given Market Green at midday with full schedules, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).
    • AC-2 perf Given the same scene on the Low preset, when measured, then p95 <= 16.7 ms at 1080p on the Low preset on an Intel Iris Xe / base M1 8 GB class machine, with p99 <= 33.3 ms (30 fps floor) during worst-case combat.
    • AC-3 perf Given a warm cache, when entering town from the Briarwood, then the transition completes in <= 3 s and heap stays <= 1.5 GB.
    • AC-4 manual Given 5 testers, when asked to find the bookshop, the well and a way into Vane House, then >= 4 find all three without help within 20 minutes.

    Waits on

    • mw-e24.19 Light and score Briar Glen for day, dusk and night open
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    • mw-e32.6 Implement Low/High graphics presets and dynamic resolution open
    area:perfepic:e24milestone:m4
E25Wilderness RegionThe Briarwood, Mooring's Watch, the River Wend and the Deepworks' exterior approach form an interconnected wilderness around Briar Glen: the Sleepers' Path, the Standing Horn, the wolf den, the woodcutter's hut, the millpond and drowned lane, the watchtower with its signal mirror and supply tunnel, and the boarded mine gate, plus the river (Briar Glen Quay and the Stone Stair, the Millweir sluice walk, the Weeping Adit into the lower mine, the towpath and Kestrel Lock, and barge travel to Wendmouth) — with loops and shortcuts unlocked by abilities.4/26 done · 15%

M3 MVP content 21

  • mw-e25.2Reveal the Sleepers' Path at night or to a tracker's eyeopenP1M3feature

    Description

    Why

    The trail of trampled ferns is the forest's mystery and the archer's signature clue.

    What

    As an archer, I want to see the Sleepers' Path when others cannot so that my tracking fantasy pays off.

    A fern-trail decal set visible when time.phase is night (any class, low contrast) or always to players with sense.tracking (archer), or with Arcane Sight / a lantern held low. Leads from town to the mine gate with a branch to the priory (sets path.found; unlocks Captain's Boots shortcut knowledge).

    Scope

    • In: Trail decal entities with visibility conditions, branch to priory, fact wiring
    • Out: Tracking capability definition (e19-archer-arrow-channel / class data)

    Notes

    If sense.tracking does not exist in class data, raise a bead with systems; fallback is night-only visibility.

    Acceptance criteria

    • AC-1 integration Given day and a non-archer, when looking at the trail, then it is not rendered; at night it is rendered at low contrast.
    • AC-2 integration Given an archer with sense.tracking at noon, when looking at the trail, then it is rendered at full contrast.
    • AC-3 integration Given the player follows the branch to the priory, when reached, then path.found is set and the priory shortcut is known on the map (edge: sets once).

    Waits on

    • mw-e19.2 Create capability registry with source-tracked grants done
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    area:contentclass:archerepic:e25milestone:m3
  • mw-e25.4Build the wolf den encounter with feed, scare, sneak and fight routesblockedP1M3feature

    Description

    Why

    The silent pack is the first creature encounter with real options.

    What

    As a player, I want to deal with the Briar Wolf pack my own way so that my first wilderness threat has choices.

    Den hollow with 4–5 wolves, carcass bait spot, rocky overlooks (archer), bramble cover (thief), a fallen log bridge (knight shoves to block a flank), fire pit (scare). Juniper's hunting snare cache nearby. Pack-memory facts drive later reactions.

    Scope

    • In: Encounter placement, overlooks, cover, bait spot, snare cache
    • Out: Wolf behaviour (e13-briar-wolves)

    Notes

    Resolves rumour 1 when observing wolves ignoring a sleepwalker (first night or later).

    Acceptance criteria

    • AC-1 integration Given the player drops meat at the bait spot, when the pack eats, then the den path can be crossed without combat for 120 s.
    • AC-2 integration Given a thief crouched in bramble cover at night, when crossing, then no wolf exceeds Suspicious in the scenario replay.
    • AC-3 integration Given the pack is killed, when the player returns in the "Vespers Rung" ending, then the den is empty rather than respawned (edge: pack memory).

    Waits on

    • mw-e13.8 Add silent Briar Wolf packs that can be fed, scared or remembered open
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    area:contentepic:e25milestone:m3
  • mw-e25.5Build the millpond and drowned lane with a Hushling and a lost lanternblockedP1M3feature

    Description

    Why

    "Something at the millpond sings on still nights. Not a bird." True, and dangerous.

    What

    As a player, I want a flooded lane haunted at night by a voice-mimicking Hushling so that the wilderness foreshadows the Knot.

    Millpond with a sluice (open/close changes the lane's water level), the drowned lane (wade, freeze, or drain it), a sleepwalker's lost lantern (item and clue), a single night-only Hushling that mimics one of the missing, and the woodcutter's empty hut nearby (safe rest spot, axe, lore).

    Scope

    • In: Pond and lane scene, sluice mechanism, water level states, night-only Hushling spawn, lantern item, woodcutter's hut
    • Out: Hushling behaviour (e13-hushlings)

    Notes

    Resolves rumour 9. The woodcutter's hut is folded in here as the nearby safe spot.

    Acceptance criteria

    • AC-1 integration Given the sluice is opened, when simulated, then the lane water level drops to wading depth within 20 s.
    • AC-2 integration Given day, when the lane is entered, then no Hushling is present; at night it spawns and mimics one of the missing by name.
    • AC-3 integration Given the player rings any loud noise source >= 0.85 near it, when propagated, then the Hushling dissipates and does not respawn until the next night (edge).

    Waits on

    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e03.6 Simulate water volumes, splashes, wetness and drying done
    • mw-e13.9 Add blind Hushlings that hunt by sound and break at loud noises open
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    area:contentepic:e25milestone:m3
  • mw-e25.7Place the Hollow Sentinels and goblin lookout with class resolutionsblockedP1M3feature

    Description

    Why

    The Watch Still Stands: watchword, formal relief, bell cord, dispel, stealth or smash.

    What

    As a player of any class, I want to end the watch my class's way so that the tower becomes my safe base.

    Sentinels on armour stands named in the keeper's log; goblin lookout (2–3 goblins with an alarm pot) below. Resolutions wired as facts: watchword from the keeper's log (any), knight formal relief, archer shoots the bell cord (watch.ended), sorcerer dispel/overload binding, thief sneaks to the roof, smash. Reward: tower as safe base (rest point), Sergeant Mooring's watch-key, closing line in the log.

    Scope

    • In: Creature placement, bell cord shootable, log item, safe-base conversion, rewards
    • Out: Quest graph (e39-side-quests-wilds)
    • Out: Sentinel behaviour (e13-hollow-sentinels)

    Notes

    Resolves rumour 2.

    Acceptance criteria

    • AC-1 integration Given the bell cord hit by any projectile or cut, when it rings, then watch.ended is set and all sentinels stand down.
    • AC-2 integration Given the watchword read in the log, when spoken to a sentinel, then that sentinel and its peers stand down.
    • AC-3 integration Given the goblin lookout raises the alarm, when the sentinels hear it, then they do not leave the tower (edge: leash holds).
    • AC-4 integration Given watch.ended, when the player rests in the keeper's quarters, then it acts as a rest point and respawn location for the region.

    Waits on

    • mw-e05.13 Shootable triggers and cuttable ropes activate mechanisms done
    • mw-e13.12 Add Hollow Sentinels bound to hold the tower until relieved open
    • mw-e13.6 Add Rootcellar goblin combatants: slings, nets and loud alarms open
    • mw-e25.6 Block out Mooring's Watch: courtyard, tower floors, roof and tunnel done
    • mw-e27.13 Rest at inns, campfires and shrines to reset facts and pass time open
    area:contentclass:allepic:e25milestone:m3
  • mw-e25.8Turn the signal mirror to light the priory's hidden choir dooropenP1M3feature

    Description

    Why

    Redirecting light across a valley is the constitution's puzzle promise at landscape scale.

    What

    As a player, I want to rotate the tower's signal mirror at the right time of day so that a beam reveals a hidden door at the priory.

    Rotatable mirror prefab on the roof; at day or with a light source/spell at night, the beam aligned to the priory marker sets priory.choirDoor.revealed. Alternatives: Prism Ray from the priory side, the Arcane Sight reveal, or finding the choir door lever from inside.

    Scope

    • In: Mirror prefab placement, long-range beam target, cross-scene fact, alternatives declared
    • Out: Choir door itself (e26-priory-choir)

    Notes

    Beam is simulated in the tower scene and resolves to a fact; no cross-scene physics.

    Acceptance criteria

    • AC-1 integration Given sun phase day and the mirror rotated to the priory marker, when evaluated, then priory.choirDoor.revealed is set.
    • AC-2 integration Given night and no light source on the mirror, when rotated to the marker, then nothing happens (edge).
    • AC-3 content Given the puzzle file, when the solvability validator runs, then >= 2 distinct solutions are found.

    Waits on

    • mw-e03.17 Redirect light beams with mirrors and lenses onto receivers done
    • mw-e15.4 Ship reusable puzzle prefabs built only from world components done
    • mw-e25.6 Block out Mooring's Watch: courtyard, tower floors, roof and tunnel done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    area:contentepic:e25milestone:m3
  • mw-e25.9Make the collapsed supply tunnel a class-gated shortcut to the mineopenP1M3feature

    Description

    Why

    The watchtower-to-mine loop is the "long way in" for any class and a shortcut once cleared.

    What

    As a player, I want to clear the collapsed tunnel under the tower so that I reach the upper Deepworks without Vane's gate.

    Collapse with routes: knight clears rubble by hand (heavy push/lift), sorcerer Gravity Well or Telekinetic Throw removes key stones, thief squeezes through a gap (crawl), archer shoots a rotten prop to drop a section (then climb), any class with a pick item digs slowly. Clearing sets shortcut.supplyTunnel.

    Scope

    • In: Collapse entities, routes, fact wiring to E26 upper mine node
    • Out: Mine interior beyond the collapse (e26-deepworks-greybox)

    Notes

    Boundary between E25 and E26 is the collapse itself.

    Acceptance criteria

    • AC-1 content Given the obstacle registry, when validated, then the supply tunnel declares >= 4 class routes.
    • AC-2 integration Given the collapse cleared by any route, when evaluated, then shortcut.supplyTunnel is set and persists after reload.
    • AC-3 integration Given the archer drops the rotten prop while standing under it, when it falls, then crush damage applies via environmental damage (edge).

    Waits on

    • mw-e02.18 Push and pull heavy objects such as crates and statues done
    • mw-e03.11 Break fragile objects and smash weakened walls into debris done
    • mw-e04.19 Fall, crush and hazard damage through the damage model done
    • mw-e25.6 Block out Mooring's Watch: courtyard, tower floors, roof and tunnel done
    area:contentepic:e25milestone:m3
  • mw-e25.10Build the boarded mine gate with every class's way inblockedP1M3feature

    Description

    Why

    Getting in is the first big class-choice moment (bible §4.1 beat 5).

    What

    As a player of any class, I want several ways past Vane's sealed gate so that my class decides how I enter the Deepworks.

    Mine gate exterior: Bell Line rule carved above ("No shaft below the Bell Line. The hill is kept."), padlocked gate (Vane's key or lockpick), rotted side-boarding (knight smash), winch pulley (archer shot drops the cage), inner bar (Mage Hand) and rope latch (Ember/any heat), ventilation chimney up the hillside (thief climb). Bell Line boundary stones where Hale's sleepwalk stops.

    Scope

    • In: Gate exterior scene, routes, readable carving, Bell Line stones, transition into E26
    • Out: Winch house interior (e26-deepworks-greybox)

    Notes

    Target 4 classes + the long way (supply tunnel) + the river way (e25-weeping-adit, the sixth entry route, registered as its own obstacle).

    Acceptance criteria

    • AC-1 content Given the obstacle registry, when validated, then the mine gate declares routes for all four classes plus the key route.
    • AC-2 integration Given the rope latch exposed to any heat stimulus, when it burns, then the gate unbars.
    • AC-3 integration Given the knight smashes the side-boarding, when broken, then the gap persists after reload and fact mine.boardsBroken is set (Vane remarks).
    • AC-4 integration Given the player opens the gate at night while a sleepwalker event is active, when entered, then the sleepwalker path is not blocked (edge).

    Waits on

    • mw-e04.17 Smash breakable walls and objects by impact force open
    • mw-e05.13 Shootable triggers and cuttable ropes activate mechanisms done
    • mw-e10.7 Pick locks as an in-world, interruptible, noisy action open
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e17.5 Auto-use keys from the keyring on matching locks done
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    area:contentclass:allepic:e25milestone:m3
  • mw-e25.11Build Briar Glen Quay and the Stone Stair slipway down from the mineopenP1M3feature

    Description

    Why

    The river is the town's second heart; the Stone Stair turns the mine's cutting hall and the quay into a loop.

    What

    As a player, I want a working quay below town and a stepped stone slipway from the Deepworks so that the river connects to the mine.

    Briar Glen Quay: moorings for Mags Oakum's stone barge Patient Ann, dressed glenstone blocks stacked on timber cradles, bollards, a crane, a toll shed and the barge departure point. The Stone Stair: a stepped slipway for blocks from the Deepworks' old cutting hall (goblin camp) down to the quay — slide down one-way from the top (shortcut.stoneStair), climbable upward only by climbers or with a rope arrow anchor.

    Scope

    • In: Quay scene area, Stone Stair slipway with slide and climb routes, connectivity edges to town and the E26 cutting hall
    • Out: Barge travel (e25-barge-travel)
    • Out: Cutting hall interior (e26-deepworks-greybox)

    Notes

    Standing water only: the quay basin is an e03 water volume (wading, swimming, freezing); the river does not flow in the sim.

    Acceptance criteria

    • AC-1 integration Given the player at the top of the Stone Stair in the cutting hall, when they slide down, then they arrive at the quay within 10 s and shortcut.stoneStair is set.
    • AC-2 integration Given a non-climbing player at the quay, when trying to go up the slipway, then no route exists until a climb or rope-arrow capability is used (edge).
    • AC-3 integration Given the quay basin, when any cold stimulus freezes it, then it becomes walkable ice via e03 rules.
    • AC-4 content Given connectivity.json, when validated, then quay ↔ town and stone-stair (one-way) edges exist with their unlock conditions.

    Waits on

    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    area:contentepic:e25milestone:m3
  • mw-e25.12Build the Millweir and its sluice walk to the Briarwood far bankopenP1M3feature

    Description

    Why

    The Vesperine-built weir is a river loop: crossing it opens the forest's far bank.

    What

    As a player, I want to cross the Millweir on its sluice walk so that I reach the Briarwood's far bank without the long road.

    Weir below town with a narrow sluice walk; sluice gates set the standing-water level above and below the weir (two states); the walk is slippery when wet and gains grip when dry; a gap mid-walk needs a plank, a jump, Blink or a rope anchor. Crossing sets shortcut.millweir.

    Scope

    • In: Weir scene area, sluice gate mechanism with two water-level states, walk traversal with gap, connectivity edge
    • Out: Flowing-water simulation (not planned — water is standing volumes only)

    Notes

    Falling off the walk drops the player into the pool below, never kills from full health.

    Acceptance criteria

    • AC-1 integration Given the sluice gate closed, when toggled open, then the upper pool level drops to its low state within 20 s and a submerged stepping stone path is exposed.
    • AC-2 integration Given the player crosses the walk by any route, when they reach the far bank, then shortcut.millweir is set and persists after reload.
    • AC-3 integration Given the player falls from the walk, when landing in the pool, then they take no fall damage and can swim to the bank (edge).

    Waits on

    • mw-e02.14 Wade and swim in water and slide on frozen surfaces done
    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e03.6 Simulate water volumes, splashes, wetness and drying done
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    area:contentepic:e25milestone:m3
  • mw-e25.13Build the Weeping Adit: the flooded sixth way into the lower DeepworksblockedP1M3feature

    Description

    Why

    The river's source is also the mine's back door; going up the Adit is the sixth entry route (bible §4.1 beat 5).

    What

    As a player of any class, I want to go up the flooded drainage tunnel where the Wend springs so that I reach the lower Deepworks without Vane's gate.

    Adit mouth on the hillside (humming audible at night — rumour 16), a flooded tunnel of standing-water chambers with a push-current volume (external impulse, not a flow sim) at the narrows. Routes: swim with air pockets; freeze the current's edge into an ice ledge (any cold stimulus); ride in on an empty stone barge being winched back up (winch mechanism, timed by Mags' schedule); climb the dry drainage ledge (climbers). Emerges in the Deepworks' flooded lower gallery (E26).

    Scope

    • In: Adit mouth and tunnel scene, push-current volume, air pockets, winched-barge ride, ice-ledge route, transition to the E26 flooded gallery
    • Out: Lower Deepworks interior (e26-deepworks-greybox)
    • Out: Mags' dialogue about the Adit (e39-dialogue-harbor-folk)

    Notes

    Registered as its own mine-entry obstacle so the E16 audit counts the Adit separately from the gate. Resolves rumour 16. Buoyancy (e03-buoyancy, P2) is not required: the barge is a mechanism on a winch path.

    Acceptance criteria

    • AC-1 integration Given the push-current volume at the narrows, when a swimming player enters it, then they are pushed back toward the mouth unless they hold to a ledge or the edge is frozen.
    • AC-2 integration Given any cold stimulus on the current's edge, when frozen, then an ice ledge forms and the narrows can be walked for as long as it stays frozen.
    • AC-3 integration Given the winch is running and the player rides the empty barge, when it reaches the top, then the player arrives in the flooded lower gallery and mine.entry.adit is set.
    • AC-4 content Given the obstacle registry, when validated, then the Adit declares >= 3 class routes plus an any-class swim route.
    • AC-5 integration Given the player runs out of air in the tunnel, when drowning damage would kill them, then they are washed out to the Adit mouth instead (edge: failure moves them, not a reload).

    Waits on

    • mw-e01.12 Wake in context after death instead of reloading open
    • mw-e02.14 Wade and swim in water and slide on frozen surfaces done
    • mw-e02.15 Apply knockback, launches and fall damage to the player controller done
    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    area:contentclass:allepic:e25milestone:m3
  • mw-e25.14Build the towpath and Kestrel Lock with the keeper's cottageblockedP1M3feature

    Description

    Why

    The towpath is the always-open road to Wendmouth; Kestrel Lock is its halfway landmark and gossip post.

    What

    As a player, I want to walk the towpath down the valley past Kestrel Lock so that I can reach Wendmouth on foot and meet Old Reed.

    A compressed towpath route in two legs (Briar Glen Quay → Kestrel Lock → Wendmouth outskirts); each leg transition advances the world clock (6 game hours per leg). Kestrel Lock: two gates and a lock chamber whose standing-water level is raised or lowered by paddles (two states), a lock beam walk, the toll board, and Old Reed's cottage (toll-in-gossip rumour source, rest point).

    Scope

    • In: Two towpath legs with transitions and time advance, lock chamber with two water states, paddles, cottage interior, rest point
    • Out: Barge travel (e25-barge-travel)
    • Out: Old Reed dialogue (e39-dialogue-harbor-folk)
    • Out: Toll board text (e39-harbor-rumors-texts)

    Notes

    Distances are compressed; the fiction is "a day downriver". Time advance keeps the Tern's Act III departure unaffected (it is quest-gated, not clock-gated).

    Acceptance criteria

    • AC-1 integration Given the player completes a towpath leg transition, when they arrive, then game time has advanced by exactly 6 hours via advanceTime.
    • AC-2 integration Given the lock paddles are opened, when simulated, then the chamber moves to the other water-level state within 30 s and the lower gate can be opened only when levels match.
    • AC-3 integration Given the player tries to open a lock gate against unequal levels, when interacted, then it refuses with a visible strain cue and no state change (edge).
    • AC-4 perf Given the lock with the cottage and towpath foliage in view, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).

    Waits on

    • mw-e01.11 Connect scenes with area transitions and named spawn points done
    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e03.6 Simulate water volumes, splashes, wetness and drying done
    • mw-e25.11 Build Briar Glen Quay and the Stone Stair slipway down from the mine open
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e27.13 Rest at inns, campfires and shrines to reset facts and pass time open
    area:contentepic:e25milestone:m3
  • mw-e25.15Ride Mags Oakum's barge between Briar Glen Quay and WendmouthblockedP1M3feature

    Description

    Why

    Wendmouth must be quick to reach from the morning after the first night; a narrated barge ride is the fast way.

    What

    As a player, I want to pay Mags for passage on the Patient Ann so that I travel downriver in one narrated ride instead of walking.

    Travel service at Briar Glen Quay, Kestrel Lock and the Wendmouth Stone Wharf: departs mornings only (refuses at night: "not with whatever's singing up there"); downriver advances 1 game day, upriver 2 (towed); a short narrated ride card with class-flavoured Mags lines; optional stowaway under the tarpaulin (thief, for a fee) that skips the customs inspection on arrival. Available from the morning after night 1.

    Scope

    • In: Travel service data and runtime (fare, schedule window, direction durations), ride card UI hook, stowaway flag, arrival spawn points
    • Out: Flowing-water or boat-handling simulation (not planned)
    • Out: Ride text (e39-dialogue-harbor-folk)
    • Out: Customs inspection (e40-customs-house)

    Notes

    No other plan owns fast travel; this is deliberately a narrow travel-service item, reusable later for other routes.

    Acceptance criteria

    • AC-1 unit Given the player at the quay at 08:00 on day 2 with the fare, when they board downriver, then they arrive at the Wendmouth Stone Wharf at 08:00 on day 3 and the fare is deducted.
    • AC-2 unit Given an upriver trip, when taken, then exactly 2 game days elapse and time events fire in order via advanceTime.
    • AC-3 integration Given night or night 1 not yet resolved, when the player asks for passage, then Mags refuses and no time passes (edge).
    • AC-4 integration Given the stowaway option taken, when arriving at Wendmouth, then the customs inspection trigger is skipped for that arrival only.
    • AC-5 e2e Given a save at the quay, when the player rides down and back, then both arrivals load in <= 3 s warm with zero console errors.

    Waits on

    • mw-e00.23 Build HUD/menu UI layer, component kit, focus nav and UI test harness done
    • mw-e01.11 Connect scenes with area transitions and named spawn points done
    • mw-e20.9 Add purchasable services as meaningful gold sinks open
    • mw-e25.11 Build Briar Glen Quay and the Stone Stair slipway down from the mine open
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    area:gameepic:e25milestone:m3
  • mw-e25.16Art-dress, light and score the River Wend locationsblockedP1M3feature

    Description

    Why

    The river should read as the valley's working artery: tarred wood, brown water, herons and stone barges loaded with pale glenstone.

    What

    As a player, I want the quay, Millweir, Adit, towpath and Kestrel Lock to look and sound like the story bible so that the river has identity.

    Final environment kit and props for the river locations, water surface materials for standing-water volumes, lighting per time-of-day, the river music cue and river ambience bindings; gameplay ids and collision unchanged.

    Scope

    • In: Art swap for five river locations, water material presets, lighting, music/ambience bindings
    • Out: Asset creation (E37/E38)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item. Related: e28-ambience, e28-reverb-zones and e29-environment-fx are P2 in the combat plan; bind ambience beds, reverb zones and fog/firefly FX here when they land, otherwise ship lighting + music only.

    Acceptance criteria

    • AC-1 integration Given the dressed river locations, when all E25 river replays and route replays run, then they pass unchanged.
    • AC-2 integration Given the player enters any river location, when crossing its trigger, then the river music cue plays within 3 s.
    • AC-3 perf Given the quay with the barge, crane and water surface in view, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent) and p95 <= 16.7 ms at 1080p on the Low preset on an Intel Iris Xe / base M1 8 GB class machine, with p99 <= 33.3 ms (30 fps floor) during worst-case combat (edge: water shader on Low).

    Waits on

    • mw-e25.12 Build the Millweir and its sluice walk to the Briarwood far bank open
    • mw-e25.13 Build the Weeping Adit: the flooded sixth way into the lower Deepworks open
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e25.15 Ride Mags Oakum's barge between Briar Glen Quay and Wendmouth open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.146 Integrate approved River Wend environment concepts open
    • mw-e37.154 Integrate approved River Wend tileables open
    • mw-e37.196 Integrate approved river quay, weir and lock props open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e38.68 Integrate approved River Wend and barge music into adaptive music open
    • mw-e38.80 Integrate approved River Wend ambience open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:artepic:e25milestone:m3
  • mw-e25.17Author class routes and ability-gated shortcuts across the wildernessblockedP1M3feature

    Description

    Why

    Paths loop together and reveal shortcuts as players acquire abilities.

    What

    As a player of any class, I want new abilities to open new wilderness shortcuts so that returning to the forest feels different.

    Shortcuts: rope-arrow anchor up the priory crag, the Millweir gap (plank/jump/Blink/rope), climbing the Stone Stair upward, frozen millpond crossing, bramble burn-through to the tower spur, a climbable ravine to the mine hillside, a Blink gap over the drowned lane. Registry entries and replays.

    Scope

    • In: Shortcut affordances, registry entries, replays, connectivity updates
    • Out: Gap closing after audit (e16-gap-pass-surface)

    Notes

    Each shortcut is one-way until opened from the far side where sensible.

    Acceptance criteria

    • AC-1 content Given the registry, when validated, then every E25 obstacle has >= 3 class routes.
    • AC-2 integration Given each shortcut, when opened, then its fact persists and connectivity reachability updates.
    • AC-3 integration Given a frozen-pond crossing, when the ice melts while the player is on it, then the player drops into water and can swim out (edge).

    Waits on

    • mw-e05.10 Rope arrows anchor into wood and create climbable ropes open
    • mw-e16.2 Declare obstacles and class routes as validated content data open
    • mw-e25.10 Build the boarded mine gate with every class's way in open
    • mw-e25.12 Build the Millweir and its sluice walk to the Briarwood far bank open
    • mw-e25.13 Build the Weeping Adit: the flooded sixth way into the lower Deepworks open
    • mw-e25.5 Build the millpond and drowned lane with a Hushling and a lost lantern open
    • mw-e25.9 Make the collapsed supply tunnel a class-gated shortcut to the mine open
    area:contentclass:allepic:e25milestone:m3
  • mw-e25.19Art-dress the Briarwood and Mooring's Watch with final assetsblockedP1M3feature

    Description

    Why

    The forest must feel old and thick — oak, holly, bramble — without hurting perf.

    What

    As a player, I want the Briarwood and the watchtower to look like the story bible describes so that the region has identity.

    Foliage (instanced), terrain textures, ruined tower kit, props; keep collision and gameplay ids intact.

    Scope

    • In: Foliage/terrain/tower art swap, LODs, instancing setup
    • Out: Asset creation (E37)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item.

    Acceptance criteria

    • AC-1 integration Given the dressed region, when all E25 route replays run, then they pass unchanged.
    • AC-2 perf Given the densest forest view, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).
    • AC-3 perf Given the same view on Low, when measured, then p95 <= 16.7 ms at 1080p on the Low preset on an Intel Iris Xe / base M1 8 GB class machine, with p99 <= 33.3 ms (30 fps floor) during worst-case combat (edge: foliage density scales by preset).

    Waits on

    • mw-e25.17 Author class routes and ability-gated shortcuts across the wilderness open
    • mw-e25.7 Place the Hollow Sentinels and goblin lookout with class resolutions open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.14 Legibility kit: visual cues for every exploitable world property open
    • mw-e37.250 Integrate approved Briarwood and Mooring's Watch concepts open
    • mw-e37.270 Integrate approved Briarwood and Mooring's Watch tileables open
    • mw-e37.306 Integrate approved wilderness props open
    • mw-e37.352 Integrate approved world prop gap-fill open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artepic:e25milestone:m3
  • mw-e25.20Light and score the wilderness for day, night and still nightsblockedP1M3feature

    Description

    Why

    The wolves' silence and the song on still nights are sound-design beats.

    What

    As a player, I want the forest to sound alive by day and wrong by night so that dread builds before the dungeon.

    Lighting per phase with moonlight and fog; ambience beds (forest day, forest night without wolf howls, millpond water, tower wind); music cues for Briarwood explore and Mooring's Watch; fireflies and fog volumes.

    Scope

    • In: Lighting, ambience zones, music bindings, environment FX placement
    • Out: Audio assets (E38)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item. Related: e28-ambience, e28-reverb-zones and e29-environment-fx are P2 in the combat plan; bind ambience beds, reverb zones and fog/firefly FX here when they land, otherwise ship lighting + music only.

    Acceptance criteria

    • AC-1 integration Given night in the Briarwood, when wolf vocal cues are queried, then no howl cue is playable while fact breach.sealed is false.
    • AC-2 integration Given the player enters Mooring's Watch, when crossing the trigger, then the music crossfades to the tower cue within 3 s.
    • AC-3 perf Given night with moonlight, lanterns and any bound environment FX, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent) (edge: FX within budget).

    Waits on

    • mw-e25.19 Art-dress the Briarwood and Mooring's Watch with final assets open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e37.282 Integrate approved location skies and backdrops open
    • mw-e38.112 Integrate approved wilderness music families into adaptive music open
    • mw-e38.136 Integrate approved Briar Glen and wilderness ambience open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:audioepic:e25milestone:m3
  • mw-e25.23Link the Miners' Bridge to the boarded mine gateopenP1M3task

    Description

    Planned world-map edge miners-bridge (mw-e24.1): the bridge past the Bridge Watch post leads across the Wend to the Deepworks gate exterior (E25 owns the exterior, mw-e25.10 builds the gate).

    Acceptance criteria

    AC-1 integration Given the player at the town end of the bridge, when they cross it, then the mine gate exterior scene loads. AC-2 content edge miners-bridge lists its transitions in world:connectivity.

    area:contentepic:e25milestone:m3
  • mw-e25.24Link the riverbank under the bridge to Briar Glen Quay and the towpathopenP1M3task

    Description

    Planned world-map edges under-the-bridge-quay, quay-millweir, millweir-kestrel-lock (mw-e24.1): the riverbank path from under-the-bridge continues downriver to the quay, the Millweir and the towpath to Kestrel Lock.

    Acceptance criteria

    AC-1 integration Given the player under the bridge, when they follow the riverbank, then the quay loads, and the towpath leads on to the Millweir and Kestrel Lock. AC-2 content the edges list their transitions.

    area:contentepic:e25milestone:m3
  • mw-e25.3Place the Standing Horn menhir and its readable inscriptionblockedP2M3feature

    Description

    Why

    Statues speak through posture; the menhir teaches the Hornfolk visual language early.

    What

    As a player, I want a Hornfolk stone with hands over its ears so that I start to understand the people who built the Knot.

    Clearing with the menhir (hands over ears), an inscription band readable in part by any class and fully by a sorcerer holding Hornfolk fragments (reveals the first rule of the Knot), a hidden horn-coin under a root, and a quiet spot where the song is audible at night (hint of what is below).

    Scope

    • In: Menhir placement, inscription readable with conditions, hidden coin, night audio emitter
    • Out: Inscription text (e39-books-lore)

    Notes

    Resolves rumour 12.

    Acceptance criteria

    • AC-1 integration Given a sorcerer with the Hornfolk fragment item, when reading, then the full inscription shows and lore.knot.rule1 is set.
    • AC-2 integration Given a non-sorcerer, when reading, then a partial translation shows and no fact is set (edge).
    • AC-3 integration Given the player reaches the clearing, when entered, then rumour 12 resolves.

    Waits on

    • mw-e07.5 Translate books written in unknown languages open
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    area:contentepic:e25milestone:m3
  • mw-e25.18Place wilderness and river secrets, lore caches and treasureblockedP2M3feature

    Description

    Why

    The world rewards curiosity: a hollow tree, a drowned cart, a goblin stash.

    What

    As a curious player, I want hidden things in the Briarwood and the tower so that detours pay.

    Placement: Tansy's hair ribbon on the mine rail, the keeper's log pages, a goblin stash in a hollow oak, a drowned cart in the lane, a Juniper snare cache, a spellbook page in the woodcutter's hut, Mags' split-plank horn-coin at the quay, the Kestrel Lock toll board, a lost cargo crate in the lock chamber, and 8–12 small treasures.

    Scope

    • In: Placements, discovery rules, facts
    • Out: Text (e39-books-lore, e39-item-creature-text)

    Notes

    Use e18 treasure density guidance.

    Acceptance criteria

    • AC-1 content Given the wilderness scenes, when audited, then every "interesting-looking" landmark tag has >= 1 placed discovery.
    • AC-2 integration Given Tansy's ribbon picked up, when inspected, then its item text matches e39 text ids.
    • AC-3 integration Given a cache looted, when saved and reloaded, then it remains empty (edge).

    Waits on

    • mw-e18.5 Support designer-placed and hidden treasure with discovery rules open
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e25.6 Block out Mooring's Watch: courtyard, tower floors, roof and tunnel done
    area:contentepic:e25milestone:m3
  • mw-e25.26Enforce a data-level fire-spread cap for bramble walls (both leaves burning, 12 m)openP2M3task

    Description

    mw-e25.1 AC-2 (PR #413) caps Briarwood fire spread only through firebreak layout, tested with one torched gate leaf. Add a data-level spread cap (e.g. per-scene or per-material max spread radius from ignition origin) and an integration test with both leaves of a bramble gate burning and wind/adjacent flammables, proving nothing ignites beyond 12 m.

    area:contentepic:e25milestone:m3

M4 Fun validation 1

  • mw-e25.21Perf-pass and playtest the wilderness on both presetsblockedP1M4task

    Description

    Why

    Foliage-heavy scenes are the classic browser perf trap.

    What

    Perf suite runs over Briarwood, Mooring's Watch, the quay, the Adit and Kestrel Lock on reference and low-tier machines; a 5-tester navigation playtest (can they find the tower, the den and the mine gate without a map?). Findings and beads in docs/playtests/wilderness.md.

    Scope

    • In: Perf captures and fixes, playtest, findings
    • Out: Global perf work (E32)

    Notes

    Related: e32-reference-runbook.

    Acceptance criteria

    • AC-1 perf Given the densest Briarwood view, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).
    • AC-2 perf Given a wolf fight near fire on Low, when measured, then p95 <= 16.7 ms at 1080p on the Low preset on an Intel Iris Xe / base M1 8 GB class machine, with p99 <= 33.3 ms (30 fps floor) during worst-case combat.
    • AC-3 manual Given 5 testers, when asked to reach Mooring's Watch and the mine gate, then >= 4 do so within 15 minutes without help.

    Waits on

    • mw-e25.16 Art-dress, light and score the River Wend locations open
    • mw-e25.20 Light and score the wilderness for day, night and still nights open
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    • mw-e32.6 Implement Low/High graphics presets and dynamic resolution open
    area:perfepic:e25milestone:m4
E26First DungeonOne exceptional multi-route dungeon network — the Deepworks mine, Bellwater Priory and the Knot labyrinth (Outer Ring, Ossuary Galleries, Chapel of Echoes, the Fold, Horn's Hall, Sounding Shaft, the Cradle) — combining combat, stealth, the six MVP puzzles, creatures and secrets, ending in the Sounding Shaft climb and the ringing of the Vesper Bell, with level states for all four endings.5/28 done · 18%

M3 MVP content 21

  • mw-e26.3Populate the Deepworks: goblin camp, miner Forgotten, mine hazardsblockedP1M3feature

    Description

    Why

    The goblin camp can be fought, sneaked through or talked to — the space must support all three.

    What

    As a player, I want a goblin camp with lookouts, alarms and side passages so that I choose between talking, sneaking and fighting.

    Camp layout (Kettleback's kettle throne, Duggan's crate, hammocks incl. Snig's with the primer, alarm pots), patrols, lookouts; miner Forgotten hauling stone below; systemic objects: oil lamps, mine carts (pushable, ride-able downhill), rotten supports (breakable collapse), spilled lamp-oil channels (flammable liquid), the sleepwalker scrawl "it's so pretty down here".

    Scope

    • In: Creature placement and patrols, props with material presets, alarm devices, side passages
    • Out: Social behaviour (E14)
    • Out: Goblin combat (e13-rootcellar-goblins)

    Notes

    Goblin rumours 10–11 are sourced here. Related: e03-gas-clouds (P2) — if it lands, add a firedamp pocket that explodes on ignition.

    Acceptance criteria

    • AC-1 integration Given a thief entering via the side vent at night, when the stealth replay runs, then Duggan's crate is reachable without any goblin reaching Alerted.
    • AC-2 integration Given a spilled lamp-oil channel under a rotten support, when any heat source ignites the oil, then the fire spreads along the channel and the burnt support collapses.
    • AC-3 integration Given a mine cart pushed downhill into goblins, when it hits, then knockback applies via physics impulse (not scripted).
    • AC-4 integration Given every alarm pot is destroyed beforehand, when the camp is alerted, then goblins fall back to shouting (edge: alarm degraded, not broken).

    Waits on

    • mw-e03.13 Support hanging objects on ropes that burn, cut or snap done
    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e13.4 Add monk Forgotten and habit routines that ignore quiet players open
    • mw-e13.6 Add Rootcellar goblin combatants: slings, nets and loud alarms open
    • mw-e14.2 Make the Rootcellar clan talkable, bribable and forgiving of capture open
    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    area:contentepic:e26milestone:m3
  • mw-e26.4Build Vane's sealed gallery, the ledger and the sealable breachblockedP1M3feature

    Description

    Why

    The gallery holds the proof of Vane's lie; sealing the breach is the best outcome's key act.

    What

    As a player, I want to find Vane's ledger and the horn-ring and seal the breach so that I can expose him and restore the Knot's sentence.

    Sealed gallery door (Vane key, pick, smash), gallery 9 carvings with pry marks, the Deepworks Ledger, the horn-ring pried from a carving, the breach. Sealing options (fact breach.sealed): collapse Vane's tunnel (break supports / Thunderclap), freeze and shore (frozen + timber), or goblins wall it (goblins.hired.breach).

    Scope

    • In: Gallery scene content, ledger and horn-ring items, three sealing routes
    • Out: Framed in Brass quest (e39-side-quests-wilds)

    Notes

    Sealing should be possible only after horn.befriended (Help path) or explicitly allowed earlier with a warning — decide in e26-dungeon-layout.

    Acceptance criteria

    • AC-1 integration Given the supports broken by any force above threshold, when collapsed, then breach.sealed is set and the breach navmesh link is removed.
    • AC-2 integration Given goblins.hired.breach, when the player returns, then the wall is built and breach.sealed is set.
    • AC-3 integration Given the player is inside the breach when it collapses, when resolved, then they are pushed to the gallery side, never trapped (edge).

    Waits on

    • mw-e03.11 Break fragile objects and smash weakened walls into debris done
    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e14.3 Bring Mother Kettleback to life: trade, Duggan crate and carrying fees open
    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    area:contentepic:e26milestone:m3
  • mw-e26.6Place the Watchers statue puzzle in the priory choirblockedP1M3feature

    Description

    Why

    Statues that do something; the choir puzzle reveals the pact and the Sounding Shaft.

    What

    As a player, I want to turn the singing-monk statues to face the altar so that the choir reveals its secrets.

    Watchers puzzle from e15-reference-puzzles-b placed in the choir (rotate, levitate-rotate, or topple one — the destructive solution), rewarding the pact scroll and the abbot's letters cache. The hidden choir door (revealed by the signal mirror, or lever from inside) is a second entry.

    Scope

    • In: Puzzle instance, rewards, hidden door states
    • Out: Puzzle mechanics (e15-reference-puzzles-b)
    • Out: Mirror (e25-signal-mirror)

    Notes

    One of the six MVP puzzles.

    Acceptance criteria

    • AC-1 content Given the placed puzzle, when the solvability validator runs, then >= 2 distinct solutions pass and >= 3 classes can solve it.
    • AC-2 integration Given a statue is toppled, when evaluated, then the puzzle remains solvable and no softlock is reported (edge).
    • AC-3 integration Given priory.choirDoor.revealed, when the choir is approached from the garden, then the hidden door is open.

    Waits on

    • mw-e15.10 Build greybox reference puzzles for statues, darkness and sound done
    • mw-e25.8 Turn the signal mirror to light the priory's hidden choir door open
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    area:contentepic:e26milestone:m3
  • mw-e26.7Build the scriptorium with book mimics, tallow ooze and abbot lettersblockedP1M3feature

    Description

    Why

    A library that bites: surviving pages, mimics and wax — and fire is both weapon and risk.

    What

    As a sorcerer, I want a ruined scriptorium full of pages, candles and dangers so that curiosity is rewarded and punished.

    Book mimics among real shelves; Tallow Ooze in the candle store; the abbot's letters fragments; loose lore and spellbook pages; flammable paper everywhere (fire spreads fast here — burning the room destroys loot).

    Scope

    • In: Creature and item placement, flammable density design, page placements
    • Out: Mimic and ooze behaviour (E13)
    • Out: Letter text (e39-books-lore)

    Notes

    Fire destroying lore is a valid, story-creating failure; key lore has a second copy elsewhere. Related: e07-damaged-books (P2) — if it lands, some pages become missing pages of damaged books.

    Acceptance criteria

    • AC-1 integration Given a fire started in the scriptorium, when it burns out, then destroyed pages are recorded as facts and each key lore item has a surviving alternate source.
    • AC-2 integration Given a book mimic, when the player feeds it a paper item, then it pacifies and yields a page.
    • AC-3 integration Given the ooze melted by fire, when its puddle ignites, then fire spreads to adjacent flammable shelves (edge: systemic chain).

    Waits on

    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e13.10 Add Tallow Ooze that melts into fire puddles and shatters when frozen open
    • mw-e13.11 Add book, lectern and chest mimics with tells and feeding open
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    area:contentepic:e26milestone:m3
  • mw-e26.8Build the belfry and the sour-bell consequence of early ringingblockedP1M3feature

    Description

    Why

    Ringing the bell without its tongue should create a story, not a no-op.

    What

    As a player, I want to be able to strike the cracked bell early so that I face the consequence and meet Horn.

    Belfry climb, bell frame, bell ropes. Striking the tongueless bell with any heavy impact or loud force (hammer, mace, arrow, Thunderclap) plays a sour note: wakes every Forgotten in the priory, +1 song intensity for 5 minutes, Hushlings rise up the shaft, and Horn comes toward the sound (horn.heardBell).

    Scope

    • In: Belfry content, bell impact detection by force/noise, consequence wiring
    • Out: The finale ring (e26-vesper-bell-finale)

    Notes

    This is a "failure creates stories" beat and a Horn-meeting route.

    Acceptance criteria

    • AC-1 integration Given the tongueless bell struck by any impact >= threshold, when resolved, then a sour-bell event fires and every priory Forgotten enters Searching.
    • AC-2 integration Given the sour bell, when evaluated, then song.intensity rises by 1 for 300 s and horn.heardBell is set.
    • AC-3 integration Given the bell struck repeatedly, when evaluated, then consequences apply once per 300 s window (edge: no stacking exploit).

    Waits on

    • mw-e03.25 Emit noise events from world interactions with material loudness done
    • mw-e13.4 Add monk Forgotten and habit routines that ignore quiet players open
    • mw-e13.5 Drive creature behaviour from a global song-intensity world state open
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    area:contentepic:e26milestone:m3
  • mw-e26.11Make the Knot loop unless you follow its runesblockedP1M3feature

    Description

    Why

    The first rule of the Knot — followed runes lead somewhere; ignored runes lead in circles — is the labyrinth's identity.

    What

    As a player, I want the labyrinth to quietly loop me back when I ignore the runes so that reading the walls becomes the way through.

    Loop junctions: data-driven portal-free loops (corridor segments that reconnect) plus conditional junction doors that route by whether the player followed the rune sequence (tracked per junction). Loom-spider webs copying runes act as clues. Goblins pass freely (cannot read, never caught). Chalk marks from the "friend below" help early.

    Scope

    • In: Junction state logic, rune sequence data, web clue placements, chalk mark placements
    • Out: Rune text/art (E37/E39)

    Notes

    Must never feel like a bug: loops show a recurring landmark (a specific carved face) so players notice.

    Acceptance criteria

    • AC-1 unit Given a junction expecting rune "horn-left" and the player takes the unmarked path, when crossing, then they are routed back to the loop start landmark.
    • AC-2 integration Given the player follows the rune sequence through 3 junctions, when completed, then they reach the Ossuary entrance.
    • AC-3 integration Given the player loops 3 times at one junction, when evaluated, then a diegetic hint (a web clue lit, a chalk mark) appears (edge: anti-frustration).

    Waits on

    • mw-e03.21 Wire trigger volumes and mechanisms with data-defined signal graphs done
    • mw-e13.7 Add Loom Spiders that weave readable webs and fear bright light open
    • mw-e26.9 Block out the Knot's Outer Ring, Ossuary Galleries and Chapel done
    area:contentepic:e26milestone:m3
  • mw-e26.12Populate the Outer Ring: spiders, first Forgotten, Horn sightingblockedP1M3feature

    Description

    Why

    Act II's first steps into the Knot must introduce its creatures and the warden at a distance.

    What

    As a player, I want my first minutes in the Knot to introduce spiders, the Forgotten and a glimpse of the minotaur so that I feel watched and curious.

    Loom spider nests with web routes, the first sweeping Forgotten, a scripted distant sighting of Horn dragging a wrapped figure across a gallery, "friend below" notes and chalk arrows (genuinely helpful), systemic lights (braziers for scaring spiders).

    Scope

    • In: Creature placement, sighting trigger, notes and chalk placement, braziers
    • Out: Note text (e39-dialogue-abbot)

    Notes

    The sighting must not be interactable at range (Horn exits before the player can reach him).

    Acceptance criteria

    • AC-1 integration Given the player crosses the sighting trigger, when fired, then Horn crosses the far gallery and exits within 8 s and fact horn.sighted is set.
    • AC-2 integration Given a brazier lit near a spider nest, when light exceeds 0.7, then the nest's spiders flee and the web route can be burned.
    • AC-3 integration Given the player shoots at Horn during the sighting, when hit, then he does not engage and still exits (edge).

    Waits on

    • mw-e13.13 Add Brother Horn's creature data: charges, grabs and throws to stop open
    • mw-e13.4 Add monk Forgotten and habit routines that ignore quiet players open
    • mw-e13.7 Add Loom Spiders that weave readable webs and fear bright light open
    • mw-e26.11 Make the Knot loop unless you follow its runes open
    area:contentepic:e26milestone:m3
  • mw-e26.13Populate the Ossuary: Forgotten habits, Clatter's garden, the psalterblockedP1M3feature

    Description

    Why

    Among the skeletons, one keeps apologising — the Ossuary is where the game's warmest quest begins.

    What

    As a player, I want galleries of praying and sweeping dead and one who remembers so that I learn the dead were people.

    Monk and miner Forgotten on habit routines, bone piles for scatter/burn tactics, Clatter tending pale mushrooms in the "flower room", his psalter hidden among the niches, the Dark Crossing pit (placed in e26-dungeon-puzzles), holy-water font (consecrated).

    Scope

    • In: Creature/habit placement, Clatter spawn, psalter item, font, bone piles
    • Out: Clatter logic (e14-clatter)

    Notes

    Resolves rumour 11.

    Acceptance criteria

    • AC-1 integration Given a crouched player humming the hymn, when crossing the Ossuary, then no Forgotten enters Combat at song intensity <= 2.
    • AC-2 integration Given the psalter picked up, when inspected, then clatter.piece.psalter is set.
    • AC-3 integration Given Clatter killed accidentally while hostile, when evaluated, then he reassembles unless bones burned, and the quest records clatter.harmed (edge).

    Waits on

    • mw-e13.3 Forgotten crumble and reassemble unless bones are scattered or burned open
    • mw-e14.5 Build Clatter: the apologetic skeleton who can remember his name open
    • mw-e26.9 Block out the Knot's Outer Ring, Ossuary Galleries and Chapel done
    area:contentepic:e26milestone:m3
  • mw-e26.14Build the Chapel of Echoes with the Chimes puzzle and portcullis trapblockedP1M3feature

    Description

    Why

    Sound misbehaves here: the chapel is the sound puzzle, a Hushling hunting ground and a Horn trap.

    What

    As a player, I want a chapel where echoes carry and misdirect so that sound becomes both clue and danger.

    Chimes puzzle (e15-reference-puzzles-b) placed: reproduce a chime order heard behind a wall, shoot bells from the balcony, or read the order in a book. Acoustic trick: noise from certain points is re-emitted at mirror points (misdirects hunters). Hushlings patrol. Portcullis trap: lure Horn under it and drop it (horn.trapped) — the archer's single-shot resolution.

    Scope

    • In: Puzzle instance, echo emitters, Hushling placement, portcullis trap state
    • Out: Echo propagation engine changes (E09) — use noise re-emitters only

    Notes

    One of the six MVP puzzles.

    Acceptance criteria

    • AC-1 content Given the Chimes instance, when validated, then >= 2 solutions pass and >= 3 classes can solve it.
    • AC-2 integration Given a noise at an echo point, when propagated, then a copy is emitted at the mirror point and Hushlings investigate the mirror point.
    • AC-3 integration Given Horn pursuing the player under the portcullis, when it drops, then horn.trapped is set and Horn cannot reach the Fold side.
    • AC-4 integration Given the portcullis dropped with no one under it, when evaluated, then a winch on the far side can raise it (edge: no softlock).

    Waits on

    • mw-e13.14 Build the Warden boss encounter with yield, spare and Trial of Horns open
    • mw-e13.9 Add blind Hushlings that hunt by sound and break at loud noises open
    • mw-e15.10 Build greybox reference puzzles for statues, darkness and sound done
    • mw-e26.9 Block out the Knot's Outer Ring, Ossuary Galleries and Chapel done
    area:contentepic:e26milestone:m3
  • mw-e26.15Place the Frozen Channel, Sunbeam, Scales and Dark Crossing puzzlesopenP1M3feature

    Description

    Why

    The MVP needs ~6 meaningful puzzles built from world systems; four are placed here (Watchers and Chimes in their rooms).

    What

    As a player, I want dungeon puzzles that use light, ice, weight and darkness so that the systems I have learned open the way.

    Place from e15 references: Frozen Channel (Deepworks flooded gallery), Sunbeam (priory crypt stair, light down to a sensor), Scales (Outer Ring Hornfolk gate — crates, bodies, ice blocks), Dark Crossing (Ossuary pit — torches, light spell, braziers or smoke drafts). Each rethemed to its area with area props.

    Scope

    • In: 4 puzzle instances, retheming, solution replays, softlock policies
    • Out: Puzzle kit (E15)

    Notes

    Zero new TypeScript: engine gaps become E03/E15 beads.

    Acceptance criteria

    • AC-1 content Given the 4 instances, when the solvability validator runs, then each has >= 2 distinct solutions.
    • AC-2 integration Given e15-solution-audit, when run, then each is solvable by >= 3 classes at MVP capability levels.
    • AC-3 integration Given each declared solution, when its replay runs, then the puzzle reaches solved.
    • AC-4 integration Given the Scales gate solved with an ice block that later melts, when evaluated, then the gate stays open (edge: one-shot).

    Waits on

    • mw-e15.10 Build greybox reference puzzles for statues, darkness and sound done
    • mw-e15.8 Report and enforce per-class solution coverage for puzzles in CI done
    • mw-e15.9 Build greybox reference puzzles for light, freezing and weight done
    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    • mw-e26.9 Block out the Knot's Outer Ring, Ossuary Galleries and Chapel done
    area:contentepic:e26milestone:m3
  • mw-e26.16Stage Horn's Hall and the Fold, the reveal and the wake-up pointblockedP1M3feature

    Description

    Why

    The reveal lands visually before anyone explains it: the missing asleep on moss beds, bread at their sides.

    What

    As a player, I want to enter the Fold and see the sleepers safe so that I understand Horn before he says a word.

    Horn's Hall arena (pillars, bronze-wired horn racks, Horn's resting spot for the "rests one eye" trick), the Fold door (horn-key on Horn's belt; pickpocketable), the Fold: seven moss beds (six missing + Tansy after night 1), goblin bread, chalk tallies (sleepers and the player's rescues). Respawn rules: death in the Knot wakes here (horn alive); variants: goblin camp (Horn dead, goblins friendly), Forgotten laying-out (hostile goblins).

    Scope

    • In: Hall arena, Fold scene, sleeper placements, tallies updating from facts, respawn rules content
    • Out: Horn encounter (e13-horn-encounter)
    • Out: Sleeper wake-up (e26-vesper-bell-finale)

    Notes

    Chalk tallies read rescues.byHorn.

    Acceptance criteria

    • AC-1 integration Given the player enters the Fold, when inside, then all seven sleepers are present on beds and fact fold.seen is set.
    • AC-2 integration Given the player dies in the Knot with horn alive, when resolved, then they wake on a Fold moss bed and the tally shows one more mark.
    • AC-3 integration Given horn.killed and goblins Hostile, when the player dies in the Knot, then they wake among the Forgotten in the Ossuary laying-out niche (edge).
    • AC-4 integration Given the horn-key is pickpocketed while Horn rests, when used, then the Fold opens without combat.

    Waits on

    • mw-e01.12 Wake in context after death instead of reloading open
    • mw-e10.8 Pickpocket and plant items on creatures from behind open
    • mw-e13.14 Build the Warden boss encounter with yield, spare and Trial of Horns open
    • mw-e26.10 Block out the Fold, Horn's Hall, Sounding Shaft foot and the Cradle done
    area:contentepic:e26milestone:m3
  • mw-e26.17Stage the Cradle arena for the abbot confrontationblockedP1M3feature

    Description

    Why

    The heart of the Knot, where the dream leaks into the physical, is the final stage.

    What

    As a player, I want a round chamber that bends toward its centre so that the finale feels dreamlike.

    Place the four anchor lanterns (shootable, extinguishable), Hushling emergence points, Forgotten stirring positions, Tansy hostage position, Clatter's entrance, cover pillars, a balcony ring (archer), shadowed alcoves (thief), and the sorcerer's secret route arrival. Dream-leak zones (low gravity puddles / drifting objects) as world-property volumes.

    Scope

    • In: Arena placement, anchor lanterns, spawn points, dream-leak volumes
    • Out: Abbot encounter logic (e13-abbot-encounter)

    Notes

    Dream-leak volumes use existing gravity/force properties only.

    Acceptance criteria

    • AC-1 integration Given the four anchor lanterns, when each is extinguished by any means, then the abbot's max health drops by 25%.
    • AC-2 integration Given each class's Cradle replay, when run, then the encounter can be resolved by at least one path per class.
    • AC-3 integration Given all lanterns destroyed before the abbot appears, when the encounter begins, then he relights one lantern (edge: encounter cannot be trivially skipped).
    • AC-4 perf Given the Cradle fight with 4 Hushlings, 4 Forgotten and dream VFX, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent) and p95 <= 16.7 ms at 1080p on the Low preset on an Intel Iris Xe / base M1 8 GB class machine, with p99 <= 33.3 ms (30 fps floor) during worst-case combat.

    Waits on

    • mw-e13.16 Build the Cradle encounter with fight, trick, persuade and join paths open
    • mw-e26.10 Block out the Fold, Horn's Hall, Sounding Shaft foot and the Cradle done
    area:contentepic:e26milestone:m3
  • mw-e26.18Build the Sounding Shaft climb with defenders and chase variantsblockedP1M3feature

    Description

    Why

    With the tongue recovered, the bell must ring: a vertical ascent with the song rising behind.

    What

    As a player, I want to climb from the Cradle to the belfry on ropes, counterweights and old bell-ropes so that the finale is a set piece.

    Shaft interior: ledges, bell-rope climbs, counterweight lifts, a collapsing stair section. Variants by facts: Horn holds the foot (horn alive and healed/befriended); goblins or Clatter hold it; knight holds while restored Clatter climbs (sacrifice beat); nobody → chase with Hushlings climbing. Archer shortcut: rope line skips half the climb.

    Scope

    • In: Shaft scene, climb routes, defender variants, chase spawner, archer shortcut
    • Out: Ally behaviours (e14-horn-befriend-help)

    Notes

    Falling during the chase drops the player to the last ledge checkpoint, not the bottom (anti-frustration).

    Acceptance criteria

    • AC-1 integration Given no defender facts, when the climb begins, then Hushlings spawn below and climb at 80% of player climb speed.
    • AC-2 integration Given an archer fires a rope arrow into the marked beam, when climbed, then half the shaft is skipped.
    • AC-3 integration Given the player falls mid-climb, when they land, then they respawn on the last ledge checkpoint with the chase paused 3 s (edge).
    • AC-4 integration Given the knight-hold variant, when chosen, then the player fights at the foot until the bell rings and Clatter completes the climb.

    Waits on

    • mw-e05.10 Rope arrows anchor into wood and create climbable ropes open
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e14.6 Befriend and help Brother Horn without fighting open
    • mw-e26.10 Block out the Fold, Horn's Hall, Sounding Shaft foot and the Cradle done
    • mw-e26.8 Build the belfry and the sour-bell consequence of early ringing open
    area:contentepic:e26milestone:m3
  • mw-e26.19Ring the Vesper Bell: hang the tongue, mend it and wake the sleepersblockedP1M3feature

    Description

    Why

    The solution is a lullaby. Ringing the cracked bell — wrong and beautiful — is the climax.

    What

    As a player, I want to hang the bronze tongue and ring the bell so that the Nightjar sleeps and the missing wake.

    Belfry finale: hang tongue (or Oswin's recast), optional mend first (Frostglass/Alteration-class property effect sets bell.mended for a truer note), ring. Song falters (song.intensity → 0), Hushlings dissolve, the Fold sleepers wake (sleepers.woken), Tansy asks who you are. Sets vespers.rung.

    Scope

    • In: Tongue hang interaction, mend option, ring sequence, facts, dissolve/wake hooks
    • Out: Endings text (e39-intro-endings-text)
    • Out: Ending level states (e26-ending-states)

    Notes

    Mend is systemic: any freeze or alteration effect applied to the crack entity counts.

    Acceptance criteria

    • AC-1 integration Given the tongue hung, when the bell is rung, then vespers.rung is set, song.intensity becomes 0 and all Hushlings dissolve.
    • AC-2 integration Given bell.mended before ringing, when rung, then the truer-note variant plays and fact bell.trueNote is set.
    • AC-3 integration Given the tongue was destroyed and no recast exists, when the belfry is reached, then Oswin's recast path is signposted (edge: never unwinnable).

    Waits on

    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e13.5 Drive creature behaviour from a global song-intensity world state open
    • mw-e26.18 Build the Sounding Shaft climb with defenders and chase variants open
    • mw-e26.8 Build the belfry and the sour-bell consequence of early ringing open
    area:contentepic:e26milestone:m3
  • mw-e26.20Wire dungeon shortcuts: crypt, cistern, cage lift and one-way doorsblockedP1M3feature

    Description

    Why

    Every loop is a shortcut the player can open; the dungeon should fold back on itself.

    What

    As a player, I want to open doors from the far side and ride lifts back up so that returning to earlier areas is fast.

    Shortcuts: crypt passage Knot ↔ priory (Horn opens, or pry from below), cistern ↔ priory (gate from the priory side), winch cage mine top ↔ bottom, supply-tunnel arrival ↔ goblin hall, Outer Ring ↔ Deepworks breach bypass. One-way doors with a visible "barred on this side" state.

    Scope

    • In: Shortcut doors/lifts, facts, connectivity updates
    • Out: Transition engine (e01-area-transitions)

    Notes

    Each shortcut fact persists and shows on the world map notes.

    Acceptance criteria

    • AC-1 integration Given a one-way door approached from the locked side, when interacted, then it shows the barred state and does not open.
    • AC-2 integration Given each shortcut opened, when saved and reloaded, then it remains open.
    • AC-3 integration Given the cage lift at the bottom and the player at the top, when the call lever is used, then the cage returns (edge: never stranded).

    Waits on

    • mw-e14.6 Befriend and help Brother Horn without fighting open
    • mw-e26.10 Block out the Fold, Horn's Hall, Sounding Shaft foot and the Cradle done
    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    area:contentepic:e26milestone:m3
  • mw-e26.21Author first-pass class routes through every dungeon areablockedP1M3feature

    Description

    Why

    The knight forces, the thief infiltrates, the archer manipulates distant mechanisms, the sorcerer alters the dungeon.

    What

    As a player of any class, I want each dungeon area to offer my class a route so that the Labyrinth plays differently for me.

    Per area: knight (weak walls, heavy doors, holding chokepoints), archer (distant mechanisms, open-chamber dominance, rope anchors), sorcerer (freeze/levitate/blink/illusion affordances), thief (vents, crawlspaces, hidden passages, dark routes). Registry entries and replays.

    Scope

    • In: Route affordances across mine/priory/Knot, registry entries, replays
    • Out: Gap closing after audit (e16-gap-pass-dungeon)

    Notes

    Every thief hidden passage should be discoverable by others too (with effort) — secrets are for everyone.

    Acceptance criteria

    • AC-1 content Given the registry, when validated, then every E26 mandatory obstacle has >= 3 class routes declared.
    • AC-2 integration Given each declared route, when replayed, then the obstacle exit fact is set.
    • AC-3 integration Given a thief hidden passage, when a non-thief searches the wall, then it can be found with a light or search action (edge).

    Waits on

    • mw-e16.2 Declare obstacles and class routes as validated content data open
    • mw-e26.13 Populate the Ossuary: Forgotten habits, Clatter's garden, the psalter open
    • mw-e26.14 Build the Chapel of Echoes with the Chimes puzzle and portcullis trap open
    • mw-e26.16 Stage Horn's Hall and the Fold, the reveal and the wake-up point open
    • mw-e26.3 Populate the Deepworks: goblin camp, miner Forgotten, mine hazards open
    area:contentclass:allepic:e26milestone:m3
  • mw-e26.23Build the four endings' level states across town and dungeonblockedP1M3feature

    Description

    Why

    Endings are assembled from world facts; the world itself should show the ending.

    What

    As a player, I want the world to visibly change after my ending so that my choices feel real.

    Fact-gated variants (e27-world-variants): Vespers Rung (bell rung each dusk by goblins/Hale/Tansy, bread at the mine gate, wolves howl again if breach sealed); The Last Warden (Horn's absence, goblin watch or Clatter humming, lantern and footprints at the gate); The Hireling's Silence (mine reopened, Vane prosperous, sleepwalker sitting up); The Long Vespers (sleeping valley, goblin with a stick in the Cradle).

    Scope

    • In: Variant entity sets per ending in town, gate, Fold, Cradle; epilogue camera anchors
    • Out: Ending logic and text (e39-main-quest-data, e39-intro-endings-text)

    Notes

    Epilogue slides are text over these level states.

    Acceptance criteria

    • AC-1 integration Given the facts for each ending, when the town and gate load, then the matching variant set is active and no other ending's variants are.
    • AC-2 integration Given breach.sealed with Vespers Rung, when night falls in the Briarwood, then wolf howls resume.
    • AC-3 integration Given contradictory facts (horn.killed and horn.befriended), when evaluated, then killed takes precedence and a content warning is logged (edge).

    Waits on

    • mw-e26.19 Ring the Vesper Bell: hang the tongue, mend it and wake the sleepers open
    • mw-e27.8 Spawn fact-gated entity variants so the world reacts to choices done
    • mw-e39.4 Script the main quest graph with four endings as quest data done
    area:contentepic:e26milestone:m3
  • mw-e26.24Art-dress the Deepworks and Bellwater Priory with final assetsblockedP1M3feature

    Description

    Why

    Timbered galleries and a roofless nave must read instantly as different places.

    What

    As a player, I want the mine and the priory to look like the story bible so that each layer of the dungeon has its own identity.

    Swap grey-box for mine kit (pale cut-glenstone galleries, timber supports, rails, block carts, frost-bright silver seams, goblin junk) and priory kit (Vesperine stone, singing statues, bell); keep gameplay ids and collision.

    Scope

    • In: Art swap for Deepworks and priory scenes, LODs, decals
    • Out: Asset creation (E37)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item.

    Acceptance criteria

    • AC-1 integration Given the dressed scenes, when all E26 route and puzzle replays in these areas run, then they pass unchanged.
    • AC-2 perf Given the goblin hall and the nave, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).
    • AC-3 manual Given the art review, when compared to the style bible, then silhouettes of interactables remain readable against dressing (edge).

    Waits on

    • mw-e26.21 Author first-pass class routes through every dungeon area open
    • mw-e26.6 Place the Watchers statue puzzle in the priory choir open
    • mw-e26.7 Build the scriptorium with book mimics, tallow ooze and abbot letters open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.14 Legibility kit: visual cues for every exploitable world property open
    • mw-e37.254 Integrate approved Deepworks and Bellwater Priory concepts open
    • mw-e37.274 Integrate approved Deepworks and priory tileables open
    • mw-e37.310 Integrate approved dungeon props open
    • mw-e37.314 Integrate approved puzzle reskin and ending props open
    • mw-e37.334 Integrate approved Rootcellar goblin camp props open
    • mw-e37.346 Integrate approved set-piece hero props open
    • mw-e37.352 Integrate approved world prop gap-fill open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artepic:e26milestone:m3
  • mw-e26.25Art-dress the Knot with Hornfolk stone, runes and dream visualsblockedP1M3feature

    Description

    Why

    The Knot is a sentence carved as corridors; its art must make runes legible and the Cradle dreamlike.

    What

    As a player, I want the labyrinth's walls to be written in Hornfolk runes and the Cradle to shimmer so that the place feels ancient and alive.

    Hornfolk stone kit, rune band decals (readable, with landmark faces), bone niches, chapel acoustics visuals, Fold moss, Cradle dream-leak shaders.

    Scope

    • In: Art swap for Knot scenes, rune decals, Cradle shaders
    • Out: Asset creation (E37)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item.

    Acceptance criteria

    • AC-1 integration Given the dressed Knot, when rune-navigation tests and all Knot replays run, then they pass unchanged.
    • AC-2 perf Given the Cradle fight with dream shaders, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).
    • AC-3 manual Given 3 testers, when asked to follow runes, then >= 2 identify the rune to follow from art alone (edge: legibility).

    Waits on

    • mw-e26.11 Make the Knot loop unless you follow its runes open
    • mw-e26.17 Stage the Cradle arena for the abbot confrontation open
    • mw-e26.21 Author first-pass class routes through every dungeon area open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.14 Legibility kit: visual cues for every exploitable world property open
    • mw-e37.258 Integrate approved Knot environment concepts open
    • mw-e37.278 Integrate approved Knot tileables and rune bands open
    • mw-e37.310 Integrate approved dungeon props open
    • mw-e37.314 Integrate approved puzzle reskin and ending props open
    • mw-e37.340 Integrate approved Hornfolk and Knot props open
    • mw-e37.430 Integrate approved world and dream VFX open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artepic:e26milestone:m3
  • mw-e26.26Light and score the dungeon: mine, priory, Knot and the finaleblockedP1M3feature

    Description

    Why

    Darkness is a stealth system and a mood; the song must be heard growing.

    What

    As a player, I want each dungeon layer to have its own light and sound so that descending feels like going deeper into a dream.

    Lighting per area (lamps in the mine, moonlight in the priory, rune glow in the Knot), ambience beds (mine drips and creaks, priory wind, Knot hum, Chapel echoes), music cues per area plus the song layer driven by song.intensity, set-piece audio (sour bell, Horn's Hall, Cradle, climb, Vespers ring).

    Scope

    • In: Lighting, ambience zones, reverb zones, music cue bindings, set-piece cue wiring
    • Out: Audio assets (E38)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item. Related: e28-ambience, e28-reverb-zones and e29-environment-fx are P2 in the combat plan; bind ambience beds, reverb zones and fog/firefly FX here when they land, otherwise ship lighting + music only.

    Acceptance criteria

    • AC-1 integration Given song.intensity changes, when evaluated, then the song music layer gain follows within 2 s.
    • AC-2 integration Given the Vespers ring, when triggered, then all other music ducks and the bell cue plays uninterrupted.
    • AC-3 integration Given dungeon lighting, when sampled along each thief route, then at least 40% of each route has light <= 0.3 (edge: stealth remains viable).
    • AC-4 perf Given the Chapel with 3 Hushlings and all area lights, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).

    Waits on

    • mw-e13.5 Drive creature behaviour from a global song-intensity world state open
    • mw-e26.24 Art-dress the Deepworks and Bellwater Priory with final assets open
    • mw-e26.25 Art-dress the Knot with Hornfolk stone, runes and dream visuals open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.116 Integrate approved mine and priory music families into adaptive music open
    • mw-e38.120 Integrate approved Knot, Fold and Cradle music into adaptive music open
    • mw-e38.124 Integrate approved boss, climb and finale music into adaptive music open
    • mw-e38.140 Integrate approved Deepworks, priory and Knot ambience open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:audioepic:e26milestone:m3
  • mw-e26.22Place dungeon secrets, notes, horn-coins and lore booksblockedP2M3feature

    Description

    Why

    Lore is offered, not lectured; the dungeon should reward every detour.

    What

    As a curious player, I want hidden rooms, notes and relics so that I piece together the history myself.

    Place 6–8 "friend below" notes, horn-coins (tiny ox asleep on the back), Hornfolk inscription fragments (sorcerer route), Mooring-era items, damaged spellbook pages, the Ox Beneath the Hill last page, 12–20 treasures per the e18 guide, and one book mimic trap per area.

    Scope

    • In: Placements, discovery rules, facts
    • Out: Text (e39-books-lore, e39-dialogue-abbot)

    Notes

    Three sources that disagree for each big fact (bible §7.1).

    Acceptance criteria

    • AC-1 content Given the dungeon scenes, when audited, then every "friend below" note id from e39 is placed exactly once.
    • AC-2 content Given the big facts (Long Vespers, the minotaur), when audited, then each has >= 3 placed sources (book, object, person).
    • AC-3 integration Given a secret room opened, when saved and reloaded, then it stays open (edge).

    Waits on

    • mw-e18.5 Support designer-placed and hidden treasure with discovery rules open
    • mw-e26.21 Author first-pass class routes through every dungeon area open
    • mw-e39.13 Write in-game books, notes and inscriptions done
    area:contentepic:e26milestone:m3

M4 Fun validation 2

  • mw-e26.27Perf-pass every dungeon area on both presetsblockedP1M4task

    Description

    Why

    The dungeon hosts the heaviest fights and effects; it must hold budgets everywhere.

    What

    Perf suite scenes for the goblin hall, scriptorium fire, Ossuary fight, Chapel, Horn's Hall, Cradle and the climb; captures on reference and low-tier machines; fixes within budget; area load times.

    Scope

    • In: Perf scenes, captures, fixes, report
    • Out: Engine-level perf (E32)

    Notes

    Related: e32-reference-runbook, e32-memory-leak-test.

    Acceptance criteria

    • AC-1 perf Given each listed dungeon perf scene, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).
    • AC-2 perf Given the Cradle fight on Low, when measured, then p95 <= 16.7 ms at 1080p on the Low preset on an Intel Iris Xe / base M1 8 GB class machine, with p99 <= 33.3 ms (30 fps floor) during worst-case combat.
    • AC-3 perf Given warm caches, when transitioning between any two adjacent dungeon areas, then load <= 3 s and heap <= 1.5 GB after 30 transitions (edge).

    Waits on

    • mw-e26.26 Light and score the dungeon: mine, priory, Knot and the finale open
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    • mw-e32.12 Detect memory leaks across repeated scene loads open
    • mw-e32.6 Implement Low/High graphics presets and dynamic resolution open
    area:perfepic:e26milestone:m4
  • mw-e26.28Playtest the full dungeon per class and replay each critical pathblockedP1M4task

    Description

    Why

    The MVP's defining scenario must be completable and memorable for every class.

    What

    Automated critical-path replays per class from the mine gate to "Vespers rung"; one internal playtest per class through the whole dungeon; findings to docs/playtests/dungeon.md with beads.

    Scope

    • In: 4 critical-path replays, 4 playtests, findings
    • Out: External playtests (e35-external-round-1)

    Notes

    Replays must cover two different macro-routes per class across the four runs.

    Acceptance criteria

    • AC-1 e2e Given a save at the mine gate, when each class's critical-path replay runs, then vespers.rung is set with zero console errors.
    • AC-2 manual Given one tester per class, when finished, then each rates the dungeon >= 4/5 for "my class mattered".
    • AC-3 manual Given testers who got stuck > 5 minutes, when observed, then each stuck point has a bead or accepted note (edge).

    Waits on

    • mw-e16.6 Close class-route gaps in the Deepworks, priory and the Knot open
    • mw-e26.23 Build the four endings' level states across town and dungeon open
    • mw-e26.27 Perf-pass every dungeon area on both presets open
    area:qaepic:e26milestone:m4
E27Dynamic World StateMeaningful actions persist: doors opened, walls smashed, ropes burned, chests looted, creatures befriended, treasures stolen, characters helped. A typed, deterministic world-fact store plus per-entity deltas against authored baselines captures the world as the player left it and flows through e30 save serialization. Quests, dialogue, puzzles and level variants all read the same facts.10/16 done · 63%

M1 Grey-box slice 3

  • mw-e27.14Assign stable GUIDs to scene placements and lint orphaned persistent idsopenP1M1task

    Description

    Why

    mw-e27.3 (PR #158) keys authored-entity deltas by placement index (piece:<n>), so reordering placements in a scene orphans their deltas. The bead's notes require GUIDs assigned by the level pipeline and a lint that warns when a persistent entity id disappears.

    What

    Give every scene placement an authored, stable id (GUID) assigned by tooling; switch sceneAuthoredEntities to use it; add a content lint that diffs ids against the previous build and warns on removed persistent ids.

    Acceptance criteria

    AC-1 unit Reordering placements in a scene leaves every authored entity id unchanged.

    AC-2 content Removing a placement that had an id in the committed lock produces a lint warning naming it.

    AC-3 unit Existing piece:<n> deltas migrate to GUID ids via the save migration runner.

    area:simepic:e27milestone:m1
  • mw-e27.15Integration test: burnt rope bridge stays gone across a level round-tripopenP1M1task

    Description

    Why

    mw-e27.3 AC-5 was covered only partially in PR #158 (weak-wall room, scene reload) because the slice has no rope bridge or area transitions yet.

    What

    Once area transitions (mw-e01.11) exist and the greybox slice has a burnable rope bridge, add the integration test: burn the bridge, leave the level, return; bridge still gone and replay hashes match.

    Acceptance criteria

    AC-1 integration Given the greybox slice, when the player burns a rope bridge, leaves the level and returns, then the bridge is still gone and replay hashes match.

    Waits on

    • mw-e01.11 Connect scenes with area transitions and named spawn points done
    area:simepic:e27milestone:m1
  • mw-e27.16Prove world saves on the greybox slice: opened door and looted chest survive a tab closeopenP1M1feature

    Description

    Why

    mw-e27.4 AC-4 asks for the greybox slice, which did not exist when it shipped. Its e2e (e2e/world-saves.spec.ts) plays the testbed instead: the closet door is the door and the floor items (healing draught, closet key) stand in for a chest (owner decision recorded in PR for mw-e27.4).

    What

    As a player, I want a door I opened and a chest I emptied in the slice to stay that way after I save, close the tab and load, so that I trust the game with my progress.

    Port the AC-4 e2e to the slice level once its alcove chest exists (mw-e01.6): open the slice door, loot the chest's container pack, save, close the tab, load. Assert the container delta (inventory.pack emptied) as well as the door.

    Scope

    • In: e2e on the slice with a real container entity; container aspect asserted
    • Out: Save format and sections (done in mw-e27.4); slice save triggers (mw-e01.7)

    Notes

    The loaded level is restored from the world section and its deltas are measured against the fresh baseline; deltas are applied only when a level is entered fresh (no area transitions yet, mw-e01.11).

    Acceptance criteria

    • AC-1 e2e Given the greybox slice, when the player opens the door, loots the alcove chest, saves, closes the browser tab and loads the save, then the door is open and the chest's pack is empty.
    • AC-2 e2e Given the same save, when it is loaded, then #app[data-level-deltas] lists the door and container aspects for the slice level.

    Waits on

    • mw-e01.4 Build the slice grey-box level: room, corridor, arena, loot, exit done
    • mw-e01.6 Add slice loot: skeleton key drop and an alcove chest done
    area:simclass:allepic:e27milestone:m1size:s

M2 Class fantasies 1

  • mw-e27.13Rest at inns, campfires and shrines to reset facts and pass timeopenP1M2feature

    Description

    Why

    Persistence policies reset "on rest", archers assemble arrows and everyone swaps loadouts "at rest points", artifacts recharge on rest — but no item defined what resting is. A shared rest verb gives the world a rhythm and gives failure a place to happen (a campfire in the wild can be interrupted).

    What

    As a player, I want to rest at an inn bed, a campfire or a shrine so that I recover, the world moves on and I can reorganise my kit.

    • Rest point entity: kind inn (paid through e20-services later; free in grey-box), campfire (must be burning — any heat stimulus lights it; wet/extinguished fires refuse), shrine. Data per kind: restoration table, allowed durations, interrupt table.
    • Request: interact → choose duration (until dawn / until dusk / N hours). Refused when unsafe: reuses the autosave "unsafe" veto registry (combat/alert ≥ Searching/hostile within radius) with reasons.
    • Rest: advanceTime, restore health/stamina/mana per kind, emit rest.completed{kind, hours, point} which triggers rest-reset persistence policies. A scheduled or data-rolled (seeded RNG) interrupt stops rest early with prorated restoration and fires its event — a new situation, not a reload.
    • Rest actions hook: a registry lets other systems add actions to the rest menu while at a rest point (arrow assembly, loadout swap, artifact recharge). This item owns the hook only.
    • Autosave once after a completed or interrupted rest.

    Scope

    • In: Rest point component/schema, safety check, duration selection, time advance, restoration, rest.completed event, interrupts, rest-action registry, autosave trigger, minimal rest menu on e00-ui-framework
    • Out: Inn payment — see e20-services
    • Out: Arrow assembly — e19-archer-arrow-channel; loadout swap — e19-respec-policy; artifact recharge — e18-unique-artifacts (register rest actions)
    • Out: Which facts reset — see e27-persistence-policies

    Notes

    Canon: the Sleeping Ox is Briar Glen's inn (story bible §3.5). Resting is not a save-scum tool: autosave after rest uses the normal ring.

    Integration note: Quest-registered vetoes (e.g. the E24 first-night beat) use the same veto registry as AC-2.

    Acceptance criteria

    • AC-1 unit Given a campfire rest point that is not burning, when rest is requested, then it fails with reason no-fire; after a heat stimulus ignites it, the same request succeeds.
    • AC-2 unit Given a registered unsafe veto (hostile within 20 m or any alert state ≥ Searching), when rest is requested, then it fails with reason unsafe and game time does not advance.
    • AC-3 unit Given rest until dawn requested at 22:00, when completed, then the clock reads 06:00 next day, rest.completed fires once, restoration follows the kind's table, rest-reset facts reset and permanent facts are unchanged.
    • AC-4 unit Given two registered rest actions, when the rest menu opens at a rest point, then both are listed in priority order; when invoked away from a rest point, then each fails with reason not-at-rest.
    • AC-5 unit Given an interrupt scheduled at 02:00 during an 8 h rest starting 22:00, when resting, then rest stops at 02:00, restoration is prorated to 4/8 and the interrupt event fires once (edge).
    • AC-6 integration Given a completed rest, when it ends, then exactly one autosave is written after the rest.completed event.
    • AC-7 e2e Given the greybox testbed with an unlit campfire, when the player lights it and rests 8 h, then the HUD clock shows +8 h, health is full and no console errors occur.

    Waits on

    • mw-e00.23 Build HUD/menu UI layer, component kit, focus nav and UI test harness done
    • mw-e02.5 Focus and interact with world objects via contextual prompts done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e27.7 Apply permanent, rest-reset and transient persistence policies done
    • mw-e30.5 Autosave on area transitions and checkpoints into a rotating ring done
    area:simclass:allepic:e27milestone:m2size:m

M3 MVP content 2

  • mw-e27.10Resolve elapsed time for unloaded levels when the player returnsopenP2M3feature

    Description

    Why

    Leaving a freezing spell on a river and returning a day later should find it melted; a fire should have burned out. Cheap catch-up rules preserve consistency without simulating unloaded levels.

    What

    As a player, I want time to have passed in places I left so that the world feels continuous.

    On level load, compute elapsed sim time since last visit and apply analytic catch-up rules per component (ice melts after X, fires resolve to burnt, doors on timers close, puzzle respawners complete, reset policies apply) instead of simulating.

    Scope

    • In: Last-visited tick per level, catch-up rule registry per component
    • In: Deterministic ordered application
    • Out: NPC off-screen schedules — see mw-e22

    Notes

    Catch-up rules are pure functions (state, elapsed) → state, 100% unit-tested.

    Acceptance criteria

    • AC-1 unit Given ice created with melt time 10 min and a return after 30 min, when the level loads, then the ice is gone and water volume restored.
    • AC-2 unit Given a return after 1 min, when loaded, then the ice remains with proportionally reduced thickness.
    • AC-3 unit Given a timed door open when left, when returning after its timer, then it is closed.
    • AC-4 unit Given elapsed time is negative or zero (clock anomaly / immediate re-entry), when loaded, then no catch-up applies and no error occurs (edge).

    Waits on

    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e27.7 Apply permanent, rest-reset and transient persistence policies done
    area:simclass:allepic:e27milestone:m3size:s
  • mw-e27.11Budget world-state save size and serialization timeopenP2M3task

    Description

    Why

    Browser saves live in IndexedDB and autosave during play; large or slow saves cause hitches and quota errors.

    What

    Stress fixture with 10,000 facts + 5,000 deltas across 6 levels; perf tests for serialize/deserialize time and compressed size; autosave must not hitch the main thread (serialize off the sim tick via snapshot + worker compression).

    Scope

    • In: Stress fixture, perf tests, snapshot-then-compress in a worker
    • Out: IndexedDB quota handling — see e30-save-serialization

    Notes

    Budgets from epic exit criteria.

    Acceptance criteria

    • AC-1 perf Given the stress fixture, when serialized on the reference machine, then snapshot time on the main thread ≤ 50 ms and compressed size ≤ 1 MB.
    • AC-2 perf Given autosave during 60 s of play, when measured, then no frame exceeds 33 ms due to save work.
    • AC-3 unit Given a snapshot taken while the sim continues ticking, when compressed in the worker, then the saved state equals the state at snapshot tick (edge: no tearing).

    Waits on

    • mw-e27.4 Serialize world facts and entity deltas through the save system done
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    area:perfepic:e27milestone:m3size:s
E28Audio & Combat FeedbackWeapons, spells, footsteps, creatures and environments have satisfying positional audio and feedback, driven by data from sim events, within the browser and performance baseline.12/20 done · 60%

M1 Grey-box slice 1

  • mw-e28.17Playtest: hear block, parry and clean hit apart with eyes closedopenP2M1task

    Description

    Why

    mw-e28.4 AC-5 is a manual listening test and cannot be claimed by automated tests.

    What

    In the combat sandbox, three playtesters close their eyes during a dummy fight and name block, parry and clean hit by sound alone. Record the result in the bead.

    Scope

    • In: the listening session and its notes
    • Out: sound changes (file beads for any)

    Acceptance criteria

    • AC-1 manual Given the sandbox, when three playtesters close their eyes during a dummy fight, then each can distinguish block, parry and clean hit by sound alone (mw-e28.4 AC-5).

    Waits on

    • mw-e28.16 Parry and riposte cues that are never stolen done
    area:audioclass:allepic:e28milestone:m1milestone:m3

M2 Class fantasies 4

  • mw-e28.7Bow audio: draw creak, release, flyby and payload cuesblockedP1M2feature

    Description

    Why

    A creaking draw and a sharp release make the bow feel tense and powerful (Archery epic outcome: bows feel excellent).

    What

    As an archer, I want the bow to creak as I draw and arrows to whistle past so that shots feel tense and physical.

    Draw creak loop whose playbackRate (0.9→1.1) and gain follow draw fraction; focused-release chime; release twang by draw strength; arrow flyby when passing within 3 m of the listener (pitch bend simulating doppler); impacts reuse the combat material matrix; ricochet; trick payload cues (ignite, splash, rope unfurl, rattle); pickup cue on retrieval.

    Scope

    • In: Continuous draw loop control, flyby detection, cue rules for bow events
    • Out: Final bow SFX (asset group)

    Notes

    Acceptance criteria

    • AC-1 unit Given draw fraction 0.5, when the creak loop updates, then playbackRate is 1.0 and gain is the 50% curve value.
    • AC-2 unit Given an arrow passing 2 m from the listener, when its closest approach occurs, then one flyby cue plays; at 4 m, then none.
    • AC-3 integration Given a focused release event, when processed, then the chime plays in the same frame as the release twang.
    • AC-4 unit Given the draw is cancelled, when processed, then the creak loop fades out within 100 ms and no release twang plays.

    Waits on

    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    • mw-e28.3 Data-driven cue sheets map sim events to sounds done
    area:audioclass:archerepic:e28milestone:m2
  • mw-e28.10Audio occlusion through walls and doorsopenP2M2feature

    Description

    Why

    Hearing a muffled fight behind a door is atmosphere and information; it should match how creatures hear (the stealth model) conceptually.

    What

    As a player, I want sounds behind walls and doors to be muffled so that I can judge where things are and whether a door is open.

    For the top 16 priority sources within 30 m, raycast listener↔source at 10 Hz (staggered). Occluded: low-pass 22 kHz→900 Hz and −8 dB; closed door on the path: −12 dB and 600 Hz; open door: unoccluded path. 150 ms smoothing. Door states from e03-doors-locks-switches; acoustic values shared with the stealth group's door constants.

    Scope

    • In: Ray scheduling, filter/gain mapping, door state lookup, smoothing
    • Out: Sim noise occlusion for creatures (e09-sound-propagation)
    • Out: Full path-finding propagation (post-MVP)

    Notes

    Budget: ≤ 16 rays per 100 ms.

    Acceptance criteria

    • AC-1 integration Given a source behind a solid wall, when occlusion updates, then its low-pass cutoff settles at 900 Hz and gain at −8 dB within 150 ms.
    • AC-2 integration Given a source behind a closed door that then opens, when occlusion updates, then filtering clears within 150 ms.
    • AC-3 unit Given 40 eligible sources, when scheduled, then only the 16 highest-priority are raycast and no more than 16 rays run per 100 ms.
    • AC-4 unit Given the listener inside a collider (camera clipping), when raycasting, then the result is treated as unoccluded (no false muffling).

    Waits on

    • mw-e03.18 Build doors, locks, levers and buttons as data-wired mechanisms done
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e28.1 Web Audio engine: registry, buses, voice pool, positional audio done
    area:audioclass:allepic:e28milestone:m2
  • mw-e28.18Feed armour weight class into the footstep armour layeropenP2M2task

    Description

    Why

    The footsteps cue sheet (mw-e28.6) plays sfx-armor-plate-layer / sfx-armor-chain-layer on each step when the cue lookups know a character's armour class, but nothing supplies it until armour weight exists, so the layer is silent in the testbed.

    What

    Pass armorOf (attachGameAudio option) from the e04.16 armour weight class so the knight in plate clanks as it walks; add the leather layer placeholder.

    Scope

    • In: armorOf wiring in main.ts, leather placeholder
    • Out: final armour SFX (mw-e38.24 to mw-e38.27)

    Acceptance criteria

    • AC-1 integration Given the player in plate armour in the testbed, when walking, then each footstep also plays sfx-armor-plate-layer.

    Waits on

    • mw-e04.16 Armor weight sets roll class, stamina regen, poise and noise done
    area:audioclass:allepic:e28milestone:m2milestone:m3
  • mw-e28.19Wall recoil and charge-ready combat cuesopenP2M2task

    Description

    Why

    mw-e28.4 lists distinct cues for a swing recoiling off a wall and a charged attack reaching full charge; the sim emits neither event yet, so the placeholder ids sfx-knight-wall-recoil-clang and sfx-knight-charge-ready are unused.

    What

    Once the sim emits a wall-recoil event (mw-e04.15) and a charge-full event (mw-e04.13), add them to the cue-event table and bind combat cue rules.

    Scope

    • In: cue events and rules
    • Out: the sim events themselves

    Acceptance criteria

    • AC-1 integration Given a charged heavy held to full charge, when it becomes ready, then sfx-knight-charge-ready plays at the knight.
    • AC-2 integration Given a sword swing that hits a wall, when it recoils, then sfx-knight-wall-recoil-clang plays at the contact.

    Waits on

    • mw-e04.13 Heavy and charged attacks with hyperarmor done
    • mw-e04.15 Weapon reach classes and swing-type wall recoil done
    area:audioclass:allepic:e28milestone:m2milestone:m3

M3 MVP content 2

  • mw-e28.12Reverb zones per space: caves, halls, interiors, forestopenP2M3feature

    Description

    Why

    Acoustic space sells the dungeon: a sword clang should echo in the labyrinth and die in the forest.

    What

    As a player, I want each space to sound like its size and material so that caves, halls and forests feel different.

    Convolution reverb sends per zone type (cave, stone hall, wooden interior, forest, open field) using impulse-response assets; zone chosen via e03-triggers volumes; 1 s crossfade across boundaries; Low preset uses a single shared convolver with fewer IRs.

    Scope

    • In: Reverb send buses, zone volumes, crossfade, Low-preset fallback, placeholder IRs
    • Out: Recorded/generated IR assets (asset group)

    Notes

    Acceptance criteria

    • AC-1 integration Given the listener entering a cave trigger volume, when processed, then the cave send ramps to its target over 1 s while the previous zone fades.
    • AC-2 unit Given overlapping zones, when resolved, then the zone with the highest declared priority wins.
    • AC-3 unit Given the Low preset, when zones switch, then at most one ConvolverNode exists.
    • AC-4 unit Given a missing IR asset, when the zone activates, then the dry signal plays unaffected and a warning is logged.

    Waits on

    • mw-e03.21 Wire trigger volumes and mechanisms with data-defined signal graphs done
    • mw-e28.1 Web Audio engine: registry, buses, voice pool, positional audio done
    area:audioclass:allepic:e28milestone:m3
  • mw-e28.20Bind menu snapshot, critical-hit duck and UI stinger duck to game eventsopenP3M3task

    Description

    Follow-up from mw-e28.9 (PR #312). src/audio/mix-snapshots.ts defines the menu snapshot and the critical and ui-stinger ducks, but nothing triggers them: no critical-hit event exists in src/sim yet, and title/full-screen menus don't set the menu snapshot. Also tune snapshot dB values by ear.

    AC-1 unit Title and full-screen menus apply the menu snapshot and restore on close.

    AC-2 unit A critical-hit event (once defined) triggers the critical duck.

    AC-3 unit UI stingers trigger the ui-stinger duck.

    area:audioclass:allepic:e28milestone:m3

M4 Fun validation 1

  • mw-e28.15Audio performance and download budgetsopenP1M4task

    Description

    Why

    Audio must fit the hardware baseline: ≤ 50 MB initial download and steady 60 fps.

    What

    Budgets added to the e32 perf suite: decoded audio memory ≤ 96 MB; main-thread audio work ≤ 0.5 ms/frame p95; voices ≤ 48 High / 24 Low; audio share of initial download ≤ 12 MB (music streamed); format strategy (Opus in WebM/Ogg with AAC fallback for Safari).

    Scope

    • In: Budget assertions, format pipeline, lazy-load per area
    • Out: Global perf suite (e32-perf-budgets)

    Notes

    Cites the contract hardware baseline; no new targets invented beyond audio shares.

    Acceptance criteria

    • AC-1 perf Given the combat stress scene, when profiled on the reference machine, then main-thread audio work ≤ 0.5 ms per frame p95.
    • AC-2 perf Given a cold load of the vertical slice, when measured, then audio bytes before playable ≤ 12 MB.
    • AC-3 perf Given a 20-minute scripted session, when measured, then decoded audio memory never exceeds 96 MB.
    • AC-4 e2e Given Safari (WebKit), when sounds load, then the AAC fallback is selected and plays without errors.

    Waits on

    • mw-e28.1 Web Audio engine: registry, buses, voice pool, positional audio done
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    area:perfclass:allepic:e28milestone:m4
E29VFX & Magical SpectacleMagic, impacts, destruction, stealth feedback and environmental effects establish the game's visual identity, derived from sim events and world properties, within the particle and frame budgets.12/19 done · 63%

M2 Class fantasies 5

  • mw-e29.9Destruction VFX: fracture chunks, dust and crack stagesblockedP1M2feature

    Description

    Why

    Smashing a wall has to look as good as it feels; crack stages make breakable things readable (Zelda-like readability).

    What

    As a knight, I want smashed walls and crates to burst convincingly and cracked walls to look weak so that I know what I can break.

    On ObjectBroken: pre-fractured chunk meshes when available, otherwise procedural box chunks for greybox; dust cloud; cosmetic debris render-only (cap 200 pieces, fade after 8 s) — gameplay rubble remains sim physics from e03. Crack stage visuals (0/1/2) for breakable objects so weak walls read as weak before any hit.

    Scope

    • In: Chunk spawner, dust, cosmetic debris cap/fade, crack stage materials
    • Out: Break rules (e04-smash-breakables)
    • Out: Fractured art assets (asset group)

    Notes

    Acceptance criteria

    • AC-1 integration Given a weak wall broken, when processed, then chunks and a dust cloud spawn and cosmetic debris count stays ≤ 200.
    • AC-2 integration Given crack stage 1 in sim, when rendered, then the stage-1 crack material is applied.
    • AC-3 unit Given 250 cosmetic debris requests, when processed, then the oldest 50 are removed.
    • AC-4 perf Given 3 simultaneous wall breaks, when measured, then frame time p95 ≤ 16.7 ms on the reference machine (High).

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e04.17 Smash breakable walls and objects by impact force open
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    area:renderclass:knightepic:e29milestone:m2
  • mw-e29.13Projected decals: scorch, frost, wet, arrow holes, cracksopenP2M2feature

    Description

    Why

    Decals leave evidence of what happened — scorch after fire, wet stone after a splash — making the world feel reactive.

    What

    As a player, I want surfaces to show scorch, frost, wetness and arrow holes so that the world visibly remembers what happened.

    Projected decals with a cap of 128 (High) / 48 (Low), FIFO fade-out. Wet decals match the sim wet duration exactly so visuals never lie about state; scorch remains after burning ends; frost while frozen; arrow holes when arrows are pulled; crack decals for crack stages.

    Scope

    • In: Decal projector, cap/fade, state-synced lifetimes
    • Out: Decal textures (asset group)

    Notes

    Rule: a decal never conveys a gameplay state unless that state exists in the sim.

    Acceptance criteria

    • AC-1 unit Given 129 decals on High, when the 129th spawns, then the oldest fades out over 1 s.
    • AC-2 integration Given a surface becoming wet in sim for 20 s, when rendered, then the wet decal appears and is gone within one frame of the sim state clearing.
    • AC-3 integration Given a burning object that is extinguished, when processed, then a scorch decal remains.
    • AC-4 unit Given the Low preset, when decals spawn, then the cap is 48.

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    area:renderclass:allepic:e29milestone:m2
  • mw-e29.17Soft depth fade for the main VFX particle rendereropenP2M2task

    Description

    mw-e29.7 ships soft particles (src/render/magic-materials/soft-particle.ts) and the depth pass behind them (SoftDepthPass: half-resolution depth of the opaque scene, drawn only while a soft particle exists), but the batched particle renderer (src/render/vfx/index.ts) does not use it, so smoke, glow and sparks still cut a hard line through floors and walls. Wire a depth fade into the batch shader on High, decide the pass cost against the frame budget (a second scene draw; consider drawing depth only when particles are near geometry, or moving the main render to a target with a depth texture), keep Low on the plain fade, and measure with ?vfx=stress.

    area:renderclass:allepic:e29milestone:m2milestone:m3
  • mw-e29.18Rune decals projected onto uneven surfacesopenP3M2task

    Description

    mw-e29.7's rune decal (src/render/magic-materials/rune.ts) is a flat disc on the ground plane with a polygon offset, so it floats over stairs and cuts into slopes. Project it as a box decal that reads the scene depth (SoftDepthPass already renders it while a soft particle exists) so it wraps floors, walls and steps; keep the flat disc as the Low fallback.

    area:renderclass:allepic:e29milestone:m2milestone:m3
  • mw-e29.19Creature corpses: dissolve ones loaded already dead, and keep the burning look while dissolvingopenP3M2task

    Description

    mw-e29.7 dissolves a creature that dies in play and removes its render entity. Creatures drawn already dead (a loaded save, a level re-entry) still lie on the ground for ever (src/main.ts: deaths.start(..., lying=true)), so a corpse seen dissolving in one session is back, lying, after a reload. Decide what a persistent corpse should be (dissolve on load, or keep until loot is taken, see src/sim/loot) and make it consistent. Also: a creature that dies while burning, wet, frozen or charged loses its element look at death (the element look is withheld from dying bodies so it cannot put the original materials back over the dissolve's copies); let the two coexist so a burning skeleton burns while it dissolves.

    area:renderclass:allepic:e29milestone:m2milestone:m3

M3 MVP content 1

  • mw-e29.14Ambient environment VFX: dust motes, embers, fireflies, fogopenP2M3feature

    Description

    Why

    Light shafts full of dust and torches spitting embers give Briar Glen and the Labyrinth their mood (visual identity).

    What

    As a player, I want places to feel alive with dust, embers, fireflies and fog so that exploring is atmospheric.

    Ambient effects placed via level data or derived from properties: dust motes in light shafts, torch embers and flicker (auto on burning light sources), fireflies (forest night), falling leaves, height fog / fog volumes, water drips and ripples. Environment effects are limited to ≤ 25% of the particle budget.

    Scope

    • In: Ambient effect set, placement data, budget share
    • Out: Level dressing (location epics)

    Notes

    Acceptance criteria

    • AC-1 unit Given ambient effects requesting 40% of the particle cap, when evaluated, then they are throttled to 25%.
    • AC-2 integration Given a torch with burning, when loaded, then the ember effect attaches without per-torch authoring.
    • AC-3 e2e Given an environment test scene in Chromium, when loaded, then all ambient effects render with no console errors.
    • AC-4 perf Given the forest test scene at night, when measured, then frame time p95 ≤ 16.7 ms on the reference machine (High).

    Waits on

    • mw-e29.8 Visuals derived from element states: burning, wet, frozen, shock done
    area:renderclass:allepic:e29milestone:m3

M4 Fun validation 1

  • mw-e29.15VFX stress scene, quality tiers and auto-degradeopenP1M4task

    Description

    Why

    Spectacle must never break frame pacing on the target hardware (hardware baseline).

    What

    A combat stress scene: 12 creatures, 4 simultaneous spells, fire spreading over 10 objects, 2 destructions. Budgets added to the e32 suite. Quality tiers per preset, plus auto-degrade: when frame time exceeds budget for 2 s, halve emission rates, then disable distortion, then reduce decal cap; recover after 10 s under budget.

    Scope

    • In: Stress scene, budget assertions, auto-degrade controller
    • Out: Global perf suite (e32-perf-budgets)

    Notes

    Cites contract baseline: High 60 fps reference machine at 1440p-equivalent; Low 60 fps at 1080p, 30 fps floor in worst-case combat on Iris Xe / base M1 class.

    Acceptance criteria

    • AC-1 perf Given the stress scene on the reference machine (High), when measured for 60 s, then frame time p95 ≤ 16.7 ms.
    • AC-2 perf Given the stress scene on the Low preset on a base-M1-class device, when measured, then frame rate never drops below 30 fps.
    • AC-3 unit Given frame time over budget for 2 s, when the controller evaluates, then emission rates halve; after 10 s under budget, they restore.
    • AC-4 unit Given frame time spikes shorter than 2 s, when evaluated, then no degradation occurs.

    Waits on

    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.7 Magical material library: dissolve, glow, distortion, runes done
    • mw-e29.8 Visuals derived from element states: burning, wet, frozen, shock done
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    area:perfclass:allepic:e29milestone:m4
E30Save/LoadBrowser-safe saves reliably preserve character and world state across sessions, browser restarts and game updates; a corrupted or interrupted save never costs the player all their progress.9/15 done · 60%

M1 Grey-box slice 4

  • mw-e30.13Autosave at a testbed checkpoint volume shows in the slot list (e2e) and HUD indicatoropenP1M1task

    Description

    Why

    mw-e30.5 shipped the autosave scheduler as API only: its AC-5 e2e (checkpoint volume in the testbed -> autosave in the slot list with the area name) is proven at the sim level in src/game/save/autosave/autosave.integration.test.ts because the greybox testbed (mw-e00.21) and HUD layer (mw-e00.23) do not exist yet.

    What

    Wire AutosaveScheduler into the game loop (update between sim steps, reset after load), mark a testbed checkpoint volume via autosaveAtCheckpoints, render the HUD saving indicator and the non-blocking failure warning from scheduler.subscribe, and add the Playwright test.

    Acceptance criteria

    • AC-1 e2e Given the testbed with a checkpoint volume, when the player enters it, then an autosave appears in the slot list with the area name.
    • AC-2 e2e Given an autosave write fails twice, then a non-blocking HUD warning is shown and play continues.

    Acceptance criteria

    • AC-1 e2e Given the testbed with a checkpoint volume, when the player enters it, then an autosave appears in the slot list with the area name.
    • AC-2 e2e Given an autosave write fails twice, then a non-blocking HUD warning is shown and play continues.

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e00.23 Build HUD/menu UI layer, component kit, focus nav and UI test harness done
    area:gamearea:simepic:e30milestone:m1
  • mw-e30.6Add quicksave and quickload actionsopenP2M1feature

    Description

    Why

    Experimentation-heavy play (constitution: "too useful" spells) benefits from instant save-scumming for players who want it.

    What

    As a player, I want quicksave/quickload keys so that I can try risky ideas instantly.

    Quicksave writes the single quicksave slot (subject to the same safety vetoes as autosave, except combat is allowed); quickload asks for confirmation if unsaved progress > 60 s.

    Scope

    • In: Quicksave/quickload actions registered in the action map
    • In: Confirmation prompt
    • Out: Default key bindings list (e02-input-actions)

    Notes

    • None.

    Acceptance criteria

    • AC-1 unit Given quicksave during combat, when triggered, then the save succeeds (combat not vetoed for quicksave) but mid-air/dialogue still vetoes with a HUD message.
    • AC-2 integration Given no quicksave exists, when quickload is pressed, then a "no quicksave" toast appears and nothing else changes.
    • AC-3 e2e Given progress of 90 s since the last save, when quickload is pressed, then a confirmation dialog appears before loading.

    Waits on

    • mw-e02.1 Map remappable KB/M input to deterministic per-tick action frames done
    • mw-e30.4 Support manual save slots with metadata and thumbnails done
    area:gameepic:e30milestone:m1
  • mw-e30.12Wire canvas thumbnail capture into saves and verify it in a browseropenP2M1task

    Description

    Why

    mw-e30.4 added captureCanvasThumbnail (src/render/thumbnail.ts, coverage-excluded) and the SaveSlots captureThumbnail seam, but no renderer exists yet (mw-e00.13), so the capture is never exercised in a real browser.

    What

    Once the renderer exists, pass () => captureCanvasThumbnail(canvas) to SaveSlots saves (pause-menu save, autosave, quicksave), make sure the WebGL canvas is captured right after a render (or preserveDrawingBuffer), and add a Playwright check that a saved slot shows a non-placeholder WebP/PNG thumbnail within 256x144 and 64 KiB in Chromium, Firefox and WebKit.

    Acceptance criteria

    AC-1 e2e Given a manual save from the running game, when the slot list is read, then the slot has a captured thumbnail (not the placeholder) in each of Chromium, Firefox and WebKit.

    Waits on

    • mw-e00.13 Spike: choose Three.js vs Babylon.js and physics engine (ADR-0001) done
    • mw-e30.4 Support manual save slots with metadata and thumbnails done
    area:renderarea:simepic:e30milestone:m1
  • mw-e30.15Veto saving while the player is mid-airopenP2M1task

    Description

    Why

    The autosave contract (mw-e30.5) and the pause menu (mw-e01.3) say saving waits while the player is mid-air, so a save never captures a fall in progress. Only the combat veto exists today (src/game/creatures/save-veto.ts).

    What

    Register a mid-air safety veto alongside the combat veto in src/main.ts's saveVetoes: it objects with "Can't save while falling" while the player is not grounded (jumping, falling, hanging from a ledge or climbing count as mid-air; standing on a ladder rung is the owner's call). The pause menu's Save shows the reason and autosaves wait for landing, through the same SafetyVetoes.

    Scope

    • In: the veto, its reason text, wiring into the shared vetoes
    • Out: dialogue veto (lands with the dialogue runtime)

    Notes

    Discovered while building the pause menu (mw-e01.3).

    Acceptance criteria

    • AC-1 unit Given the player airborne after a jump, when the veto is asked, then it returns "Can't save while falling"; grounded, it returns null.
    • AC-2 integration Given a checkpoint crossed mid-jump, when the player lands, then the autosave is written after landing, never before.
    • AC-3 integration Given the pause menu opened mid-air, then Save is disabled with the reason.
    area:gamearea:simepic:e30milestone:m1

M3 MVP content 2

  • mw-e30.9Prevent two open tabs from clobbering each other's savesopenP2M3task

    Description

    Why

    Browser games are easily opened twice; concurrent writers silently overwrite progress.

    What

    Use the Web Locks API (fallback: BroadcastChannel heartbeat) to elect a single "active" tab. A second tab shows "Game already open in another tab" with a "Play here instead" option that asks the first tab to release (it autosaves and pauses).

    Scope

    • In: Lock acquisition, takeover protocol, fallback
    • Out: Cross-device sync (not planned)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given the game open in tab A, when opened in tab B, then B shows the already-open message and makes no writes.
    • AC-2 e2e Given B chooses "Play here instead", when A receives the request, then A autosaves, pauses with a notice, and B loads that autosave.
    • AC-3 e2e Given tab A crashes (closed abruptly), when tab B retries, then it acquires the lock within 5 s.

    Waits on

    • mw-e30.5 Autosave on area transitions and checkpoints into a rotating ring done
    area:gameepic:e30milestone:m3
  • mw-e30.10Export and import save filesopenP2M3feature

    Description

    Why

    Browser storage can be cleared; players and playtesters need a way to back up and share saves.

    What

    As a player, I want to export a save to a file and import it later so that clearing browser data does not erase my adventure.

    Export produces the-vesper-bell-<slot>-<date>.vbsave (JSON envelope, gzip). Import validates envelope, checksum and version, then runs migrations and places it into a chosen slot.

    Scope

    • In: Export/import in settings/load menu
    • In: Validation errors shown in plain language
    • Out: Cloud sync

    Notes

    • None.

    Acceptance criteria

    • AC-1 integration Given an exported save, when imported into a fresh profile, then loading it yields the same sim state hash.
    • AC-2 integration Given a file that is not a save (random JSON or PNG), when imported, then a clear "not a save from The Vesper Bell" error is shown and no slot changes.
    • AC-3 integration Given a save from an older schema version, when imported, then migrations run and it loads.
    • AC-4 unit Given a save file larger than 20 MB, when imported, then it is rejected before parsing.

    Waits on

    • mw-e30.4 Support manual save slots with metadata and thumbnails done
    area:gameepic:e30milestone:m3
E31Accessibility & SettingsPlayers can tailor controls, text, camera, audio, visuals and difficulty so the game is comfortable and playable for a broad audience, meeting the basic tier of the Game Accessibility Guidelines.13/17 done · 76%

M3 MVP content 3

  • mw-e31.12Add gamepad deadzone, sensitivity curve and vibration settingsopenP2M3feature

    Description

    Why

    Gamepad is second-class but supported; stick drift and vibration sensitivity vary by player and hardware.

    What

    As a player, I want to tune stick deadzones, response curves and vibration so that my gamepad feels accurate.

    Inner/outer deadzone per stick, response curve (linear/exponential), vibration intensity 0–100% (where Gamepad haptics are supported).

    Scope

    • In: Settings + input-layer processing
    • Out: Gamepad action mapping (e02-input-actions)

    Notes

    • None.

    Acceptance criteria

    • AC-1 unit Given inner deadzone 0.15, when stick magnitude is 0.1, then output is 0; at 1.0 output is 1.0 (rescaled).
    • AC-2 unit Given vibration 0%, when a haptic request is made, then no vibration API call occurs.
    • AC-3 integration Given a browser without vibrationActuator, when haptics are requested, then no error is thrown.

    Waits on

    • mw-e02.1 Map remappable KB/M input to deterministic per-tick action frames done
    • mw-e31.1 Create typed settings store and options menu skeleton done
    area:gameepic:e31milestone:m3
  • mw-e31.16Gamepad rebinding in the Key bindings panelopenP2M3task

    Description

    Follow-up from mw-e31.2 (PR #317). The binding model and storage already carry pad bindings, but the Controls > Key bindings panel only captures keyboard/mouse. Capturing a pad button needs the UI pad adapter suspended during capture (A/B otherwise act as confirm/back). Also count pad bindings toward the Pause required-action rule.

    AC-1 unit In capture mode, a pad button press binds that button and does not trigger UI confirm/back.

    AC-2 unit Removing the last keyboard binding for Pause is allowed when a pad binding remains, and refused when none does.

    AC-3 e2e A rebound pad button persists across reload.

    area:uiepic:e31milestone:m3
  • mw-e31.17Camera options follow-up: camera distance, separate X/Y and stick sensitivity, lock-on switch sensitivityopenP2M3task

    Description

    mw-e31.6 shipped look sensitivity (mouse + stick, one slider), invert X/Y, FOV 60-100 and auto-centre. Still open from its description: camera distance default, separate X and Y sensitivity, separate stick sensitivity, lock-on switch sensitivity.

    area:gamearea:uiepic:e31milestone:m3

M4 Fun validation 1

  • mw-e31.13Audit MVP against Game Accessibility Guidelines basic tieropenP1M4task

    Description

    Why

    Individual features do not guarantee an accessible whole; an audit before external playtests catches gaps.

    What

    Walk through every GAG "basic" guideline (motor, cognitive, vision, hearing, speech, general) against the MVP build; record pass/fail/N-A with evidence in docs/accessibility/audit-<date>.md; file beads for each failure.

    Scope

    • In: Audit doc, beads for findings
    • Out: Fixing findings (separate beads)

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given the MVP build, when every GAG basic guideline is assessed, then the audit doc records a status and evidence for each.
    • AC-2 manual Given any failing guideline, when the audit completes, then a bead exists for it with priority and a link from the audit doc.
    • AC-3 manual Given the audit, when complete, then zero failures are left without a decision (fix, defer with reason, or N/A).

    Waits on

    • mw-e31.11 Make every menu keyboard- and gamepad-operable with visible focus done
    • mw-e31.2 Let players remap keyboard, mouse and gamepad bindings done
    • mw-e31.4 Scale UI text 80–200% with readable defaults done
    • mw-e31.5 Caption gameplay-critical sounds with direction indicators done
    area:qaepic:e31milestone:m4needs-human
E32Performance & Browser CompatibilityStable frame pacing and fast loading on the hardware baseline across current desktop Chrome, Edge, Firefox and Safari, protected by automated budgets so regressions are caught in PRs rather than playtests.4/19 done · 21%

M1 Grey-box slice 6

  • mw-e32.2Benchmark sim tick cost in CI with regression alertsopenP1M1task

    Description

    Why

    The sim runs every tick regardless of GPU; its cost is measurable headlessly and must stay well inside the frame budget.

    What

    vitest bench suites for representative sim loads (500 entities with propagation, 30 AI agents perceiving, 200 physics props) with a budget: mean tick ≤ 4 ms in Node on CI hardware. CI compares against main baseline artifact and fails on > 25% regression.

    Scope

    • In: Bench suites, baseline artifact, comparison script
    • Out: Frame-time budgets (e32-perf-budgets)

    Notes

    • None.

    Acceptance criteria

    • AC-1 perf Given the "full-load" bench, when run in CI, then mean tick ≤ 4 ms and p99 ≤ 8 ms.
    • AC-2 unit Given baseline 2.0 ms and PR 2.6 ms, when compared, then the check fails (30% > 25%); at 2.4 ms it passes.
    • AC-3 unit Given no baseline available, when compared, then it records a new baseline and passes with a warning.

    Waits on

    • mw-e00.15 Build deterministic fixed-step sim loop, entity store and event bus done
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    area:perfepic:e32milestone:m1
  • mw-e32.4Run smoke suite on Chromium, Firefox and WebKit in CIopenP1M1task

    Description

    Why

    Target browsers are current Chrome, Edge, Firefox and Safari; engine-specific breakage must be caught before players see it.

    What

    Playwright projects for chromium, firefox, webkit running the boot + testbed smoke specs in CI (chromium required per-PR; firefox/webkit required on main and nightly, optional per-PR label full-matrix). Known-difference allowlist per browser with bead references.

    Scope

    • In: Playwright project matrix, CI job(s), docs of manual Edge/Safari checks
    • Out: Mobile browsers (mw-e36)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given the smoke suite, when run on chromium, firefox and webkit, then the testbed boots with zero console errors on all three.
    • AC-2 integration Given a nightly run failing on webkit only, when complete, then a GitHub issue is opened/updated with the failing spec and trace artifact.
    • AC-3 integration Given a known-difference allowlist entry without a bead id, when validated, then CI fails.

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e00.3 Add CI with per-layer coverage gates, ratchet and Playwright smoke done
    area:qaepic:e32milestone:m1
  • mw-e32.5Detect GPU/browser capabilities and pick a safe default presetopenP1M1task

    Description

    Why

    First impressions matter: a low-end laptop should start on Low, and unsupported browsers need a clear message.

    What

    On boot detect WebGL2 (and WebGPU if the ADR uses it), WASM + SIMD, max texture size, deviceMemory, hardwareConcurrency, renderer string (where exposed); choose default preset (High/Low) on first launch; show an unsupported screen listing what is missing; log capabilities to local telemetry.

    Scope

    • In: Capability probe, preset heuristic table, unsupported screen
    • Out: Dynamic resolution at runtime (e32-quality-presets)

    Notes

    • None.

    Acceptance criteria

    • AC-1 unit Given capabilities {deviceMemory: 4, renderer contains "Intel"}, when the heuristic runs, then Low is chosen; given an Apple M1 Pro renderer string, then High.
    • AC-2 e2e Given WebGL2 unavailable (init-script override), when loaded, then the unsupported screen names WebGL2 and links to browser help.
    • AC-3 unit Given the renderer string is masked/unavailable, when the heuristic runs, then it falls back to deviceMemory/cores and never throws.
    • AC-4 unit Given the player has already chosen a preset, when the game boots again, then detection does not override it.

    Waits on

    • mw-e00.19 Bootstrap the chosen renderer and physics with a boot smoke test done
    • mw-e31.1 Create typed settings store and options menu skeleton done
    area:gameepic:e32milestone:m1
  • mw-e32.10Show a dev perf HUD with frame graph, draw calls and heapopenP1M1feature

    Description

    Why

    Developers need to see performance cost while building content, not after CI complains.

    What

    As a developer, I want an overlay showing fps, frame-time graph (last 240 frames), sim tick ms, draw calls, triangles, textures/geometries count and JS heap so that I can spot regressions immediately.

    Toggle via debug console or F3; dev builds only.

    Scope

    • In: Overlay, renderer stats adapter
    • Out: Automated budgets (e32-perf-budgets)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given a dev build, when F3 is pressed, then the HUD shows fps, frame-time graph, sim ms, draw calls and heap values that update each frame.
    • AC-2 integration Given a production build, when F3 is pressed, then nothing happens and HUD code is absent from the bundle.
    • AC-3 unit Given performance.memory is unavailable (Firefox/Safari), when the HUD renders, then heap shows "n/a" without errors.

    Waits on

    • mw-e00.19 Bootstrap the chosen renderer and physics with a boot smoke test done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e32milestone:m1
  • mw-e32.16Chart reference perf results from perf/results as a trendopenP2M1task

    Description

    Why

    mw-e32.1 commits each reference run as perf/results/<date>-<sha>.json so performance can be followed over time, but nothing draws those results yet; a trend nobody can see does not catch slow drift (constitution §10, good browser performance).

    What

    As a developer, I want a trend chart of reference-mode frame time built from perf/results so that I can see whether the perf-baseline scene is getting slower across commits.

    A page published with the site on every merge to main plots p50/p95 frame time per committed reference result (x: date/commit, y: ms) with the 16.7 ms budget line from perf/perf-budgets.json.

    Scope

    • In: reading perf/results/*.json (the PerfRunReport format in scripts/perf/report.ts), a static chart page in the site build, a unit-tested data loader.
    • Out: running the reference suite (mw-e32.15), CI-mode software frame time (compared against main per PR in mw-e32.1).

    Notes

    Results files are written by e2e/perf/reporter.ts; frames[].frame holds the percentiles.

    Acceptance criteria

    • AC-1 unit Given perf/results files from two or more reference runs, when the trend data is built, then it lists p50 and p95 per run in date order with the commit SHA.
    • AC-2 unit Given a malformed or non-reference results file, when the trend data is built, then it is skipped with a warning naming the file rather than breaking the build.
    • AC-3 e2e Given the built site, when the trend page loads, then it shows one point per committed result and the 16.7 ms budget line, with no console errors.

    Waits on

    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    area:perfepic:e32milestone:m1milestone:m4
  • mw-e32.19Re-encode music-open-world.m4a under the 3 MB audio loop capopenP2M1task

    Description

    Why

    music-open-world.m4a is 3.65 MB, over the 3 MB audio loop cap; it is waived in perf/size-budgets.json (mw-e32.3).

    What

    Re-encode the approved take at a lower AAC bitrate (or trim the loop) so it fits, then delete the waiver.

    Scope

    • In: the m4a encode; waiver removal
    • Out: the general compression pipeline (mw-e32.7)

    Acceptance criteria

    AC-1 integration Given the production build, when pnpm size:check runs without the music-open-world waiver, then every audio loop is at most 3 MB.

    area:perfepic:e32milestone:m1milestone:m4

M3 MVP content 7

  • mw-e32.6Implement Low/High graphics presets and dynamic resolutionblockedP1M3feature

    Description

    Why

    The baseline defines two presets; they must actually hit 60 fps on their target hardware.

    What

    As a player, I want Low/High presets plus individual toggles and optional dynamic resolution so that the game runs smoothly on my machine.

    Preset controls render scale, shadow resolution/cascades, max dynamic lights, post-processing, particle density, LOD bias, draw distance. Dynamic resolution adjusts render scale between 50–100% to hold a frame-time target, with hysteresis.

    Scope

    • In: Preset table, settings UI section, dynamic resolution controller (pure logic unit-tested)
    • Out: Asset LODs creation (art epics)

    Notes

    • None.

    Acceptance criteria

    • AC-1 unit Given frame times consistently 20 ms with target 16.7 ms, when the controller updates, then render scale steps down by ≤ 10% per second and never below 50%.
    • AC-2 unit Given frame times oscillating around target ±0.5 ms, when the controller runs, then scale changes at most once per 2 s (hysteresis).
    • AC-3 perf Given the combat stress scene on Low at 1080p on an Iris Xe / base M1 class machine, when measured, then p50 ≥ 60 fps and p95 frame time ≤ 33.3 ms.
    • AC-4 e2e Given a preset switch at runtime, when applied, then it takes effect within 1 s without reload or console errors.

    Waits on

    • mw-e00.19 Bootstrap the chosen renderer and physics with a boot smoke test done
    • mw-e32.5 Detect GPU/browser capabilities and pick a safe default preset open
    area:renderepic:e32milestone:m3
  • mw-e32.7Stream and compress assets with a progress-reporting loaderblockedP1M3task

    Description

    Why

    Load to playable ≤ 10 s requires compressed assets and loading only what the current area needs.

    What

    Asset manifest generated at build (id → hashed URL, size, area tags); area-based preloading with priority; texture compression (KTX2/Basis), mesh compression (meshopt or Draco per ADR), audio as Opus/AAC with fallback; loading screen showing real progress; failed-fetch retry with backoff.

    Scope

    • In: Manifest build step, loader with priorities/retries, compression tooling scripts
    • In: Loading screen progress
    • Out: Service-worker/HTTP caching (e32-asset-caching)

    Notes

    • None.

    Acceptance criteria

    • AC-1 perf Given a cold load at 50 Mbps throttling in CI mode, when Briar-Glen-equivalent testbed area loads, then playable ≤ 10 s.
    • AC-2 unit Given a fetch failing twice then succeeding, when loading, then the loader retries with backoff and completes; after 3 failures it surfaces a retry UI.
    • AC-3 unit Given the manifest, when an asset id is missing, then a typed error names the id at build time (build fails).
    • AC-4 e2e Given the loading screen, when assets load, then the progress bar increases monotonically from 0 to 100%.

    Waits on

    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    area:perfepic:e32milestone:m3
  • mw-e32.8Cache hashed assets for warm reload ≤ 3 sblockedP1M3task

    Description

    Why

    Warm reload ≤ 3 s keeps the death/retry and playtest loops snappy.

    What

    Immutable caching for content-hashed assets (Pages headers are limited, so add a service worker with cache-first for hashed URLs and network-first for index.html); versioned cache names with cleanup of old versions on activate; opt-out via ?nosw.

    Scope

    • In: Service worker (Workbox or hand-rolled), update flow ("new version available — reload")
    • Out: Offline play guarantee (nice side effect, not a goal)

    Notes

    • None.

    Acceptance criteria

    • AC-1 perf Given a previously loaded build, when the page is reloaded, then load to playable ≤ 3 s on the reference machine.
    • AC-2 e2e Given a new deployment, when the page loads, then the old cache version is deleted after activation and a "new version available" prompt appears.
    • AC-3 e2e Given ?nosw, when loaded, then no service worker is registered and existing ones are unregistered.

    Waits on

    • mw-e32.7 Stream and compress assets with a progress-reporting loader open
    area:perfepic:e32milestone:m3
  • mw-e32.9Eliminate frame hitches from GC, shader compilation and long tasksopenP1M3task

    Description

    Why

    Stable frame pacing matters more than average fps for combat feel (parry timing).

    What

    Detect and fix hitch sources: shader/pipeline pre-warm during loading, object pooling for projectiles/particles/events on hot paths, long-task detection in dev overlay, allocation audit of the sim tick (target near-zero allocations per tick).

    Scope

    • In: Shader pre-warm, pools, allocation test for sim tick
    • Out: Perf HUD (e32-perf-hud)

    Notes

    • None.

    Acceptance criteria

    • AC-1 perf Given the combat stress scene for 60 s on the reference machine, when measured, then frames > 33 ms number ≤ 3 and none > 50 ms after warm-up.
    • AC-2 unit Given 1,000 steady-state sim ticks, when heap allocations are measured in Node (--expose-gc heap delta), then growth ≤ 64 KB.
    • AC-3 e2e Given the first cast of each VFX type after loading, when measured, then no frame exceeds 33 ms (pre-warm effective).

    Waits on

    • mw-e00.20 Bind fixed-step sim to rAF rendering with interpolation done
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    area:perfepic:e32milestone:m3
  • mw-e32.12Detect memory leaks across repeated scene loadsopenP1M3task

    Description

    Why

    Area transitions and reloads after death repeat hundreds of times per session; leaks compound into crashes.

    What

    Playwright test (Chromium, CDP heap) loads/unloads testbed scenes and save/load cycles 20 times, forcing GC, and asserts heap growth and GPU resource counts stay bounded.

    Scope

    • In: Leak test spec, renderer resource counters
    • Out: Fixing specific leaks (bug beads)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given 20 scene load/unload cycles, when heap is sampled after forced GC, then growth from cycle 2 to cycle 20 ≤ 5%.
    • AC-2 e2e Given 20 save/load cycles, when renderer geometry/texture counts are read, then they return to the cycle-2 value (±2).
    • AC-3 integration Given a deliberately leaking fixture, when the test runs, then it fails (test proves it can detect leaks).

    Waits on

    • mw-e30.1 Define versioned save format with section registry and migrations done
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    area:qaepic:e32milestone:m3
  • mw-e32.13Add combat stress scene with 12 creatures and heavy VFXopenP1M3task

    Description

    Why

    The worst case — a chaotic fight with spells flying — is what players remember; budgets must be measured there.

    What

    Scene perf-combat in the greybox kit: 12 active creatures in combat AI, 4 simultaneous spell effects, 30 physics props, fire propagation active, 8 dynamic lights. Scripted deterministic camera path and input replay so measurements are repeatable. Added to both perf modes.

    Scope

    • In: Scene data, scripted replay, perf-budgets.json entries
    • Out: Creature content (mw-e13)

    Notes

    • None.

    Acceptance criteria

    • AC-1 perf Given perf-combat on the reference machine (High), when measured over 1,800 frames, then p95 frame time ≤ 16.7 ms.
    • AC-2 perf Given perf-combat on Low at 1080p on the low-tier class machine, when measured, then worst-case frames stay ≥ 30 fps (p99 ≤ 33.3 ms).
    • AC-3 unit Given the scripted replay, when run twice, then sim state hashes match (repeatable measurement).

    Waits on

    • mw-e00.17 Record inputs and replay them to identical state hashes in tests done
    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e06.2 Run data-driven spells through a cast→deliver→effect pipeline done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    area:perfepic:e32milestone:m3
  • mw-e32.11Recover gracefully from WebGL/GPU context lossopenP2M3task

    Description

    Why

    GPU resets happen (driver updates, sleep/wake); losing a session to a black screen is avoidable.

    What

    Handle webglcontextlost/restored (or WebGPU device lost): pause sim, show overlay, rebuild GPU resources from the asset cache on restore, resume; if restore fails within 10 s, autosave (if safe) and offer reload.

    Scope

    • In: Context-loss handler, resource rebuild path
    • Out: Save logic (e30-autosave)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given WEBGL_lose_context.loseContext() then restoreContext(), when triggered in the testbed, then rendering resumes within 5 s with the same sim state hash as before loss.
    • AC-2 e2e Given the context is never restored, when 10 s pass, then an autosave is attempted and a reload prompt appears.
    • AC-3 e2e Given loss during loading, when restored, then loading completes without duplicate resources or errors.

    Waits on

    • mw-e00.19 Bootstrap the chosen renderer and physics with a boot smoke test done
    • mw-e30.5 Autosave on area transitions and checkpoints into a rotating ring done
    area:renderepic:e32milestone:m3

M4 Fun validation 2

  • mw-e32.14Run and record a full perf pass on reference and low-tier machinesblockedP1M4task

    Description

    Why

    Absolute frame-time budgets cannot run on GPU-less CI; a documented manual pass before playtests closes the loop.

    What

    Write docs/perf/runbook.md (machine prep, browser versions, pnpm perf:ref steps) and execute it on the reference machine and a low-tier machine across Chrome, Edge, Firefox, Safari; commit results to perf/results/; file beads for any budget misses.

    Scope

    • In: Runbook doc, committed results, beads for misses
    • Out: Fixes (separate beads)

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given the runbook, when executed on the reference machine in all 4 browsers, then results files are committed with browser/OS versions.
    • AC-2 perf Given the results, when compared to the baseline, then every budget passes or has a filed bead with owner and priority.
    • AC-3 manual Given the low-tier machine run, when complete, then Low preset results are recorded for perf-baseline and perf-combat.

    Waits on

    • mw-e32.13 Add combat stress scene with 12 creatures and heavy VFX open
    • mw-e32.4 Run smoke suite on Chromium, Firefox and WebKit in CI open
    • mw-e32.6 Implement Low/High graphics presets and dynamic resolution open
    area:perfepic:e32milestone:m4needs-human
  • mw-e32.17Firefox warns about the shadow map's depth texture filtering on every sceneopenP3M4bug

    Description

    Firefox 159 logs 'WebGL warning: drawElementsInstanced: Depth texture comparison requests (e.g. LINEAR) Filtering, but behavior is implementation-defined...' once on every scene, the plain testbed (?scene=testbed) included, so any Firefox smoke that fails on console warnings (mw-e32.4) will fail on it. It comes from the soft shadow map (PCF sampling a depth texture with a linear filter), not from the magical materials; found while running mw-e29.7's material test scene in Firefox, where e2e/magic-materials.spec.ts lets it through. Decide whether to switch the shadow map type or accept the warning in the cross-browser smoke.

    area:perfarea:renderclass:allepic:e32milestone:m4
E33Developer/Content ToolsDevelopers and designers can create, tune and debug spells, creatures, loot, encounters, dialogue and puzzles in minutes, with visual insight into the systemic simulation and one-keypress bug capture.4/17 done · 24%

M1 Grey-box slice 7

  • mw-e33.2Pause, slow-motion and frame-step the simulationopenP1M1feature

    Description

    Why

    Tuning parry windows and debugging propagation needs time slowed or stepped one tick at a time.

    What

    As a developer, I want to pause, change timescale (0.1×–4×) and step single ticks so that I can inspect fast interactions.

    Implemented in the game loop (sim steps at fixed dt; timescale changes how many steps per real second), so determinism is preserved.

    Scope

    • In: Loop timescale, pause, step; console commands and hotkeys (dev)
    • Out: Replay scrubbing (possible follow-up)

    Notes

    • None.

    Acceptance criteria

    • AC-1 unit Given timescale 0.5, when 1 real second passes at 60 Hz, then 30 sim steps occur.
    • AC-2 unit Given paused, when "step" is invoked 3 times, then exactly 3 ticks advance.
    • AC-3 integration Given a session played at mixed timescales and recorded, when replayed at 1×, then the final state hash matches.

    Waits on

    • mw-e00.20 Bind fixed-step sim to rAF rendering with interpolation done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e33milestone:m1
  • mw-e33.3Inspect and edit entity components liveopenP1M1feature

    Description

    Why

    Systemic bugs ("why didn't the rope burn?") are solved by seeing the properties involved.

    What

    As a developer, I want to click an entity and see/edit its components live so that I can debug systemic interactions.

    Pick via raycast (or list/search), panel showing components with schema-driven editors (number, bool, enum, vector), edits applied through a debug.setComponent sim command (recorded), highlight selected entity.

    Scope

    • In: Picker, inspector panel, edit command
    • Out: World overlays (e33-world-overlays)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given the testbed, when a crate is clicked in inspect mode, then its components (e.g. Position, Physics) are listed with current values updating live.
    • AC-2 unit Given an edit setting a numeric field to a string, when applied, then schema validation rejects it and the sim is unchanged.
    • AC-3 integration Given an edit to flammable=true, when recorded and replayed, then the replay reproduces the edited state.
    • AC-4 e2e Given the selected entity is destroyed, when the next frame renders, then the panel shows "entity destroyed" instead of throwing.

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e33milestone:m1
  • mw-e33.4Add `pnpm content:check` validator with cross-reference reportopenP1M1task

    Description

    Why

    Designers need fast, readable validation of all content before committing; CI needs the same check.

    What

    CLI wrapping the content pipeline: validates all content types, cross-references (loot tables → items, spawns → creatures, dialogue → quests), orphan detection (defined but never referenced), string-table key existence; human-readable output with file:line, --json for CI annotations; runs in CI job content.

    Scope

    • In: CLI, CI job, GitHub annotation formatter
    • Out: Schemas themselves (owned by respective epics)

    Notes

    • None.

    Acceptance criteria

    • AC-1 integration Given all committed content, when pnpm content:check runs, then it exits 0 in ≤ 10 s.
    • AC-2 unit Given a loot table referencing a missing item, when checked, then it exits non-zero printing the file, JSON path and missing id.
    • AC-3 unit Given an item defined but never referenced by any loot table, shop or placement, when checked with --orphans, then it is listed as a warning (not an error).
    • AC-4 integration Given --json, when run in CI with an error, then a GitHub annotation appears on the offending file.

    Waits on

    • mw-e00.18 Load schema-validated content with a per-entry test harness done
    • mw-e00.3 Add CI with per-layer coverage gates, ratchet and Playwright smoke done
    area:toolsepic:e33milestone:m1
  • mw-e33.5Scaffold new content entries with a test stub via CLIopenP1M1task

    Description

    Why

    Every content entry must have a test (contract §3); scaffolding makes the right thing the easy thing.

    What

    pnpm new <type> <id> creates content/<type>/<id>.json from a per-type template (valid defaults) and a test stub test/content/<type>/<id>.test.ts that exercises the entry via describeContent; refuses duplicate ids; validates id format (kebab-case).

    Scope

    • In: CLI, per-type templates registered alongside schemas
    • Out: GUI editors (not planned for MVP)

    Notes

    • None.

    Acceptance criteria

    • AC-1 integration Given pnpm new testprop lantern, when run, then the JSON and test stub are created, pnpm content:check passes and the new test runs green.
    • AC-2 unit Given an id that already exists, when run, then it exits non-zero without overwriting.
    • AC-3 unit Given id Big Lantern, when run, then it rejects with a kebab-case suggestion big-lantern.

    Waits on

    • mw-e00.18 Load schema-validated content with a per-entry test harness done
    area:toolsepic:e33milestone:m1
  • mw-e33.6Hot-reload content JSON into the running gameopenP1M1feature

    Description

    Why

    Tuning spells and creatures by editing JSON and seeing the change in under a second is the core of fast content iteration.

    What

    As a designer, I want edits to content files to apply to the running game without restart so that tuning is instant.

    Vite HMR for content/** → re-validate the changed file → swap catalogue entry → notify systems (content.on("changed", id)) which refresh live instances where safe (e.g. spell damage, creature speed); invalid edits keep the old version and show an overlay error.

    Scope

    • In: HMR handler, catalogue swap, change notifications, error overlay
    • Out: Production (dev only)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given the dev server and testbed running, when a testprop JSON field is edited, then the change is visible in-game within 1 s without page reload.
    • AC-2 e2e Given an edit introducing a schema error, when saved, then an overlay shows the error with file and path and the game keeps running on the previous valid data.
    • AC-3 unit Given a hot-swapped entry, when the content hash is recomputed, then it changes and the replay recorder marks the recording as content-modified.

    Waits on

    • mw-e00.18 Load schema-validated content with a per-entry test harness done
    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    area:toolsepic:e33milestone:m1
  • mw-e33.8Capture a reproducible bug report with one keypressopenP1M1feature

    Description

    Why

    Emergent systems create hard-to-reproduce bugs; a deterministic replay of the last minutes turns "it happened once" into a failing test.

    What

    As a developer or playtester, I want to press F9-dev (configurable) to save a bug bundle so that the exact situation can be replayed.

    The game continuously keeps a rolling buffer: a save snapshot every 60 s plus input commands since. Capture writes bug-<timestamp>.mwbug (snapshot + inputs + build SHA + content hash + settings + recent console/errors + screenshot + optional note). ?bug=<file> or drag-drop loads and replays it; pnpm bug:test <file> converts it into a golden replay test.

    Scope

    • In: Rolling buffer, bundle format (zod), loader, conversion to test
    • Out: Telemetry export bundles (e34-playtest-export) — reuse format pieces

    Notes

    • None.

    Acceptance criteria

    • AC-1 integration Given 3 minutes of play then capture, when the bundle is replayed on a fresh load of the same build, then the final state hash equals the captured final hash.
    • AC-2 unit Given a bundle from a different build SHA, when loaded, then the user is warned that replay may diverge and divergence is reported at the first checkpoint mismatch.
    • AC-3 perf Given the rolling buffer active, when measured in the testbed, then added cost is ≤ 0.2 ms per frame and memory ≤ 20 MB.
    • AC-4 integration Given pnpm bug:test, when run on a bundle, then a replay test file is generated that passes.

    Waits on

    • mw-e00.17 Record inputs and replay them to identical state hashes in tests done
    • mw-e30.1 Define versioned save format with section registry and migrations done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e33milestone:m1
  • mw-e33.7Add named teleport bookmarks and dev state snapshotsopenP2M1feature

    Description

    Why

    Reaching the room you are working on in seconds, in the right world state, removes most iteration friction.

    What

    As a developer, I want named bookmarks and instant dev snapshots so that I can jump to a place and state repeatedly.

    Bookmarks as content (content/dev/bookmarks.json) + console tp <name>; snap save <name> / snap load <name> store full save envelopes in a dev IndexedDB store; URL ?snap=<name> boots into a snapshot.

    Scope

    • In: Bookmarks, snapshot commands, URL param
    • Out: Player save slots (e30-save-slots)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given bookmark arena-center, when tp arena-center runs, then the player is placed there next tick.
    • AC-2 integration Given snap save a then changes then snap load a, when compared, then the state hash equals the snapshot's.
    • AC-3 integration Given a snapshot from an older save schema, when loaded, then save migrations apply; if they fail, a clear error is shown.

    Waits on

    • mw-e30.1 Define versioned save format with section registry and migrations done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e33milestone:m1

M2 Class fantasies 4

  • mw-e33.9Visualize perception cones, alert states and noise eventsopenP1M2feature

    Description

    Why

    Stealth that feels fair requires designers to see exactly what creatures perceive and why.

    What

    As a designer, I want overlays for sight cones, hearing radii, current alert state, last-known-position markers, search paths and noise events so that I can tune stealth encounters.

    Overlay toggles per category; reads sim data only (no sim changes).

    Scope

    • In: Overlay renderer for AI/perception data, toggles via console
    • Out: AI logic (mw-e11)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given a guard in the testbed with the overlay on, when the player is in the sight cone, then the cone renders and the guard's alert label changes as the state progresses.
    • AC-2 e2e Given a noise event, when emitted, then an expanding ring shows its propagated radius for 1 s.
    • AC-3 integration Given overlays toggled on vs off, when the same replay runs, then sim state hashes are identical (overlay is read-only).

    Waits on

    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e11.17 AI debug overlay: sight cones, hearing, states, LKP and paths done
    • mw-e11.5 Creature perception: sight cones, hearing and special senses done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e33milestone:m2
  • mw-e33.10Visualize light levels, element propagation and trigger volumesopenP1M2feature

    Description

    Why

    The systemic world (fire, water, light, triggers) is invisible data until visualized; debugging emergent interactions depends on it.

    What

    As a designer, I want heatmap overlays for light level, temperature/fire, wetness/electricity and trigger volume outlines so that I can see why systemic interactions do or do not happen.

    Grid-sampled overlays from sim queries; property-tag filter ("show all flammable").

    Scope

    • In: Light field heatmap, element overlays, trigger volume wireframes, property filter
    • Out: The systems themselves (mw-e03)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given the light overlay in a room with one torch, when shown, then sampled values decrease with distance from the torch.
    • AC-2 e2e Given the property filter flammable, when enabled, then exactly the entities with that tag are highlighted.
    • AC-3 integration Given overlays on vs off, when the same replay runs, then state hashes are identical.

    Waits on

    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e03.21 Wire trigger volumes and mechanisms with data-defined signal graphs done
    • mw-e03.29 Show properties, element fields and light levels in a debug overlay done
    • mw-e03.5 Ignite, burn, spread and extinguish fire from heat and properties done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e33milestone:m2
  • mw-e33.11Create a spell sandbox scene with live parameter tuningblockedP1M2feature

    Description

    Why

    Magic must feel magical; designers need a playground to cast every spell against every material and creature.

    What

    As a designer, I want a sandbox with material stations (water, oil, wood, rope, metal) and dummies where I can cast any spell and tweak its parameters live so that I can find surprising combinations.

    Scene sandbox-spells, console learnall, cast <spellId>, parameter panel bound to hot-reloadable spell data.

    Scope

    • In: Sandbox scene, commands, parameter panel
    • Out: Spell content (mw-e08)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given ?scene=sandbox-spells and learnall, when opened, then every spell in content is castable from a list.
    • AC-2 e2e Given a spell's radius changed in the panel, when cast again, then the new radius applies without reload.
    • AC-3 content Given the sandbox scene, when validated, then it contains at least one entity for every property tag defined in e03-world-properties.

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e06.2 Run data-driven spells through a cast→deliver→effect pipeline done
    • mw-e33.6 Hot-reload content JSON into the running game open
    area:toolsepic:e33milestone:m2
  • mw-e33.12Create a creature arena to spawn and pit creaturesopenP1M2feature

    Description

    Why

    Creatures are creatures, not target dummies; their behaviours and relationships need a place to be observed.

    What

    As a designer, I want an arena where I can spawn any creature with chosen disposition/faction and watch interactions so that I can tune behaviours.

    Scene sandbox-creatures, commands spawn <creature> --faction --disposition, ai freeze/unfreeze, faction set.

    Scope

    • In: Arena scene, commands
    • Out: AI implementation (mw-e11/mw-e12)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given the arena, when spawn goblin-grunt --disposition hostile and spawn wolf --disposition neutral run, then both spawn with those dispositions visible in the inspector.
    • AC-2 unit Given ai freeze, when ticks advance, then frozen creatures' AI systems do not update while physics still does.
    • AC-3 unit Given a creature id with invalid disposition, when spawned, then validation fails with allowed values listed.

    Waits on

    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e33milestone:m2

M3 MVP content 2

  • mw-e33.13Preview dialogue graphs and edit quest/world state in-gameopenP1M3feature

    Description

    Why

    Branching quests with multiple resolutions are untestable by playing through every path manually.

    What

    As a narrative designer, I want a dialogue previewer and a quest/world-fact editor so that I can test any branch instantly.

    Dialogue previewer runs a dialogue graph standalone with editable condition inputs (disposition, facts, inventory). Quest panel lists quests, states, objectives; set state/fact via recorded debug commands. Graph lint: unreachable nodes, dead ends without exit.

    Scope

    • In: Previewer panel, quest/fact panel, graph lint in content:check
    • Out: Runtimes (e22-dialogue-runtime, e23-quest-runtime, e27-world-state-store)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given a dialogue id, when opened in the previewer with disposition=friendly, then only nodes whose conditions pass are selectable.
    • AC-2 unit Given a dialogue graph with an unreachable node, when linted, then content:check reports the node id.
    • AC-3 integration Given quest set <id> <state>, when executed, then dependent world facts update and the change is recorded in the replay.

    Waits on

    • mw-e22.5 Implement dialogue graph runtime with conditions and effects done
    • mw-e23.2 Implement quest state machine with branching and multi-resolution done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    • mw-e33.1 Add in-game debug console with commands, cheats and spawners done
    area:toolsepic:e33milestone:m3
  • mw-e33.14Simulate loot tables and report drop distributionsblockedP2M3task

    Description

    Why

    Exploration should produce interesting discoveries; designers need to see actual distributions, not guess from weights.

    What

    CLI pnpm loot:sim <tableId> --rolls 10000 --seed 1 prints item frequencies, expected gold, and flags items with 0 drops or duplicates of "unique" items; also available as console command.

    Scope

    • In: CLI + console command using sim loot roller with seeded RNG
    • Out: Loot runtime (e18-loot-tables)

    Notes

    • None.

    Acceptance criteria

    • AC-1 unit Given a table with weights 1:3, when 10,000 rolls simulate with seed 1, then frequencies are 25% ± 1.5% and 75% ± 1.5% and the output is identical across runs.
    • AC-2 unit Given a unique item that can drop twice in one roll, when simulated, then it is flagged.
    • AC-3 unit Given an unknown table id, when run, then it exits non-zero listing close matches.

    Waits on

    • mw-e18.1 Implement loot table schema and deterministic seeded roller done
    • mw-e33.4 Add `pnpm content:check` validator with cross-reference report open
    area:toolsepic:e33milestone:m3
E34Telemetry & PlaytestingPrivacy-first, local-first, opt-in measurement of deaths, abandoned encounters, spell usage, puzzle completion and other signals that complements — never replaces — direct observation of players.0/8 done · 0%

M2 Class fantasies 1

  • mw-e34.1Define local-first telemetry event schema, store and exportopenP1M2task

    Description

    Why

    Measuring deaths, abandonments and spell usage guides design — but this is a free game and players' privacy comes first.

    What

    Add src/game/telemetry: a zod-typed event catalogue ({type, v, sessionId (random per session), tick, simTimeMs, area, payload}), a typed emit() API, a bounded local ring buffer in IndexedDB (max 50k events / 20 MB, oldest dropped), and export to NDJSON (gzip). No network code in this item. Events are only recorded if telemetry is enabled (e34-consent) except a small in-memory buffer used for bug reports.

    Scope

    • In: Event catalogue, emitter, IndexedDB store, export, clear-all
    • In: Schema rule: no free-text string fields except enumerated ids (enforced by schema test)
    • Out: Consent UI (e34-consent)
    • Out: Specific gameplay events (e34-gameplay-events)
    • Out: Any upload (e34-opt-in-upload)

    Notes

    • Session id is random, not derived from device; no user id, no IP, no fingerprinting data (UA only as coarse browser family + version).

    Integration note: Moved to m2 — e04-skeleton-fun-validation (m2) consumes it.

    Acceptance criteria

    • AC-1 unit Given an event missing a required payload field, when emitted, then it is dropped and a dev-only warning logged (never throws into gameplay).
    • AC-2 unit Given the ring buffer at capacity, when a new event is stored, then the oldest is evicted and count stays at the cap.
    • AC-3 unit Given the event catalogue, when a schema-lint test inspects it, then no event has an unconstrained free-text string field.
    • AC-4 integration Given 1,000 stored events, when exported, then the NDJSON file has 1,000 valid lines that re-parse against the schema.
    • AC-5 e2e Given telemetry disabled (default), when playing for 2 minutes, then nothing is written to the telemetry IndexedDB store and zero network requests carry telemetry.

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e31.1 Create typed settings store and options menu skeleton done
    area:gameepic:e34milestone:m2

M3 MVP content 4

  • mw-e34.2Add opt-in telemetry consent, privacy notice and data controlsblockedP1M3feature

    Description

    Why

    Privacy-first: players must knowingly opt in, see exactly what is recorded, and delete it anytime.

    What

    As a player, I want to choose whether gameplay statistics are recorded, see what is recorded and delete it so that I stay in control.

    Off by default. First-launch (or playtest-mode) prompt explains local-first recording; settings toggle; "View my data" (event counts by type + sample), "Export", "Delete all". docs/privacy.md published with the site.

    Scope

    • In: Consent prompt, settings controls, privacy doc
    • Out: Upload consent (separate, e34-opt-in-upload)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given a fresh profile, when the game starts, then telemetry is off until the player explicitly opts in.
    • AC-2 e2e Given telemetry on with stored events, when "Delete all" is confirmed, then the store is empty and the counts show 0.
    • AC-3 e2e Given the player opts out after opting in, when playing further, then no new events are stored.
    • AC-4 manual Given docs/privacy.md, when reviewed, then it lists every event type and field recorded and states nothing leaves the device without a separate explicit action.

    Waits on

    • mw-e34.1 Define local-first telemetry event schema, store and export open
    area:uiepic:e34milestone:m3
  • mw-e34.3Emit core gameplay events: deaths, encounters, spells, puzzlesblockedP1M3task

    Description

    Why

    E34 outcome names these signals explicitly: deaths, abandoned encounters, spell usage and puzzle completion.

    What

    Instrument: session_start/end (class, build), death (cause type, killer content id, area, position bucketed to 2 m), encounter_start/complete/abandon (encounter id, duration, resolution: combat/stealth/social/avoid), spell_cast (spell id, target type, outcome tags), puzzle_start/solve/abandon (puzzle id, solution path id), ability_used (class verb id), setting_changed (difficulty/assist ids only), item_acquired (source: loot/shop/steal).

    Scope

    • In: Event definitions + emit points in game glue listening to sim events
    • In: Encounter/puzzle id conventions in content
    • Out: Analysis (e34-analysis-scripts)

    Notes

    • Emit from game layer listening to the sim event bus — never call telemetry from src/sim.
    • Abandon = left encounter/puzzle volume for > 60 s without resolution (configurable).

    Acceptance criteria

    • AC-1 integration Given the testbed with a scripted fight replay ending in player death, when run, then exactly one death event is recorded with cause, killer id and 2 m-bucketed position.
    • AC-2 integration Given the player leaves an encounter volume for 61 s unresolved, when evaluated, then encounter_abandon is emitted once; returning at 59 s emits nothing.
    • AC-3 integration Given a puzzle solved via an alternative solution path, when emitted, then puzzle_solve.solutionPath identifies that path id.
    • AC-4 unit Given telemetry disabled, when sim events fire, then emitters short-circuit without allocation-heavy work (≤ 0.01 ms per event measured).

    Waits on

    • mw-e03.21 Wire trigger volumes and mechanisms with data-defined signal graphs done
    • mw-e06.2 Run data-driven spells through a cast→deliver→effect pipeline done
    • mw-e15.3 Run data-defined puzzles composed from reusable world objects done
    • mw-e34.1 Define local-first telemetry event schema, store and export open
    area:gameepic:e34milestone:m3
  • mw-e34.4Capture uncaught errors locally for playtest bundlesblockedP1M3task

    Description

    Why

    Playtesters rarely report console errors; capturing them locally makes crashes diagnosable without third-party services.

    What

    Global error/unhandledrejection handlers record {message, stack (sanitized of URLs query strings), buildSha, area, tick} into a small local error log (always on, local only, max 200 entries) shown in the bug/feedback bundle and "View my data".

    Scope

    • In: Handlers, sanitizer, local log
    • Out: Remote error reporting services (not used)

    Notes

    • None.

    Acceptance criteria

    • AC-1 unit Given a thrown error with a stack containing ?token=abc, when sanitized, then query strings are stripped.
    • AC-2 e2e Given an unhandled promise rejection, when it occurs, then an entry is logged and the game continues running.
    • AC-3 unit Given 250 errors, when logged, then only the latest 200 are kept and repeated identical errors are counted rather than duplicated.

    Waits on

    • mw-e34.1 Define local-first telemetry event schema, store and export open
    area:gameepic:e34milestone:m3
  • mw-e34.5Add an in-game feedback hotkey capturing context and a noteblockedP1M3feature

    Description

    Why

    Players' moments of delight or confusion are best captured in the moment, tied to where and when they happened.

    What

    As a playtester, I want to press a key, type a quick note and tag it (bug / confusing / fun / idea) so that my feedback carries its context.

    Captures screenshot, area, position, tick, recent 60 s of events (if enabled), optional bug bundle (e33-replay-bug-capture); stored locally and included in the playtest export.

    Scope

    • In: Feedback overlay, local storage, inclusion in export
    • Out: Uploading (e34-opt-in-upload)

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given the feedback key pressed, when the overlay opens, then the game pauses and resumes on close.
    • AC-2 e2e Given a submitted note tagged "fun", when exported, then the bundle contains the note, tag, screenshot and area/tick.
    • AC-3 unit Given a note longer than 2,000 characters, when submitted, then it is truncated with an indicator.

    Waits on

    • mw-e34.1 Define local-first telemetry event schema, store and export open
    area:uiepic:e34milestone:m3

M4 Fun validation 2

  • mw-e34.6Export a single playtest bundle file for testers to sendblockedP1M4feature

    Description

    Why

    External testers need a one-click way to share everything useful, without accounts or servers.

    What

    As a playtester, I want one "Export playtest data" button producing one file so that sending results to the team is trivial.

    Bundle .mwplay (zip): telemetry NDJSON, error log, feedback notes + screenshots, settings, build SHA, capability summary, optional latest save and bug bundles. Shows file size and a contents preview before saving.

    Scope

    • In: Bundle writer (zip in browser), preview dialog
    • Out: Analysis (e34-analysis-scripts)

    Notes

    • None.

    Acceptance criteria

    • AC-1 integration Given a session with events, feedback and errors, when exported, then the bundle contains each component and a manifest listing them with counts.
    • AC-2 integration Given telemetry disabled, when exported, then the bundle omits telemetry and the manifest says so.
    • AC-3 unit Given the bundle manifest schema, when an exported bundle is parsed by the analysis tooling, then it validates.

    Waits on

    • mw-e34.3 Emit core gameplay events: deaths, encounters, spells, puzzles open
    • mw-e34.4 Capture uncaught errors locally for playtest bundles open
    • mw-e34.5 Add an in-game feedback hotkey capturing context and a note open
    area:gameepic:e34milestone:m4
  • mw-e34.7Aggregate playtest bundles into a death heatmap and usage reportblockedP1M4task

    Description

    Why

    Telemetry only matters if it turns into decisions; the team needs a quick report per playtest round.

    What

    pnpm playtest:report <dir> reads N .mwplay bundles and writes a single-file HTML report: death heatmap over top-down area maps, encounter resolution breakdown (combat/stealth/social/avoid) and abandonment rates, spell usage frequency per class, puzzle solve rates and solution-path distribution, session length, feedback notes by tag with screenshots.

    Scope

    • In: Node aggregation (100% covered pure functions), HTML report generator
    • In: Top-down map images generated from greybox scenes
    • Out: Qualitative observation notes (e35 protocol)

    Notes

    • None.

    Acceptance criteria

    • AC-1 unit Given 3 fixture bundles with known deaths, when aggregated, then per-area death counts and heatmap bins match expected values.
    • AC-2 unit Given a corrupt or wrong-version bundle among valid ones, when processed, then it is skipped with a warning and the report still builds.
    • AC-3 integration Given the report, when opened in Playwright offline, then it renders all sections with zero console errors.
    • AC-4 unit Given encounters resolved 5 combat / 3 stealth / 2 avoided, when aggregated, then the breakdown shows 50/30/20%.

    Waits on

    • mw-e34.6 Export a single playtest bundle file for testers to send open
    area:toolsepic:e34milestone:m4

Post-MVP 1

  • mw-e34.8Offer optional, explicit upload of a playtest bundleblockedP3post-MVPfeature

    Description

    Why

    Manual file sending adds friction for remote testers; an explicit upload button can help, but only with separate consent.

    What

    As a playtester, I want to optionally upload my bundle with one click after reviewing it so that I do not have to email files.

    Separate consent per upload (preview + "Upload" button), minimal endpoint (e.g. serverless function writing to private storage) with size limit and rate limiting, no cookies, delete-by-receipt-code.

    Scope

    • In: Upload UI, endpoint spec, ADR on hosting choice
    • Out: Automatic/background upload (never)

    Notes

    • Deferred post-MVP: file export covers MVP playtests. Requires secret handling for the endpoint — no secrets in the repo.

    Acceptance criteria

    • AC-1 e2e Given the upload dialog, when the player does not press Upload, then zero network requests leave the page.
    • AC-2 integration Given a bundle > 25 MB, when upload is attempted, then it is refused client-side with a message.
    • AC-3 integration Given a successful upload, when complete, then a receipt code is shown that can be used to request deletion.

    Waits on

    • mw-e34.6 Export a single playtest bundle file for testers to send open
    area:infraepic:e34milestone:post-mvp
E35MVP Fun ValidationExternal players demonstrate that combat, magic, stealth and exploration are intrinsically enjoyable, measured against fun hypotheses written before testing.0/10 done · 0%

M1 Grey-box slice 4

  • mw-e35.1Pre-register measurable fun hypotheses for MVP validationopenP1M1decision

    Description

    Why

    Fun validation is only honest if success criteria are written before playtests, not rationalized after.

    What

    Write docs/playtesting/fun-hypotheses.md: per pillar (combat intrinsically fun, magic feels magical, stealth satisfying, world rewards curiosity, classes change possibilities) define hypotheses with measures and thresholds, e.g. "≥ 70% of testers rate fighting a skeleton ≥ 4/5 with loot/XP disabled", "≥ 3 self-reported 'Wait… I can do that?' moments per hour (median)", "≥ 25% of dungeon encounters resolved without combat across thief players", "≥ 60% of sorcerers try a spell on the environment unprompted within 15 min". Includes go/no-go rule.

    Scope

    • In: Hypotheses doc with measures, thresholds, data source (survey/observation/telemetry)
    • Out: Running tests (later e35 items)

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given the doc, when reviewed, then each constitution design pillar has ≥ 1 hypothesis with a numeric threshold and named data source.
    • AC-2 manual Given the doc, when merged, then it defines an explicit go/no-go rule (e.g. which hypotheses must pass).
    • AC-3 manual Given a hypothesis relying on telemetry, when reviewed, then the corresponding event exists or is listed as a needed bead.
    area:designepic:e35milestone:m1
  • mw-e35.2Write playtest protocol, consent form, surveys and observation sheetblockedP1M1task

    Description

    Why

    Telemetry must not replace direct observation; a consistent protocol makes sessions comparable.

    What

    docs/playtesting/protocol.md: session script (setup, minimal briefing, think-aloud prompts, no-help rule, time-boxes), observer sheet (timestamped notes, "confusion/delight/wait-I-can-do-that" tags aligned with feedback tags), post-session survey (Likert items mapped to hypotheses + open questions), consent/recording form template, remote-session variant.

    Scope

    • In: Protocol, templates in docs/playtesting/templates/
    • Out: Recruitment (e35-recruit-testers)

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given the survey, when mapped to fun-hypotheses.md, then every survey-sourced hypothesis has a corresponding question.
    • AC-2 manual Given a dry-run session with one internal tester, when completed, then the protocol fits in 60 minutes and gaps found are fixed in the doc.
    • AC-3 manual Given the consent form, when reviewed, then it states what is recorded, how long it is kept, and how to withdraw.

    Waits on

    • mw-e35.1 Pre-register measurable fun hypotheses for MVP validation open
    area:qaepic:e35milestone:m1
  • mw-e35.3Deploy playtest builds to GitHub Pages with build IDsopenP1M1task

    Description

    Why

    Testers need a stable URL per round and bug reports must identify the exact build.

    What

    CI workflow deploys the game to Pages under /play/ (latest main) and /play/<tag>/ for tagged playtest releases (playtest-rN), alongside backlog.html. Build SHA + tag shown in the title screen corner and embedded in bundles; ?debug=1 enables console on playtest builds.

    Scope

    • In: Pages workflow extension (shared Pages site with backlog)
    • In: Version stamping
    • In: Release notes from CHANGELOG
    • Out: Hosting elsewhere (itch.io mirror optional later)

    Notes

    • None.

    Acceptance criteria

    • AC-1 integration Given tag playtest-r1 pushed, when the workflow runs, then /play/playtest-r1/ serves that build and /play/ still serves main.
    • AC-2 e2e Given a deployed build, when loaded, then the title screen shows the tag/SHA matching the commit.
    • AC-3 integration Given a backlog-only workflow run, when deploying, then existing /play/ builds are preserved (no Pages artifact clobbering).

    Waits on

    • mw-e00.11 Generate backlog.html from issues.jsonl and deploy to GitHub Pages done
    • mw-e00.3 Add CI with per-layer coverage gates, ratchet and Playwright smoke done
    area:infraepic:e35milestone:m1
  • mw-e35.4Internal playtest: is greybox combat fun with no rewards?blockedP1M1task

    Description

    Why

    Constitution: fighting a skeleton should be enjoyable even without XP or loot — test this at greybox, when it is cheapest to fix.

    What

    Run 5 internal/friendly sessions of the m1 greybox fight with loot/XP disabled using the protocol; record ratings and observations; report in docs/playtesting/reports/m1-combat.md with recommended changes filed as beads.

    Scope

    • In: Sessions, report, beads for findings
    • Out: Implementing fixes

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given 5 sessions, when completed, then the report includes per-tester combat fun rating, median, and top 3 frictions with timestamps.
    • AC-2 manual Given the median rating < 4/5, when the report is written, then it proposes specific changes as beads before m2 begins.
    • AC-3 manual Given the report, when merged, then every finding links to a bead or is marked won't-fix with a reason.

    Waits on

    • mw-e04.6 Knight light attack chain and shield block with guard break done
    • mw-e35.2 Write playtest protocol, consent form, surveys and observation sheet open
    area:qaepic:e35milestone:m1needs-human

M2 Class fantasies 1

  • mw-e35.5Internal playtests proving each class fantasy in greyboxblockedP1M2task

    Description

    Why

    m2 exit: each class's core verbs must feel like its fantasy before content production scales up.

    What

    Per class (knight, archer, sorcerer, thief): 3 sessions on a greybox encounter with multiple routes; measure route choice, verb usage (telemetry), and fantasy rating; report docs/playtesting/reports/m2-classes.md.

    Scope

    • In: 12 sessions, telemetry report, written findings, beads
    • Out: Content (m3)

    Notes

    • None.

    Integration note: Dropped hard dependency on e34-analysis-scripts (m4); m2 sessions are analysed from exported logs by hand.

    Acceptance criteria

    • AC-1 manual Given 3 sessions per class, when completed, then each class has a fantasy rating and a list of verbs used vs available.
    • AC-2 manual Given a class whose testers used < 50% of its core verbs unprompted, when reported, then discoverability beads are filed.
    • AC-3 integration Given the sessions' playtest bundles, when pnpm playtest:report runs, then per-class ability usage charts are included in the report.

    Waits on

    • mw-e04 E04 — Knight Combat open
    • mw-e05 E05 — Archery open
    • mw-e06 E06 — Magic Framework open
    • mw-e10 E10 — Thief Toolkit open
    • mw-e35.4 Internal playtest: is greybox combat fun with no rewards? open
    area:qaclass:allepic:e35milestone:m2needs-human

M4 Fun validation 5

  • mw-e35.6Recruit external playtesters and schedule sessionsblockedP1M4task

    Description

    Why

    External players, not the team, must demonstrate the game is fun.

    What

    Recruit ≥ 16 external testers (two rounds of ≥ 8) spanning genre veterans and casual players, with at least 2 using accessibility settings; screener form, scheduling, consent collection; tracking sheet (no personal data in the repo).

    Scope

    • In: Screener, outreach, scheduling
    • Out: Paid recruitment platforms (only if needed)

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given recruitment, when complete, then ≥ 16 consenting testers are scheduled across two rounds with a mix recorded as aggregate counts only.
    • AC-2 manual Given the repo, when checked, then no tester personal data (names, emails) is committed.
    • AC-3 manual Given no-shows exceed 25% in a round, when detected, then backup testers are scheduled to maintain ≥ 8 sessions.

    Waits on

    • mw-e35.2 Write playtest protocol, consent form, surveys and observation sheet open
    area:qaepic:e35milestone:m4needs-human
  • mw-e35.7Run external playtest round 1 on the MVP buildblockedP1M4task

    Description

    Why

    The first honest measurement of the fun hypotheses with players who owe us nothing.

    What

    Run ≥ 8 sessions with the protocol on a tagged playtest-r1 build; collect bundles, observer notes and surveys; produce docs/playtesting/reports/r1.md scoring each hypothesis.

    Scope

    • In: Sessions, report with hypothesis scorecard
    • Out: Triage (e35-findings-triage)

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given ≥ 8 completed sessions, when the report is written, then each pre-registered hypothesis has a measured value and pass/fail.
    • AC-2 integration Given the collected bundles, when the analysis script runs, then the report embeds its heatmap and usage sections.
    • AC-3 manual Given a session with a crash, when reported, then its error log and bug bundle are attached to a bead.

    Waits on

    • mw-e34.7 Aggregate playtest bundles into a death heatmap and usage report open
    • mw-e35.3 Deploy playtest builds to GitHub Pages with build IDs open
    • mw-e35.6 Recruit external playtesters and schedule sessions open
    area:qaepic:e35milestone:m4needs-human
  • mw-e35.8Triage round-1 findings into prioritized beadsblockedP1M4task

    Description

    Why

    Findings are worthless unless they become prioritized work before round 2.

    What

    Cluster observations, survey comments and telemetry anomalies into issues; file beads with evidence links; prioritize by hypothesis impact; select the set to fix before round 2.

    Scope

    • In: Triage doc section in r1 report, beads
    • Out: Fixes themselves

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given the r1 report, when triaged, then every failed hypothesis has at least one linked bead with a proposed change.
    • AC-2 manual Given the triaged beads, when prioritized, then a "before round 2" set is labelled and each has an owner/estimate.
    • AC-3 manual Given a finding judged out of scope, when recorded, then the reason is written in the report.

    Waits on

    • mw-e35.7 Run external playtest round 1 on the MVP build open
    area:designepic:e35milestone:m4
  • mw-e35.9Run external playtest round 2 to validate fixesblockedP1M4task

    Description

    Why

    Confirms changes improved the experience rather than just changing it.

    What

    Run ≥ 8 sessions with new testers on playtest-r2; same protocol and analysis; report r2 with deltas vs r1 per hypothesis.

    Scope

    • In: Sessions, r2 report with r1→r2 deltas
    • Out: Decision (e35-mvp-go-no-go)

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given ≥ 8 sessions with testers not in round 1, when reported, then each hypothesis shows r1 value, r2 value and delta.
    • AC-2 manual Given a hypothesis that regressed, when reported, then the likely cause is analysed and a bead filed.
    • AC-3 integration Given r1 and r2 bundles, when the analysis script runs in comparison mode, then side-by-side charts are produced.

    Waits on

    • mw-e35.8 Triage round-1 findings into prioritized beads open
    area:qaepic:e35milestone:m4needs-human
  • mw-e35.10Record MVP go/no-go decision against fun hypothesesblockedP1M4decision

    Description

    Why

    Constitution: mobile and expansion only after the MVP proves the game is fun; this is that gate.

    What

    ADR docs/adr/NNNN-mvp-go-no-go.md applying the pre-registered go/no-go rule to r2 results: go (proceed to post-MVP: E36 etc.), iterate (another round with named changes), or pivot; lists evidence and next steps.

    Scope

    • In: ADR with evidence links
    • Out: Post-MVP planning itself

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given r2 results, when the ADR is written, then it applies the pre-registered rule verbatim and states the outcome.
    • AC-2 manual Given an "iterate" outcome, when recorded, then the ADR names the hypotheses to re-test and the changes planned.
    • AC-3 manual Given a "go" outcome, when recorded, then mw-e36 stubs are unblocked for re-planning.

    Waits on

    • mw-e35.9 Run external playtest round 2 to validate fixes open
    area:designepic:e35milestone:m4
E36Mobile AdaptationOnly after MVP validation: touch UX, mobile performance profiles, interface redesign and mobile browser support.0/4 done · 0%

Post-MVP 4

  • mw-e36.1Spike: mobile browser feasibility and target devicesblockedP4post-MVPspike

    Description

    Why

    Mobile only after MVP validation; before committing, measure what mobile browsers can actually run.

    What

    Time-box 2 days: run the MVP build on representative iOS Safari and Android Chrome devices, measure fps/memory/load on a mobile preset, identify blockers (memory limits, WASM, audio unlock, fullscreen/orientation); ADR recommending target devices and scope.

    Scope

    • In: Measurements, ADR
    • Out: Implementation

    Notes

    • None.

    Acceptance criteria

    • AC-1 manual Given 2 iOS and 2 Android devices, when the MVP build runs, then fps, memory and load time are recorded in the ADR.
    • AC-2 manual Given a device that crashes or fails to load, when recorded, then the cause (memory, API) is identified or marked unknown with next steps.
    • AC-3 manual Given the ADR, when merged, then it states go/no-go for mobile and target device floor.

    Waits on

    • mw-e35.10 Record MVP go/no-go decision against fun hypotheses open
    area:perfepic:e36milestone:post-mvp
  • mw-e36.2Design touch controls for movement, camera and class verbsblockedP4post-MVPfeature

    Description

    Why

    Keyboard/mouse verbs must map to touch without losing class expressiveness.

    What

    As a mobile player, I want virtual stick, camera drag and contextual verb buttons so that I can play every class on touch. Coarse placeholder — split after the feasibility spike.

    Scope

    • In: Touch input adapter onto the action map, layout customization
    • Out: Anything before e36-mobile-feasibility

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given touch emulation, when the virtual stick is dragged, then the player moves proportionally.
    • AC-2 e2e Given simultaneous stick + camera drags (multi-touch), when performed, then both apply independently.
    • AC-3 manual Given each class, when played on a phone for 10 minutes, then its core verbs are usable (rated ≥ 3/5 by testers).

    Waits on

    • mw-e02.1 Map remappable KB/M input to deterministic per-tick action frames done
    • mw-e36.1 Spike: mobile browser feasibility and target devices open
    area:uiepic:e36milestone:post-mvp
  • mw-e36.3Create a mobile performance preset and memory budgetblockedP4post-MVPtask

    Description

    Why

    Mobile GPUs and memory limits (esp. iOS Safari) need their own budgets.

    What

    Mobile preset (render scale, shadows off/low, reduced particles, texture downscale), memory budget per spike findings, added to perf suite. Coarse placeholder.

    Scope

    • In: Preset, budgets, perf suite entries
    • Out: Desktop presets

    Notes

    • None.

    Acceptance criteria

    • AC-1 perf Given the target floor device, when the combat stress scene runs on the mobile preset, then p95 frame time ≤ 33.3 ms.
    • AC-2 perf Given iOS Safari, when played for 20 minutes, then the tab is not killed for memory (heap within the spike-defined budget).
    • AC-3 unit Given a desktop capability profile, when presets are chosen, then the mobile preset is never auto-selected.

    Waits on

    • mw-e32.6 Implement Low/High graphics presets and dynamic resolution open
    • mw-e36.1 Spike: mobile browser feasibility and target devices open
    area:perfepic:e36milestone:post-mvp
  • mw-e36.4Redesign HUD and menus for small touch screensblockedP4post-MVPfeature

    Description

    Why

    Desktop menus and dense HUDs are unusable at phone sizes with touch targets.

    What

    As a mobile player, I want HUD and menus sized for touch so that I can manage inventory, books and dialogue comfortably. Coarse placeholder.

    Scope

    • In: Touch-target sizing (≥ 44 px), portrait/landscape handling, safe areas
    • Out: Desktop UI

    Notes

    • None.

    Acceptance criteria

    • AC-1 e2e Given a 390×844 viewport, when each menu renders, then all interactive targets are ≥ 44×44 CSS px and nothing overflows.
    • AC-2 e2e Given a device rotation, when it occurs, then layout adapts without losing game state.
    • AC-3 e2e Given a notched device safe area, when the HUD renders, then no HUD element is under the notch.

    Waits on

    • mw-e31.11 Make every menu keyboard- and gamepad-operable with visible focus done
    • mw-e36.1 Spike: mobile browser feasibility and target devices open
    area:uiepic:e36milestone:post-mvp
E37Art Direction & Asset PipelineThe Vesper Bell has one coherent, readable, performant visual identity — a hand-painted, chunky low-poly storybook world — produced by a solo developer with GPT image generation, CC0 kits and one image-to-3D tool, and every art asset flows through a validated, licence-tracked pipeline from prompt to runtime.3/432 done · 1%

M1 Grey-box slice 8

  • mw-e37.2Asset validator: naming, budgets and licence entries in CIopenP1M1task

    Description

    Why

    A solo developer cannot manually police hundreds of assets. Budgets and licences must be enforced by machine or they will drift — and a licence mistake in a public repo is expensive to undo.

    What

    As a developer, I want pnpm assets:validate to check every asset against the bibles so that CI rejects misnamed, over-budget or unlicensed assets. Checks: asset-id naming regex and category prefix; source/runtime folder mirroring; assets/CREDITS.md row exists with an allowed licence and required fields; glTF budgets (triangles, materials, bones, texture sizes by asset class per style bible §13.2); texture power-of-two + KTX2 for runtime; filled prompt files contain the verbatim preamble; placeholder flags reported.

    Scope

    • In: Validator module in src/tools/assets/ with pure functions (parsing CREDITS table, naming, budget rules as data)
    • In: glTF inspection via a glTF parsing library (no renderer)
    • In: CI job + JSON/markdown report
    • In: Budget table as a data file shared with docs
    • Out: Audio-specific checks (see e38-audio-validator, which extends this)
    • Out: Import/compression (see e37-model-import-pipeline)

    Notes

    Owner requirement: 100 % tested (lines/branches/functions/statements) even though src/tools normally needs ≥ 90 % — add the path to the 100 % group in coverage config. Budget classes are inferred from the asset-id prefix (model-char-*, model-creature-*, model-prop-*) with an override in a sidecar JSON.

    Acceptance criteria

    • AC-1 unit Given asset ids model-creature-minotaur-01 and Model_Minotaur, when validated, then the first passes and the second fails with a message naming the naming rule.
    • AC-2 unit Given a runtime asset with no matching assets/CREDITS.md row, or a row whose licence is CC-BY-NC-4.0, when validated, then validation fails listing the asset id and reason.
    • AC-3 unit Given a glTF fixture for a standard creature with 7 000 triangles, 2 materials or a 2048² texture, when validated against the creature budget (≤ 6 k tris, 1 material, ≤ 512²), then each violation is reported separately with actual vs limit.
    • AC-4 unit Given a filled prompt file whose preamble differs from style bible §14 by one character, when validated, then it fails and shows the first differing position.
    • AC-5 integration Given the CI pipeline, when a PR adds an invalid asset, then the assets:validate job fails and uploads a markdown report artifact.
    • AC-6 unit Edge: given a malformed CREDITS table row (missing columns) or a corrupt .glb, when validated, then the validator reports a parse error for that file and continues validating the rest instead of crashing.
    • AC-7 unit Given the validator source, when coverage runs, then lines, branches, functions and statements are all 100 %.

    Waits on

    • mw-e00.1 Scaffold TypeScript/Vite/pnpm repo with lint, typecheck and Vitest done
    • mw-e00.18 Load schema-validated content with a per-entry test harness done
    area:artarea:toolsepic:e37milestone:m1
  • mw-e37.3Record owner approval gates and block unapproved assets in CIblockedP1M1task

    Description

    Why

    Claude generates the assets; the owner's taste is exercised only at approval gates (flat image, 3D turntable, music take, SFX batch). Those decisions must be durable and machine-checked, or unapproved generations will slip into the game.

    What

    As the owner, I want every approval I give recorded with the exact file version so that nothing I have not approved can ship. Add assets/approvals.json (zod schema): entries of { assetId, gate: "image"|"turntable"|"music-take"|"sfx-batch", version, sha256, decision: "approved"|"rejected", approver, date, note }; a small CLI (pnpm assets:approve <asset-id> <gate> <version> [--reject --note]) that hashes the candidate and appends the record; and a validator rule: any non-placeholder runtime asset must have approved records for every gate its category requires, matching the committed source file hash.

    Scope

    • In: Schema + CLI in src/tools/assets/approvals/
    • In: Required gates per category as data (images: image; 3D: image + turntable; music: music-take; SFX: sfx-batch)
    • In: Validator rule wired into assets:validate
    • Out: The preview UIs themselves (turntable: see e37-turntable-preview)
    • Out: Licence checks (see e37-asset-validator)

    Notes

    100 % coverage (same rule as the validator). The approver field is a name/handle only — no emails or secrets.

    Acceptance criteria

    • AC-1 unit Given a final 3D asset with an approved image record but no turntable record, when validated, then validation fails naming the missing gate.
    • AC-2 unit Given an approval record whose sha256 does not match the committed source file (file changed after approval), when validated, then validation fails with "approval stale" and both hashes.
    • AC-3 unit Given pnpm assets:approve model-creature-minotaur-01 turntable v3, when run, then a schema-valid record with the file sha256 and ISO date is appended and the file is otherwise unchanged.
    • AC-4 unit Given a placeholder asset (placeholder: yes in CREDITS), when validated, then no approval is required.
    • AC-5 unit Edge: given a rejected record followed by an approved record for a later version, when validated, then only the approved version's hash is accepted; a malformed approvals.json fails with a parse error location.
    • AC-6 unit Given the approvals module, when coverage runs, then all four metrics are 100 %.

    Waits on

    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    area:artarea:toolsepic:e37milestone:m1
  • mw-e37.4Image generation runner wrapping codex exec with Images API fallbackopenP1M1task

    Description

    Why

    Claude generates all 2D images; the owner only approves. A reliable, logged runner turns a filled prompt file into a versioned candidate image with provenance, so image "generate" tasks are Claude-run rather than needs-human.

    What

    As a developer, I want pnpm assets:gen-image <prompt-file> to run the OpenAI Codex CLI non-interactively (codex exec, signed in with the owner's ChatGPT subscription, built-in gpt-image tool), pick up the new image from ~/.codex/generated_images/, and copy it to assets/_incoming/<asset-id>/vN.png with vN.json recording prompt file path + hash, tool, model, date and attempt count. On usage-limit errors: exponential backoff with jitter and resumable batch queue. Fallback: OpenAI Images API when OPENAI_API_KEY is set and subscription generation is unavailable/rate-limited beyond a threshold.

    Scope

    • In: Runner in src/tools/assets/image-gen/ with the codex process and HTTP behind injectable interfaces
    • In: Prompt-file parsing (extract filled prompt block; verify verbatim preamble before spending a generation)
    • In: Batch mode over a list of prompt files with a max-per-session cap
    • In: Versioning vN, never overwriting
    • Out: Approval recording (see e37-asset-approval-log)
    • Out: Post-processing/compression (see e37-model-import-pipeline)

    Notes

    Owner requirement: 100 % coverage with the codex process mocked (spawn stub emitting stdout/exit codes; fake generated_images dir). Risk: ChatGPT subscription image usage limits — generate in planned batches, not bursts; the runner must stop cleanly and report remaining queue. OPENAI_API_KEY read from env only, never logged (redact in error output). Transparent backgrounds: request in prompt; validate alpha channel for categories that need it.

    Acceptance criteria

    • AC-1 unit Given a filled prompt file for icon-item-lockpick-iron-01 and a mocked codex run that writes one PNG to the generated-images dir, when the runner executes, then assets/_incoming/icon-item-lockpick-iron-01/v1.png and v1.json (prompt hash, tool "codex-gpt-image", model, ISO date) exist; a second run produces v2 without touching v1.
    • AC-2 unit Given a prompt file whose preamble differs from the style bible, when the runner starts, then it refuses before invoking codex and reports the first differing position.
    • AC-3 unit Given codex exits with a usage-limit error twice then succeeds, when run, then the runner retries with exponential backoff (injected clock) and succeeds on attempt 3, recording attempts: 3.
    • AC-4 unit Given usage-limit errors persist past the threshold and OPENAI_API_KEY is set, when run, then the runner falls back to the mocked Images API and records tool "openai-images-api"; without the key it stops and reports the remaining batch queue.
    • AC-5 unit Edge: given codex exits 0 but produces no new image (or a non-PNG), when run, then the attempt is marked failed with a clear message and no empty version folder is left behind.
    • AC-6 unit Given any error path, when logs are captured, then no API key or auth token value appears in output (redaction test).
    • AC-7 unit Given the runner module, when coverage runs, then all four metrics are 100 %.

    Waits on

    • mw-e00.1 Scaffold TypeScript/Vite/pnpm repo with lint, typecheck and Vitest done
    area:artarea:toolsasset:conceptepic:e37milestone:m1
  • mw-e37.5Review and finalize image prompt templatesblockedP1M1task

    Description

    Why

    Every per-asset prompt bead copies a template; errors or gaps in templates multiply across the whole asset set.

    What

    Review the 14 image templates in assets/prompts/_templates/ (concept-art, character-reference-sheet, creature-reference-sheet, environment-concept, tileable-texture, prop-sheet, ui-element, item-icon, spell-icon, npc-portrait, book-cover-and-page, vfx-flipbook-texture, skybox-backdrop, key-art-title-screen) and assets/prompts/README.md against the signed-off style bible; fill one example per template category that has a first real asset (anchor assets for series: item icon, spell frame, portrait, UI panel).

    Scope

    • In: Template edits to match the signed-off bible
    • In: One worked example each for item-icon, spell-icon, npc-portrait and ui-element (these become the series anchors)
    • In: README workflow review
    • Out: Music/SFX templates (see e38-prompt-templates)
    • Out: Per-asset prompt beads (later wave)

    Notes

    Templates carry {{GPT_STYLE_PREAMBLE}} placeholders — the validator (e37-asset-validator) can check filled prompt files contain the verbatim preamble text.

    Acceptance criteria

    • AC-1 content Given every file in assets/prompts/_templates/ for image categories, when inspected, then each contains the contract §6 fields: asset id, consuming bead(s), filled prompt with preamble placeholder, output spec, consistency checklist, iteration log and provenance table.
    • AC-2 manual Given the 4 worked examples, when Claude generates them via e37-image-gen-runner, then each passes its own consistency checklist, is approved by the owner (recorded in assets/approvals.json) and is committed as the series anchor with a CREDITS row.
    • AC-3 content Given a filled prompt file, when the validator checks it, then it fails if the preamble text differs from style bible §14 by any character.
    • AC-4 manual Edge: given a template whose instructions produced a failed generation twice (e.g. flipbook grid misalignment), when reviewed, then the template intro documents the workaround used.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artepic:e37milestone:m1
  • mw-e37.6Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-offblockedP1M1spike

    Description

    Why

    The owner will do NO 3D work: Claude must produce every model by API from owner-approved flat concept images, within budget on Iris Xe and consistent with the style bible. Hero creatures (the misunderstood minotaur) must be memorable, so they need bespoke models without hand-modelling.

    What

    Time-box 2 days. Question: how does Claude, with zero owner 3D work, source (a) bulk props/environments, (b) player/NPC characters with animations, and (c) hero/unique creatures, consistent with the style bible and licensable for a free public repo? Run a head-to-head Meshy API vs Tripo API bake-off using the SAME owner-approved GPT minotaur concept, scripted end-to-end by Claude (ad-hoc scripts in spikes/3d-pipeline/), and validate the CC0-kit path with one character + one prop set. Output an ADR in docs/adr/ naming ONE image-to-3D provider and at most ONE paid month / prepaid credit purchase, with rationale.

    Scope

    • In: CC0 kit evaluation: KayKit (characters, dungeon, skeletons), Quaternius (modular village/dungeon, monsters, universal animation library), Kenney — style fit after palette recolour
    • In: Meshy API vs Tripo API bake-off on one owner-approved GPT minotaur concept (generated with the creature template), each run image-to-3D → remesh/retopo → rig → animation → glb download
    • In: Scoring rubric (below) and time log
    • In: Round-trip into the renderer via the draft import path
    • In: Animation source evaluation (CC0 animation libraries vs Mixamo)
    • Out: Production import pipeline (see e37-model-import-pipeline)
    • Out: Retargeting tooling (see e37-animation-pipeline)
    • Out: Generating production hero assets (later prompt/generate beads)

    Notes

    Recommendation going in (to confirm or overturn with evidence):

    1. Default for bulk props, environments, modular architecture and most characters: CC0 low-poly kits (KayKit + Quaternius as the primary families, Kenney for gaps). They are already chunky/bevelled, use gradient/palette atlases that we recolour with tex-palette-master-01, and carry zero licence risk. Mixing kit families is the main consistency risk — mitigated by one shared stylized material and palette remap.
    2. Animations: CC0 first (KayKit character animations, Quaternius Universal Animation Library) retargeted to one humanoid skeleton. Mixamo only as fallback: its terms allow use in games but restrict redistributing raw animation files, and our repo is public — only commit animations baked into our own .glb, never raw FBX, and record the decision in the ADR.
    3. Hero/unique assets (minotaur, bespoke NPCs such as the bookseller, unique props): Meshy is the named candidate (owner preference), contested by Tripo in the bake-off. Flow: approved GPT reference sheet → image-to-3D → remesh/retopo to budget (≤ 20 k tris minotaur, 4–7 k key NPC) → auto-rig → export glTF → gltf-transform (meshopt + KTX2) → renderer.
    4. No DCC at all: the owner never opens Blender. Everything is API + gltf-transform CLI (simplify/weld/compress/pivot/scale fixes) scripted by Claude; if a model needs manual DCC fixes to be usable, that counts against it in scoring.
    5. Workflow (style bible §17.2): concept → OWNER GATE (flat image) → API image-to-3D → remesh/retopo → rig/animate via API → glb → validator → turntable preview → OWNER GATE (turntable) → commit + CREDITS + approvals.

    Meshy facts (owner-verified, Sept 2026): Web app — Free = 100 credits/mo, outputs CC BY 4.0 (attribution in assets/CREDITS.md + in-game credits — acceptable for this free game); Pro = $20/mo ($240/yr), 1,000 credits/mo, private licence; image-to-3D 25 (Meshy 7) / 20 (Meshy 6), text-to-3D 20 (Meshy 6 only), AI texturing 10, remesh/rigging/animation free in-app. API (what Claude uses): prepaid API credits — image-to-3D 30 (2K textures), remesh 5, rigging 5, animation 3 per action ⇒ ≈ 46 credits for one hero with 2 actions. Confirm output licence for API-generated assets in the ADR.

    Tripo facts (Aug–Sep 2026, official pricing page blocked — medium confidence, re-verify): Web — Free 200–300 credits/mo, CC BY 4.0, ~15 downloads/mo cap; Pro $19.90/mo with ~3,000 credits. API: $0.01/credit — image-to-3D 20–30, smart low-poly retopo 30, auto-rig 25, animation retarget 10 each ⇒ ≈ 95–105 credits (≈ $1) per hero with 2 actions.

    Bake-off scoring rubric (each 1–5, weighted): topology & tri count after reduction to budget (×3), texture fidelity vs style bible palette/painted look (×3), rig quality — deformation at shoulders/hips/knees in walk + attack (×2), time-to-glTF in our renderer incl. automated fixes (×2), API ergonomics for an unattended client — task submit/poll/download, errors, rate limits (×2), licence clarity for a public repo (×1), cost for the MVP hero set (×1). Same input image, same target budget.

    Owner prerequisites: API keys in env (MESHY_API_KEY, TRIPO_API_KEY) and a small prepaid credit top-up for each provider; keys never logged or committed.

    Decision output: one image-to-3D provider, at most one paid month / one prepaid credit purchase sized for the MVP hero set, with rationale and evidence files. Feeds e37-3d-gen-api-client.

    Related: e39-story-bible (minotaur design intent).

    Acceptance criteria

    • AC-1 integration Given the owner-approved GPT minotaur concept (approval recorded), when Claude runs it through the Meshy API image-to-3D → remesh to ≤ 20 k triangles → rigging → one animation → glb download → KTX2/meshopt compression → import into the renderer test scene, then the model renders animated (idle + one attack) with no console errors, and elapsed time and credits used are logged in the ADR.
    • AC-2 manual Given the SAME concept image, when run through the equivalent Tripo API pipeline (image-to-3D → smart low-poly retopo → auto-rig → retarget → glb → import), then its results are scored with the same rubric and both scorecards appear side by side in the ADR with turntable renders under spikes/3d-pipeline/, and the owner picks a winner at a recorded turntable gate.
    • AC-3 manual Given one KayKit or Quaternius character and one prop set, when recoloured with the palette texture and rendered with the draft stylized material next to the minotaur, then the ADR records whether kit and generated assets read as one style (with screenshot).
    • AC-4 content Given every spike output kept in the repo, when inspected, then each has an assets/CREDITS.md row (tool, model, tier, date, CC BY 4.0 attribution text where applicable) and is flagged placeholder: yes.
    • AC-5 manual Given the ADR, when read, then it names exactly one image-to-3D provider, at most one paid month / credit purchase (with timing and size), the animation source (provider API vs CC0 library vs Mixamo with redistribution caveat), and confirms no step requires owner DCC work.
    • AC-6 manual Edge: given an image-to-3D result that cannot reach the tri budget without visible collapse, a rig that breaks at the shoulders, or an API task that fails/times out, when scored, then the ADR documents the fallback (retry policy, CC0 kit recolour, or simplified hero concept) rather than accepting an over-budget asset.

    Waits on

    • mw-e00.13 Spike: choose Three.js vs Babylon.js and physics engine (ADR-0001) done
    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m1
  • mw-e37.7Placeholder asset kit: CC0 stand-ins at correct scale and namingblockedP1M1task

    Description

    Why

    Gameplay is never blocked by final art (contract §5). Placeholders with the final naming, scale and pivots make integration a file swap later.

    What

    Assemble a placeholder kit from CC0 packs: one humanoid for each class (colour-coded by class accent), skeleton, goblin, wolf, spider, minotaur stand-in (scaled humanoid/ogre), and props for every Legibility cue (door, lever, chest, climbable ledge, flammable rope/barrel, breakable crate, weak wall, pushable block, lockable door), each named with its final asset id and placed under assets/kits/ + assets/source/.

    Scope

    • In: CC0 selection and download, unmodified kits in assets/kits/<kit>/ with licence files
    • In: Scale (1 unit = 1 m), pivot at base centre, forward = +Z (or engine convention)
    • In: CREDITS rows flagged placeholder: yes
    • In: Kit catalogue page listing asset id → placeholder file
    • Out: Greybox level geometry kit (owned by e00-greybox-testbed)
    • Out: Final assets (per-asset beads)

    Notes

    Candidate sources: KayKit Adventurers/Skeletons/Dungeon, Quaternius Ultimate Monsters/Modular Dungeon, Kenney. Keep total kit ≤ 15 MB built.

    Acceptance criteria

    • AC-1 content Given the kit catalogue, when validated, then every placeholder has a final-format asset id, a CREDITS row with CC0-1.0 and placeholder: yes.
    • AC-2 e2e Given the greybox testbed, when the kit showcase scene loads, then all placeholders render at correct relative scale (humanoid 1.7–1.9 m, minotaur stand-in 2.6–3.2 m) and screenshot sanity passes.
    • AC-3 integration Given the built kit, when measured, then total runtime size ≤ 15 MB and every asset passes the validator budgets.
    • AC-4 manual Given each Legibility cue prop, when viewed at 20 m on the Low preset, then the cue (cracks, pale ledge, straw/rope, brass keyhole) is identifiable by a second person.
    • AC-5 integration Edge: given a placeholder swapped for a file with a different pivot or scale, when the validator runs, then it flags the pivot/scale deviation beyond 5 %.

    Waits on

    • mw-e00.21 Create greybox testbed scene, level kit, scene loader and debug camera done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    area:artepic:e37milestone:m1
  • mw-e37.8Model import pipeline: glTF optimise, meshopt and KTX2 compressionblockedP1M1task

    Description

    Why

    The 50 MB initial download and Iris Xe texture memory budgets are only reachable if every model is optimised the same way, automatically.

    What

    As a developer, I want pnpm assets:build to turn assets/source/** models and textures into optimised runtime files under public/assets/ so that I never hand-optimise. Steps: glTF/GLB/FBX-converted input → weld/dedup/prune → optional simplify to budget → meshopt compression → textures resized to tier (High/Low variants) and encoded KTX2 (ETC1S albedo, UASTC normals/UI) → validator run → manifest JSON (asset id → URLs, sizes, tris).

    Scope

    • In: Node build script using gltf-transform (and KTX-Software/basis encoder)
    • In: High/Low texture variants
    • In: Incremental builds (hash cache)
    • In: Manifest for the loader
    • In: Loader smoke test in the renderer
    • Out: Texture atlas packing (see e37-texture-atlas-build)
    • Out: Animation retargeting (see e37-animation-pipeline)
    • Out: Audio (see e38-audio-import-pipeline)

    Notes

    Compression choice (meshopt vs Draco) follows e00-engine-decision; default meshopt. The encoder binary must be installable on CI (pin version). Outputs are generated — do not hand-edit public/assets/.

    Acceptance criteria

    • AC-1 integration Given a source .glb with 2048² PNG textures, when pnpm assets:build runs, then the output .glb uses meshopt compression and KTX2 textures, with High (≤ tier size) and Low (half-size) variants, and the manifest lists both with byte sizes.
    • AC-2 integration Given no source changes, when the build runs a second time, then no files are rewritten and the run completes in ≤ 5 s for 100 cached assets.
    • AC-3 e2e Given a built model in the greybox testbed, when the scene loads in Playwright, then the model renders with no console errors and a screenshot sanity check passes.
    • AC-4 integration Given a model exceeding its budget, when the build runs, then the validator step fails the build and names the asset (no silent auto-decimation beyond the configured simplify ratio).
    • AC-5 integration Edge: given a source file with a missing texture reference or an unsupported format, when built, then the build fails with the asset id and path and leaves previous outputs untouched.

    Waits on

    • mw-e00.13 Spike: choose Three.js vs Babylon.js and physics engine (ADR-0001) done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    area:artarea:toolsepic:e37milestone:m1
  • mw-e37.17Audit CREDITS.md and asset licences at each milestone exitblockedP1M1chore

    Description

    Why

    The game is free and the repo public: every committed asset is redistributed. One unlicensed file is a takedown risk for the whole project.

    What

    At each milestone exit (m1, m2, m3), reconcile every file under assets/ and public/assets/ with assets/CREDITS.md; re-check tool terms for any tier-dependent rights (Suno, ChatGPT/gpt-image, Meshy/Tripo, SFX tool); confirm CC BY attributions appear on the in-game credits screen; list remaining placeholders.

    Scope

    • In: Validator run + manual terms check
    • In: Cross-check assets/approvals.json: every final asset has approval records for all its gates
    • In: Audit log row in CREDITS.md
    • In: In-game credits screen data generated from CREDITS.md (CC BY rows)
    • Out: Replacing flagged assets (filed as beads)

    Notes

    This bead covers the m1 audit; clone it for m2/m3 exits (or reopen). Terms pages change — record the date read. Related: in-game credits screen UI (E31/E01 owners).

    Acceptance criteria

    • AC-1 integration Given the repository, when the validator runs in audit mode, then it lists every asset file lacking a CREDITS row and every row lacking a file, and exits non-zero if either list is non-empty.
    • AC-2 content Given CREDITS rows with licence CC-BY-4.0, when the credits data is generated, then each appears in the in-game credits data file with its attribution text.
    • AC-3 manual Given tier-dependent generated assets, when audited, then each row's tier/date is checked against the tool terms as of that date and the audit log records the terms URLs consulted.
    • AC-4 manual Edge: given an asset whose licence cannot be confirmed, when audited, then it is flagged placeholder: yes and a replacement bead is filed before the milestone is closed.

    Waits on

    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    area:artarea:musicarea:sfxepic:e37milestone:m1

M2 Class fantasies 36

  • mw-e37.21Generate player class characters 3D models via image-to-3D APIin progressP1M2task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 4 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-player-classes-turntable-approve)

    Notes

    Budget: 8–12 k tris LOD0 + LOD1 50 %, one 1024² atlas, 1 material, ≤ 65 bones (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 4 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets 8–12 k tris LOD0 + LOD1 50 %, one 1024² atlas, 1 material, ≤ 65 bones (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.20 Owner approval: player class characters flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelclass:allepic:e37milestone:m2
  • mw-e37.9Image-to-3D API client and CLI for the chosen providerblockedP1M2task

    Description

    Why

    The owner does no 3D work; Claude produces every bespoke model by API. A tested, idempotent client makes 3D "generate" tasks Claude-run and repeatable rather than needs-human.

    What

    As a developer, I want pnpm assets:gen-3d <asset-id> --from <approved-image> to submit an image-to-3D task to the provider chosen by e37-3d-pipeline-decision, poll to completion, chain remesh/retopo to the asset class tri budget, rigging and requested animations where applicable, download the .glb to assets/_incoming/<asset-id>/vN.glb with vN.json (task ids, provider, model, credits used, date), then invoke the validator.

    Scope

    • In: Client in src/tools/assets/gen3d/ behind a provider interface (Meshy and Tripo adapters; only the chosen one must be complete)
    • In: Submit, poll with backoff, download, retries on 5xx/429, timeouts
    • In: Idempotency by asset id + source image hash (re-running resumes existing task ids instead of paying again)
    • In: Refuses to run unless the source image has an approved image gate record
    • Out: Turntable rendering (see e37-turntable-preview)
    • Out: Compression (see e37-model-import-pipeline)
    • Out: Retargeting CC0 animation libraries (see e37-animation-pipeline)

    Notes

    API key only from MESHY_API_KEY / TRIPO_API_KEY env vars — never logged, committed or written to vN.json. 100 % coverage with HTTP mocked (recorded fixture responses, no live calls in CI). Pricing for credit estimates (print before submit): Meshy API image-to-3D 30 (2K tex), remesh 5, rigging 5, animation 3/action; Tripo API $0.01/credit — image-to-3D 20–30, smart low-poly 30, auto-rig 25, retarget 10. A --dry-run prints the credit estimate only.

    Acceptance criteria

    • AC-1 unit Given a mocked provider that returns a task id, two IN_PROGRESS polls then SUCCEEDED with a model URL, when gen-3d runs, then the .glb is downloaded to assets/_incoming/<asset-id>/v1.glb and v1.json records task ids, credits and date.
    • AC-2 unit Given the same asset id and source image hash re-run after a crash mid-poll, when gen-3d runs, then it resumes polling the stored task id and submits no new paid task.
    • AC-3 unit Given 429 and 503 responses, when calls are made, then the client retries with exponential backoff up to the configured limit and then fails with a clear error naming the stage (submit/poll/remesh/rig/download).
    • AC-4 unit Given a source image with no approved image gate record, when gen-3d runs, then it refuses before any HTTP call.
    • AC-5 unit Given --dry-run for a creature with 2 animations on Meshy, when run, then it prints an estimate of 30 + 5 + 5 + 2×3 = 46 credits and makes no HTTP calls.
    • AC-6 unit Edge: given a missing MESHY_API_KEY/TRIPO_API_KEY, or any error response, when logs are captured, then the key value never appears in output and the missing-key case exits non-zero with setup instructions.
    • AC-7 unit Given the client module, when coverage runs, then all four metrics are 100 %.

    Waits on

    • mw-e00.1 Scaffold TypeScript/Vite/pnpm repo with lint, typecheck and Vitest done
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    area:artarea:toolsasset:modelepic:e37milestone:m2
  • mw-e37.10Headless turntable preview of a glb as PNG strip and GIFblockedP1M2task

    Description

    Why

    The owner approves 3D models without opening any 3D tool. A consistent turntable rendered with the game's own material and lighting shows exactly what will ship.

    What

    As the owner, I want pnpm assets:turntable <glb> to produce an 8-angle PNG contact strip and a looping GIF (plus a silhouette frame and a stats overlay: tris, materials, bones, texture sizes, budget pass/fail) so that I can approve or reject a model from an image. Runs the real renderer headless via Playwright with the shared stylized material, golden-hour preset, a 1.8 m scale figure, and optional animation frames.

    Scope

    • In: Playwright-driven render page in src/tools/turntable/
    • In: Outputs next to the candidate: vN-turntable.png, vN-turntable.gif, vN-silhouette.png
    • In: Animation sampling (idle + one action) when clips exist
    • In: CI-safe (software GL/SwiftShader acceptable)
    • Out: Approval recording (see e37-asset-approval-log)
    • Out: In-game model viewer (Related: e33-debug-console)

    Notes

    Silhouette frame = solid ink on parchment at 64 px height (style bible §5 test). Uses e37-stylized-material once available; before that, a basic lit material with the same light rig.

    Acceptance criteria

    • AC-1 e2e Given a valid .glb fixture, when assets:turntable runs headless, then it writes an 8-frame PNG strip, a looping GIF and a silhouette PNG, with no console errors.
    • AC-2 e2e Given a rigged fixture with an idle clip, when rendered with --anim idle, then the strip contains sampled animation frames (frames differ pixel-wise from the bind pose).
    • AC-3 integration Given a model exceeding its budget, when rendered, then the stats overlay shows the failing budget in ember red with actual vs limit.
    • AC-4 e2e Given the same fixture rendered twice, when compared, then outputs are pixel-identical (deterministic camera, lighting and animation sampling).
    • AC-5 e2e Edge: given a corrupt .glb or missing textures, when rendered, then the command exits non-zero with the asset id and error, and writes no partial output files.

    Waits on

    • mw-e00.1 Scaffold TypeScript/Vite/pnpm repo with lint, typecheck and Vitest done
    • mw-e00.13 Spike: choose Three.js vs Babylon.js and physics engine (ADR-0001) done
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:renderarea:toolsasset:modelepic:e37milestone:m2
  • mw-e37.11Character animation pipeline with retargeting to a shared humanoid rigblockedP1M2task

    Description

    Why

    Four classes, NPCs and humanoid creatures need locomotion, combat and interaction animations; authoring per-character is impossible solo. Retargeting one library onto one skeleton makes every humanoid animate for free.

    What

    As a developer, I want animations from the chosen source (per e37-3d-pipeline-decision) retargeted onto one canonical humanoid skeleton and packed into per-character clip sets so that any humanoid model gains the full move set. Includes clip naming (anim-humanoid-<action>-<nn>), root-motion policy, clip trimming/looping, and a clip manifest consumed by the renderer's animation layer.

    Scope

    • In: Canonical skeleton definition + bone-name mapping tables (KayKit/Quaternius/Mixamo/Meshy/Tripo rigs)
    • In: Batch retarget script (headless)
    • In: Root-motion extraction or in-place policy
    • In: Clip manifest with loop flags and event markers (footstep, hit frame)
    • In: Hero creature (minotaur) rig handled as its own skeleton
    • Out: Animation state machine/blending (render/game layer; Related: e02-player-controller)
    • Out: Hand-keyed bespoke animations

    Notes

    Footstep and hit-frame markers feed audio (footstep surface set) and combat timing — markers must be data, not baked guesses. If Mixamo is used, raw FBX never enters the public repo (terms); only retargeted clips baked into our .glb.

    Acceptance criteria

    • AC-1 integration Given a source animation on a KayKit-style rig and a target model on the canonical skeleton, when the retarget script runs, then the output clip plays on the target with per-bone rotation error ≤ 2° versus the reference pose sample set.
    • AC-2 unit Given the bone mapping tables, when a source rig is missing a mapped bone, then the script reports the missing bone and skips only affected tracks.
    • AC-3 content Given the clip manifest, when validated, then every locomotion clip has loop: true, every attack clip has a hit event marker, and every walk/run clip has ≥ 2 footstep markers.
    • AC-4 e2e Given each of the 4 class placeholders, when the animation showcase cycles idle/walk/run/attack/interact, then no clip errors appear in the console and screenshots show no collapsed limbs.
    • AC-5 integration Edge: given a clip with root motion when the policy is in-place, when processed, then horizontal root translation is removed and stored as a velocity curve in the manifest.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artarea:toolsasset:modelepic:e37milestone:m2
  • mw-e37.13Shared stylized lit material with ramp, rim and wet/emissive masksopenP1M2feature

    Description

    Why

    One shader used by every model is the cheapest way to make kits, generated models and painted textures read as one world, and keeps the material count within budget.

    What

    As a player, I want every object lit in the same warm-key/cool-shadow painterly way so that the world feels hand-crafted and coherent. Soft 3-band ramp diffuse, shadow tint toward dusk, rim light, optional wet mask (darker + sheen), emissive mask for glyphs/magic, per-location colour-grade LUT hook, High/Low variants.

    Scope

    • In: Material implementation in src/render/materials/
    • In: Parameters exposed as data per location preset (style bible §3)
    • In: Low variant without normal maps
    • In: Visual regression screenshots
    • Out: Lightmap baking tool choice (Related: e37-3d-pipeline-decision notes)
    • Out: VFX shaders (Related: e29-vfx-framework)

    Notes

    Wet mask must be drivable at runtime by the wet world property (Related: e03-world-properties) so rain/water/ice states are visible.

    Acceptance criteria

    • AC-1 e2e Given the material test scene, when rendered at High and Low, then screenshots match approved baselines within a 2 % pixel-difference threshold.
    • AC-2 perf Given 200 instances of 20 distinct props using the material, when rendered on the reference machine (High), then GPU frame time for the scene ≤ 6 ms.
    • AC-3 integration Given an object whose wet property becomes true, when the next frame renders, then its albedo value drops by 20–30 % and specular sheen appears; reverting clears it.
    • AC-4 e2e Given the Low preset, when the material compiles, then no normal-map sampling occurs (shader variant check) and no console errors are logged.
    • AC-5 manual Edge: given pure-black and pure-white albedo test textures, when lit, then shadows render toward #3B3A5A and highlights clamp below #FFF4DC-equivalent, never pure black/white.

    Waits on

    • mw-e00.13 Spike: choose Three.js vs Babylon.js and physics engine (ADR-0001) done
    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    area:artarea:renderepic:e37milestone:m2
  • mw-e37.14Legibility kit: visual cues for every exploitable world propertyblockedP1M2feature

    Description

    Why

    Systemic play ("Wait… I can do that?") only works if players can read what the world allows: climbable, flammable, breakable, movable, lockable, freezable, conductive, alternate routes (constitution §2, §8).

    What

    As a player, I want climbable ledges, flammable ropes, weak walls and other affordances to look consistently distinct so that I can discover solutions by observation. Build the style bible §7 cue set as reusable decals, trims and material variants, plus a validator rule linking world-property tags to required cues.

    Scope

    • In: Decals: cracks, scuffs, chalk thieves' marks, drag marks, oil stains
    • In: Trim/material variants: pale ledge bevel, climb-ivy, tan hemp vs grey chain, pale breakable wood, brass wear
    • In: Data rule: objects tagged climbable/flammable/breakable… must reference a cue asset
    • In: Optional "highlight affordances" accessibility tint hook
    • Out: Property simulation (see e03-world-properties)
    • Out: Focus highlight UI (Related: e02-interaction)

    Notes

    Rule of the kit: a cue is never used decoratively. The content validator should flag a cue asset on an object lacking the matching property tag, and vice versa.

    Acceptance criteria

    • AC-1 content Given level/content data, when validated, then any object tagged climbable, flammable, breakable, movable or lockable without its cue asset fails validation, and any cue asset on an object lacking the property also fails.
    • AC-2 manual Given the cue showcase scene on the Low preset, when 3 playtesters who have not read the bible are asked to identify climbable, flammable and breakable objects at 20 m, then ≥ 80 % of answers are correct.
    • AC-3 e2e Given the "highlight affordances" setting enabled, when the showcase renders, then each cue category is tinted with its accessibility colour and screenshots match baselines.
    • AC-4 manual Given deuteranopia and protanopia simulation filters, when the showcase is viewed, then every cue remains identifiable by shape/pattern.
    • AC-5 content Edge: given an object whose property changes at runtime (a wall that has already been broken, a burnt rope), when its state updates, then its cue decal is removed or swapped so the world never advertises an affordance that no longer exists.

    Waits on

    • mw-e03.1 Define typed world-property components for systemic interactions done
    • mw-e03.31 Consolidate world-property vocabulary assumed by other epics done
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    area:artarea:designclass:allepic:e37milestone:m2
  • mw-e37.15Build the style-target diorama as the visual and performance benchmarkblockedP1M2task

    Description

    Why

    A single finished "this is what the game looks like" slice settles style arguments, proves the pipeline end-to-end and becomes the perf benchmark before we art-up whole locations.

    What

    A small vertical diorama (~30 × 30 m): Briar Glen edge at golden hour — a cottage, a well that hides a tunnel, a stretch of forest, a ruined wall with a weak section, a climbable ledge, a flammable rope bridge, one class character, one creature, one spell VFX in flight, one lantern-lit shadow pocket. Built only from pipeline outputs (kits + generated textures + one hero model if available).

    Scope

    • In: Scene assembly with final-quality stand-ins
    • In: High/Low presets
    • In: Screenshot baselines and a camera flythrough path
    • In: Perf capture on reference + Iris Xe-class device
    • Out: Gameplay logic beyond walking around
    • Out: Audio (see e38-audio-style-target)

    Notes

    Treat as the living visual benchmark: later art passes are compared against it. Related: e24 Briar Glen level work reuses its pieces.

    Acceptance criteria

    • AC-1 perf Given the diorama flythrough on the reference machine at High (1440p-equivalent), when measured, then frame time p95 ≤ 16.7 ms, draw calls ≤ 250 and visible triangles ≤ 1.2 M.
    • AC-2 perf Given the diorama on an Iris Xe-class device at Low (1080p), when measured, then frame time p95 ≤ 16.7 ms (floor ≤ 33.3 ms), draw calls ≤ 150, visible triangles ≤ 500 k.
    • AC-3 integration Given the diorama package, when built, then its download size is ≤ 25 MB and every asset passes the validator.
    • AC-4 manual Given the diorama screenshots, when reviewed against the style bible checklist (palette ratio, warm/cool, shape language, Legibility cues), then the owner signs off or files specific fix beads.
    • AC-5 e2e Edge: given a texture or model missing at load, when the diorama loads, then a placeholder is shown, a warning is logged once, and the scene remains navigable.

    Waits on

    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.14 Legibility kit: visual cues for every exploitable world property open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artarea:perfepic:e37milestone:m2
  • mw-e37.18Write player class characters concept prompts (4 images)blockedP1M2task

    Description

    Why

    The four class fantasies (constitution pillar: every class is a different way to play) must read by silhouette alone in the class lineup and at 30 m; these are the most-seen models in the game and the first style anchor.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: character) from character-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Turnaround reference sheets for knight, archer, sorcerer and thief per style bible §5.1 (primary shape, signature prop, palette accent), then Claude-run image-to-3D, retopo to 8–12 k tris, one 1024² atlas, rig on the canonical humanoid skeleton.

    Concept image ids (4):

    • char-knight-base-01
    • char-archer-base-01
    • char-sorcerer-base-01
    • char-thief-base-01

    Target model ids (4):

    • model-char-knight-01
    • model-char-archer-01
    • model-char-sorcerer-01
    • model-char-thief-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-player-classes-3d-generate)

    Notes

    Milestone m2 (earlier than most assets) because the class-fantasy playtests (e35-class-fantasy-tests) read much better with real silhouettes, and these sheets are style anchors for e37-asset-style-lock. Gameplay still runs on e37-greybox-asset-kit placeholders until integration. Held weapons are a separate set (e37-asset-weapons-*). Thief disguise recolour lives in e37-asset-thief-props-*.

    Budget: 8–12 k tris LOD0 + LOD1 50 %, one 1024² atlas, 1 material, ≤ 65 bones (style bible §13.2).

    Acceptance criteria

    • AC-1 content Given the 4 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (8–12 k tris LOD0 + LOD1 50 %, one 1024² atlas, 1 material, ≤ 65 bones (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelclass:allepic:e37milestone:m2
  • mw-e37.19Generate player class characters concepts via Codex CLIblockedP1M2task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 4 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-player-classes-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 4 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.18 Write player class characters concept prompts (4 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelclass:allepic:e37milestone:m2
  • mw-e37.20Owner approval: player class characters flat conceptsblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 4 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-player-classes-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each class is identifiable by silhouette alone when filled solid ink at 64 px tall, and the four read as one family in a side-by-side lineup. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each class is identifiable by silhouette alone when filled solid ink at 64 px tall, and the four read as one family in a side-by-side lineup.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-player-classes-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.19 Generate player class characters concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelclass:allepic:e37milestone:m2needs-human
  • mw-e37.22Owner approval: player class characters turntablesblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 4 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-player-classes-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each class is identifiable by silhouette alone when filled solid ink at 64 px tall, and the four read as one family in a side-by-side lineup. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each class is identifiable by silhouette alone when filled solid ink at 64 px tall, and the four read as one family in a side-by-side lineup.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-player-classes-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.21 Generate player class characters 3D models via image-to-3D API in progress
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelclass:allepic:e37milestone:m2needs-human
  • mw-e37.23Integrate approved player class charactersblockedP1M2task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e19-class-definitions, e02-animation-hooks, e37-animation-pipeline, e37-stylized-material.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 4 models are under public/assets/model/ within 8–12 k tris LOD0 + LOD1 50 %, one 1024² atlas, 1 material, ≤ 65 bones (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the class-select scene, when each class is chosen, then its final model loads, plays idle/walk/run/attack from the retargeted clip set with no console errors, and a Playwright screenshot shows all four in the lineup.
    • AC-4 perf Given the combat stress scene with these models, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e02.6 Drive character animation from sim locomotion state and events done
    • mw-e19.4 Define the four classes as data: kit, capabilities, proficiencies done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.22 Owner approval: player class characters turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelclass:allepic:e37milestone:m2
  • mw-e37.24Write school frames and glyphs prompts (26 assets)blockedP1M2task

    Description

    Why

    Thirteen schools cannot be told apart by hue alone; the shared rim frame and glyph per school carry identity for colour-blind players (style bible §2.3, §9.2) and anchor every spell icon.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: icon-spell / ui) from template spell-icon.md (frames) + ui-element.md (glyphs), with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    One painted medallion rim frame per school (school core/highlight/shadow colours, shape language from §2.3) and one flat ink-brush school glyph per school for grimoire ribbons, hotbar and book spines.

    Asset ids (26):

    • ui-spell-frame-fire-01
    • ui-spell-frame-frost-01
    • ui-spell-frame-storm-01
    • ui-spell-frame-arcane-01
    • ui-spell-frame-illusion-01
    • ui-spell-frame-alteration-01
    • ui-spell-frame-conjuration-01
    • ui-spell-frame-necromancy-01
    • ui-spell-frame-nature-01
    • ui-spell-frame-light-01
    • ui-spell-frame-shadow-01
    • ui-spell-frame-gravity-01
    • ui-spell-frame-time-01
    • ui-glyph-school-fire-01
    • ui-glyph-school-frost-01
    • ui-glyph-school-storm-01
    • ui-glyph-school-arcane-01
    • ui-glyph-school-illusion-01
    • ui-glyph-school-alteration-01
    • ui-glyph-school-conjuration-01
    • ui-glyph-school-necromancy-01
    • ui-glyph-school-nature-01
    • ui-glyph-school-light-01
    • ui-glyph-school-shadow-01
    • ui-glyph-school-gravity-01
    • ui-glyph-school-time-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-school-identity-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Frames are generated first because the spell-icon template attaches the school frame as a series anchor. Glyphs are flat single-colour 64² (§9.2 UI glyphs) and are vectorised to SVG during integration.

    Acceptance criteria

    • AC-1 content Given the 26 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (frames 1024² generate → 256²/128²/64² transparent PNG with an empty centre; glyphs flat single-colour ink on transparent, exported 64²) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: the 13 frames are distinguishable in greyscale by shape/rim motif (not only hue) and every glyph reads at 32 px.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:iconclass:sorcererepic:e37milestone:m2
  • mw-e37.25Generate school frames and glyphs via Codex CLIblockedP1M2task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 26 prompt files of e37-asset-school-identity-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-school-identity-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: frames 1024² generate → 256²/128²/64² transparent PNG with an empty centre; glyphs flat single-colour ink on transparent, exported 64². Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 26 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (frames 1024² generate → 256²/128²/64² transparent PNG with an empty centre; glyphs flat single-colour ink on transparent, exported 64²), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.24 Write school frames and glyphs prompts (26 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:iconclass:sorcererepic:e37milestone:m2
  • mw-e37.26Owner approval: school frames and glyphsblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 26 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-school-identity-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the 13 frames are distinguishable in greyscale by shape/rim motif (not only hue) and every glyph reads at 32 px. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 26 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the 13 frames are distinguishable in greyscale by shape/rim motif (not only hue) and every glyph reads at 32 px.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-school-identity-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.25 Generate school frames and glyphs via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:iconclass:sorcererepic:e37milestone:m2needs-human
  • mw-e37.27Integrate approved school frames and glyphsblockedP1M2task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e07-grimoire-ui, e06-spell-hotbar-ui, e08-school-conventions.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 26 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the grimoire and hotbar, when a spell of each school is displayed, then its school frame and glyph render from the atlas and a greyscale screenshot comparison shows 13 distinct rim shapes.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e06.16 Select spells from a hotbar and quick-select wheel with mana HUD done
    • mw-e07.10 Browse known spells, insights and verb chains in the grimoire open
    • mw-e08.1 Document magic schools, spell data conventions and too-useful policy open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.26 Owner approval: school frames and glyphs open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:iconclass:sorcererepic:e37milestone:m2
  • mw-e37.28Write spell icons prompts (23 assets)blockedP1M2task

    Description

    Why

    The sorcerer picks spells from a hotbar in the middle of a fight; every icon must be readable at 48 px within a school frame (style bible §9.2).

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: icon-spell) from template spell-icon.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    One painted circular medallion per MVP spell (23): the approved school rim frame as anchor plus a single bold central symbol unique to the spell.

    Asset ids (23):

    • icon-spell-fire-ember-01
    • icon-spell-fire-firebolt-01
    • icon-spell-fire-flame-jet-01
    • icon-spell-fire-fire-wall-01
    • icon-spell-frost-frostglass-01
    • icon-spell-conjuration-wellspring-01
    • icon-spell-storm-gust-01
    • icon-spell-storm-thunderclap-01
    • icon-spell-storm-arc-lash-01
    • icon-spell-arcane-mage-hand-01
    • icon-spell-arcane-telekinetic-throw-01
    • icon-spell-arcane-blink-01
    • icon-spell-arcane-arcane-sight-01
    • icon-spell-gravity-levitate-01
    • icon-spell-gravity-gravity-well-01
    • icon-spell-illusion-mirror-self-01
    • icon-spell-light-wisp-light-01
    • icon-spell-light-prism-ray-01
    • icon-spell-shadow-snuff-01
    • icon-spell-nature-grasping-vines-01
    • icon-spell-necromancy-animate-bones-01
    • icon-spell-alteration-polymorph-01
    • icon-spell-time-stasis-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-spell-icons-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Includes the four P2 spells (fire-wall, arcane-sight, snuff, stasis) because icons are cheap and needed for the grimoire silhouettes; drop those four ids if their spells are cut. One of the three style-anchor sets for e37-asset-style-lock (hence m2). Generation needs the approved school frames as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 23 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate → 256²/128²/64² transparent PNG, medallion centred, school frame matches the approved anchor) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: every symbol is distinguishable from its school siblings at 48 px and the frame matches the approved school frame.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.26 Owner approval: school frames and glyphs open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:iconclass:sorcererepic:e37milestone:m2
  • mw-e37.29Generate spell icons via Codex CLIblockedP1M2task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 23 prompt files of e37-asset-spell-icons-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-spell-icons-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate → 256²/128²/64² transparent PNG, medallion centred, school frame matches the approved anchor. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 23 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate → 256²/128²/64² transparent PNG, medallion centred, school frame matches the approved anchor), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.28 Write spell icons prompts (23 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:iconclass:sorcererepic:e37milestone:m2
  • mw-e37.30Owner approval: spell iconsblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 23 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-spell-icons-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every symbol is distinguishable from its school siblings at 48 px and the frame matches the approved school frame. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 23 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every symbol is distinguishable from its school siblings at 48 px and the frame matches the approved school frame.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-spell-icons-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.29 Generate spell icons via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:iconclass:sorcererepic:e37milestone:m2needs-human
  • mw-e37.31Integrate approved spell iconsblockedP1M2task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e06-spell-hotbar-ui, e07-grimoire-ui, e06-spell-schema.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 23 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell hotbar with all 23 spells assigned via debug console, when rendered at 1920×1080, then every slot shows its final icon (no placeholder flag) and no console errors occur.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e06.1 Define zod spell schema with delivery, effect ops and cue ids done
    • mw-e06.16 Select spells from a hotbar and quick-select wheel with mana HUD done
    • mw-e07.10 Browse known spells, insights and verb chains in the grimoire open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.30 Owner approval: spell icons open
    area:artasset:iconclass:sorcererepic:e37milestone:m2
  • mw-e37.32Write menu kit and journal UI prompts (21 assets)blockedP1M2task

    Description

    Why

    Every menu (options, save/load, journal) shares the "illuminated field journal" look (style bible §9); one kit keeps them coherent and is the UI style anchor.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: ui) from template ui-element.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Generic parchment 9-slice panel, button states, focus ring, slider, checkbox, scrollbar, tooltip and divider, plus the journal parchment frame, tab icons (quest, rumour, note), quest state icons (active, resolved, failed), new-entry toast, compass nudge glyph and objective marker.

    Asset ids (21):

    • ui-panel-parchment-9slice-01
    • ui-button-normal-01
    • ui-button-hover-01
    • ui-button-pressed-01
    • ui-button-disabled-01
    • ui-focus-ring-01
    • ui-slider-01
    • ui-checkbox-01
    • ui-scrollbar-01
    • ui-tooltip-9slice-01
    • ui-divider-flourish-01
    • ui-panel-journal-9slice-01
    • ui-glyph-tab-quest-01
    • ui-glyph-tab-rumour-01
    • ui-glyph-tab-note-01
    • ui-glyph-quest-active-01
    • ui-glyph-quest-resolved-01
    • ui-glyph-quest-failed-01
    • ui-toast-journal-01
    • ui-glyph-compass-nudge-01
    • ui-marker-objective-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-menus-journal-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    The generic menu kit (panel/button/focus/slider/checkbox/scrollbar/tooltip/divider) is not in plan/gameplay-asset-needs.md but every menu bead needs it; added here. Wayfinding glyphs also serve e23-wayfinding-hints (P2). m2 because it is one of the three style-anchor sets. Focus ring must satisfy e31-menu-navigation visible-focus contrast.

    Acceptance criteria

    • AC-1 content Given the 21 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate, transparent, 9-slice insets recorded per frame, glyphs flat single-colour 64²) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: panels tile cleanly under 9-slice stretch from 200 px to 1600 px wide and body text on panels meets ≥ 7:1 contrast (§9).
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:uiepic:e37milestone:m2
  • mw-e37.33Generate menu kit and journal UI via Codex CLIblockedP1M2task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 21 prompt files of e37-asset-ui-menus-journal-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-menus-journal-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate, transparent, 9-slice insets recorded per frame, glyphs flat single-colour 64². Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 21 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate, transparent, 9-slice insets recorded per frame, glyphs flat single-colour 64²), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.32 Write menu kit and journal UI prompts (21 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:uiepic:e37milestone:m2
  • mw-e37.34Owner approval: menu kit and journal UIblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 21 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-menus-journal-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: panels tile cleanly under 9-slice stretch from 200 px to 1600 px wide and body text on panels meets ≥ 7:1 contrast (§9). Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 21 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then panels tile cleanly under 9-slice stretch from 200 px to 1600 px wide and body text on panels meets ≥ 7:1 contrast (§9).
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-menus-journal-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.33 Generate menu kit and journal UI via Codex CLI open
    area:artasset:uiepic:e37milestone:m2needs-human
  • mw-e37.35Integrate approved menu kit and journal UIblockedP1M2task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e23-journal-ui, e30-save-load-ui, e31-settings-framework.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 21 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the options, save/load and journal screens, when opened at 75 % and 200 % UI scale, then all frames render from the final kit with no 9-slice seams visible in Playwright screenshots and no placeholder flags.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e23.6 Build in-character journal for quests, rumors and notes done
    • mw-e30.11 Build Continue / Load / Save menu screens done
    • mw-e31.1 Create typed settings store and options menu skeleton done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.34 Owner approval: menu kit and journal UI open
    area:artasset:uiepic:e37milestone:m2
  • mw-e37.36Write player weapons concept prompts (12 images)blockedP1M2task

    Description

    Why

    Each class has one signature prop always visible in silhouette (shield, bow, staff, hood) — the weapons carry the class fantasy and must match the approved character sheets.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    One flat front-facing concept image per held weapon or arrow variant (sword, wood and metal shields, bow, daggers, staff/focus, standard + fire/water/rope/noise/blunt arrows), then Claude-run image-to-3D (or CC0 kit match), retopo to 300–1.5 k tris, sharing the character or prop atlas.

    Concept image ids (12):

    • prop-weapon-sword-01
    • prop-weapon-shield-wood-01
    • prop-weapon-shield-metal-01
    • prop-weapon-bow-01
    • prop-weapon-dagger-01
    • prop-weapon-staff-01
    • prop-weapon-arrow-standard-01
    • prop-weapon-arrow-fire-01
    • prop-weapon-arrow-water-01
    • prop-weapon-arrow-rope-01
    • prop-weapon-arrow-noise-01
    • prop-weapon-arrow-blunt-01

    Target model ids (12):

    • model-weapon-sword-01
    • model-weapon-shield-wood-01
    • model-weapon-shield-metal-01
    • model-weapon-bow-01
    • model-weapon-dagger-01
    • model-weapon-staff-01
    • model-weapon-arrow-standard-01
    • model-weapon-arrow-fire-01
    • model-weapon-arrow-water-01
    • model-weapon-arrow-rope-01
    • model-weapon-arrow-noise-01
    • model-weapon-arrow-blunt-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-weapons-3d-generate)

    Notes

    m2 alongside the class models (a knight without a sword breaks the class playtests). Arrow variants are one shaft with swappable heads/payloads where possible. Concept images are one object per image (image-to-3D friendly), not a multi-object sheet. Post-MVP trick arrows (e05-trick-arrows-extended) are out.

    Budget: 300–1.5 k tris per held weapon, arrows ≤ 300, no LODs, character or prop atlas, shared material (style bible §13.2).

    Acceptance criteria

    • AC-1 content Given the 12 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (300–1.5 k tris per held weapon, arrows ≤ 300, no LODs, character or prop atlas, shared material (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.20 Owner approval: player class characters flat concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelclass:allepic:e37milestone:m2
  • mw-e37.37Generate player weapons concepts via Codex CLIblockedP1M2task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 12 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-weapons-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 12 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.36 Write player weapons concept prompts (12 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelclass:allepic:e37milestone:m2
  • mw-e37.38Owner approval: player weapons flat conceptsblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 12 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-weapons-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each weapon matches the approved class sheet palette and remains readable at 30 m game distance. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each weapon matches the approved class sheet palette and remains readable at 30 m game distance.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-weapons-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.37 Generate player weapons concepts via Codex CLI open
    area:artasset:modelclass:allepic:e37milestone:m2needs-human
  • mw-e37.39Generate player weapons 3D models via image-to-3D APIblockedP1M2task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 12 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-weapons-turntable-approve)

    Notes

    Budget: 300–1.5 k tris per held weapon, arrows ≤ 300, no LODs, character or prop atlas, shared material (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 12 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets 300–1.5 k tris per held weapon, arrows ≤ 300, no LODs, character or prop atlas, shared material (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.38 Owner approval: player weapons flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelclass:allepic:e37milestone:m2
  • mw-e37.40Owner approval: player weapons turntablesblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 12 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-weapons-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each weapon matches the approved class sheet palette and remains readable at 30 m game distance. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each weapon matches the approved class sheet palette and remains readable at 30 m game distance.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-weapons-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.39 Generate player weapons 3D models via image-to-3D API open
    area:artasset:modelclass:allepic:e37milestone:m2needs-human
  • mw-e37.41Integrate approved player weaponsblockedP1M2task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e04-melee-core, e05-bow-core, e05-arrow-schema, e10-takedowns, e06-casting-input-aiming.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 12 models are under public/assets/model/ within 300–1.5 k tris per held weapon, arrows ≤ 300, no LODs, character or prop atlas, shared material (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the combat sandbox and archery range, when each class equips its kit, then the final weapon models attach to the correct sockets, arrows stick and are retrievable, and no console errors occur.
    • AC-4 perf Given the combat stress scene with these models, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e04.6 Knight light attack chain and shield block with guard break done
    • mw-e05.1 Data schema for arrow types and property-based payloads done
    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    • mw-e06.15 Aim and cast spells with reticle, ground targeting and cancel done
    • mw-e10.4 Backstabs and non-lethal takedowns on unaware targets open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.40 Owner approval: player weapons turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelclass:allepic:e37milestone:m2
  • mw-e37.86Write combat impact VFX prompts (10 assets)blockedP1M2task

    Description

    Why

    Souls-like weight lives in the moment of impact; material-specific hits tell the player what they struck and whether the parry landed.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Impact flipbooks by material (metal sparks, wood splinters, bone dust, ichor puff, stone chips), block spark, parry flash, guard-break shatter, critical burst and arrow deflect sparks.

    Asset ids (10):

    • vfx-hit-spark-metal-01
    • vfx-hit-splinter-wood-01
    • vfx-hit-bone-dust-01
    • vfx-hit-ichor-puff-01
    • vfx-hit-stone-chips-01
    • vfx-block-spark-01
    • vfx-parry-flash-01
    • vfx-guard-break-shatter-01
    • vfx-critical-burst-01
    • vfx-deflect-sparks-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-combat-impacts-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    m2 because combat feel is validated in e04-skeleton-fun-validation / e35-class-fantasy-tests; the procedural placeholders still keep gameplay unblocked. No gore: ichor is a stylised puff. Parry flash obeys the ≤ 25 % screen-area flash rule.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 10 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² sheet, 4×4 exact grid, black background for additive sparks/flashes, alpha for dust/chips, 18–24 fps, non-looping) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each material hit is distinguishable without sound and parry flash is clearly different from a normal block.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxclass:knightepic:e37milestone:m2
  • mw-e37.87Generate combat impact VFX via Codex CLIblockedP1M2task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 10 prompt files of e37-asset-vfx-combat-impacts-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-combat-impacts-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² sheet, 4×4 exact grid, black background for additive sparks/flashes, alpha for dust/chips, 18–24 fps, non-looping. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 10 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² sheet, 4×4 exact grid, black background for additive sparks/flashes, alpha for dust/chips, 18–24 fps, non-looping), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.86 Write combat impact VFX prompts (10 assets) open
    area:artasset:vfxclass:knightepic:e37milestone:m2
  • mw-e37.88Owner approval: combat impact VFXblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 10 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-combat-impacts-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each material hit is distinguishable without sound and parry flash is clearly different from a normal block. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each material hit is distinguishable without sound and parry flash is clearly different from a normal block.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-combat-impacts-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.87 Generate combat impact VFX via Codex CLI open
    area:artasset:vfxclass:knightepic:e37milestone:m2needs-human
  • mw-e37.89Integrate approved combat impact VFXblockedP1M2task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e29-hit-sparks, e04-parry-riposte, e05-weak-points.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 10 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the combat sandbox, when the knight strikes metal, wood, bone, ichor and stone dummies and parries, then each final effect plays within the particle budget with no console errors.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e04.12 Parry window and riposte critical attack done
    • mw-e05.6 Headshots, weak points and armored regions that deflect done
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.4 Impact VFX by material: sparks, splinters, bone dust, parry flash done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.88 Owner approval: combat impact VFX open
    area:artasset:vfxclass:knightepic:e37milestone:m2
  • mw-e37.142Lock approved style anchor images for all later image promptsblockedP1M2task

    Description

    Why

    Generative tools drift; locking a few approved images as series anchors keeps 300+ later assets looking like one game (style bible §12).

    What

    After the first anchor sets (player class sheets, school frames + spell icons, core menu kit) are approved, Claude proposes 1–3 anchor images per category (character, prop, icon, UI, VFX, key art) with rationale; the owner confirms. Anchors are recorded in assets/prompts/_anchors.json (category → asset ids + SHA-256) and every later prompt file must list its category anchors as reference inputs.

    Scope

    • In: Anchor proposal + owner confirmation
    • In: Anchor registry file
    • In: Validator rule: non-anchor prompt files must cite their category anchors
    • Out: Changing the style bible itself (bible bead + version bump)

    Notes

    Anchor sets: e37-asset-player-classes-*, e37-asset-school-identity-*, e37-asset-spell-icons-*, e37-asset-ui-menus-journal-*. VFX anchors may be added after the first VFX set is approved (registry is append-only with owner sign-off).

    Acceptance criteria

    • AC-1 manual Given the approved anchor sets, when the owner reviews the proposal, then anchors for character, prop, icon and UI categories are confirmed and recorded in assets/approvals.json with gate "style-lock".
    • AC-2 content Given assets/prompts/_anchors.json, when validated, then every anchor id resolves to an approved asset whose SHA-256 matches its approval record.
    • AC-3 integration Given a non-anchor image prompt file that omits its category anchors, when the asset validator runs, then it fails naming the file.
    • AC-4 integration Edge: given an anchor asset that is later replaced (hash change), when CI runs, then the validator flags every prompt file citing the old hash for re-review instead of passing silently.

    Waits on

    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.20 Owner approval: player class characters flat concepts open
    • mw-e37.30 Owner approval: spell icons open
    • mw-e37.34 Owner approval: menu kit and journal UI open
    area:artasset:conceptepic:e37milestone:m2needs-human
  • mw-e37.12Texture atlas and palette-remap build step for prop setsblockedP2M2task

    Description

    Why

    Draw-call budgets (≤ 150 on Low) require one material per prop set; kits from different families only look like one world after palette remapping.

    What

    As a developer, I want prop sets declared in a data file to be packed into one atlas with UVs rewritten, and kit gradient textures remapped to tex-palette-master-01, so that each set uses one material. Supports palette-atlas (KayKit-style) and painted-texture atlases, padding/bleed for mips, High/Low sizes.

    Scope

    • In: Set definition data (assets/sets/*.json)
    • In: Atlas packer with UV rewrite in glTF
    • In: Palette remap table (kit colour → palette token)
    • In: Integration with assets:build
    • Out: Tileable textures (not atlased)
    • Out: Character atlases (authored per character)

    Notes

    Mip bleed: ≥ 8 px padding at 2048² so Low (1024²) mips do not bleed.

    Acceptance criteria

    • AC-1 integration Given a set of 12 props with 12 materials, when atlased, then output meshes reference exactly 1 material and render pixel-identical within ΔE ≤ 3 against the unatlased screenshot at LOD0.
    • AC-2 unit Given a palette remap table, when applied to a kit gradient texture, then every mapped source colour is replaced by its palette token hex and unmapped colours are reported.
    • AC-3 integration Given the atlas at Low size, when mip level 2 is inspected, then no island samples a neighbour island (bleed check passes).
    • AC-4 integration Edge: given a set whose islands cannot fit in the maximum atlas size, when packed, then the build fails with the set id and the required size instead of shrinking texel density silently.

    Waits on

    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artarea:toolsasset:textureepic:e37milestone:m2

M3 MVP content 385

  • mw-e37.16Style consistency review gate before MVP content lockblockedP1M3task

    Description

    Why

    Generated assets drift: each prompt is "on style" alone but the set diverges. A scheduled gate catches drift before it ships.

    What

    A structured review of all integrated art per location against the style bible and the style-target diorama: contact sheets of icons, portraits, props and textures; in-engine captures per location; silhouette lineup of classes and creatures; Legibility cue audit. Output: pass, or fix beads per offending asset.

    Scope

    • In: Contact-sheet generator script output (icons/portraits/textures side by side)
    • In: Per-location capture set
    • In: Review checklist + findings file in docs/art/reviews/
    • Out: Fixing assets (filed as beads)
    • Out: Audio review (see e38-mix-review)

    Notes

    Run once at m2 exit (informal) and once before m3 content lock (formal gate).

    Acceptance criteria

    • AC-1 integration Given all icon, portrait and texture assets, when the contact-sheet script runs, then it produces one sheet per category ordered by asset id with each tile labelled.
    • AC-2 manual Given the class and creature silhouette lineup rendered in solid ink at 64 px, when reviewed, then every class and creature family is identified correctly by a reviewer unfamiliar with the models.
    • AC-3 manual Given the review checklist, when completed, then every failing asset has a filed fix bead referencing its asset id, and the review file records pass/fail per location.
    • AC-4 manual Edge: given an asset that fails review but is on the MVP critical path, when triaged, then it is either fixed before m3 or explicitly waived by the owner with a reason in the review file.

    Waits on

    • mw-e37.15 Build the style-target diorama as the visual and performance benchmark open
    area:artepic:e37milestone:m3needs-human
  • mw-e37.42Write spell-summoned models concept prompts (3 images)blockedP1M3task

    Description

    Why

    Polymorph, Grasping Vines and Wisp Light create physical things in the world; they need bespoke models that read as magical but belong in the world.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: creature / prop) from creature-reference-sheet.md (critter) + prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    The polymorph critter (a harmless farm fowl — matches sfx-...-critter-cluck), a restraining vine entity (erupt/hold/wither poses) and the wisp orb shell, generated as flat concepts then Claude-run image-to-3D; the critter is rigged with a simple walk/flee/idle set.

    Concept image ids (3):

    • creature-polymorph-critter-01
    • prop-vine-entity-01
    • prop-wisp-orb-01

    Target model ids (3):

    • model-creature-polymorph-critter-01
    • model-prop-vine-entity-01
    • model-prop-wisp-orb-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-magic-summon-models-3d-generate)

    Notes

    The Forgotten (animated remains) raised by Animate Bones reuse the world group's Forgotten creature model (see plan/world-asset-needs.md). Vine and wisp are mostly shader/VFX driven; models are low-poly shells (≤ 2 k tris).

    Budget: critter 2–4 k tris, T1 512², ≤ 40 bones; vine ≤ 2 k tris with 3 morph/pose targets; wisp ≤ 300 tris emissive.

    Acceptance criteria

    • AC-1 content Given the 3 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (critter 2–4 k tris, T1 512², ≤ 40 bones; vine ≤ 2 k tris with 3 morph/pose targets; wisp ≤ 300 tris emissive) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelclass:sorcererepic:e37milestone:m3
  • mw-e37.43Generate spell-summoned models concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 3 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-magic-summon-models-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 3 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.42 Write spell-summoned models concept prompts (3 images) open
    area:artasset:modelclass:sorcererepic:e37milestone:m3
  • mw-e37.44Owner approval: spell-summoned models flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 3 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-magic-summon-models-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the critter reads as harmless and comic, never as a threat, and all three sit in the school palettes (§2.3 alteration/nature/light). Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 3 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the critter reads as harmless and comic, never as a threat, and all three sit in the school palettes (§2.3 alteration/nature/light).
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-magic-summon-models-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.43 Generate spell-summoned models concepts via Codex CLI open
    area:artasset:modelclass:sorcererepic:e37milestone:m3needs-human
  • mw-e37.45Generate spell-summoned models 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 3 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-magic-summon-models-turntable-approve)

    Notes

    Budget: critter 2–4 k tris, T1 512², ≤ 40 bones; vine ≤ 2 k tris with 3 morph/pose targets; wisp ≤ 300 tris emissive. API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 3 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets critter 2–4 k tris, T1 512², ≤ 40 bones; vine ≤ 2 k tris with 3 morph/pose targets; wisp ≤ 300 tris emissive, or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.44 Owner approval: spell-summoned models flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelclass:sorcererepic:e37milestone:m3
  • mw-e37.46Owner approval: spell-summoned models turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 3 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-magic-summon-models-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the critter reads as harmless and comic, never as a threat, and all three sit in the school palettes (§2.3 alteration/nature/light). Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 3 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the critter reads as harmless and comic, never as a threat, and all three sit in the school palettes (§2.3 alteration/nature/light).
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-magic-summon-models-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.45 Generate spell-summoned models 3D models via image-to-3D API open
    area:artasset:modelclass:sorcererepic:e37milestone:m3needs-human
  • mw-e37.47Integrate approved spell-summoned modelsblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e08-spell-polymorph, e08-spell-grasping-vines, e08-spell-wisp-light, e06-summon-framework.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 3 models are under public/assets/model/ within critter 2–4 k tris, T1 512², ≤ 40 bones; vine ≤ 2 k tris with 3 morph/pose targets; wisp ≤ 300 tris emissive and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the spell sandbox, when Polymorph, Grasping Vines and Wisp Light are cast, then the final models spawn, animate and despawn with no console errors.
    • AC-4 perf Given the combat stress scene with these models, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e06.10 Summon temporary creatures and objects with allegiance and caps open
    • mw-e08.17 Add Wisp Light: a floating orb that lights darkness and repels open
    • mw-e08.20 Add Grasping Vines: roots burst up and restrain creatures open
    • mw-e08.22 Add Polymorph: temporarily turn a creature into a harmless animal open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.46 Owner approval: spell-summoned models turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelclass:sorcererepic:e37milestone:m3
  • mw-e37.48Write thief props concept prompts (4 images)blockedP1M3task

    Description

    Why

    Thief play depends on reading which objects hide you, which traps are armed and what can be thrown (Legibility Language, style bible §7).

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Three prop sheets (hiding props: wardrobe, barrel, tall grass, curtain alcove; traps: bear trap, caltrops, tripwire, noisemaker; throwables: bottle, coin, smoke bomb, rope coil) plus a guard-uniform recolour texture for disguises. Models come from CC0 kits recoloured to the palette atlas first; only unmatched props go through image-to-3D.

    Concept image ids (4):

    • prop-hiding-set-01
    • prop-thief-traps-set-01
    • prop-throwables-set-01
    • tex-disguise-guard-uniform-01

    Target model ids (12):

    • model-prop-wardrobe-hide-01
    • model-prop-barrel-hide-01
    • model-prop-tall-grass-01
    • model-prop-curtain-alcove-01
    • model-prop-trap-bear-01
    • model-prop-caltrops-01
    • model-prop-trap-tripwire-01
    • model-prop-trap-noisemaker-01
    • model-prop-bottle-throwable-01
    • model-prop-coin-01
    • model-prop-smoke-bomb-01
    • model-prop-rope-coil-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-thief-props-3d-generate)

    Notes

    Wardrobe and barrel may overlap with the world group's town props — whichever set lands first owns the model; the other references it. Disguise recolour serves e10-disguises (P2) and trap-placement preview serves e10-trap-placement (P2).

    Budget: small props 50–400 tris, medium 400–2 k, prop atlas, shared material (style bible §13.2).

    Acceptance criteria

    • AC-1 content Given the 4 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (small props 50–400 tris, medium 400–2 k, prop atlas, shared material (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelclass:thiefepic:e37milestone:m3
  • mw-e37.49Generate thief props concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 4 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-thief-props-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 4 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.48 Write thief props concept prompts (4 images) open
    area:artasset:modelclass:thiefepic:e37milestone:m3
  • mw-e37.50Owner approval: thief props flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 4 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-thief-props-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: hiding props visibly signal "enterable" per the Legibility Language and armed traps are distinguishable from disarmed ones at 10 m. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then hiding props visibly signal "enterable" per the Legibility Language and armed traps are distinguishable from disarmed ones at 10 m.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-thief-props-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.49 Generate thief props concepts via Codex CLI open
    area:artasset:modelclass:thiefepic:e37milestone:m3needs-human
  • mw-e37.51Generate thief props 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 12 target models: first try a CC0 kit match recoloured to the palette atlas; otherwise call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-thief-props-turntable-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, prop atlas, shared material (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 12 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, prop atlas, shared material (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.50 Owner approval: thief props flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelclass:thiefepic:e37milestone:m3
  • mw-e37.52Owner approval: thief props turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 12 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-thief-props-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: hiding props visibly signal "enterable" per the Legibility Language and armed traps are distinguishable from disarmed ones at 10 m. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then hiding props visibly signal "enterable" per the Legibility Language and armed traps are distinguishable from disarmed ones at 10 m.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-thief-props-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.51 Generate thief props 3D models via image-to-3D API open
    area:artasset:modelclass:thiefepic:e37milestone:m3needs-human
  • mw-e37.53Integrate approved thief propsblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e09-hiding-places, e03-hiding-containers, e10-trap-disarm, e10-thrown-distractions.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 12 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, prop atlas, shared material (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the stealth grey-box course, when the thief hides, throws and disarms, then every final prop loads with its legibility cue, draw calls stay within budget, and no console errors occur.
    • AC-4 perf Given the combat stress scene with these models, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e03.23 Hide in wardrobes, barrels and haystacks and search containers done
    • mw-e09.8 Hiding places: wardrobes, barrels, tall grass and shadowed alcoves open
    • mw-e10.12 Detect and disarm world traps; failures trigger them open
    • mw-e10.2 Throw objects to create noise distractions guards investigate open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.52 Owner approval: thief props turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelclass:thiefepic:e37milestone:m3
  • mw-e37.54Write stealth animations motion briefs (10 clips)blockedP1M3task

    Description

    Why

    Stealth reads through bodies: a guard scanning upward or yawning tells the thief when to move; takedowns and carries must look deliberate (constitution: stealth is systemic and readable).

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md: asset table, brief, sourcing (CC0 library clip or provider animation API prompt), motion spec (frames, loop, root motion, event markers), readability checklist and iteration log.

    Motion briefs, then Claude sources each clip from a CC0 animation library or generates it via the image-to-3D provider's animation API, retargets it to the canonical skeleton with e37-animation-pipeline, and adds event markers (footstep, hit, grab).

    Clip ids (10):

    • anim-humanoid-climb-01
    • anim-humanoid-carry-body-01
    • anim-humanoid-takedown-choke-01
    • anim-humanoid-backstab-01
    • anim-humanoid-lean-peek-left-01
    • anim-humanoid-lean-peek-right-01
    • anim-humanoid-pick-lock-01
    • anim-humanoid-guard-idle-stretch-01
    • anim-humanoid-guard-idle-yawn-01
    • anim-humanoid-guard-look-up-scan-01

    Scope

    • In: One brief per clip id
    • In: Event marker list per clip (footstep, hit, grab, release)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Core locomotion/combat clips

    Notes

    No animation prompt template exists in assets/prompts/_templates/; briefs use the common sections (asset, brief, output spec, consistency checklist, iteration log) with a motion spec (frames, loop, root motion, markers) instead of an image prompt. Lean/peek serves e10-peek-lean (P2). Core locomotion/combat clips come from the animation pipeline's base library, not this set.

    Acceptance criteria

    • AC-1 content Given the 10 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-humanoid-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states frame count, loop flag, root-motion policy and the required event markers.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo).
    • AC-4 content Edge: given a brief with no event markers for a clip that emits noise or contact, when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelclass:thiefepic:e37milestone:m3
  • mw-e37.55Source and retarget stealth animationsblockedP1M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief, retarget to the canonical skeleton with e37-animation-pipeline, add markers, and render preview GIFs on the class placeholder model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-stealth-actions-approve)

    Notes

    glb clip on the canonical skeleton, 30 fps, in-place with root velocity curve, loop flag and event markers per the clip manifest

    Acceptance criteria

    • AC-1 integration Given the 10 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags and event markers match each brief.
    • AC-3 integration Given each clip, when previewed, then a GIF exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.54 Write stealth animations motion briefs (10 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelclass:thiefepic:e37milestone:m3
  • mw-e37.56Owner approval: stealth animationsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 10 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-stealth-actions-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each clip reads clearly from the default third-person camera distance and shows no foot sliding or limb interpenetration in the preview. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each clip reads clearly from the default third-person camera distance and shows no foot sliding or limb interpenetration in the preview.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-stealth-actions-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.55 Source and retarget stealth animations open
    area:artasset:modelclass:thiefepic:e37milestone:m3needs-human
  • mw-e37.57Integrate approved stealth animationsblockedP1M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads)

    Notes

    Consumers: e10-climbing, e10-body-carry-hide, e10-takedowns, e10-lockpicking, e11-patrol-routines.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 10 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence.
    • AC-3 e2e Given the thief grey-box challenge, when climbing, carrying, taking down, lockpicking and peeking, then the final clips play with correct markers and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e10.4 Backstabs and non-lethal takedowns on unaware targets open
    • mw-e10.5 Carry and hide unconscious or dead bodies open
    • mw-e10.7 Pick locks as an in-world, interruptible, noisy action open
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e11.9 Patrol routes, guard posts and idle routines authored as data done
    • mw-e37.56 Owner approval: stealth animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelclass:thiefepic:e37milestone:m3
  • mw-e37.58Write spellbook covers prompts (24 assets)blockedP1M3task

    Description

    Why

    Books are the sorcerer's progression; a cover glimpsed on a bookshop shelf should hint at its school and make the player want it.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: book) from template book-cover-and-page.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    One cover per MVP spellbook (23) with a school-coloured binding and embossed motif (no text), plus one generic cover palette-remapped per school for placeholder/lore books.

    Asset ids (24):

    • book-spell-ember-cover-01
    • book-spell-firebolt-cover-01
    • book-spell-flame-jet-cover-01
    • book-spell-fire-wall-cover-01
    • book-spell-frostglass-cover-01
    • book-spell-wellspring-cover-01
    • book-spell-gust-cover-01
    • book-spell-thunderclap-cover-01
    • book-spell-arc-lash-cover-01
    • book-spell-mage-hand-cover-01
    • book-spell-telekinetic-throw-cover-01
    • book-spell-blink-cover-01
    • book-spell-arcane-sight-cover-01
    • book-spell-levitate-cover-01
    • book-spell-gravity-well-cover-01
    • book-spell-mirror-self-cover-01
    • book-spell-wisp-light-cover-01
    • book-spell-prism-ray-cover-01
    • book-spell-snuff-cover-01
    • book-spell-grasping-vines-cover-01
    • book-spell-animate-bones-cover-01
    • book-spell-polymorph-cover-01
    • book-spell-stasis-cover-01
    • book-generic-cover-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-book-covers-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Input list used ui-book-cover-<slug>; ids follow the style bible book-<subject>-cover-01 pattern instead. School-colour placeholder covers are one generic cover recoloured by e37-texture-atlas-build palette remap rather than 13 generations. Titles are rendered by the game (IM Fell), never painted.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 24 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (cover 2:3 1024×1536, transparent around the book object, blank title plate, text-safe rectangle recorded) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each cover's school is identifiable from binding colour + motif without reading, and no letters appear anywhere.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:conceptclass:sorcererepic:e37milestone:m3
  • mw-e37.59Generate spellbook covers via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 24 prompt files of e37-asset-book-covers-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-book-covers-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: cover 2:3 1024×1536, transparent around the book object, blank title plate, text-safe rectangle recorded. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 24 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (cover 2:3 1024×1536, transparent around the book object, blank title plate, text-safe rectangle recorded), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.58 Write spellbook covers prompts (24 assets) open
    area:artasset:conceptclass:sorcererepic:e37milestone:m3
  • mw-e37.60Owner approval: spellbook coversblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 24 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-book-covers-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each cover's school is identifiable from binding colour + motif without reading, and no letters appear anywhere. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 24 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each cover's school is identifiable from binding colour + motif without reading, and no letters appear anywhere.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-book-covers-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.59 Generate spellbook covers via Codex CLI open
    area:artasset:conceptclass:sorcererepic:e37milestone:m3needs-human
  • mw-e37.61Integrate approved spellbook coversblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e07-book-reader-ui, e21-bookshop-ui, e07-book-item-schema.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 24 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the fixture bookshop and book reader, when every spellbook is shown, then its final cover renders with the title overlaid in the text-safe area and no placeholder flags remain.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e07.1 Define book item schema: spell, language, condition, legality done
    • mw-e07.9 Read books in a page-turning reader with a study action open
    • mw-e21.8 Browse bookshop shelves with covers, previews and known markers open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.60 Owner approval: spellbook covers open
    area:artasset:conceptclass:sorcererepic:e37milestone:m3
  • mw-e37.62Write magic and grimoire UI prompts (17 assets)blockedP1M3task

    Description

    Why

    Casting, reading and shopping for books are the sorcerer's core loop; the UI must feel like a well-loved grimoire while staying legible mid-fight.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: ui) from template ui-element.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Hotbar frame, quick-select wheel, mana brushstroke bar, cooldown sweep mask, spell aiming reticle, ground-target marker, revealed-object outline ramp; grimoire spread with school ribbon tab and locked-verb silhouette; two-page reader spread with parchment, torn-page and garbled-text styles; bookshop shelf; forbidden and "already known" markers.

    Asset ids (17):

    • ui-hotbar-frame-01
    • ui-spell-wheel-01
    • ui-bar-mana-01
    • ui-cooldown-sweep-01
    • ui-reticle-spell-aim-01
    • ui-marker-ground-target-01
    • ui-outline-reveal-ramp-01
    • ui-grimoire-spread-01
    • ui-grimoire-ribbon-tab-01
    • ui-grimoire-verb-locked-01
    • ui-book-reader-spread-01
    • ui-book-page-parchment-01
    • ui-book-page-torn-01
    • ui-book-page-garbled-01
    • ui-bookshop-shelf-01
    • ui-marker-book-forbidden-01
    • ui-marker-book-known-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-magic-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Ribbon tab is tinted per school at runtime (school core colours, §9). Torn/garbled pages also serve e07-damaged-books / e07-untranslated-books (P2); outline ramp also serves e08-spell-arcane-sight (P2).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 17 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate, transparent, 9-slice insets for frames/spreads, page spreads 3:2 1536×1024 opaque) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: the reticle and ground marker stay readable over both bright and dark scenes and the grimoire matches the approved menu kit.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:uiclass:sorcererepic:e37milestone:m3
  • mw-e37.63Generate magic and grimoire UI via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 17 prompt files of e37-asset-ui-magic-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-magic-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate, transparent, 9-slice insets for frames/spreads, page spreads 3:2 1536×1024 opaque. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 17 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate, transparent, 9-slice insets for frames/spreads, page spreads 3:2 1536×1024 opaque), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.62 Write magic and grimoire UI prompts (17 assets) open
    area:artasset:uiclass:sorcererepic:e37milestone:m3
  • mw-e37.64Owner approval: magic and grimoire UIblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 17 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-magic-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the reticle and ground marker stay readable over both bright and dark scenes and the grimoire matches the approved menu kit. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 17 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the reticle and ground marker stay readable over both bright and dark scenes and the grimoire matches the approved menu kit.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-magic-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.63 Generate magic and grimoire UI via Codex CLI open
    area:artasset:uiclass:sorcererepic:e37milestone:m3needs-human
  • mw-e37.65Integrate approved magic and grimoire UIblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e06-spell-hotbar-ui, e06-casting-input-aiming, e07-grimoire-ui, e07-book-reader-ui, e21-bookshop-ui.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 17 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell sandbox, when casting, opening the grimoire, reading a book and browsing the fixture bookshop, then every element renders from final art with no placeholder flags and no console errors.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e06.15 Aim and cast spells with reticle, ground targeting and cancel done
    • mw-e06.16 Select spells from a hotbar and quick-select wheel with mana HUD done
    • mw-e07.10 Browse known spells, insights and verb chains in the grimoire open
    • mw-e07.9 Read books in a page-turning reader with a study action open
    • mw-e21.8 Browse bookshop shelves with covers, previews and known markers open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.64 Owner approval: magic and grimoire UI open
    area:artasset:uiclass:sorcererepic:e37milestone:m3
  • mw-e37.66Write school default and miscast VFX prompts (26 assets)blockedP1M3task

    Description

    Why

    Any spell without bespoke art (NPC casts, data-only spells) must still read as its school, and botched casts must look distinct from successful ones (failure creates stories).

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Per school: one default cast/impact flipbook in the school's colours and motion signature (§2.3), and one miscast flipbook (sputter, backfire) that keeps the school identity but signals failure.

    Asset ids (26):

    • vfx-spell-fire-default-01
    • vfx-spell-frost-default-01
    • vfx-spell-storm-default-01
    • vfx-spell-arcane-default-01
    • vfx-spell-illusion-default-01
    • vfx-spell-alteration-default-01
    • vfx-spell-conjuration-default-01
    • vfx-spell-necromancy-default-01
    • vfx-spell-nature-default-01
    • vfx-spell-light-default-01
    • vfx-spell-shadow-default-01
    • vfx-spell-gravity-default-01
    • vfx-spell-time-default-01
    • vfx-spell-fire-miscast-01
    • vfx-spell-frost-miscast-01
    • vfx-spell-storm-miscast-01
    • vfx-spell-arcane-miscast-01
    • vfx-spell-illusion-miscast-01
    • vfx-spell-alteration-miscast-01
    • vfx-spell-conjuration-miscast-01
    • vfx-spell-necromancy-miscast-01
    • vfx-spell-nature-miscast-01
    • vfx-spell-light-miscast-01
    • vfx-spell-shadow-miscast-01
    • vfx-spell-gravity-miscast-01
    • vfx-spell-time-miscast-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-school-defaults-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    These are final-quality fallbacks, distinct from the procedural placeholders of e29-placeholder-vfx. Storm flashes obey the ≤ 3 Hz photosensitivity cap.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 26 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores, 12–24 fps, loop flag recorded) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each school default is identifiable in greyscale by motion/shape (not only hue) and every miscast reads as "went wrong" beside its default.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.67Generate school default and miscast VFX via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 26 prompt files of e37-asset-vfx-school-defaults-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-school-defaults-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores, 12–24 fps, loop flag recorded. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 26 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores, 12–24 fps, loop flag recorded), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.66 Write school default and miscast VFX prompts (26 assets) open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.68Owner approval: school default and miscast VFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 26 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-school-defaults-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each school default is identifiable in greyscale by motion/shape (not only hue) and every miscast reads as "went wrong" beside its default. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 26 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each school default is identifiable in greyscale by motion/shape (not only hue) and every miscast reads as "went wrong" beside its default.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-school-defaults-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.67 Generate school default and miscast VFX via Codex CLI open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3needs-human
  • mw-e37.69Integrate approved school default and miscast VFXblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e29-spell-vfx-hooks, e06-spell-cue-binding, e06-botched-casts.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 26 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell sandbox, when a data-only test spell of each school is cast and botched, then the default and miscast effects play from final textures within the particle budget and with no console errors.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e06.13 Resolve botched casts into data-driven miscast outcomes open
    • mw-e06.17 Bind spell events to placeholder VFX and SFX cues open
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.10 Spell VFX slots and templates for the spell pipeline done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.68 Owner approval: school default and miscast VFX open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.70Write elemental spell VFX prompts (18 assets)blockedP1M3task

    Description

    Why

    Elemental spells are how the sorcerer changes the systemic world (burn, freeze, soak, shock); their visuals must communicate the resulting world state instantly.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Phase flipbooks for ember, firebolt, flame-jet, frostglass, wellspring, gust, thunderclap, arc-lash (cast/travel/impact/channel/cone/wave/beam/chain/ice-sheet/puddle as listed).

    Asset ids (18):

    • vfx-spell-fire-ember-cast-01
    • vfx-spell-fire-ember-travel-01
    • vfx-spell-fire-ember-impact-01
    • vfx-spell-fire-firebolt-cast-01
    • vfx-spell-fire-firebolt-travel-01
    • vfx-spell-fire-firebolt-impact-01
    • vfx-spell-fire-flame-jet-channel-01
    • vfx-spell-frost-frostglass-cast-01
    • vfx-spell-frost-frostglass-travel-01
    • vfx-spell-frost-frostglass-impact-01
    • vfx-spell-frost-frostglass-ice-sheet-01
    • vfx-spell-conjuration-wellspring-cast-01
    • vfx-spell-conjuration-wellspring-burst-01
    • vfx-spell-conjuration-wellspring-puddle-01
    • vfx-spell-storm-gust-cone-01
    • vfx-spell-storm-thunderclap-wave-01
    • vfx-spell-storm-arc-lash-beam-01
    • vfx-spell-storm-arc-lash-chain-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-spells-elemental-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Wellspring is conjuration school (water palette #3F7FA0 with conjuration portal accents). Ice-sheet and puddle textures must match the elemental surface colours used by e29-elemental-fx.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 18 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores (alpha for smoke/steam), 12–24 fps) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each spell's phases read as one effect and match its school motion signature (§2.3).
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.71Generate elemental spell VFX via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 18 prompt files of e37-asset-vfx-spells-elemental-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-spells-elemental-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores (alpha for smoke/steam), 12–24 fps. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 18 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores (alpha for smoke/steam), 12–24 fps), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.70 Write elemental spell VFX prompts (18 assets) open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.72Owner approval: elemental spell VFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 18 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-spells-elemental-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each spell's phases read as one effect and match its school motion signature (§2.3). Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 18 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each spell's phases read as one effect and match its school motion signature (§2.3).
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-spells-elemental-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.71 Generate elemental spell VFX via Codex CLI open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3needs-human
  • mw-e37.73Integrate approved elemental spell VFXblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e29-spell-vfx-hooks, e08-spell-ember, e08-spell-firebolt-flame-jet, e08-spell-frostglass, e08-spell-wellspring, e08-spell-gust, e08-spell-thunderclap, e08-spell-arc-lash.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 18 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell sandbox, when each elemental spell is cast at a target, then every phase plays from final textures and live particles stay ≤ 800 on the Low preset.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e08.2 Add Ember: precise ignition of flammable things done
    • mw-e08.3 Add Firebolt and its Flame Jet follow-on verb open
    • mw-e08.5 Add Frostglass: freeze targets and create temporary ice surfaces open
    • mw-e08.6 Add Wellspring: conjure a burst of water that soaks an area open
    • mw-e08.7 Add Gust: blast creatures back, clear gas and propel objects open
    • mw-e08.8 Add Thunderclap: a violent shockwave that breaks and deafens open
    • mw-e08.9 Add Arc Lash: lightning that chains through conductive and wet open
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.10 Spell VFX slots and templates for the spell pipeline done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.72 Owner approval: elemental spell VFX open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.74Write arcane and mystic spell VFX prompts (22 assets)blockedP1M3task

    Description

    Why

    Kinetic, illusion, light and life spells are the "too useful" toolbox; their effects must make the systemic consequence (grabbed, pulled, doubled, lit, rooted, raised, transformed) obvious.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Phase flipbooks for mage-hand, telekinetic-throw, blink, levitate, gravity-well, mirror-self, wisp-light, prism-ray, grasping-vines, animate-bones, polymorph across schools arcane, gravity, illusion, light, nature, necromancy, alteration.

    Asset ids (22):

    • vfx-spell-arcane-mage-hand-tether-01
    • vfx-spell-arcane-mage-hand-grab-01
    • vfx-spell-arcane-telekinetic-throw-launch-01
    • vfx-spell-arcane-telekinetic-throw-catch-01
    • vfx-spell-arcane-blink-depart-01
    • vfx-spell-arcane-blink-arrive-01
    • vfx-spell-gravity-levitate-loop-01
    • vfx-spell-gravity-gravity-well-loop-01
    • vfx-spell-gravity-gravity-well-collapse-01
    • vfx-spell-illusion-mirror-self-spawn-01
    • vfx-spell-illusion-mirror-self-shimmer-01
    • vfx-spell-illusion-mirror-self-dispel-01
    • vfx-spell-light-wisp-light-orb-01
    • vfx-spell-light-prism-ray-beam-01
    • vfx-spell-light-prism-ray-reflect-01
    • vfx-spell-nature-grasping-vines-erupt-01
    • vfx-spell-nature-grasping-vines-hold-01
    • vfx-spell-nature-grasping-vines-wither-01
    • vfx-spell-necromancy-animate-bones-assemble-01
    • vfx-spell-necromancy-animate-bones-crumble-01
    • vfx-spell-alteration-polymorph-poof-in-01
    • vfx-spell-alteration-polymorph-poof-out-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-spells-arcane-mystic-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Prism Ray beam and reflect must work with e03-light-beams mirrors; Gravity Well uses the lensing rim; Polymorph poofs are comic, not horrific.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 22 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores, 12–24 fps) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each spell's phases read as one effect and match its school motion signature (§2.3).
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.75Generate arcane and mystic spell VFX via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 22 prompt files of e37-asset-vfx-spells-arcane-mystic-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-spells-arcane-mystic-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores, 12–24 fps. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 22 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores, 12–24 fps), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.74 Write arcane and mystic spell VFX prompts (22 assets) open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.76Owner approval: arcane and mystic spell VFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 22 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-spells-arcane-mystic-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each spell's phases read as one effect and match its school motion signature (§2.3). Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 22 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each spell's phases read as one effect and match its school motion signature (§2.3).
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-spells-arcane-mystic-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.75 Generate arcane and mystic spell VFX via Codex CLI open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3needs-human
  • mw-e37.77Integrate approved arcane and mystic spell VFXblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e29-spell-vfx-hooks, e29-spectacle-shaders, e08-spell-mage-hand, e08-spell-telekinetic-throw, e08-spell-blink, e08-spell-levitate, e08-spell-gravity-well, e08-spell-mirror-self, e08-spell-wisp-light, e08-spell-prism-ray, e08-spell-grasping-vines, e08-spell-animate-bones, e08-spell-polymorph.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 22 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell sandbox, when each spell in the set is cast, then every phase plays from final textures and live particles stay ≤ 800 on the Low preset.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e08.10 Add Mage Hand: grab, move and use distant objects done
    • mw-e08.11 Add Telekinetic Throw & Catch: hurl objects, creatures and arrows open
    • mw-e08.12 Add Blink: teleport several metres through open space open
    • mw-e08.13 Add Levitate: float the caster or an object upward slowly open
    • mw-e08.14 Add Gravity Well: pull creatures and loose objects to a point open
    • mw-e08.15 Add Mirror Self: an illusory double that draws attention open
    • mw-e08.17 Add Wisp Light: a floating orb that lights darkness and repels open
    • mw-e08.18 Add Prism Ray: a light beam that reflects off reflective surfaces open
    • mw-e08.20 Add Grasping Vines: roots burst up and restrain creatures open
    • mw-e08.21 Add Animate Bones: raise nearby remains as a temporary servant open
    • mw-e08.22 Add Polymorph: temporarily turn a creature into a harmless animal open
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.10 Spell VFX slots and templates for the spell pipeline done
    • mw-e29.7 Magical material library: dissolve, glow, distortion, runes done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.76 Owner approval: arcane and mystic spell VFX open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.82Write base VFX textures and decals prompts (16 assets)blockedP1M3task

    Description

    Why

    Most effects are built from a handful of shared textures; painting them once in the house style makes every derived effect consistent and cheap.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md (+ tileable-texture.md for decals), with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Base particle textures (soft circle, spark streak, smoke noise, ring, shard, flame flipbook), the six spell VFX templates (cast wind-up, projectile head, projectile trail, impact, area ring, beam) and projected decals (scorch, frost, wet, arrow hole).

    Asset ids (16):

    • vfx-base-soft-circle-01
    • vfx-base-spark-streak-01
    • vfx-base-smoke-noise-01
    • vfx-base-ring-01
    • vfx-base-shard-01
    • vfx-base-flame-8x8-01
    • vfx-template-cast-windup-01
    • vfx-template-projectile-head-01
    • vfx-template-projectile-trail-01
    • vfx-template-impact-01
    • vfx-template-area-ring-01
    • vfx-template-beam-01
    • vfx-decal-scorch-01
    • vfx-decal-frost-01
    • vfx-decal-wet-01
    • vfx-decal-arrow-hole-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-base-textures-decals-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Ids must match those already emitted by e29-placeholder-vfx so integration is a file swap. Decals also serve e29-decals (P2).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 16 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² or 512² sheets, exact grid for flipbooks, black (additive) or transparent (alpha) background; decals transparent with soft edges) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: base textures look painted (no photographic noise) and decals sit in the world palette without hard rectangular edges.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.83Generate base VFX textures and decals via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 16 prompt files of e37-asset-vfx-base-textures-decals-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-base-textures-decals-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² or 512² sheets, exact grid for flipbooks, black (additive) or transparent (alpha) background; decals transparent with soft edges. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 16 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² or 512² sheets, exact grid for flipbooks, black (additive) or transparent (alpha) background; decals transparent with soft edges), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.82 Write base VFX textures and decals prompts (16 assets) open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.84Owner approval: base VFX textures and decalsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 16 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-base-textures-decals-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: base textures look painted (no photographic noise) and decals sit in the world palette without hard rectangular edges. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 16 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then base textures look painted (no photographic noise) and decals sit in the world palette without hard rectangular edges.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-base-textures-decals-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.83 Generate base VFX textures and decals via Codex CLI open
    area:artasset:vfxepic:e37milestone:m3needs-human
  • mw-e37.85Integrate approved base VFX textures and decalsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e29-vfx-framework, e29-placeholder-vfx, e29-spell-vfx-hooks.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 16 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the VFX stress scene, when effects built on the base textures run, then no placeholder flags remain for these ids and no console errors occur.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.10 Spell VFX slots and templates for the spell pipeline done
    • mw-e29.2 Procedural placeholder VFX textures keyed by final asset ids done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.84 Owner approval: base VFX textures and decals open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.90Write trail, telegraph and stealth VFX prompts (16 assets)blockedP1M3task

    Description

    Why

    Gameplay cues — a charged swing, a focused arrow, an enemy wind-up, a noise the guards will hear, a smoke escape — must be readable at a glance (Legibility Language, §7–8).

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Weapon trail, charge glow and ready burst; arrow trails (standard, focused), water burst, rope unfurl, noise-arrow ring; stealth noise ripple, smoke-bomb cloud, flash-powder burst, trap reveal highlight; warm-red enemy telegraph decals (circle, cone, line); last-known-position ghost ramp.

    Asset ids (16):

    • vfx-weapon-trail-default-01
    • vfx-charge-glow-01
    • vfx-charge-ready-burst-01
    • vfx-arrow-trail-01
    • vfx-arrow-trail-focused-01
    • vfx-water-burst-01
    • vfx-rope-unfurl-01
    • vfx-noise-ring-01
    • vfx-noise-ripple-01
    • vfx-smoke-bomb-cloud-01
    • vfx-flash-powder-burst-01
    • vfx-trap-reveal-highlight-01
    • vfx-telegraph-circle-01
    • vfx-telegraph-cone-01
    • vfx-telegraph-line-01
    • vfx-lkp-ghost-ramp-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-cues-trails-stealth-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Telegraphs use #C8553D at 40 % alpha (style bible §8) and must stay distinguishable from player AoEs. LKP ghost ramp serves e09-lkp-ghost (P2). Flash powder obeys photosensitivity limits.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 16 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² sheet or 512² strip, exact grid, black (additive) or transparent (alpha) background; telegraph decals transparent) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: hostile telegraphs are never confusable with friendly effects and the smoke cloud visibly blocks sight lines.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.91Generate trail, telegraph and stealth VFX via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 16 prompt files of e37-asset-vfx-cues-trails-stealth-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-cues-trails-stealth-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² sheet or 512² strip, exact grid, black (additive) or transparent (alpha) background; telegraph decals transparent. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 16 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² sheet or 512² strip, exact grid, black (additive) or transparent (alpha) background; telegraph decals transparent), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.90 Write trail, telegraph and stealth VFX prompts (16 assets) open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.92Owner approval: trail, telegraph and stealth VFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 16 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-cues-trails-stealth-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: hostile telegraphs are never confusable with friendly effects and the smoke cloud visibly blocks sight lines. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 16 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then hostile telegraphs are never confusable with friendly effects and the smoke cloud visibly blocks sight lines.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-cues-trails-stealth-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.91 Generate trail, telegraph and stealth VFX via Codex CLI open
    area:artasset:vfxepic:e37milestone:m3needs-human
  • mw-e37.93Integrate approved trail, telegraph and stealth VFXblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e29-weapon-trails, e29-arrow-fx, e29-stealth-feedback-fx, e10-smoke-escape, e10-trap-disarm, e04-creature-attack-hooks.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 16 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the combat sandbox and stealth grey-box course, when charged attacks, arrows, telegraphs, noise and smoke are triggered, then every final effect plays with no console errors.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e04.20 Creatures attack via the move system with readable telegraphs done
    • mw-e10.12 Detect and disarm world traps; failures trigger them open
    • mw-e10.13 Smoke bombs and flash powder break line of sight for escapes open
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.11 Arrow VFX: trails, payload bursts, stuck and broken arrows done
    • mw-e29.12 World-space awareness indicators and optional noise ripples done
    • mw-e29.6 Weapon swing trails and charge build-up glow done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.92 Owner approval: trail, telegraph and stealth VFX open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.94Write element and destruction VFX prompts (13 assets)blockedP1M3task

    Description

    Why

    The systemic world only works if the player can see what is burning, wet, frozen, charged or about to break (constitution: systemic interactions over scripted ones).

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Burning (small/large flame), smoke plume, steam puff, frost crust, wet drips, electric arc, gas fog, extinguish puff; destruction dust cloud and two crack stages; creature dissolve-on-death.

    Asset ids (13):

    • vfx-debris-dust-cloud-01
    • vfx-crack-stage-1-01
    • vfx-crack-stage-2-01
    • vfx-fire-flame-small-01
    • vfx-fire-flame-large-01
    • vfx-smoke-plume-01
    • vfx-steam-puff-01
    • vfx-frost-crust-01
    • vfx-wet-drips-01
    • vfx-electric-arc-01
    • vfx-gas-fog-01
    • vfx-extinguish-puff-01
    • vfx-dissolve-death-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-elemental-destruction-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Physical elements follow §2.3 (water #3F7FA0, poison gas #9BBF3A). Extinguish puff is shared by stealth light-dousing.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 13 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² sheet, 8×8 loops for flames/smoke, 4×4 one-shots, alpha for smoke/steam/dust, additive for flame/arc cores) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each element state is identifiable in greyscale by shape and motion, and crack stages read as progressively weaker.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.95Generate element and destruction VFX via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 13 prompt files of e37-asset-vfx-elemental-destruction-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-elemental-destruction-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² sheet, 8×8 loops for flames/smoke, 4×4 one-shots, alpha for smoke/steam/dust, additive for flame/arc cores. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 13 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² sheet, 8×8 loops for flames/smoke, 4×4 one-shots, alpha for smoke/steam/dust, additive for flame/arc cores), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.94 Write element and destruction VFX prompts (13 assets) open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.96Owner approval: element and destruction VFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 13 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-elemental-destruction-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each element state is identifiable in greyscale by shape and motion, and crack stages read as progressively weaker. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 13 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each element state is identifiable in greyscale by shape and motion, and crack stages read as progressively weaker.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-elemental-destruction-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.95 Generate element and destruction VFX via Codex CLI open
    area:artasset:vfxepic:e37milestone:m3needs-human
  • mw-e37.97Integrate approved element and destruction VFXblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e29-elemental-fx, e29-destruction-fx, e29-spectacle-shaders, e03-state-feedback-bridge.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 13 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the greybox chaos room, when objects are burned, soaked, frozen, charged and smashed, then every final effect plays and live particles stay ≤ 800 on Low.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e03.28 Show burning, wet, frozen and charged states through VFX and audio done
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.7 Magical material library: dissolve, glow, distortion, runes done
    • mw-e29.8 Visuals derived from element states: burning, wet, frozen, shock done
    • mw-e29.9 Destruction VFX: fracture chunks, dust and crack stages open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.96 Owner approval: element and destruction VFX open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.102Write combat HUD prompts (8 assets)blockedP1M3task

    Description

    Why

    Combat decisions depend on reading health, stamina, poise and lock-on in a split second, in the brushstroke HUD style (§9).

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: ui) from template ui-element.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Curved brushstroke health and stamina bars with frame and damage-chip overlay, lock-on reticle, target health/poise bar, hit marker and low-health edge vignette.

    Asset ids (8):

    • ui-bar-health-01
    • ui-bar-stamina-01
    • ui-bar-frame-vitals-01
    • ui-bar-damage-chip-01
    • ui-reticle-lockon-01
    • ui-bar-target-poise-01
    • ui-marker-hit-01
    • ui-vignette-low-health-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-combat-hud-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    No full-screen red vignette (§8): the low-health vignette is a subtle edge treatment. Must pass e31-colorblind-support (shape + position, not colour alone).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 8 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate, transparent, fill-able bar masks with recorded fill axis, reticle 256²) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: bars read over bright snow and dark dungeon backgrounds and health vs stamina are distinguishable without colour.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.103Generate combat HUD via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 8 prompt files of e37-asset-ui-combat-hud-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-combat-hud-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate, transparent, fill-able bar masks with recorded fill axis, reticle 256². Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 8 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate, transparent, fill-able bar masks with recorded fill axis, reticle 256²), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.102 Write combat HUD prompts (8 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.104Owner approval: combat HUDblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 8 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-combat-hud-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: bars read over bright snow and dark dungeon backgrounds and health vs stamina are distinguishable without colour. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then bars read over bright snow and dark dungeon backgrounds and health vs stamina are distinguishable without colour.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-combat-hud-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.103 Generate combat HUD via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3needs-human
  • mw-e37.105Integrate approved combat HUDblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e04-hud-vitals, e04-hud-target, e29-screen-feedback.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 8 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the combat sandbox, when the player takes damage, spends stamina and locks on, then the final HUD renders, damage chip animates, and no placeholder flags remain.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e04.10 Combat HUD: health and stamina bars with damage feedback done
    • mw-e04.21 Lock-on reticle, target health/poise bar and hit markers done
    • mw-e29.5 Camera shake, damage vignette and low-health effects done
    • mw-e37.104 Owner approval: combat HUD open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.106Write stealth HUD and overlays prompts (25 assets)blockedP1M3task

    Description

    Why

    The thief needs to know how visible and how loud they are and what each guard believes, without a full-screen alarm (§8 stealth feedback).

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: ui) from template ui-element.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Light gem in 5 bands, noise ring, stance/gait glyphs, awareness chevrons in 6 distinct shapes (one per alert state) with eye/ear/hand sense glyphs, in-world lockpicking overlay, pickpocket list panel, throw trajectory arc + landing marker, trap placement ghost.

    Asset ids (25):

    • ui-light-gem-band-01
    • ui-light-gem-band-02
    • ui-light-gem-band-03
    • ui-light-gem-band-04
    • ui-light-gem-band-05
    • ui-noise-ring-01
    • ui-glyph-stance-stand-01
    • ui-glyph-stance-crouch-01
    • ui-glyph-gait-sneak-01
    • ui-glyph-gait-walk-01
    • ui-glyph-gait-run-01
    • ui-awareness-unaware-01
    • ui-awareness-suspicious-01
    • ui-awareness-investigating-01
    • ui-awareness-searching-01
    • ui-awareness-alerted-01
    • ui-awareness-combat-01
    • ui-glyph-sense-eye-01
    • ui-glyph-sense-ear-01
    • ui-glyph-sense-hand-01
    • ui-lockpick-overlay-01
    • ui-pickpocket-panel-01
    • ui-throw-arc-01
    • ui-marker-throw-landing-01
    • ui-trap-placement-ghost-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-stealth-hud-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Awareness shapes must differ by shape, not only colour (parchment → hearth → ember). Trap placement ghost serves e10-trap-placement (P2).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 25 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (glyphs flat single-colour 64² (SVG after vectorising), light gem 256² per band, overlays 1024² transparent) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: the 6 awareness chevrons are distinguishable in greyscale at 24 px and light gem bands are ordered by value.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:uiclass:thiefepic:e37milestone:m3
  • mw-e37.107Generate stealth HUD and overlays via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 25 prompt files of e37-asset-ui-stealth-hud-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-stealth-hud-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: glyphs flat single-colour 64² (SVG after vectorising), light gem 256² per band, overlays 1024² transparent. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 25 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (glyphs flat single-colour 64² (SVG after vectorising), light gem 256² per band, overlays 1024² transparent), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.106 Write stealth HUD and overlays prompts (25 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:uiclass:thiefepic:e37milestone:m3
  • mw-e37.108Owner approval: stealth HUD and overlaysblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 25 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-stealth-hud-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the 6 awareness chevrons are distinguishable in greyscale at 24 px and light gem bands are ordered by value. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 25 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the 6 awareness chevrons are distinguishable in greyscale at 24 px and light gem bands are ordered by value.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-stealth-hud-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.107 Generate stealth HUD and overlays via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiclass:thiefepic:e37milestone:m3needs-human
  • mw-e37.109Integrate approved stealth HUD and overlaysblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e09-visibility-hud, e09-awareness-indicators, e10-lockpicking, e10-pickpocketing, e10-thrown-distractions.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 25 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the stealth grey-box course, when the thief moves through light bands and guards cycle all six alert states, then every final HUD element renders with no placeholder flags.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e09.10 Stealth HUD: light exposure, noise ring and stance readout open
    • mw-e09.11 Directional awareness indicators showing each enemy’s alert state open
    • mw-e10.2 Throw objects to create noise distractions guards investigate open
    • mw-e10.7 Pick locks as an in-world, interruptible, noisy action open
    • mw-e10.8 Pickpocket and plant items on creatures from behind open
    • mw-e37.108 Owner approval: stealth HUD and overlays open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiclass:thiefepic:e37milestone:m3
  • mw-e37.110Write kit item icons prompts (21 assets)blockedP1M3task

    Description

    Why

    Players manage their kit in the inventory and quick slots; every starting weapon, arrow type and thief tool needs a readable icon that matches its world model.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: icon-item) from template item-icon.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Painted ¾ top-down item icons for the four class kits: sword, shields, bow, arrow variants, dagger, staff, and thief tools (lockpick, coin, bottle, smoke bomb, noisemaker and tripwire traps, caltrops, water flask, sap).

    Asset ids (21):

    • icon-item-sword-01
    • icon-item-shield-wood-01
    • icon-item-shield-metal-01
    • icon-item-bow-01
    • icon-item-arrow-standard-01
    • icon-item-arrow-fire-01
    • icon-item-arrow-water-01
    • icon-item-arrow-rope-01
    • icon-item-arrow-noise-01
    • icon-item-arrow-blunt-01
    • icon-item-dagger-01
    • icon-item-staff-01
    • icon-item-lockpick-iron-01
    • icon-item-coin-01
    • icon-item-bottle-01
    • icon-item-smoke-bomb-01
    • icon-item-trap-noisemaker-01
    • icon-item-trap-tripwire-01
    • icon-item-caltrops-01
    • icon-item-water-flask-01
    • icon-item-sap-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-icons-items-kit-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Weapon icons use the approved weapon concepts as reference inputs. Loot/world item icons (potions, keys, treasures) are owned by the world/items asset set.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 21 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: every icon is identifiable at 64 px and arrow variants are distinguishable by head/payload shape, not colour alone.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.38 Owner approval: player weapons flat concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.111Generate kit item icons via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 21 prompt files of e37-asset-icons-items-kit-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-icons-items-kit-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 21 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.110 Write kit item icons prompts (21 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.112Owner approval: kit item iconsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 21 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-icons-items-kit-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every icon is identifiable at 64 px and arrow variants are distinguishable by head/payload shape, not colour alone. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 21 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every icon is identifiable at 64 px and arrow variants are distinguishable by head/payload shape, not colour alone.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-icons-items-kit-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.111 Generate kit item icons via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:iconepic:e37milestone:m3needs-human
  • mw-e37.113Integrate approved kit item iconsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e17-inventory-ui, e17-item-schema, e10-thief-tool-items, e05-arrow-schema.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 21 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the inventory with every kit item granted via debug console, when opened, then all 21 icons render from the atlas with no placeholder flags.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e05.1 Data schema for arrow types and property-based payloads done
    • mw-e10.1 Define thief tool item data: lockpicks, throwables, smoke, traps open
    • mw-e17.10 Build inventory screen with category tabs, inspect and actions done
    • mw-e17.2 Define item definition schema and content validator done
    • mw-e37.112 Owner approval: kit item icons open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.114Write inventory UI prompts (16 assets)blockedP1M3task

    Description

    Why

    The inventory is opened constantly; category tabs and the stolen-item marker must be instantly readable (theft has consequences).

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: ui) from template ui-element.md (+ item-icon.md for gold coin), with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    12 category tab glyphs, gold coin icon, stolen-item marker, quick-slot frame and inventory panel 9-slice.

    Asset ids (16):

    • ui-glyph-cat-weapon-01
    • ui-glyph-cat-armor-01
    • ui-glyph-cat-shield-01
    • ui-glyph-cat-ammo-01
    • ui-glyph-cat-book-01
    • ui-glyph-cat-key-01
    • ui-glyph-cat-consumable-01
    • ui-glyph-cat-tool-01
    • ui-glyph-cat-quest-01
    • ui-glyph-cat-artifact-01
    • ui-glyph-cat-currency-01
    • ui-glyph-cat-misc-01
    • icon-item-gold-coin-01
    • ui-marker-stolen-01
    • ui-quickslot-frame-01
    • ui-panel-inventory-9slice-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-inventory-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Quick-slot frame matches the brass-rimmed circles of the HUD (§9).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 16 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (glyphs flat single-colour 64²; panel 1024² transparent 9-slice; coin as item icon 256²) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: all 12 category glyphs are distinguishable at 24 px and the stolen marker is visible on any icon.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.115Generate inventory UI via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 16 prompt files of e37-asset-ui-inventory-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-inventory-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: glyphs flat single-colour 64²; panel 1024² transparent 9-slice; coin as item icon 256². Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 16 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (glyphs flat single-colour 64²; panel 1024² transparent 9-slice; coin as item icon 256²), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.114 Write inventory UI prompts (16 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.116Owner approval: inventory UIblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 16 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-inventory-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: all 12 category glyphs are distinguishable at 24 px and the stolen marker is visible on any icon. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 16 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then all 12 category glyphs are distinguishable at 24 px and the stolen marker is visible on any icon.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-inventory-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.115 Generate inventory UI via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3needs-human
  • mw-e37.117Integrate approved inventory UIblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e17-inventory-ui, e17-consumables-quickslots, e18-ownership-stolen.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 16 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the inventory screen, when switching every category tab and viewing a stolen item, then all elements render from final art with no placeholder flags.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e17.10 Build inventory screen with category tabs, inspect and actions done
    • mw-e17.6 Use consumables from inventory and assignable quick slots done
    • mw-e18.6 Track item ownership and flag stolen items on witnessed theft open
    • mw-e37.116 Owner approval: inventory UI open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.118Write equipment and loot UI prompts (14 assets)blockedP1M3task

    Description

    Why

    Finding a unique artifact should feel like a discovery, and equipping gear should make trade-offs (verbs, stealth) visible.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: ui) from template ui-element.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Nine equipment slot silhouettes, compare up/down arrows, container window 9-slice, pickup toast frame and artifact discovery banner.

    Asset ids (14):

    • ui-slot-head-01
    • ui-slot-body-01
    • ui-slot-hands-01
    • ui-slot-feet-01
    • ui-slot-main-hand-01
    • ui-slot-off-hand-01
    • ui-slot-trinket-01
    • ui-slot-ammo-01
    • ui-slot-tool-01
    • ui-glyph-compare-up-01
    • ui-glyph-compare-down-01
    • ui-panel-container-9slice-01
    • ui-toast-pickup-01
    • ui-banner-artifact-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-equipment-loot-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Compare arrows must differ by shape, not only colour.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 14 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (slot silhouettes flat ink 128²; panels/banners 1024² transparent 9-slice) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: every slot silhouette is recognisable at 48 px and the artifact banner feels celebratory but on-style.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.119Generate equipment and loot UI via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 14 prompt files of e37-asset-ui-equipment-loot-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-equipment-loot-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: slot silhouettes flat ink 128²; panels/banners 1024² transparent 9-slice. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 14 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (slot silhouettes flat ink 128²; panels/banners 1024² transparent 9-slice), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.118 Write equipment and loot UI prompts (14 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.120Owner approval: equipment and loot UIblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 14 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-equipment-loot-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every slot silhouette is recognisable at 48 px and the artifact banner feels celebratory but on-style. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 14 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every slot silhouette is recognisable at 48 px and the artifact banner feels celebratory but on-style.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-equipment-loot-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.119 Generate equipment and loot UI via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3needs-human
  • mw-e37.121Integrate approved equipment and loot UIblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e17-equipment-ui, e18-container-ui, e18-unique-artifacts.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 14 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the equipment and container screens, when an artifact is looted and equipped, then all elements render from final art with no placeholder flags.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e17.11 Add equipment paper-doll view with verb and stealth comparison open
    • mw-e18.4 Build container window and loot pickup notifications done
    • mw-e18.8 Add unique artifacts with active verbs and lore open
    • mw-e37.120 Owner approval: equipment and loot UI open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.122Write class select art prompts (8 assets)blockedP1M3task

    Description

    Why

    Class selection is the player's first real choice; each card should sell a different way to play.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: keyart / ui) from template key-art-title-screen.md (cards) + ui-element.md (emblems), with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Four class card illustrations depicting the approved character designs in a signature moment, and four class emblems (flat, heraldic, one per class).

    Asset ids (8):

    • keyart-class-card-knight-01
    • keyart-class-card-archer-01
    • keyart-class-card-sorcerer-01
    • keyart-class-card-thief-01
    • ui-emblem-class-knight-01
    • ui-emblem-class-archer-01
    • ui-emblem-class-sorcerer-01
    • ui-emblem-class-thief-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-class-select-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Cards use the approved character sheets as reference inputs so the card and the model match.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 8 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (cards 2:3 1024×1536 opaque; emblems 1024² transparent → 256²/128²) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each card matches its approved character sheet and the four emblems are distinguishable by silhouette.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.20 Owner approval: player class characters flat concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:conceptclass:allepic:e37milestone:m3
  • mw-e37.123Generate class select art via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 8 prompt files of e37-asset-ui-class-select-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-class-select-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: cards 2:3 1024×1536 opaque; emblems 1024² transparent → 256²/128². Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 8 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (cards 2:3 1024×1536 opaque; emblems 1024² transparent → 256²/128²), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.122 Write class select art prompts (8 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptclass:allepic:e37milestone:m3
  • mw-e37.124Owner approval: class select artblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 8 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-class-select-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each card matches its approved character sheet and the four emblems are distinguishable by silhouette. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each card matches its approved character sheet and the four emblems are distinguishable by silhouette.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-class-select-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.123 Generate class select art via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptclass:allepic:e37milestone:m3needs-human
  • mw-e37.125Integrate approved class select artblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e19-class-selection.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 8 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given a new game, when the class select screen opens, then four final cards and emblems render with no placeholder flags and no console errors.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e19.5 Add class selection at new game that applies kit and capabilities done
    • mw-e37.124 Owner approval: class select art open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptclass:allepic:e37milestone:m3
  • mw-e37.126Write class verb icons prompts (25 assets)blockedP1M3task

    Description

    Why

    Progression is capability unlocks, not numbers; each new verb deserves an icon and a moment.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: ui) from template ui-element.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Verb glyphs per class (knight 6, archer 6, thief 8, sorcerer 4) and the "new verb learned" banner frame.

    Asset ids (25):

    • ui-glyph-verb-knight-block-01
    • ui-glyph-verb-knight-parry-01
    • ui-glyph-verb-knight-riposte-01
    • ui-glyph-verb-knight-heavy-charge-01
    • ui-glyph-verb-knight-shield-bash-01
    • ui-glyph-verb-knight-kick-01
    • ui-glyph-verb-archer-draw-aim-01
    • ui-glyph-verb-archer-focused-release-01
    • ui-glyph-verb-archer-breath-hold-01
    • ui-glyph-verb-archer-quickstep-01
    • ui-glyph-verb-archer-aerial-shot-01
    • ui-glyph-verb-archer-retrieve-arrow-01
    • ui-glyph-verb-thief-lockpick-01
    • ui-glyph-verb-thief-pickpocket-01
    • ui-glyph-verb-thief-takedown-01
    • ui-glyph-verb-thief-carry-body-01
    • ui-glyph-verb-thief-climb-01
    • ui-glyph-verb-thief-disguise-01
    • ui-glyph-verb-thief-place-trap-01
    • ui-glyph-verb-thief-lean-peek-01
    • ui-glyph-verb-sorcerer-study-book-01
    • ui-glyph-verb-sorcerer-cast-01
    • ui-glyph-verb-sorcerer-channel-01
    • ui-glyph-verb-sorcerer-experiment-insight-01
    • ui-banner-verb-learned-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-capabilities-verbs-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Verb list is provisional; reconcile with the capability registry in e19-class-definitions before writing prompts (add/remove ids in this bead's description). Sorcerer spells use spell icons, so only meta-verbs are here.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 25 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (glyphs flat single-colour 64²/128² transparent; banner 1024² transparent 9-slice) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: verb glyphs read at 32 px and each class's set shares a consistent visual motif.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:uiclass:allepic:e37milestone:m3
  • mw-e37.127Generate class verb icons via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 25 prompt files of e37-asset-ui-capabilities-verbs-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-capabilities-verbs-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: glyphs flat single-colour 64²/128² transparent; banner 1024² transparent 9-slice. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 25 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (glyphs flat single-colour 64²/128² transparent; banner 1024² transparent 9-slice), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.126 Write class verb icons prompts (25 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:uiclass:allepic:e37milestone:m3
  • mw-e37.128Owner approval: class verb iconsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 25 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-capabilities-verbs-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: verb glyphs read at 32 px and each class's set shares a consistent visual motif. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 25 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then verb glyphs read at 32 px and each class's set shares a consistent visual motif.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-capabilities-verbs-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.127 Generate class verb icons via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiclass:allepic:e37milestone:m3needs-human
  • mw-e37.129Integrate approved class verb iconsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e19-capabilities-screen, e19-class-definitions.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 25 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the capabilities screen with every verb granted via debug console, when opened, then all verb glyphs render and the verb-learned banner plays on unlock with no placeholder flags.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e19.12 Build capabilities screen and "new verb learned" feedback open
    • mw-e19.4 Define the four classes as data: kit, capabilities, proficiencies done
    • mw-e37.128 Owner approval: class verb icons open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiclass:allepic:e37milestone:m3
  • mw-e37.130Write input glyphs prompts (24 assets)blockedP1M3task

    Description

    Why

    Contextual prompts and remapping must show the player's actual bindings in the house ink-brush style.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: ui) from template ui-element.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Blank key caps (key label rendered by the game), mouse buttons/wheel/move, and generic gamepad glyphs (face buttons by position, bumpers, triggers, sticks, d-pad, start/select).

    Asset ids (24):

    • ui-glyph-input-key-cap-01
    • ui-glyph-input-key-cap-wide-01
    • ui-glyph-input-mouse-left-01
    • ui-glyph-input-mouse-right-01
    • ui-glyph-input-mouse-middle-01
    • ui-glyph-input-mouse-wheel-01
    • ui-glyph-input-mouse-move-01
    • ui-glyph-input-pad-face-south-01
    • ui-glyph-input-pad-face-east-01
    • ui-glyph-input-pad-face-west-01
    • ui-glyph-input-pad-face-north-01
    • ui-glyph-input-pad-bumper-left-01
    • ui-glyph-input-pad-bumper-right-01
    • ui-glyph-input-pad-trigger-left-01
    • ui-glyph-input-pad-trigger-right-01
    • ui-glyph-input-pad-stick-left-01
    • ui-glyph-input-pad-stick-right-01
    • ui-glyph-input-pad-stick-press-01
    • ui-glyph-input-pad-dpad-up-01
    • ui-glyph-input-pad-dpad-down-01
    • ui-glyph-input-pad-dpad-left-01
    • ui-glyph-input-pad-dpad-right-01
    • ui-glyph-input-pad-start-01
    • ui-glyph-input-pad-select-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-input-glyphs-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    No letters in images: key labels and brand-specific face-button letters are rendered in Alegreya Sans SC over the blank glyph. Generic positional face buttons avoid platform trademarks. Glyphs may be traced to SVG in integration.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 24 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (flat single-colour ink glyphs, 1024² generate → 64² PNG + SVG trace, transparent) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: glyphs are legible at 24 px beside Alegreya Sans text and share stroke weight.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.131Generate input glyphs via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 24 prompt files of e37-asset-ui-input-glyphs-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-input-glyphs-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: flat single-colour ink glyphs, 1024² generate → 64² PNG + SVG trace, transparent. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 24 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (flat single-colour ink glyphs, 1024² generate → 64² PNG + SVG trace, transparent), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.130 Write input glyphs prompts (24 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.132Owner approval: input glyphsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 24 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-input-glyphs-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: glyphs are legible at 24 px beside Alegreya Sans text and share stroke weight. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 24 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then glyphs are legible at 24 px beside Alegreya Sans text and share stroke weight.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-input-glyphs-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.131 Generate input glyphs via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3needs-human
  • mw-e37.133Integrate approved input glyphsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e02-interaction, e02-input-gamepad, e31-remap-ui.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 24 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the remap screen and an interaction prompt, when switching between KB/M and gamepad, then the matching final glyphs render with the bound key label overlaid.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e02.5 Focus and interact with world objects via contextual prompts done
    • mw-e02.9 Support gamepad input with deadzones and remappable bindings done
    • mw-e31.2 Let players remap keyboard, mouse and gamepad bindings done
    • mw-e37.132 Owner approval: input glyphs open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.134Write shop and dialogue UI prompts (18 assets)blockedP1M3task

    Description

    Why

    Talking and trading are how the player learns the world and its people; class-gated options must be visible so each class feels its own way through a conversation.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: ui) from template ui-element.md (+ npc-portrait.md for the generic silhouette), with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Shop panel, merchant portrait frame, specialty badge, buyback glyph; dialogue box, portrait frame, generic silhouette portrait, class tag icons, persuasion approach glyphs (persuade, intimidate, deceive, charm), locked-option glyph, subtitle plate and off-screen speaker chevron.

    Asset ids (18):

    • ui-panel-shop-9slice-01
    • ui-frame-merchant-portrait-01
    • ui-badge-specialty-01
    • ui-glyph-buyback-01
    • ui-panel-dialogue-9slice-01
    • ui-frame-dialogue-portrait-01
    • portrait-generic-silhouette-01
    • ui-tag-class-knight-01
    • ui-tag-class-archer-01
    • ui-tag-class-sorcerer-01
    • ui-tag-class-thief-01
    • ui-glyph-persuade-01
    • ui-glyph-intimidate-01
    • ui-glyph-deceive-01
    • ui-glyph-charm-01
    • ui-glyph-option-locked-01
    • ui-plate-subtitle-01
    • ui-glyph-offscreen-chevron-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-ui-shop-dialogue-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    NPC portraits themselves are owned by the world/character asset set. Subtitle plate must keep text ≥ 7:1 contrast over any scene.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 18 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (panels 1024² transparent 9-slice; glyphs flat single-colour 64²; generic portrait bust 1024² per npc-portrait template) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: the four persuasion glyphs and four class tags are distinguishable at 24 px and panels match the approved menu kit.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.135Generate shop and dialogue UI via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 18 prompt files of e37-asset-ui-shop-dialogue-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-ui-shop-dialogue-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: panels 1024² transparent 9-slice; glyphs flat single-colour 64²; generic portrait bust 1024² per npc-portrait template. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 18 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (panels 1024² transparent 9-slice; glyphs flat single-colour 64²; generic portrait bust 1024² per npc-portrait template), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.134 Write shop and dialogue UI prompts (18 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.136Owner approval: shop and dialogue UIblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 18 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ui-shop-dialogue-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the four persuasion glyphs and four class tags are distinguishable at 24 px and panels match the approved menu kit. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 18 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the four persuasion glyphs and four class tags are distinguishable at 24 px and panels match the approved menu kit.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ui-shop-dialogue-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.135 Generate shop and dialogue UI via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3needs-human
  • mw-e37.137Integrate approved shop and dialogue UIblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e20-shop-ui, e22-dialogue-ui, e22-class-dialogue-options, e22-persuasion-checks.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 18 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the reference quest fixture and a fixture merchant, when talking and trading, then every element renders from final art with no placeholder flags.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e20.10 Build shop UI with merchant identity, buy/sell and price breakdown done
    • mw-e22.10 Build accessible dialogue UI with choices, tags and history done
    • mw-e22.6 Add class- and capability-gated dialogue options with tags done
    • mw-e22.7 Add deterministic persuasion checks with fail branches done
    • mw-e37.136 Owner approval: shop and dialogue UI open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:uiepic:e37milestone:m3
  • mw-e37.138Write title and loading art prompts (6 assets)blockedP1M3task

    Description

    Why

    The title screen is the first impression and sets the tone: souls-like weight and mystery, but warm and hopeful.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: keyart) from template key-art-title-screen.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Title screen key art with negative space for the logo, a painted logo emblem (the wordmark itself is typeset in Cinzel Decorative, never generated), and four loading-screen illustrations, one per class.

    Asset ids (6):

    • keyart-title-screen-01
    • ui-logo-emblem-01
    • keyart-loading-knight-01
    • keyart-loading-archer-01
    • keyart-loading-sorcerer-01
    • keyart-loading-thief-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-keyart-title-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Prompts wait for e39-title-decision (logo) and the approved character sheets (classes appear in the art). Related: no dedicated title/main-menu bead exists yet — e30-save-load-ui (Continue/Load) is the nearest consumer; flag for the integration pass.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 6 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (title 16:9 1536×1024 master (upscaled to 3840×2160 in pipeline), loading 16:9 opaque, emblem 1024² transparent) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: the title art leaves a clean logo area, reads warm rather than bleak, and no letters appear anywhere.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.20 Owner approval: player class characters flat concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.2 Decide the shipping title and record it as an ADR done
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.139Generate title and loading art via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 6 prompt files of e37-asset-keyart-title-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-keyart-title-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: title 16:9 1536×1024 master (upscaled to 3840×2160 in pipeline), loading 16:9 opaque, emblem 1024² transparent. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 6 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (title 16:9 1536×1024 master (upscaled to 3840×2160 in pipeline), loading 16:9 opaque, emblem 1024² transparent), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.138 Write title and loading art prompts (6 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.140Owner approval: title and loading artblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 6 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-keyart-title-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the title art leaves a clean logo area, reads warm rather than bleak, and no letters appear anywhere. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 6 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the title art leaves a clean logo area, reads warm rather than bleak, and no letters appear anywhere.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-keyart-title-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.139 Generate title and loading art via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3needs-human
  • mw-e37.141Integrate approved title and loading artblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e30-save-load-ui, e32-asset-loading.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 6 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given a cold boot, when the title and a loading screen show, then final art renders with the typeset logo overlaid and the initial-download budget (≤ 50 MB) still passes.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e01.2 Title screen flows into class select, spawn and continue done
    • mw-e30.11 Build Continue / Load / Save menu screens done
    • mw-e32.7 Stream and compress assets with a progress-reporting loader open
    • mw-e37.140 Owner approval: title and loading art open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.143Write River Wend environment concepts prompts (5 assets)blockedP1M3task

    Description

    Why

    The River Wend links Briar Glen to the sea and adds three class-route set pieces (Stone Stair, Millweir, Weeping Adit) plus the towpath and Kestrel Lock; they need a shared look before any river asset is made (style bible §2.2 River Wend row).

    What

    Write one prompt file per asset in assets/prompts/environment/<asset-id>.md (category: environment) from template environment-concept.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Briar Glen Quay with the stone barge *Patient Ann* (ochre hull stripe, no painted name) taking on dressed glenstone blocks from their timber cradles, a quay crane, and the Stone Stair, a stepped slipway for blocks coming down from the Deepworks' cutting hall, pale with stone dust; the Vesperine Millweir with a bell-mark keystone, clear walkable sluice top and two water levels; the Weeping Adit mouth where the Wend springs from the hill (cold, dripping, a faint Nightjar shimmer #CFC6F2 on the water), flooded tunnel with air pockets and an empty stone barge being winched back up on its chain; the towpath down the valley; Kestrel Lock with balance-beam gates, windlasses, a flaking toll board (no legible text) and Old Reed's cottage.

    Asset ids (5):

    • env-briar-glen-quay-01
    • env-millweir-sluice-walk-01
    • env-weeping-adit-mouth-01
    • env-towpath-valley-01
    • env-kestrel-lock-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-env-river-concepts-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Water is standing water only (no flowing-river sim); the barge ride is a narrated card (e37-asset-barge-ride-cards-*), so env-barge-ride-card-01 from the needs list is produced there as runtime key art.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 5 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each painting sits in the River Wend palette (brown water #6B5A3E, reeds #8FA05A, tarred timber #3A2E26, lock-gate red #A8473A), water reads as water but not as a current, and every class route (climb the Stone Stair, walk the sluice top, swim the Adit air pockets) is visible.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.245 Owner approval: Briar Glen environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.144Generate River Wend environment concepts via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 5 prompt files of e37-asset-env-river-concepts-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-env-river-concepts-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 5 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.143 Write River Wend environment concepts prompts (5 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.145Owner approval: River Wend environment conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 5 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-env-river-concepts-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each painting sits in the River Wend palette (brown water #6B5A3E, reeds #8FA05A, tarred timber #3A2E26, lock-gate red #A8473A), water reads as water but not as a current, and every class route (climb the Stone Stair, walk the sluice top, swim the Adit air pockets) is visible. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 5 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each painting sits in the River Wend palette (brown water #6B5A3E, reeds #8FA05A, tarred timber #3A2E26, lock-gate red #A8473A), water reads as water but not as a current, and every class route (climb the Stone Stair, walk the sluice top, swim the Adit air pockets) is visible.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-env-river-concepts-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.144 Generate River Wend environment concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3needs-human
  • mw-e37.146Integrate approved River Wend environment conceptsblockedP1M3task

    Description

    Why

    Approved environment concepts are the art-dress target: the art-dress, lighting and style-consistency beads compare in-engine screenshots against them.

    What

    Promote approved versions to assets/source/environment/<asset-id>/, add assets/CREDITS.md rows and approval records, register each concept as the artReference of its area in the area content data, and add it to the art-dress checklist and e37-style-consistency-review comparison sheet.

    Scope

    • In: Source promotion, CREDITS rows + approval records in the same commit
    • In: Area artReference entries and the art-dress comparison sheet
    • Out: Art-dressing the areas (art-dress beads); concepts are not runtime assets

    Notes

    Consumers: e25-quay-stone-stair, e25-millweir-sluice-walk, e25-weeping-adit, e25-towpath-kestrel-lock. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e25-river-art-audio.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when e37-asset-validator runs, then every id has a source folder, CREDITS row and a matching approval hash, and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 content Given the area content data for the River Wend locations, when schema-validated, then each area in this set names its concept id in artReference and the id resolves to an approved asset.
    • AC-4 integration Given the art-dress comparison sheet generator, when it runs, then each concept is paired with the latest Playwright screenshot of its area from the same camera preset.
    • AC-5 integration Edge: given an area whose artReference points at an id without an approval record, when CI runs, then the content check fails naming the area and id.

    Waits on

    • mw-e25.11 Build Briar Glen Quay and the Stone Stair slipway down from the mine open
    • mw-e25.12 Build the Millweir and its sluice walk to the Briarwood far bank open
    • mw-e25.13 Build the Weeping Adit: the flooded sixth way into the lower Deepworks open
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e37.145 Owner approval: River Wend environment concepts open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.147Write Wendmouth environment concepts prompts (12 assets)blockedP1M3task

    Description

    Why

    Wendmouth is loud, cheerful, crooked and built like a city out of the valley's glenstone — the opposite of Briar Glen's golden-hour cosiness (style bible §2.2 Wendmouth row) — and it is the thief's playground; every harbour asset is judged against these paintings.

    What

    Write one prompt file per asset in assets/prompts/environment/<asset-id>.md (category: environment) from template environment-concept.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Establishing harbour view of a monumental glenstone harbour (colossal stepped quays worn smooth by hulls, the great curving breakwater of mason-marked reject blocks, vaulted stone warehouses, the columned Customs House, treadwheel cranes on stone piers and block yards of cut stone, with timber net lofts, tarred sheds and bright shopfronts perched on the stone; people, sheds and boats small against it; the Gilded Tern in the pool); the harbour at night (lantern pools on wet flagstones, ship lamps, lighthouse sweep); the Stone Wharf on Tidefair day (stone barges unloading dressed blocks, treadwheel cranes, cargo nets, contests on the open flagstones, the gated Silver Quay with imperial guards at its far end, seen not entered); the columned glenstone Customs House (Lantern Court flag, cargo scale, Cray's office, strongroom); the vaulted stone Bonded Warehouse with bay nine, skylights and hoists; the Drowned Gull; the Tidemarket; the Undertow in the low vaulted block-vaults under the fish market; the net-loft rooftop route; the Tern's deck and rigging; the Tern's hold, cabin and locked berth; the mason-marked block breakwater with the sunken figurehead and sea-door at low and high tide.

    Asset ids (12):

    • env-wendmouth-harbour-01
    • env-wendmouth-night-01
    • env-wendmouth-stone-wharf-tidefair-01
    • env-wendmouth-customs-house-01
    • env-wendmouth-bonded-warehouse-01
    • env-drowned-gull-interior-01
    • env-wendmouth-tidemarket-01
    • env-wendmouth-undertow-01
    • env-wendmouth-rooftops-net-lofts-01
    • env-gilded-tern-deck-01
    • env-gilded-tern-hold-cabin-01
    • env-wendmouth-breakwater-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-env-wendmouth-concepts-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Also mood targets for e40-stone-wharf, e40-customs-house, e40-bonded-warehouse, e40-drowned-gull, e40-tidemarket, e40-undertow, e40-rooftops-net-lofts, e40-gilded-tern, e40-breakwater-sea-door, e40-tidefair-strength. Night concept also informs e40-harbor-lighting-audio.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 12 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: Wendmouth reads high-key, breezy and busier in colour than Briar Glen (salt-bleached #B8AE9A, tar #2F2A28, bunting turquoise/sunflower/coral), climbable taut nets and rigging read distinct from loose drying nets, and the rooftop route reads as one continuous line from the wharf.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.245 Owner approval: Briar Glen environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.148Generate Wendmouth environment concepts via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 12 prompt files of e37-asset-env-wendmouth-concepts-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-env-wendmouth-concepts-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 12 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.147 Write Wendmouth environment concepts prompts (12 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.149Owner approval: Wendmouth environment conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 12 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-env-wendmouth-concepts-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Wendmouth reads high-key, breezy and busier in colour than Briar Glen (salt-bleached #B8AE9A, tar #2F2A28, bunting turquoise/sunflower/coral), climbable taut nets and rigging read distinct from loose drying nets, and the rooftop route reads as one continuous line from the wharf. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Wendmouth reads high-key, breezy and busier in colour than Briar Glen (salt-bleached #B8AE9A, tar #2F2A28, bunting turquoise/sunflower/coral), climbable taut nets and rigging read distinct from loose drying nets, and the rooftop route reads as one continuous line from the wharf.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-env-wendmouth-concepts-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.148 Generate Wendmouth environment concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3needs-human
  • mw-e37.150Integrate approved Wendmouth environment conceptsblockedP1M3task

    Description

    Why

    Approved environment concepts are the art-dress target: the art-dress, lighting and style-consistency beads compare in-engine screenshots against them.

    What

    Promote approved versions to assets/source/environment/<asset-id>/, add assets/CREDITS.md rows and approval records, register each concept as the artReference of its area in the area content data, and add it to the art-dress checklist and e37-style-consistency-review comparison sheet.

    Scope

    • In: Source promotion, CREDITS rows + approval records in the same commit
    • In: Area artReference entries and the art-dress comparison sheet
    • Out: Art-dressing the areas (art-dress beads); concepts are not runtime assets

    Notes

    Consumers: e40-harbor-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e40-harbor-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when e37-asset-validator runs, then every id has a source folder, CREDITS row and a matching approval hash, and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 content Given the area content data for Wendmouth, when schema-validated, then each area in this set names its concept id in artReference and the id resolves to an approved asset.
    • AC-4 integration Given the art-dress comparison sheet generator, when it runs, then each concept is paired with the latest Playwright screenshot of its area from the same camera preset.
    • AC-5 integration Edge: given an area whose artReference points at an id without an approval record, when CI runs, then the content check fails naming the area and id.

    Waits on

    • mw-e37.149 Owner approval: Wendmouth environment concepts open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.151Write River Wend tileables prompts (5 assets)blockedP1M3task

    Description

    Why

    Brown river water, tarred barge timber, towpath clay and green lock gates carry the river palette across the quay, weir, lock and adit.

    What

    Write one prompt file per asset in assets/prompts/texture/<asset-id>.md (category: texture) from template tileable-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Brown river water surface (standing water, readable as freezable/swimmable), tarred timber, lock-gate paint, towpath clay, and Vesperine weir stone with the bell-mark keystone as a trim.

    Asset ids (5):

    • tex-water-river-brown-01
    • tex-timber-tarred-01
    • tex-lock-gate-green-01
    • tex-towpath-clay-01
    • tex-trim-millweir-stone-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-tex-river-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    tex-towpath-clay-01 and tex-trim-millweir-stone-01 are added from the style bible River Wend row. The style bible names lock-gate red #A8473A while the needs list says tex-lock-gate-green-01; the id is kept and the prompt follows the bible colour (flagged for reconciliation). tex-timber-tarred-01 is shared with Wendmouth.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 5 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: surfaces tile invisibly, the river water mirrors the sky and reads as water without implying a current, and the weir trim carries the bell mark as a shape only.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.145 Owner approval: River Wend environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.152Generate River Wend tileables via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 5 prompt files of e37-asset-tex-river-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-tex-river-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 5 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha), then dimensions, transparency/background, seamless tiling on both axes (automated edge-difference check) and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.151 Write River Wend tileables prompts (5 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.153Owner approval: River Wend tileablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 5 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-tex-river-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: surfaces tile invisibly, the river water mirrors the sky and reads as water without implying a current, and the weir trim carries the bell mark as a shape only. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 5 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then surfaces tile invisibly, the river water mirrors the sky and reads as water without implying a current, and the weir trim carries the bell mark as a shape only.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-tex-river-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.152 Generate River Wend tileables via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3needs-human
  • mw-e37.154Integrate approved River Wend tileablesblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/texture/<asset-id>/, build KTX2 with mips (UASTC for any normal map), register each texture in the stylized material library with its vertex-colour blend partner, add CREDITS rows and approval records, and swap the grey-box materials in the consuming areas.

    Scope

    • In: Source promotion, pipeline run, KTX2 + mip build, vertex-colour blend variants
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e25-quay-stone-stair, e25-towpath-kestrel-lock. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e25-river-art-audio.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 5 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the quay, weir, towpath and lock, when Playwright captures each, then final textures load with no placeholder materials and no console errors.
    • AC-5 perf Given the rebuilt textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the owning location package stays ≤ 25 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e25.11 Build Briar Glen Quay and the Stone Stair slipway down from the mine open
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e37.153 Owner approval: River Wend tileables open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.155Write Wendmouth tileables and trims prompts (9 assets)blockedP1M3task

    Description

    Why

    Salt-weathered glenstone, bleached planks, tar, rope and canvas dominate every harbour frame; the loud tin roof versus quiet tar roof is a thief-route rule.

    What

    Write one prompt file per asset in assets/prompts/texture/<asset-id>.md (category: texture) from template tileable-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Salt-bleached planks, hawser rope trim, cargo net alpha (climbable/flammable legibility), sailcloth, salt-weathered glenstone blocks with mason's marks (breakwater, stepped quays and warehouse walls), grey harbour water, loud tin roof vs quiet tar roof, and a Wendmouth painted-shopfront trim sheet.

    Asset ids (9):

    • tex-planks-salt-bleached-01
    • tex-rope-hawser-trim-01
    • tex-net-cargo-alpha-01
    • tex-sailcloth-01
    • tex-stone-breakwater-01
    • tex-water-harbour-grey-01
    • tex-roof-tin-harbour-01
    • tex-roof-tar-harbour-01
    • tex-trim-wendmouth-shopfront-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-tex-harbour-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    tex-trim-wendmouth-shopfront-01 is added for §6.3 trims.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 9 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: the tin and tar roofs are distinguishable at 10 m in greyscale, the cargo net alpha reads taut/climbable per style bible §5.4, and the palette stays salt-bleached and high-key.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.149 Owner approval: Wendmouth environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.156Generate Wendmouth tileables and trims via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 9 prompt files of e37-asset-tex-harbour-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-tex-harbour-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 9 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha), then dimensions, transparency/background, seamless tiling on both axes (automated edge-difference check) and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.155 Write Wendmouth tileables and trims prompts (9 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.157Owner approval: Wendmouth tileables and trimsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 9 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-tex-harbour-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the tin and tar roofs are distinguishable at 10 m in greyscale, the cargo net alpha reads taut/climbable per style bible §5.4, and the palette stays salt-bleached and high-key. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 9 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the tin and tar roofs are distinguishable at 10 m in greyscale, the cargo net alpha reads taut/climbable per style bible §5.4, and the palette stays salt-bleached and high-key.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-tex-harbour-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.156 Generate Wendmouth tileables and trims via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3needs-human
  • mw-e37.158Integrate approved Wendmouth tileables and trimsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/texture/<asset-id>/, build KTX2 with mips (UASTC for any normal map), register each texture in the stylized material library with its vertex-colour blend partner, add CREDITS rows and approval records, and swap the grey-box materials in the consuming areas.

    Scope

    • In: Source promotion, pipeline run, KTX2 + mip build, vertex-colour blend variants
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e40-harbor-greybox, e40-rooftops-net-lofts. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e40-harbor-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 9 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given Wendmouth, when Playwright captures the wharf and the rooftop route, then final textures load, the tin and tar roofs use distinct surface-acoustic material ids, and no console errors occur.
    • AC-5 perf Given the rebuilt textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the owning location package stays ≤ 25 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e37.157 Owner approval: Wendmouth tileables and trims open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    • mw-e40.13 Build a continuous rooftop and net-loft route across the waterfront open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.159Write harbour cast portraits prompts (9 assets)blockedP1M3task

    Description

    Why

    Wendmouth's shenanigans are social; text-only dialogue leans on portraits for Mags's gruffness, Nell's gold tooth and Cray's starch.

    What

    Write one prompt file per asset in assets/prompts/portrait/<asset-id>.md (category: portrait) from template npc-portrait.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Mags Oakum (pipe, forearms like hawsers), Nell Gannet (tiny, gold-toothed grin), Inspector Prudence Cray (starched, spectacles, brass lantern-in-ring badge), Tereza Maelo (elegant Saltmarch cut, scarred hands), Jasper Quell (ink-stained cuffs, nervous stoop), Big Oona (dockhand champion), Old Reed (lock keeper), Captain Hesketh, and "Mr. S—'s agent" as a veiled silhouette only.

    Asset ids (9):

    • portrait-npc-mags-bargewoman
    • portrait-npc-nell-gull-keeper
    • portrait-npc-cray-inspector
    • portrait-npc-tereza-merchant
    • portrait-npc-jasper-shipping-agent
    • portrait-npc-oona-dockhand
    • portrait-npc-reed-lock-keeper
    • portrait-npc-hesketh-captain
    • portrait-npc-agent-veiled

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-portraits-harbour-cast-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 9 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate → 512²/256² PNG → KTX2 UASTC, bust framing with head-room, softly blurred location-coloured background) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each matches story bible §5.13/§5.14 and the style bible §5.4 silhouette hooks, the set matches the approved Briar Glen cast portraits in style, and the veiled agent shows no face.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.285 Owner approval: named cast portraits open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:portraitepic:e37milestone:m3
  • mw-e37.160Generate harbour cast portraits via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 9 prompt files of e37-asset-portraits-harbour-cast-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-portraits-harbour-cast-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate → 512²/256² PNG → KTX2 UASTC, bust framing with head-room, softly blurred location-coloured background. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 9 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate → 512²/256² PNG → KTX2 UASTC, bust framing with head-room, softly blurred location-coloured background), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.159 Write harbour cast portraits prompts (9 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:portraitepic:e37milestone:m3
  • mw-e37.161Owner approval: harbour cast portraitsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 9 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-portraits-harbour-cast-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each matches story bible §5.13/§5.14 and the style bible §5.4 silhouette hooks, the set matches the approved Briar Glen cast portraits in style, and the veiled agent shows no face. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 9 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each matches story bible §5.13/§5.14 and the style bible §5.4 silhouette hooks, the set matches the approved Briar Glen cast portraits in style, and the veiled agent shows no face.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-portraits-harbour-cast-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.160 Generate harbour cast portraits via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:portraitepic:e37milestone:m3needs-human
  • mw-e37.162Integrate approved harbour cast portraitsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e22-dialogue-ui, e25-barge-travel, e25-towpath-kestrel-lock, e40-drowned-gull, e40-customs-house, e40-tidemarket, e40-bonded-warehouse, e40-gilded-tern, e40-tidefair-strength.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 9 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given each harbour character's dialogue opened in the dialogue preview runner, when rendered, then the final portrait shows with no placeholder flags and no console errors.
    • AC-5 perf Given the harbour portrait atlas, when e32-perf-budgets runs, then it streams with the Wendmouth package and resident texture memory stays ≤ 256 MB on Low.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e22.10 Build accessible dialogue UI with choices, tags and history done
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e25.15 Ride Mags Oakum's barge between Briar Glen Quay and Wendmouth open
    • mw-e37.161 Owner approval: harbour cast portraits open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e40.10 Author the Tidemarket: Tereza's arms stall and the foreign book cart open
    • mw-e40.14 Build the Gilded Tern: rigging, hold, cabin, locked berth, departure open
    • mw-e40.3 Build the Customs House, its strongroom and Cray's book confiscation open
    • mw-e40.4 Build the Bonded Warehouse: bay nine, skylights, hoists and manifests open
    • mw-e40.6 Build the Drowned Gull: arm-wrestling, dice, drinking and the trapdoor open
    • mw-e40.7 Stage the Tidefair arm-wrestling bout and the Gull brawl open
    area:artasset:portraitepic:e37milestone:m3
  • mw-e37.163Write barge ride card art prompts (2 assets)blockedP1M3task

    Description

    Why

    The barge journey is a narrated ride card, not a simulated trip (story bible §3.6); two painted cards make the fast travel feel like a place.

    What

    Write one prompt file per asset in assets/prompts/keyart/<asset-id>.md (category: keyart) from template key-art-title-screen.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    *Patient Ann* drifting downriver on a misty morning (Mags at the tiller, pipe smoke), and the barge towed back upriver by the towpath horse — no painted ship name, space left for narration text.

    Asset ids (2):

    • keyart-barge-ride-down-01
    • keyart-barge-ride-up-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-barge-ride-cards-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Replaces the needs-list id env-barge-ride-card-01 (one concept) with two runtime cards (down/up) because they ship as UI art.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 2 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (16:9, 1920×1080 generate → KTX2 UASTC full-screen card, safe area for font-rendered narration text) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: both cards read as the same barge and river as the approved river concepts, leave a clear text-safe area, and contain no letters.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.145 Owner approval: River Wend environment concepts open
    • mw-e37.161 Owner approval: harbour cast portraits open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.164Generate barge ride card art via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 2 prompt files of e37-asset-barge-ride-cards-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-barge-ride-cards-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 16:9, 1920×1080 generate → KTX2 UASTC full-screen card, safe area for font-rendered narration text. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 2 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (16:9, 1920×1080 generate → KTX2 UASTC full-screen card, safe area for font-rendered narration text), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.163 Write barge ride card art prompts (2 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.165Owner approval: barge ride card artblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 2 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-barge-ride-cards-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: both cards read as the same barge and river as the approved river concepts, leave a clear text-safe area, and contain no letters. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then both cards read as the same barge and river as the approved river concepts, leave a clear text-safe area, and contain no letters.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-barge-ride-cards-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.164 Generate barge ride card art via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3needs-human
  • mw-e37.166Integrate approved barge ride card artblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e25-barge-travel.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 2 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given Briar Glen Quay, when the player pays Mags and rides down and back up, then the matching final card shows with narration text in the safe area and no console errors.
    • AC-5 perf Given the ride cards, when e32-perf-budgets runs, then each card streams with the river package and resident texture memory stays ≤ 256 MB on Low.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e25.15 Ride Mags Oakum's barge between Briar Glen Quay and Wendmouth open
    • mw-e37.165 Owner approval: barge ride card art open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.167Write harbour and Saltmarch item icons prompts (22 assets)blockedP1M3task

    Description

    Why

    The harbour adds heist evidence, smuggler tools, Saltmarch weapons and exotic arrows; imports must read as foreign in the inventory grid (style bible §5.5).

    What

    Write one prompt file per asset in assets/prompts/icon-item/<asset-id>.md (category: icon-item) from template item-icon.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Heist and story items (Hornfolk name-stone, bay-nine manifest, Quell's honest manifest, foundry invoice, Mr. S—'s letter, customs-seal stamp, Lantern Court writ, dockhand disguise bundle, prize ribbon, barge fare token); Undertow tools (tide-silk rope, glue-soled boots, smoke pearl, skeleton-key ring); Saltmarch weapons (sabre, harpoon-spear, lacquered round shield); exotic arrows with distinct heads (whistling, netting, tar, glass-headed, grapple).

    Asset ids (22):

    • icon-item-name-stone-hornfolk-01
    • icon-item-manifest-bay-nine-01
    • icon-item-manifest-honest-01
    • icon-item-foundry-invoice-01
    • icon-item-mr-s-letter-01
    • icon-item-customs-seal-stamp-01
    • icon-item-writ-lantern-court-01
    • icon-item-dockhand-disguise-01
    • icon-item-prize-ribbon-01
    • icon-item-barge-fare-token-01
    • icon-item-tide-silk-rope-01
    • icon-item-glue-soled-boots-01
    • icon-item-smoke-pearl-01
    • icon-item-skeleton-key-ring-01
    • icon-item-saltmarch-sabre-01
    • icon-item-harpoon-spear-01
    • icon-item-lacquered-round-shield-01
    • icon-item-arrow-whistling-01
    • icon-item-arrow-netting-01
    • icon-item-arrow-tar-01
    • icon-item-arrow-glass-01
    • icon-item-arrow-grapple-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-icons-harbour-items-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Netting, tar and glass-headed arrows are added from style bible §5.5 (the needs list named only whistling and grapple). icon-item-sharkskin-brigandine-01 lives in e37-asset-icons-armour-equipment-* with the other armour. Foreign spellbook covers follow part A's book-cover pattern and are not in this set.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 22 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: every icon is identifiable at 64 px, Saltmarch items share a lacquer or sea-glass accent, the five exotic arrows differ by head shape not colour alone, and documents show seals and marks but no legible text.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.112 Owner approval: kit item icons open
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.168Generate harbour and Saltmarch item icons via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 22 prompt files of e37-asset-icons-harbour-items-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-icons-harbour-items-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 22 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.167 Write harbour and Saltmarch item icons prompts (22 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.169Owner approval: harbour and Saltmarch item iconsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 22 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-icons-harbour-items-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every icon is identifiable at 64 px, Saltmarch items share a lacquer or sea-glass accent, the five exotic arrows differ by head shape not colour alone, and documents show seals and marks but no legible text. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 22 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every icon is identifiable at 64 px, Saltmarch items share a lacquer or sea-glass accent, the five exotic arrows differ by head shape not colour alone, and documents show seals and marks but no legible text.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-icons-harbour-items-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.168 Generate harbour and Saltmarch item icons via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:iconepic:e37milestone:m3needs-human
  • mw-e37.170Integrate approved harbour and Saltmarch item iconsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e17-inventory-ui, e17-item-schema, e40-tidemarket, e40-undertow, e40-customs-house, e40-crate-heist, e25-barge-travel, e40-dockhand-disguises. Lower-priority consumers (e40-dockhand-disguises) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 22 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the inventory with every item in this set granted via the debug console, when opened, then all 22 icons render from the atlas with no placeholder flags.
    • AC-5 perf Given the rebuilt icon atlas, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e17.10 Build inventory screen with category tabs, inspect and actions done
    • mw-e17.2 Define item definition schema and content validator done
    • mw-e25.15 Ride Mags Oakum's barge between Briar Glen Quay and Wendmouth open
    • mw-e37.169 Owner approval: harbour and Saltmarch item icons open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e40.10 Author the Tidemarket: Tereza's arms stall and the foreign book cart open
    • mw-e40.12 Build the Undertow black market and its smugglers' tunnels open
    • mw-e40.20 Place The Crate for Mr. S— heist with all six solution routes open
    • mw-e40.3 Build the Customs House, its strongroom and Cray's book confiscation open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.171Write armour and equipment icons prompts (16 assets)blockedP1M3task

    Description

    Why

    The head, body, hands and feet slots had no icons in either earlier pass; players compare armour by weight and noise, so the icons must show the material class at a glance.

    What

    Write one prompt file per asset in assets/prompts/icon-item/<asset-id>.md (category: icon-item) from template item-icon.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Local barony and valley kit (squared, iron-and-oak, leather, plain): iron helm, leather cap, cloth hood; plate cuirass, chain hauberk, leather jerkin, cloth robe; plate gauntlets, leather gloves; plate sabatons, leather boots, soft-soled boots. Saltmarch imports (crescents, lacquer, sharkskin, knotted cord): crescent-crest lacquered helm, sharkskin brigandine, sharkskin gloves, cord-wrapped sea boots.

    Asset ids (16):

    • icon-item-helm-iron-01
    • icon-item-cap-leather-01
    • icon-item-hood-cloth-01
    • icon-item-cuirass-plate-01
    • icon-item-hauberk-chain-01
    • icon-item-jerkin-leather-01
    • icon-item-robe-cloth-01
    • icon-item-gauntlets-plate-01
    • icon-item-gloves-leather-01
    • icon-item-sabatons-plate-01
    • icon-item-boots-leather-01
    • icon-item-boots-soft-01
    • icon-item-helm-saltmarch-lacquer-01
    • icon-item-sharkskin-brigandine-01
    • icon-item-gloves-sharkskin-01
    • icon-item-boots-saltmarch-cord-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-icons-armour-equipment-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Gap noted by the part B pass: part A covered weapons, arrows and tools but no armour. Materials mirror the audio armour layers (plate, chain, leather, cloth) so icon, stats and sound agree. Worn armour appearance on the player models is out of scope (class models ship with their outfit).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 16 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each icon is identifiable at 64 px, plate/chain/leather/cloth read apart by shape and surface (knight plate reads heaviest), and Saltmarch pieces read foreign at a glance (curves, lacquer, sharkskin) against the squared local kit.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.112 Owner approval: kit item icons open
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.172Generate armour and equipment icons via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 16 prompt files of e37-asset-icons-armour-equipment-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-icons-armour-equipment-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 16 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.171 Write armour and equipment icons prompts (16 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.173Owner approval: armour and equipment iconsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 16 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-icons-armour-equipment-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each icon is identifiable at 64 px, plate/chain/leather/cloth read apart by shape and surface (knight plate reads heaviest), and Saltmarch pieces read foreign at a glance (curves, lacquer, sharkskin) against the squared local kit. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 16 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each icon is identifiable at 64 px, plate/chain/leather/cloth read apart by shape and surface (knight plate reads heaviest), and Saltmarch pieces read foreign at a glance (curves, lacquer, sharkskin) against the squared local kit.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-icons-armour-equipment-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.172 Generate armour and equipment icons via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:iconepic:e37milestone:m3needs-human
  • mw-e37.174Integrate approved armour and equipment iconsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e17-equipment-ui, e17-inventory-ui, e17-equipment-slots, e04-armor-weight, e40-tidemarket.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 16 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the equipment paper-doll with every armour piece granted via the debug console, when each slot is filled, then the final icon shows in the slot and in the Tidemarket stock list with no placeholder flags.
    • AC-5 perf Given the rebuilt icon atlas, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e04.16 Armor weight sets roll class, stamina regen, poise and noise done
    • mw-e17.10 Build inventory screen with category tabs, inspect and actions done
    • mw-e17.11 Add equipment paper-doll view with verb and stealth comparison open
    • mw-e17.4 Add equipment slots with class proficiencies and equip events done
    • mw-e37.173 Owner approval: armour and equipment icons open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e40.10 Author the Tidemarket: Tereza's arms stall and the foreign book cart open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.175Write Patient Ann barge models concept prompts (1 images)blockedP1M3task

    Description

    Why

    Mags Oakum's *Patient Ann* is seen at the quay, on the ride cards and (as a winched twin) in the Weeping Adit; she is the river's signature object.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Flat-bottomed, low, tarred stone barge with dressed glenstone blocks lashed on timber cradles, stern tiller, small cabin, tow-rope point and ochre hull stripe (no painted name) (style bible §5.6); plus the winched Adit stone barge variant (empty cradles, rusted, chain-hauled, half-flooded).

    Concept image ids (1):

    • prop-barge-patient-ann-01

    Target model ids (2):

    • model-barge-patient-ann-01
    • model-barge-stone-adit-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-barge-patient-ann-3d-generate)

    Notes

    Budget: hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 1 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: *Patient Ann* is identifiable by her ochre stripe and silhouette from the quay steps, the Adit barge reads as the same class of boat abandoned, and no ship name is painted.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.145 Owner approval: River Wend environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.176Generate Patient Ann barge models concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 1 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-barge-patient-ann-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 1 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.175 Write Patient Ann barge models concept prompts (1 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.177Owner approval: Patient Ann barge models flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 1 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-barge-patient-ann-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: *Patient Ann* is identifiable by her ochre stripe and silhouette from the quay steps, the Adit barge reads as the same class of boat abandoned, and no ship name is painted. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 1 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then *Patient Ann* is identifiable by her ochre stripe and silhouette from the quay steps, the Adit barge reads as the same class of boat abandoned, and no ship name is painted.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-barge-patient-ann-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.176 Generate Patient Ann barge models concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.178Generate Patient Ann barge models 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 2 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-barge-patient-ann-turntable-approve)

    Notes

    Budget: hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 2 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.177 Owner approval: Patient Ann barge models flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.179Owner approval: Patient Ann barge models turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 2 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-barge-patient-ann-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: *Patient Ann* is identifiable by her ochre stripe and silhouette from the quay steps, the Adit barge reads as the same class of boat abandoned, and no ship name is painted. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then *Patient Ann* is identifiable by her ochre stripe and silhouette from the quay steps, the Adit barge reads as the same class of boat abandoned, and no ship name is painted.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-barge-patient-ann-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.178 Generate Patient Ann barge models 3D models via image-to-3D API open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.180Integrate approved Patient Ann barge modelsblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e25-barge-travel, e25-weeping-adit, e25-quay-stone-stair.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 2 models are under public/assets/model/ within hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the quay and the Weeping Adit, when Playwright captures both barges, then the final models load with the correct colliders (standable deck, winch attach point) and no console errors.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e25.11 Build Briar Glen Quay and the Stone Stair slipway down from the mine open
    • mw-e25.13 Build the Weeping Adit: the flooded sixth way into the lower Deepworks open
    • mw-e25.15 Ride Mags Oakum's barge between Briar Glen Quay and Wendmouth open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.179 Owner approval: Patient Ann barge models turntables open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.181Write Gilded Tern ship models concept prompts (2 images)blockedP1M3task

    Description

    Why

    The Gilded Tern is a climbable, boardable heist location and leaves in Act III; it is the largest hero model in the game.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Three-masted merchantman built from modular pieces: exterior hull, masts and climbable rigging (ratlines and shrouds per style bible §5.4) with sails furled and set states; interior hold, captain's cabin and locked passenger berth sections; gilded tern figurehead.

    Concept image ids (2):

    • prop-ship-gilded-tern-01
    • prop-ship-gilded-tern-interior-01

    Target model ids (4):

    • model-ship-gilded-tern-hull-01
    • model-ship-gilded-tern-rigging-01
    • model-ship-gilded-tern-interior-01
    • model-prop-tern-figurehead-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-ship-gilded-tern-3d-generate)

    Notes

    The "sailed" absence in Act III is a world-variant state of the pool (e27-world-variants via e40-gilded-tern), not a model; sails furled/set are material/mesh states of the rigging module.

    Budget: hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 2 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: the ship reads as a proud merchantman from the wharf, rigging handholds show the climbable cue, the berth door reads locked, and interior sections match the exterior scale.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.149 Owner approval: Wendmouth environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.182Generate Gilded Tern ship models concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 2 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-ship-gilded-tern-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 2 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.181 Write Gilded Tern ship models concept prompts (2 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.183Owner approval: Gilded Tern ship models flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 2 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ship-gilded-tern-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the ship reads as a proud merchantman from the wharf, rigging handholds show the climbable cue, the berth door reads locked, and interior sections match the exterior scale. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the ship reads as a proud merchantman from the wharf, rigging handholds show the climbable cue, the berth door reads locked, and interior sections match the exterior scale.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ship-gilded-tern-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.182 Generate Gilded Tern ship models concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.184Generate Gilded Tern ship models 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 4 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-ship-gilded-tern-turntable-approve)

    Notes

    Budget: hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 4 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.183 Owner approval: Gilded Tern ship models flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.185Owner approval: Gilded Tern ship models turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 4 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ship-gilded-tern-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the ship reads as a proud merchantman from the wharf, rigging handholds show the climbable cue, the berth door reads locked, and interior sections match the exterior scale. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the ship reads as a proud merchantman from the wharf, rigging handholds show the climbable cue, the berth door reads locked, and interior sections match the exterior scale.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ship-gilded-tern-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.184 Generate Gilded Tern ship models 3D models via image-to-3D API open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.186Integrate approved Gilded Tern ship modelsblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e40-gilded-tern.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 4 models are under public/assets/model/ within hero props 2–5 k tris each (modular ship pieces ≤ 5 k per module, LOD1 50 %), T2 1024² atlas, ≤ 1 material per model (style bible §13.2, §5.6) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the harbour pool, when the player climbs the rigging, enters the hold, cabin and berth, and the Act III fact is set, then the final modules load and the ship is absent after sailing, with no console errors.
    • AC-4 perf Given the Wendmouth waterfront with the Tern in view, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.185 Owner approval: Gilded Tern ship models turntables open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.14 Build the Gilded Tern: rigging, hold, cabin, locked berth, departure open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.187Write Saltmarch weapon and arrow concept prompts (2 images)blockedP1M3task

    Description

    Why

    Tidemarket gear is plainly better and foreign; bought weapons and arrows must appear in hand and in flight, not just as icons.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Curved Saltmarch sabre ("curved like a gull's wing"), harpoon-spear, lacquered round shield; exotic arrow heads/projectiles: whistling (pierced bone), netting (weighted pod), tar (black-dipped), glass-headed (sea-glass), grapple (hooked iron).

    Concept image ids (2):

    • prop-weapon-saltmarch-set-01
    • prop-weapon-arrow-exotic-set-01

    Target model ids (8):

    • model-prop-saltmarch-sabre-01
    • model-prop-harpoon-spear-01
    • model-prop-lacquered-round-shield-01
    • model-prop-arrow-whistling-01
    • model-prop-arrow-netting-01
    • model-prop-arrow-tar-01
    • model-prop-arrow-glass-01
    • model-prop-arrow-grapple-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-saltmarch-weapons-3d-generate)

    Notes

    Complements part A e37-asset-weapons-* (local kit). Tereza wields the sabre model in her duel (e40-tereza-duel, P2).

    Budget: held weapon 300–1.5 k tris, arrows ≤ 300, character or prop atlas, shared material (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 2 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (held weapon 300–1.5 k tris, arrows ≤ 300, character or prop atlas, shared material (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: Saltmarch weapons read foreign against part A's local weapons (curves, lacquer red #8E2B2B, sharkskin grips), and each arrow is distinguishable in flight by head shape.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.149 Owner approval: Wendmouth environment concepts open
    • mw-e37.38 Owner approval: player weapons flat concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.188Generate Saltmarch weapon and arrow concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 2 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-saltmarch-weapons-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 2 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.187 Write Saltmarch weapon and arrow concept prompts (2 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.189Owner approval: Saltmarch weapon and arrow flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 2 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-saltmarch-weapons-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Saltmarch weapons read foreign against part A's local weapons (curves, lacquer red #8E2B2B, sharkskin grips), and each arrow is distinguishable in flight by head shape. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Saltmarch weapons read foreign against part A's local weapons (curves, lacquer red #8E2B2B, sharkskin grips), and each arrow is distinguishable in flight by head shape.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-saltmarch-weapons-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.188 Generate Saltmarch weapon and arrow concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.190Generate Saltmarch weapon and arrow 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 8 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-saltmarch-weapons-turntable-approve)

    Notes

    Budget: held weapon 300–1.5 k tris, arrows ≤ 300, character or prop atlas, shared material (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 8 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets held weapon 300–1.5 k tris, arrows ≤ 300, character or prop atlas, shared material (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.189 Owner approval: Saltmarch weapon and arrow flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.191Owner approval: Saltmarch weapon and arrow turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 8 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-saltmarch-weapons-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Saltmarch weapons read foreign against part A's local weapons (curves, lacquer red #8E2B2B, sharkskin grips), and each arrow is distinguishable in flight by head shape. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Saltmarch weapons read foreign against part A's local weapons (curves, lacquer red #8E2B2B, sharkskin grips), and each arrow is distinguishable in flight by head shape.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-saltmarch-weapons-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.190 Generate Saltmarch weapon and arrow 3D models via image-to-3D API open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.192Integrate approved Saltmarch weapon and arrowblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e40-tidemarket, e05-arrow-schema, e17-equipment-slots, e40-tereza-duel. Lower-priority consumers (e40-tereza-duel) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 8 models are under public/assets/model/ within held weapon 300–1.5 k tris, arrows ≤ 300, character or prop atlas, shared material (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the Tidemarket, when each weapon is bought and equipped and each arrow fired via the debug console, then final models attach to the correct sockets and fly with their trails, with no console errors.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e05.1 Data schema for arrow types and property-based payloads done
    • mw-e17.4 Add equipment slots with class proficiencies and equip events done
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.191 Owner approval: Saltmarch weapon and arrow turntables open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.10 Author the Tidemarket: Tereza's arms stall and the foreign book cart open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.193Select CC0 kit pieces for river quay, weir and lock props (14 models)blockedP1M3task

    Description

    Why

    The quay, weir, lock and adit are mechanism-heavy spaces; kit pieces keep them consistent and cheap while the puzzles read through legibility cues.

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Bollards, dressed-block stacks on timber cradles, quay crane, toll shed, Stone Stair slipway segments; weir sluice gates, lock gates, paddles and windlass, beam walk, toll board (no legible text), lock cottage interior; adit drainage timbering, adit winch, air-pocket rock shelves.

    Kit brief ids (3):

    • prop-river-quay-set-01
    • prop-river-weir-lock-set-01
    • prop-adit-set-01

    Target model ids (14):

    • model-prop-bollard-01
    • model-prop-stone-block-stack-01
    • model-prop-quay-crane-01
    • model-prop-toll-shed-01
    • model-prop-stone-stair-slipway-01
    • model-prop-weir-sluice-gate-01
    • model-prop-lock-gate-01
    • model-prop-lock-windlass-01
    • model-prop-lock-beam-walk-01
    • model-prop-toll-board-01
    • model-prop-lock-cottage-set-01
    • model-prop-adit-timbering-01
    • model-prop-adit-winch-01
    • model-prop-adit-rock-shelf-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-river-kit-kit-recolour)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 3 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 14 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.145 Owner approval: River Wend environment concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.194Recolour river quay, weir and lock props from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-river-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 14 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.193 Select CC0 kit pieces for river quay, weir and lock props (14 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.195Owner approval: river quay, weir and lock props kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 14 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-river-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: windlasses, paddles and gates read as operable mechanisms, the chute reads climbable/slideable, and the set matches the approved river concepts. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 14 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then windlasses, paddles and gates read as operable mechanisms, the chute reads climbable/slideable, and the set matches the approved river concepts.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-river-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.194 Recolour river quay, weir and lock props from CC0 kits open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.196Integrate approved river quay, weir and lock propsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e25-quay-stone-stair, e25-millweir-sluice-walk, e25-towpath-kestrel-lock, e25-weeping-adit. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e25-river-art-audio.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 14 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given the quay, weir, lock and adit, when the lock is cycled and the sluice opened via the debug console, then the final mechanism models animate on their pivots and no console errors occur.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e25.11 Build Briar Glen Quay and the Stone Stair slipway down from the mine open
    • mw-e25.12 Build the Millweir and its sluice walk to the Briarwood far bank open
    • mw-e25.13 Build the Weeping Adit: the flooded sixth way into the lower Deepworks open
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.195 Owner approval: river quay, weir and lock props kit turntables open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.197Select CC0 kit pieces for waterfront and Tidefair props (16 models)blockedP1M3task

    Description

    Why

    The wharf, rooftops, Undertow and Tidefair are the systemic harbour: cranes swing, nets are cut, lofts are climbed, booms are shot.

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Treadwheel wharf cranes on stone piers (jib + winch), cargo nets (cuttable load line with the red-white band), crate stacks, block-yard stacks of dressed glenstone, Tidefair markers, Lantern Court notice; net lofts, plank bridges, drying nets (loose), gull hoard nests; smuggler crates, lantern hooks, fence counter; Tidefair swinging boom with wooden gulls, prize ribbons, bunting, rowing boats/lighters with pennants.

    Kit brief ids (4):

    • prop-harbour-wharf-set-01
    • prop-harbour-rooftop-set-01
    • prop-harbour-undertow-set-01
    • prop-tidefair-set-01

    Target model ids (16):

    • model-prop-wharf-crane-01
    • model-prop-cargo-net-01
    • model-prop-crate-stack-01
    • model-prop-tidefair-marker-01
    • model-prop-notice-lantern-court-01
    • model-prop-net-loft-01
    • model-prop-plank-bridge-01
    • model-prop-drying-net-01
    • model-prop-gull-hoard-nest-01
    • model-prop-smuggler-crate-01
    • model-prop-lantern-hook-01
    • model-prop-fence-counter-01
    • model-prop-tidefair-boom-01
    • model-prop-wooden-gull-target-01
    • model-prop-bunting-01
    • model-prop-rowing-boat-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-harbour-waterfront-kit-kit-recolour)

    Notes

    Block-yard stacks reuse model-prop-stone-block-stack-01 from e37-asset-props-river-kit-*. Rowing boats double as harbour lighters and as regatta boats (e40-tidefair-regatta, P2).

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 4 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 16 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.149 Owner approval: Wendmouth environment concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.198Recolour waterfront and Tidefair props from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-harbour-waterfront-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 16 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.197 Select CC0 kit pieces for waterfront and Tidefair props (16 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.199Owner approval: waterfront and Tidefair props kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 16 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-harbour-waterfront-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: cuttable cargo lines carry the mechanism-for-arrows band, taut climbable nets read distinct from loose drying nets, the Tidefair boom reads as a target, and colours follow the Wendmouth palette. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 16 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then cuttable cargo lines carry the mechanism-for-arrows band, taut climbable nets read distinct from loose drying nets, the Tidefair boom reads as a target, and colours follow the Wendmouth palette.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-harbour-waterfront-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.198 Recolour waterfront and Tidefair props from CC0 kits open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.200Integrate approved waterfront and Tidefair propsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e40-stone-wharf, e40-rooftops-net-lofts, e40-undertow, e40-tidefair-shoot-pockets, e40-tidefair-strength, e40-tidefair-regatta, e40-harbor-ambient-life. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e40-harbor-art-dress. Lower-priority consumers (e40-tidefair-regatta, e40-harbor-ambient-life) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 16 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given the Stone Wharf, when a crane is swung, a cargo net cut by an arrow and the Gull Shoot boom hit, then the final models respond and no console errors occur.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.199 Owner approval: waterfront and Tidefair props kit turntables open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.12 Build the Undertow black market and its smugglers' tunnels open
    • mw-e40.13 Build a continuous rooftop and net-loft route across the waterfront open
    • mw-e40.2 Build the Stone Wharf with working cranes, cargo nets, crates and block yards open
    • mw-e40.7 Stage the Tidefair arm-wrestling bout and the Gull brawl open
    • mw-e40.8 Stage the Tidefair Gull Shoot and the Pocket Race open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.201Select CC0 kit pieces for harbour interior props (14 models)blockedP1M3task

    Description

    Why

    The Customs House, Bonded Warehouse, Drowned Gull and Tidemarket are four busy interiors that need consistent furniture without bespoke modelling.

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Customs desks and strongroom shelves; warehouse hoist beams and manifest desk, Quell's office furniture; the Gull's arm-wrestling table, dice table, tankards and trapdoor; Tidemarket stalls, spice sacks, silk bolts, foreign book cart and weapon racks. Story pieces (bay-door customs seal, relic crate, cargo scale, strongroom door, Cray's shelf, sea-door) come from e37-asset-props-harbour-story-*.

    Kit brief ids (4):

    • prop-harbour-customs-set-01
    • prop-harbour-warehouse-set-01
    • prop-harbour-tavern-set-01
    • prop-harbour-market-set-01

    Target model ids (14):

    • model-prop-customs-desk-01
    • model-prop-strongroom-shelf-01
    • model-prop-hoist-beam-01
    • model-prop-manifest-desk-01
    • model-prop-office-quell-set-01
    • model-prop-arm-wrestle-table-01
    • model-prop-dice-table-01
    • model-prop-tankard-01
    • model-prop-trapdoor-gull-01
    • model-prop-market-stall-harbour-01
    • model-prop-spice-sacks-01
    • model-prop-silk-bolts-01
    • model-prop-book-cart-foreign-01
    • model-prop-weapon-rack-saltmarch-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-harbour-interiors-kit-kit-recolour)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 4 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 14 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.149 Owner approval: Wendmouth environment concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.202Recolour harbour interior props from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-harbour-interiors-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 14 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.201 Select CC0 kit pieces for harbour interior props (14 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.203Owner approval: harbour interior props kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 14 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-harbour-interiors-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each interior reads as its owner (Cray's order, Quell's nerves, Nell's rowdy tavern, Tereza's elegant stall), the trapdoor reads as a hidden exit only on inspection, and Saltmarch goods read foreign. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 14 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each interior reads as its owner (Cray's order, Quell's nerves, Nell's rowdy tavern, Tereza's elegant stall), the trapdoor reads as a hidden exit only on inspection, and Saltmarch goods read foreign.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-harbour-interiors-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.202 Recolour harbour interior props from CC0 kits open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.204Integrate approved harbour interior propsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e40-customs-house, e40-bonded-warehouse, e40-drowned-gull, e40-tidemarket. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e40-harbor-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 14 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given each harbour interior, when Playwright loads it, then final props render with no placeholder models, the Gull trapdoor opens, and no console errors occur.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.203 Owner approval: harbour interior props kit turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.10 Author the Tidemarket: Tereza's arms stall and the foreign book cart open
    • mw-e40.3 Build the Customs House, its strongroom and Cray's book confiscation open
    • mw-e40.4 Build the Bonded Warehouse: bay nine, skylights, hoists and manifests open
    • mw-e40.6 Build the Drowned Gull: arm-wrestling, dice, drinking and the trapdoor open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.205Write harbour heist and story props concept prompts (2 images)blockedP1M3task

    Description

    Why

    The Crate for Mr. S— heist turns on a few specific objects — bay nine's customs seal, the relic crate, the strongroom, the sea-door — and the sea-serpent rumour on the sunken figurehead.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Heist sheet: bay door with the customs-seal entity in intact/broken/re-sealed states, the relic crate and its ballast twin, cargo scale, strongroom door (black-steel lock), Cray's well-read romance shelf, the barnacled iron-bound sea-door; figurehead sheet: the sunken serpent-headed figurehead with two glass "lantern eyes".

    Concept image ids (2):

    • prop-harbour-story-set-01
    • prop-breakwater-figurehead-01

    Target model ids (8):

    • model-prop-bay-door-seal-01
    • model-prop-relic-crate-01
    • model-prop-ballast-crate-01
    • model-prop-cargo-scale-01
    • model-prop-strongroom-door-01
    • model-prop-shelf-cray-01
    • model-prop-sea-door-01
    • model-prop-figurehead-serpent-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-props-harbour-story-3d-generate)

    Notes

    prop-harbour-story-set-01 is a new concept id grouping heist pieces from the warehouse, customs and undertow sets of the needs list.

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 2 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: the three seal states read apart at 3 m, the relic crate and its ballast twin are identical outside but distinguishable when opened, the strongroom lock reads hard, and the figurehead reads as a monster from above water and a carving up close.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.149 Owner approval: Wendmouth environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.206Generate harbour heist and story props concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 2 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-props-harbour-story-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 2 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.205 Write harbour heist and story props concept prompts (2 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.207Owner approval: harbour heist and story props flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 2 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-harbour-story-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the three seal states read apart at 3 m, the relic crate and its ballast twin are identical outside but distinguishable when opened, the strongroom lock reads hard, and the figurehead reads as a monster from above water and a carving up close. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the three seal states read apart at 3 m, the relic crate and its ballast twin are identical outside but distinguishable when opened, the strongroom lock reads hard, and the figurehead reads as a monster from above water and a carving up close.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-harbour-story-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.206 Generate harbour heist and story props concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.208Generate harbour heist and story props 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 8 target models: first try a CC0 kit match recoloured to the palette atlas; otherwise call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-props-harbour-story-turntable-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 8 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.207 Owner approval: harbour heist and story props flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.209Owner approval: harbour heist and story props turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 8 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-harbour-story-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the three seal states read apart at 3 m, the relic crate and its ballast twin are identical outside but distinguishable when opened, the strongroom lock reads hard, and the figurehead reads as a monster from above water and a carving up close. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the three seal states read apart at 3 m, the relic crate and its ballast twin are identical outside but distinguishable when opened, the strongroom lock reads hard, and the figurehead reads as a monster from above water and a carving up close.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-harbour-story-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.208 Generate harbour heist and story props 3D models via image-to-3D API open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.210Integrate approved harbour heist and story propsblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e40-bonded-warehouse, e40-crate-heist, e40-customs-house, e40-breakwater-sea-door. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e40-harbor-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 8 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the Bonded Warehouse and the breakwater, when a seal is broken and re-stamped, the crate swapped for ballast and the sea-door opened at low tide, then the final models swap states and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.209 Owner approval: harbour heist and story props turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.15 Build the breakwater, sunken figurehead, sea-door and harbour tides open
    • mw-e40.20 Place The Crate for Mr. S— heist with all six solution routes open
    • mw-e40.3 Build the Customs House, its strongroom and Cray's book confiscation open
    • mw-e40.4 Build the Bonded Warehouse: bay nine, skylights, hoists and manifests open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.211Write named harbour NPC characters concept prompts (8 images)blockedP1M3task

    Description

    Why

    The harbour cast are bargained with, arm-wrestled, dueled and robbed; they must match their portraits and silhouette hooks in the world.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: character) from character-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Turnaround sheets matching the approved portraits for Mags Oakum, Nell Gannet, Inspector Cray, Tereza Maelo (with sabre socket), Jasper Quell, Big Oona, Old Reed and Captain Hesketh. The veiled agent is never seen in the MVP.

    Concept image ids (8):

    • char-npc-mags-01
    • char-npc-nell-01
    • char-npc-cray-01
    • char-npc-tereza-01
    • char-npc-jasper-01
    • char-npc-oona-01
    • char-npc-reed-01
    • char-npc-hesketh-01

    Target model ids (8):

    • model-npc-mags-01
    • model-npc-nell-01
    • model-npc-cray-01
    • model-npc-tereza-01
    • model-npc-jasper-01
    • model-npc-oona-01
    • model-npc-reed-01
    • model-npc-hesketh-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-npcs-harbour-named-3d-generate)

    Notes

    Needs-list ids char-npc-oona-01, char-npc-reed-01, char-npc-hesketh-01 are added so every modelled NPC has an approved flat concept (image-to-3D input).

    Budget: key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 8 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: each NPC is recognisable against their portrait at 10 m and follows the style bible §5.4 silhouette hooks (Mags's pipe, Nell's size, Cray's starch, Tereza's Saltmarch cut, Quell's stoop).
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.161 Owner approval: harbour cast portraits open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.212Generate named harbour NPC characters concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 8 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-npcs-harbour-named-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 8 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.211 Write named harbour NPC characters concept prompts (8 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.213Owner approval: named harbour NPC characters flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 8 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-npcs-harbour-named-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each NPC is recognisable against their portrait at 10 m and follows the style bible §5.4 silhouette hooks (Mags's pipe, Nell's size, Cray's starch, Tereza's Saltmarch cut, Quell's stoop). Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each NPC is recognisable against their portrait at 10 m and follows the style bible §5.4 silhouette hooks (Mags's pipe, Nell's size, Cray's starch, Tereza's Saltmarch cut, Quell's stoop).
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-npcs-harbour-named-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.212 Generate named harbour NPC characters concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.214Generate named harbour NPC characters 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 8 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig on the canonical humanoid skeleton via e37-animation-pipeline so shared clips retarget, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-npcs-harbour-named-turntable-approve)

    Notes

    Budget: key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 8 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.213 Owner approval: named harbour NPC characters flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.215Owner approval: named harbour NPC characters turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 8 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-npcs-harbour-named-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each NPC is recognisable against their portrait at 10 m and follows the style bible §5.4 silhouette hooks (Mags's pipe, Nell's size, Cray's starch, Tereza's Saltmarch cut, Quell's stoop). Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each NPC is recognisable against their portrait at 10 m and follows the style bible §5.4 silhouette hooks (Mags's pipe, Nell's size, Cray's starch, Tereza's Saltmarch cut, Quell's stoop).
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-npcs-harbour-named-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.214 Generate named harbour NPC characters 3D models via image-to-3D API open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.216Integrate approved named harbour NPC charactersblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e25-barge-travel, e25-towpath-kestrel-lock, e40-drowned-gull, e40-customs-house, e40-tidemarket, e40-bonded-warehouse, e40-tidefair-strength, e40-gilded-tern.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 8 models are under public/assets/model/ within key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given Wendmouth and the river, when each named NPC is spawned via the debug console, then the final model plays idle and talk clips with no console errors.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e25.15 Ride Mags Oakum's barge between Briar Glen Quay and Wendmouth open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.215 Owner approval: named harbour NPC characters turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.10 Author the Tidemarket: Tereza's arms stall and the foreign book cart open
    • mw-e40.14 Build the Gilded Tern: rigging, hold, cabin, locked berth, departure open
    • mw-e40.3 Build the Customs House, its strongroom and Cray's book confiscation open
    • mw-e40.4 Build the Bonded Warehouse: bay nine, skylights, hoists and manifests open
    • mw-e40.6 Build the Drowned Gull: arm-wrestling, dice, drinking and the trapdoor open
    • mw-e40.7 Stage the Tidefair arm-wrestling bout and the Gull brawl open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.217Select CC0 kit pieces for harbour crowd and faction models (5 models)blockedP1M3task

    Description

    Why

    Dense crowds give the thief cover and pockets, and the three opposition groups must read apart at 30 m by hat and coat shape (style bible §5.4 disguise table).

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/character/<brief-id>.md from character-reference-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Harbour crowd (10–14 variants: dockhands, fishwives, sailors, merchants; pickpocketable ones show a purse on a cord), harbour watch (long coat, round brimmed hat, lantern-pole or cudgel, navy), Low Tide Company smugglers (mixed dockside clothes, sea-green neckerchief tell), Gilded Tern crew (short jacket, tarred pigtail, bare feet), and the dockhand disguise outfit the player can wear.

    Kit brief ids (1):

    • char-npc-harbour-crowd-set-01

    Target model ids (5):

    • model-npc-harbour-crowd-set-01
    • model-npc-harbour-watch-set-01
    • model-npc-low-tide-smuggler-set-01
    • model-npc-tern-crew-set-01
    • model-char-disguise-dockhand-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-npc-harbour-crowd-kit-kit-recolour)

    Notes

    Built on the same CC0 modular character kit as e37-asset-npc-crowd-kit-*. The disguise outfit is used by e40-dockhand-disguises (P2); it is cheap to include here because it is a dockhand variant.

    Budget: background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 1 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 5 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.161 Owner approval: harbour cast portraits open
    • mw-e37.361 Owner approval: crowd NPC models kit turntables open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.218Recolour harbour crowd and faction models from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-npc-harbour-crowd-kit-kit-approve)

    Notes

    Budget: background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 5 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.217 Select CC0 kit pieces for harbour crowd and faction models (5 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.219Owner approval: harbour crowd and faction models kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 5 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-npc-harbour-crowd-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the four groups read apart by silhouette at 30 m (colour second), pickpocketable crowd members show the purse cue and filler does not, and the disguise keeps one small class tell. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 5 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the four groups read apart by silhouette at 30 m (colour second), pickpocketable crowd members show the purse cue and filler does not, and the disguise keeps one small class tell.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-npc-harbour-crowd-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.218 Recolour harbour crowd and faction models from CC0 kits open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.220Integrate approved harbour crowd and faction modelsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e40-harbor-crowds, e40-harbor-opposition, e40-dockhand-disguises. Lower-priority consumers (e40-dockhand-disguises) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 5 models are under public/assets/model/ within background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given the Stone Wharf on market day, when Playwright captures the crowd and a watch patrol, then final crowd and faction models render with purse cues where pickpocketable and no console errors.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.219 Owner approval: harbour crowd and faction models kit turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.16 Fill the harbour with pickpocketable crowds that give stealth cover open
    • mw-e40.18 Add the harbour watch, Low Tide Company and Tern crew as humans open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.227Write harbour NPC and contest animations motion briefs (14 clips)blockedP1M3task

    Description

    Why

    Arm-wrestling, brawls and working dockhands are how Wendmouth reads as loud, cheerful and physical.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Arm-wrestle loop, win and lose (paired), brawl punches and a knockout, rowing, crane operating, net hauling, drinking, dice throw, deck swabbing, rigging-climb idle, barge poling (Mags).

    Clip ids (14):

    • anim-humanoid-arm-wrestle-loop-01
    • anim-humanoid-arm-wrestle-win-01
    • anim-humanoid-arm-wrestle-lose-01
    • anim-humanoid-brawl-punch-01
    • anim-humanoid-brawl-punch-02
    • anim-humanoid-brawl-knockout-01
    • anim-humanoid-rowing-01
    • anim-humanoid-crane-operate-01
    • anim-humanoid-net-haul-01
    • anim-humanoid-drink-01
    • anim-humanoid-dice-throw-01
    • anim-humanoid-deck-swab-01
    • anim-humanoid-rigging-climb-idle-01
    • anim-humanoid-barge-pole-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    Player-side climbing on rigging uses part A's anim-humanoid-climb-01; the rigging idle here is for Tern crew.

    Rig: canonical humanoid skeleton (harbour NPCs and crowd kit share it); paired clips (arm-wrestle, brawl) share a sync marker. Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 14 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.228Source and retarget harbour NPC and contest animationsblockedP1M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-harbour-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 14 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.215 Owner approval: named harbour NPC characters turntables open
    • mw-e37.219 Owner approval: harbour crowd and faction models kit turntables open
    • mw-e37.227 Write harbour NPC and contest animations motion briefs (14 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.229Owner approval: harbour NPC and contest animationsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 14 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-harbour-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: paired arm-wrestle clips stay in contact without interpenetration, brawl knockouts read comic and non-lethal, and work idles read as their trade at 15 m. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 14 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then paired arm-wrestle clips stay in contact without interpenetration, brawl knockouts read comic and non-lethal, and work idles read as their trade at 15 m.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-harbour-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.228 Source and retarget harbour NPC and contest animations open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.230Integrate approved harbour NPC and contest animationsblockedP1M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e40-drowned-gull, e40-tidefair-strength, e40-harbor-crowds, e40-stone-wharf, e25-barge-travel, e40-tidefair-regatta. Lower-priority consumers (e40-tidefair-regatta) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 14 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given the Drowned Gull and the Stone Wharf, when an arm-wrestling bout, a brawl and dock work run via the debug console, then final clips play in sync with correct markers and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e25.15 Ride Mags Oakum's barge between Briar Glen Quay and Wendmouth open
    • mw-e37.216 Integrate approved named harbour NPC characters open
    • mw-e37.220 Integrate approved harbour crowd and faction models open
    • mw-e37.229 Owner approval: harbour NPC and contest animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.16 Fill the harbour with pickpocketable crowds that give stealth cover open
    • mw-e40.2 Build the Stone Wharf with working cranes, cargo nets, crates and block yards open
    • mw-e40.6 Build the Drowned Gull: arm-wrestling, dice, drinking and the trapdoor open
    • mw-e40.7 Stage the Tidefair arm-wrestling bout and the Gull brawl open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.239Write river and harbour VFX prompts (6 assets)blockedP1M3task

    Description

    Why

    Big splashes, the Adit current, the lock churn, the lighthouse sweep and a frozen harbour pool sell water that is standing water in the sim.

    What

    Write one prompt file per asset in assets/prompts/vfx/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Large water splash (net drop, thrown off the pier), Adit current foam, lock fill churn, lighthouse sweep beam, regatta sail gust, harbour-pool freeze sheet.

    Asset ids (6):

    • vfx-water-splash-large-01
    • vfx-adit-current-foam-01
    • vfx-lock-fill-churn-01
    • vfx-lighthouse-sweep-01
    • vfx-regatta-sail-gust-01
    • vfx-harbour-pool-freeze-sheet-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-river-harbour-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    The lighthouse sweep is consumed by e40-harbor-lighting-audio (edge).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 6 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (512² or 1024² flipbook sheets (4×4 or 8×8), alpha or additive on black, loopable where marked) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: water effects read in the river/harbour palettes, the freeze sheet matches part A's frost language, and the lighthouse sweep never strobes faster than 3 Hz.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.240Generate river and harbour VFX via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 6 prompt files of e37-asset-vfx-river-harbour-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-river-harbour-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 512² or 1024² flipbook sheets (4×4 or 8×8), alpha or additive on black, loopable where marked. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 6 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (512² or 1024² flipbook sheets (4×4 or 8×8), alpha or additive on black, loopable where marked), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.239 Write river and harbour VFX prompts (6 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.241Owner approval: river and harbour VFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 6 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-river-harbour-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: water effects read in the river/harbour palettes, the freeze sheet matches part A's frost language, and the lighthouse sweep never strobes faster than 3 Hz. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 6 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then water effects read in the river/harbour palettes, the freeze sheet matches part A's frost language, and the lighthouse sweep never strobes faster than 3 Hz.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-river-harbour-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.240 Generate river and harbour VFX via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:vfxepic:e37milestone:m3needs-human
  • mw-e37.242Integrate approved river and harbour VFXblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e29-vfx-framework, e40-stone-wharf, e25-weeping-adit, e25-towpath-kestrel-lock, e40-gilded-tern, e40-tidefair-regatta. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e40-harbor-lighting-audio. Lower-priority consumers (e40-tidefair-regatta) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 6 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the wharf, lock, Adit and harbour pool, when each effect is triggered via the debug console, then final textures render and VFX GPU time stays within its 2 ms share.
    • AC-5 perf Given the harbour at night with the lighthouse and splashes active, when e32-perf-budgets runs, then live particles stay ≤ 800 and full-screen transparent layers ≤ 2 on Low.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e25.13 Build the Weeping Adit: the flooded sixth way into the lower Deepworks open
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.7 Magical material library: dissolve, glow, distortion, runes done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.241 Owner approval: river and harbour VFX open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e40.14 Build the Gilded Tern: rigging, hold, cabin, locked berth, departure open
    • mw-e40.2 Build the Stone Wharf with working cranes, cargo nets, crates and block yards open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.243Write Briar Glen environment concepts prompts (11 assets)blockedP1M3task

    Description

    Why

    Briar Glen is the first playable area and the "one warm room, one uneasy thing" tone target (style bible §2.2); every town texture, prop and light is judged against these paintings.

    What

    Write one prompt file per asset in assets/prompts/environment/<asset-id>.md (category: environment) from template environment-concept.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Eye-level third-person concept paintings for the Market Green (notice board, the Sleeping Ox, the Lamplit Stacks leaning on Brand's Forge, Vane House on the rise), the town at night with Tansy sleepwalking, and the key interiors: inn common room, three-storey bookshop, forge (bell mould on the wall), Fletchery & Simples, the bakery at 4 a.m., Watch House jail with loose drain stone, Vane House exterior and study, and the Glen Well shaft down to the flooded Vesperine cistern.

    Asset ids (11):

    • env-briar-glen-market-green-01
    • env-briar-glen-night-01
    • env-sleeping-ox-common-room-01
    • env-lamplit-stacks-interior-01
    • env-brand-forge-interior-01
    • env-fenn-fletchery-interior-01
    • env-pell-bakery-interior-01
    • env-watch-house-jail-01
    • env-vane-house-exterior-01
    • env-vane-house-study-01
    • env-glen-well-cistern-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-env-town-concepts-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Also consumed as mood targets by e24-first-night, e24-sleeping-ox, e24-lamplit-stacks, e24-trade-row, e24-watch-house-jail, e24-vane-house, e24-glen-well-cistern. The night concept shows Tansy as a sleepwalker (nightclothes, barefoot, eyes open, serene — style bible §5.2). These concepts become reference inputs for the town texture, prop and sky sets.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 11 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each painting reads as Briar Glen golden-hour/lantern palette (thatch #C9A66B, plaster #EADFC8, lantern #FFB85C), shows its gameplay affordances (hiding spots, climbable routes, the loose drain stone, the well rung) and carries one uneasy detail without horror.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.244Generate Briar Glen environment concepts via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 11 prompt files of e37-asset-env-town-concepts-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-env-town-concepts-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 11 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.243 Write Briar Glen environment concepts prompts (11 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.245Owner approval: Briar Glen environment conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 11 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-env-town-concepts-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each painting reads as Briar Glen golden-hour/lantern palette (thatch #C9A66B, plaster #EADFC8, lantern #FFB85C), shows its gameplay affordances (hiding spots, climbable routes, the loose drain stone, the well rung) and carries one uneasy detail without horror. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 11 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each painting reads as Briar Glen golden-hour/lantern palette (thatch #C9A66B, plaster #EADFC8, lantern #FFB85C), shows its gameplay affordances (hiding spots, climbable routes, the loose drain stone, the well rung) and carries one uneasy detail without horror.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-env-town-concepts-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.244 Generate Briar Glen environment concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3needs-human
  • mw-e37.246Integrate approved Briar Glen environment conceptsblockedP1M3task

    Description

    Why

    Approved environment concepts are the art-dress target: the art-dress, lighting and style-consistency beads compare in-engine screenshots against them.

    What

    Promote approved versions to assets/source/environment/<asset-id>/, add assets/CREDITS.md rows and approval records, register each concept as the artReference of its area in the area content data, and add it to the art-dress checklist and e37-style-consistency-review comparison sheet.

    Scope

    • In: Source promotion, CREDITS rows + approval records in the same commit
    • In: Area artReference entries and the art-dress comparison sheet
    • Out: Art-dressing the areas (art-dress beads); concepts are not runtime assets

    Notes

    Consumers: e24-town-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e24-town-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when e37-asset-validator runs, then every id has a source folder, CREDITS row and a matching approval hash, and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 content Given the area content data for Briar Glen, when schema-validated, then each area in this set names its concept id in artReference and the id resolves to an approved asset.
    • AC-4 integration Given the art-dress comparison sheet generator, when it runs, then each concept is paired with the latest Playwright screenshot of its area from the same camera preset.
    • AC-5 integration Edge: given an area whose artReference points at an id without an approval record, when CI runs, then the content check fails naming the area and id.

    Waits on

    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.245 Owner approval: Briar Glen environment concepts open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.247Write Briarwood and Mooring's Watch concepts prompts (8 assets)blockedP1M3task

    Description

    Why

    The wilderness is where the song's wrongness first shows in nature — silent wolves, trampled ferns, a menhir covering its ears — and it must feel cooler and bluer the deeper you go (style bible §2.2).

    What

    Write one prompt file per asset in assets/prompts/environment/<asset-id>.md (category: environment) from template environment-concept.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Briarwood trail (oak, holly, bramble, dappled light), the Sleepers' Path under moonlight, the Standing Horn clearing (menhir with hands over its ears), the wolf den hollow with overlooks and bramble cover, the millpond/sluice/drowned lane with the woodcutter's hut, Mooring's Watch exterior (goblin lookout below, signal mirror on the roof — no beacon brazier), the armour hall with names chalked on the stands, and the boarded Deepworks gate with the Bell Line carving (shape only), winch pulley and vent chimney.

    Asset ids (8):

    • env-briarwood-trail-01
    • env-sleepers-path-night-01
    • env-standing-horn-clearing-01
    • env-wolf-den-hollow-01
    • env-millpond-drowned-lane-01
    • env-moorings-watch-exterior-01
    • env-moorings-watch-armour-hall-01
    • env-deepworks-gate-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-env-wilds-concepts-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Also consumed as mood targets by e25-sleepers-path, e25-wolf-den, e25-millpond-drowned-lane, e25-mooring-watch-encounters, e25-mine-gate-approach and (P2) e25-standing-horn.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 8 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: forest paintings sit in the Briarwood palette (canopy #2E5E3E, fern #5E8C3A, shafts #F3E6A8), Mooring's Watch reads windy and high-contrast with the signal mirror as the only flash, and every class route (climb, sneak, swim, break) is visible in at least one painting.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.248Generate Briarwood and Mooring's Watch concepts via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 8 prompt files of e37-asset-env-wilds-concepts-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-env-wilds-concepts-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 8 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.247 Write Briarwood and Mooring's Watch concepts prompts (8 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.249Owner approval: Briarwood and Mooring's Watch conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 8 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-env-wilds-concepts-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: forest paintings sit in the Briarwood palette (canopy #2E5E3E, fern #5E8C3A, shafts #F3E6A8), Mooring's Watch reads windy and high-contrast with the signal mirror as the only flash, and every class route (climb, sneak, swim, break) is visible in at least one painting. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then forest paintings sit in the Briarwood palette (canopy #2E5E3E, fern #5E8C3A, shafts #F3E6A8), Mooring's Watch reads windy and high-contrast with the signal mirror as the only flash, and every class route (climb, sneak, swim, break) is visible in at least one painting.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-env-wilds-concepts-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.248 Generate Briarwood and Mooring's Watch concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3needs-human
  • mw-e37.250Integrate approved Briarwood and Mooring's Watch conceptsblockedP1M3task

    Description

    Why

    Approved environment concepts are the art-dress target: the art-dress, lighting and style-consistency beads compare in-engine screenshots against them.

    What

    Promote approved versions to assets/source/environment/<asset-id>/, add assets/CREDITS.md rows and approval records, register each concept as the artReference of its area in the area content data, and add it to the art-dress checklist and e37-style-consistency-review comparison sheet.

    Scope

    • In: Source promotion, CREDITS rows + approval records in the same commit
    • In: Area artReference entries and the art-dress comparison sheet
    • Out: Art-dressing the areas (art-dress beads); concepts are not runtime assets

    Notes

    Consumers: e25-briarwood-greybox, e25-mooring-watch-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e25-wilds-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when e37-asset-validator runs, then every id has a source folder, CREDITS row and a matching approval hash, and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 content Given the area content data for the Briarwood, Mooring's Watch and the mine gate, when schema-validated, then each area in this set names its concept id in artReference and the id resolves to an approved asset.
    • AC-4 integration Given the art-dress comparison sheet generator, when it runs, then each concept is paired with the latest Playwright screenshot of its area from the same camera preset.
    • AC-5 integration Edge: given an area whose artReference points at an id without an approval record, when CI runs, then the content check fails naming the area and id.

    Waits on

    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e25.6 Block out Mooring's Watch: courtyard, tower floors, roof and tunnel done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.249 Owner approval: Briarwood and Mooring's Watch concepts open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.251Write Deepworks and Bellwater Priory concepts prompts (8 assets)blockedP1M3task

    Description

    Why

    The Deepworks (lantern pools in the dark) and Bellwater Priory (melancholy god-rays) are the two dungeon approaches; their contrast carries the Act II mood.

    What

    Write one prompt file per asset in assets/prompts/environment/<asset-id>.md (category: environment) from template environment-concept.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Deepworks winch house and cage lift; the old glenstone cutting hall turned Rootcellar camp (kettle throne, hammocks, Duggan's crate); Vane's sealed gallery with pried Hornfolk carvings and the breach; Bellwater's roofless nave with god-rays and ivy; the choir of singing-monk statues and hidden choir door; the ruined scriptorium; the belfry with the cracked, tongueless Vesper Bell over the Sounding Shaft; the priory garden with the dead pear tree (plus a bloom variant as a second view in the same file).

    Asset ids (8):

    • env-deepworks-winch-house-01
    • env-deepworks-goblin-hall-01
    • env-deepworks-sealed-gallery-01
    • env-bellwater-nave-01
    • env-bellwater-choir-01
    • env-bellwater-scriptorium-01
    • env-bellwater-belfry-01
    • env-bellwater-garden-pear-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-env-mine-priory-concepts-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Also consumed as mood targets by e26-deepworks-encounters, e26-vane-gallery-breach, e26-priory-choir, e26-priory-scriptorium, e26-priory-belfry, e26-vesper-bell-finale.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 8 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: the Deepworks reads as lantern pools (#F0A04B) in #1C1A22 dark with the goblin camp lived-in rather than monstrous, the priory reads melancholy-beautiful in its sandstone/fresco palette, and the Vesper Bell's crack and missing tongue are readable.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.252Generate Deepworks and Bellwater Priory concepts via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 8 prompt files of e37-asset-env-mine-priory-concepts-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-env-mine-priory-concepts-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 8 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.251 Write Deepworks and Bellwater Priory concepts prompts (8 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.253Owner approval: Deepworks and Bellwater Priory conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 8 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-env-mine-priory-concepts-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the Deepworks reads as lantern pools (#F0A04B) in #1C1A22 dark with the goblin camp lived-in rather than monstrous, the priory reads melancholy-beautiful in its sandstone/fresco palette, and the Vesper Bell's crack and missing tongue are readable. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the Deepworks reads as lantern pools (#F0A04B) in #1C1A22 dark with the goblin camp lived-in rather than monstrous, the priory reads melancholy-beautiful in its sandstone/fresco palette, and the Vesper Bell's crack and missing tongue are readable.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-env-mine-priory-concepts-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.252 Generate Deepworks and Bellwater Priory concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3needs-human
  • mw-e37.254Integrate approved Deepworks and Bellwater Priory conceptsblockedP1M3task

    Description

    Why

    Approved environment concepts are the art-dress target: the art-dress, lighting and style-consistency beads compare in-engine screenshots against them.

    What

    Promote approved versions to assets/source/environment/<asset-id>/, add assets/CREDITS.md rows and approval records, register each concept as the artReference of its area in the area content data, and add it to the art-dress checklist and e37-style-consistency-review comparison sheet.

    Scope

    • In: Source promotion, CREDITS rows + approval records in the same commit
    • In: Area artReference entries and the art-dress comparison sheet
    • Out: Art-dressing the areas (art-dress beads); concepts are not runtime assets

    Notes

    Consumers: e26-deepworks-greybox, e26-priory-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-mine-priory.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when e37-asset-validator runs, then every id has a source folder, CREDITS row and a matching approval hash, and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 content Given the area content data for the Deepworks and Bellwater Priory, when schema-validated, then each area in this set names its concept id in artReference and the id resolves to an approved asset.
    • AC-4 integration Given the art-dress comparison sheet generator, when it runs, then each concept is paired with the latest Playwright screenshot of its area from the same camera preset.
    • AC-5 integration Edge: given an area whose artReference points at an id without an approval record, when CI runs, then the content check fails naming the area and id.

    Waits on

    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.253 Owner approval: Deepworks and Bellwater Priory concepts open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.255Write Knot environment concepts prompts (7 assets)blockedP1M3task

    Description

    Why

    The Knot is the MVP's heart: cold rune-carved basalt, then the warm Fold reveal that Horn is not a monster, then the dreamlike Cradle (story bible §3.5, style bible §2.2).

    What

    Write one prompt file per asset in assets/prompts/environment/<asset-id>.md (category: environment) from template environment-concept.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Outer Ring rune-banded basalt corridors with loom-spider webs copying the runes; the Ossuary bone galleries and Clatter's pale mushroom garden; the Chapel of Echoes with bells and the counterweighted portcullis; Horn's Hall arena; the Fold (warm moss beds, sleepers breathing, goblin bread, chalk tallies, skylight — the warm exception); the Sounding Shaft with bell-ropes, counterweights and ledges; the Cradle (round chamber, carved faces turned inward, dream-leak, the abbot's warm anchor lanterns the only warm light, the Nightjar only suggested).

    Asset ids (7):

    • env-knot-outer-ring-01
    • env-knot-ossuary-01
    • env-knot-chapel-echoes-01
    • env-knot-horns-hall-01
    • env-knot-fold-01
    • env-knot-sounding-shaft-01
    • env-knot-cradle-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-env-knot-concepts-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Asset id env-knot-fold-01 follows the style bible §15.1 example (the world needs list said env-knot-the-fold-01). Also consumed as mood targets by e26-ossuary-galleries, e26-chapel-of-echoes, e26-horns-hall-fold, e26-sounding-shaft-climb, e26-cradle-arena.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 7 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: the Outer Ring, Ossuary and Chapel read cold and geometric (basalt #3A3A44, glyph glow #9FD8E0), the Fold is unmistakably warm and safe (moss #7A9A4A, light-well #F6E7B0), and the Cradle is unsettling beauty with the Nightjar never shown as a creature.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.256Generate Knot environment concepts via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 7 prompt files of e37-asset-env-knot-concepts-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-env-knot-concepts-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 7 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.255 Write Knot environment concepts prompts (7 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.257Owner approval: Knot environment conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 7 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-env-knot-concepts-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the Outer Ring, Ossuary and Chapel read cold and geometric (basalt #3A3A44, glyph glow #9FD8E0), the Fold is unmistakably warm and safe (moss #7A9A4A, light-well #F6E7B0), and the Cradle is unsettling beauty with the Nightjar never shown as a creature. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 7 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the Outer Ring, Ossuary and Chapel read cold and geometric (basalt #3A3A44, glyph glow #9FD8E0), the Fold is unmistakably warm and safe (moss #7A9A4A, light-well #F6E7B0), and the Cradle is unsettling beauty with the Nightjar never shown as a creature.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-env-knot-concepts-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.256 Generate Knot environment concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3needs-human
  • mw-e37.258Integrate approved Knot environment conceptsblockedP1M3task

    Description

    Why

    Approved environment concepts are the art-dress target: the art-dress, lighting and style-consistency beads compare in-engine screenshots against them.

    What

    Promote approved versions to assets/source/environment/<asset-id>/, add assets/CREDITS.md rows and approval records, register each concept as the artReference of its area in the area content data, and add it to the art-dress checklist and e37-style-consistency-review comparison sheet.

    Scope

    • In: Source promotion, CREDITS rows + approval records in the same commit
    • In: Area artReference entries and the art-dress comparison sheet
    • Out: Art-dressing the areas (art-dress beads); concepts are not runtime assets

    Notes

    Consumers: e26-knot-outer-greybox, e26-knot-inner-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-knot.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when e37-asset-validator runs, then every id has a source folder, CREDITS row and a matching approval hash, and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 content Given the area content data for the Knot, when schema-validated, then each area in this set names its concept id in artReference and the id resolves to an approved asset.
    • AC-4 integration Given the art-dress comparison sheet generator, when it runs, then each concept is paired with the latest Playwright screenshot of its area from the same camera preset.
    • AC-5 integration Edge: given an area whose artReference points at an id without an approval record, when CI runs, then the content check fails naming the area and id.

    Waits on

    • mw-e26.10 Block out the Fold, Horn's Hall, Sounding Shaft foot and the Cradle done
    • mw-e26.9 Block out the Knot's Outer Ring, Ossuary Galleries and Chapel done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.257 Owner approval: Knot environment concepts open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.263Write Briar Glen tileables and trims prompts (8 assets)blockedP1M3task

    Description

    Why

    Large town surfaces (cobbles, plaster, thatch, slate) dominate every Briar Glen frame; the noisy loose-tile roof must look different because it plays differently for thieves (style bible §7).

    What

    Write one prompt file per asset in assets/prompts/texture/<asset-id>.md (category: texture) from template tileable-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Cobblestone, plaster-and-timber, thatch, slate roof, a visibly different loose/noisy roof tile, inn wood floor, bookshop shelf trim and a general Briar Glen timber trim sheet (beams, sills, stair noses).

    Asset ids (8):

    • tex-stone-cobble-briar-01
    • tex-plaster-timber-briar-01
    • tex-thatch-briar-01
    • tex-roof-slate-briar-01
    • tex-roof-loose-tile-01
    • tex-wood-floor-inn-01
    • tex-bookshop-shelves-trim-01
    • tex-trim-briar-glen-timber-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-tex-town-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    tex-trim-briar-glen-timber-01 is added to cover style bible §6.3 trim sheets (not in the world needs list).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 8 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: every tile repeats without an obvious feature at 3×3, colours stay in the Briar Glen palette, and the loose roof tile is distinguishable from slate at 10 m in greyscale.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.245 Owner approval: Briar Glen environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.264Generate Briar Glen tileables and trims via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 8 prompt files of e37-asset-tex-town-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-tex-town-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 8 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha), then dimensions, transparency/background, seamless tiling on both axes (automated edge-difference check) and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.263 Write Briar Glen tileables and trims prompts (8 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.265Owner approval: Briar Glen tileables and trimsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 8 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-tex-town-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every tile repeats without an obvious feature at 3×3, colours stay in the Briar Glen palette, and the loose roof tile is distinguishable from slate at 10 m in greyscale. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every tile repeats without an obvious feature at 3×3, colours stay in the Briar Glen palette, and the loose roof tile is distinguishable from slate at 10 m in greyscale.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-tex-town-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.264 Generate Briar Glen tileables and trims via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3needs-human
  • mw-e37.266Integrate approved Briar Glen tileables and trimsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/texture/<asset-id>/, build KTX2 with mips (UASTC for any normal map), register each texture in the stylized material library with its vertex-colour blend partner, add CREDITS rows and approval records, and swap the grey-box materials in the consuming areas.

    Scope

    • In: Source promotion, pipeline run, KTX2 + mip build, vertex-colour blend variants
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e24-town-greybox, e24-rooftops-thief-routes. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e24-town-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 8 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Briar Glen scene on Low and High, when Playwright captures the Market Green and a rooftop route, then final textures load with no placeholder materials, the loose-tile roof uses its own material id, and no console errors occur.
    • AC-5 perf Given the rebuilt textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the owning location package stays ≤ 25 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e24.12 Build a rooftop network across Briar Glen for thieves and climbers open
    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.265 Owner approval: Briar Glen tileables and trims open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.267Write Briarwood and Mooring's Watch tileables prompts (9 assets)blockedP1M3task

    Description

    Why

    The Briarwood floor, bark and bramble walls set the wilderness mood; the trampled-fern decal is itself a gameplay clue (the Sleepers' Path).

    What

    Write one prompt file per asset in assets/prompts/texture/<asset-id>.md (category: texture) from template tileable-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Mossy forest floor, oak bark, trampled-fern decal (Sleepers' Path), bramble wall, wet mud lane, pond water surface, weathered lichen stone and faded barony banner for Mooring's Watch, plus a watchtower stone trim sheet.

    Asset ids (9):

    • tex-forest-floor-moss-01
    • tex-bark-oak-01
    • tex-fern-trampled-decal-01
    • tex-bramble-wall-01
    • tex-mud-lane-wet-01
    • tex-pond-water-01
    • tex-stone-weathered-lichen-01
    • tex-banner-faded-01
    • tex-trim-moorings-watch-stone-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-tex-wilds-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    tex-trim-moorings-watch-stone-01 is added for §6.3 trims. The trampled-fern decal pairs with e25-sleepers-path reveal logic (night/tracker) — the decal is always present; visibility is a lighting/shader rule.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 9 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: forest surfaces sit in the Briarwood palette and tile invisibly, the trampled-fern decal is subtle at noon but readable under the night grade, and the pond water reads as freezable/swimmable per the Legibility Language.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.249 Owner approval: Briarwood and Mooring's Watch concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.268Generate Briarwood and Mooring's Watch tileables via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 9 prompt files of e37-asset-tex-wilds-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-tex-wilds-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 9 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha), then dimensions, transparency/background, seamless tiling on both axes (automated edge-difference check) and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.267 Write Briarwood and Mooring's Watch tileables prompts (9 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.269Owner approval: Briarwood and Mooring's Watch tileablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 9 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-tex-wilds-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: forest surfaces sit in the Briarwood palette and tile invisibly, the trampled-fern decal is subtle at noon but readable under the night grade, and the pond water reads as freezable/swimmable per the Legibility Language. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 9 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then forest surfaces sit in the Briarwood palette and tile invisibly, the trampled-fern decal is subtle at noon but readable under the night grade, and the pond water reads as freezable/swimmable per the Legibility Language.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-tex-wilds-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.268 Generate Briarwood and Mooring's Watch tileables via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3needs-human
  • mw-e37.270Integrate approved Briarwood and Mooring's Watch tileablesblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/texture/<asset-id>/, build KTX2 with mips (UASTC for any normal map), register each texture in the stylized material library with its vertex-colour blend partner, add CREDITS rows and approval records, and swap the grey-box materials in the consuming areas.

    Scope

    • In: Source promotion, pipeline run, KTX2 + mip build, vertex-colour blend variants
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e25-briarwood-greybox, e25-sleepers-path, e25-mooring-watch-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e25-wilds-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 9 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Briarwood and Mooring's Watch scenes, when Playwright captures day and night presets, then final textures load with no placeholder materials, the fern decal renders along the path spline, and no console errors occur.
    • AC-5 perf Given the rebuilt textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the owning location package stays ≤ 25 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e25.2 Reveal the Sleepers' Path at night or to a tracker's eye open
    • mw-e25.6 Block out Mooring's Watch: courtyard, tower floors, roof and tunnel done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.269 Owner approval: Briarwood and Mooring's Watch tileables open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.271Write Deepworks and priory tileables prompts (10 assets)blockedP1M3task

    Description

    Why

    Mine rock and shoring versus priory sandstone and fresco carry the Act II contrast; the carved Bell Line is a story landmark.

    What

    Write one prompt file per asset in assets/prompts/texture/<asset-id>.md (category: texture) from template tileable-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Mine rock, timber shoring, rail iron, carved Bell Line relief (shape only, no legible text), priory sandstone, grey marble, faded fresco, stained glass, plus Deepworks timber and priory moulding trim sheets.

    Asset ids (10):

    • tex-rock-mine-01
    • tex-timber-shoring-01
    • tex-rail-iron-01
    • tex-carved-bell-line-01
    • tex-sandstone-priory-01
    • tex-marble-grey-01
    • tex-fresco-faded-01
    • tex-stained-glass-01
    • tex-trim-deepworks-timber-01
    • tex-trim-priory-moulding-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-tex-mine-priory-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Two trim sheets are added for §6.3. Stained glass doubles as a light cookie for god-rays (e03-light-field reads light, not the texture).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 10 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: mine surfaces stay dark and low-noise so lantern pools read, priory surfaces sit in the sandstone/fresco palette, the Bell Line carving has no legible letters, and stained glass works as an emissive/light-cookie source.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.253 Owner approval: Deepworks and Bellwater Priory concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.272Generate Deepworks and priory tileables via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 10 prompt files of e37-asset-tex-mine-priory-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-tex-mine-priory-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 10 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha), then dimensions, transparency/background, seamless tiling on both axes (automated edge-difference check) and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.271 Write Deepworks and priory tileables prompts (10 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.273Owner approval: Deepworks and priory tileablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 10 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-tex-mine-priory-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: mine surfaces stay dark and low-noise so lantern pools read, priory surfaces sit in the sandstone/fresco palette, the Bell Line carving has no legible letters, and stained glass works as an emissive/light-cookie source. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then mine surfaces stay dark and low-noise so lantern pools read, priory surfaces sit in the sandstone/fresco palette, the Bell Line carving has no legible letters, and stained glass works as an emissive/light-cookie source.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-tex-mine-priory-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.272 Generate Deepworks and priory tileables via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3needs-human
  • mw-e37.274Integrate approved Deepworks and priory tileablesblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/texture/<asset-id>/, build KTX2 with mips (UASTC for any normal map), register each texture in the stylized material library with its vertex-colour blend partner, add CREDITS rows and approval records, and swap the grey-box materials in the consuming areas.

    Scope

    • In: Source promotion, pipeline run, KTX2 + mip build, vertex-colour blend variants
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e26-deepworks-greybox, e26-priory-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-mine-priory.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 10 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Deepworks and priory scenes, when Playwright captures the winch house, goblin hall, nave and belfry, then final textures load with no placeholder materials and no console errors.
    • AC-5 perf Given the rebuilt textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the owning location package stays ≤ 25 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.273 Owner approval: Deepworks and priory tileables open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.275Write Knot tileables and rune bands prompts (10 assets)blockedP1M3task

    Description

    Why

    The Knot is a sentence carved as corridors: its runes are the navigation puzzle (follow the guide-runes or loop forever), so the rune bands are gameplay-critical, not decoration (style bible §5.3).

    What

    Write one prompt file per asset in assets/prompts/texture/<asset-id>.md (category: texture) from template tileable-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Knot basalt, worn bronze, bone niche, Fold moss, the Cradle dream shader mask, a bronze trim sheet, and four Hornfolk rune bands: continuous right-angle meander lines at hand height with paired horn-crescent word breaks; guide-runes carry a small horn-crescent pointing along the route, ignored runes loop back on themselves.

    Asset ids (10):

    • tex-basalt-knot-01
    • tex-bronze-worn-01
    • tex-bone-niche-01
    • tex-moss-fold-01
    • tex-cradle-dream-01
    • tex-trim-knot-bronze-01
    • tex-rune-band-hornfolk-01
    • tex-rune-band-hornfolk-02
    • tex-rune-band-hornfolk-03
    • tex-rune-band-hornfolk-04

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-tex-knot-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Rune bands are kept in this set (not a separate one) so their palette matches the basalt; tex-cradle-dream-01 is a shader mask (painted greyscale noise), not an albedo. tex-trim-knot-bronze-01 is added for §6.3.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 10 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha; rune bands 2048×256 strips with a matching normal map (High only)) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: guide-rune bands and ignored-rune bands are distinguishable at 5 m in greyscale by shape alone (horn-crescent direction, loop-back), runes are uncarved-stone coloured unless used as a light-reactive puzzle object, and the Fold moss is unmistakably warmer than the basalt.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.257 Owner approval: Knot environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.276Generate Knot tileables and rune bands via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 10 prompt files of e37-asset-tex-knot-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-tex-knot-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha; rune bands 2048×256 strips with a matching normal map (High only). Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 10 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate (1536² for large ground/wall surfaces) → 1024²/512² KTX2 ETC1S with mips, seamless on both axes, low-contrast edges, plus vertex-colour blend variant; trims 1024×256; decals alpha; rune bands 2048×256 strips with a matching normal map (High only)), then dimensions, transparency/background, seamless tiling on both axes (automated edge-difference check) and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.275 Write Knot tileables and rune bands prompts (10 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.277Owner approval: Knot tileables and rune bandsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 10 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-tex-knot-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: guide-rune bands and ignored-rune bands are distinguishable at 5 m in greyscale by shape alone (horn-crescent direction, loop-back), runes are uncarved-stone coloured unless used as a light-reactive puzzle object, and the Fold moss is unmistakably warmer than the basalt. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then guide-rune bands and ignored-rune bands are distinguishable at 5 m in greyscale by shape alone (horn-crescent direction, loop-back), runes are uncarved-stone coloured unless used as a light-reactive puzzle object, and the Fold moss is unmistakably warmer than the basalt.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-tex-knot-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.276 Generate Knot tileables and rune bands via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3needs-human
  • mw-e37.278Integrate approved Knot tileables and rune bandsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/texture/<asset-id>/, build KTX2 with mips (UASTC for any normal map), register each texture in the stylized material library with its vertex-colour blend partner, add CREDITS rows and approval records, and swap the grey-box materials in the consuming areas.

    Scope

    • In: Source promotion, pipeline run, KTX2 + mip build, vertex-colour blend variants
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e26-knot-outer-greybox, e26-knot-inner-greybox, e26-knot-rune-navigation. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-knot.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 10 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Knot scenes, when the rune-navigation replay walks a guide-rune path and an ignored-rune loop, then both bands render from their final textures, the replay passes, and no console errors occur.
    • AC-5 perf Given the rebuilt textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the owning location package stays ≤ 25 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e26.10 Block out the Fold, Horn's Hall, Sounding Shaft foot and the Cradle done
    • mw-e26.11 Make the Knot loop unless you follow its runes open
    • mw-e26.9 Block out the Knot's Outer Ring, Ossuary Galleries and Chapel done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.277 Owner approval: Knot tileables and rune bands open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.279Write location skies and backdrops prompts (4 assets)blockedP1M3task

    Description

    Why

    Sky and distant backdrop set time-of-day for the whole surface: golden-hour town, night with the song on still nights, overcast forest, and the ending dawn.

    What

    Write one prompt file per asset in assets/prompts/sky/<asset-id>.md (category: sky) from template skybox-backdrop.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Briar Glen golden hour, Briar Glen night (moon, no aurora), Briarwood overcast, and the valley dawn used by the endings.

    Asset ids (4):

    • sky-briar-glen-golden-hour-01
    • sky-briar-glen-night-01
    • sky-briarwood-overcast-01
    • sky-valley-dawn-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-skies-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    sky-valley-dawn-01 is also consumed by e26-ending-states (epilogue); it is not linked here so the surface lighting beads do not wait on the finale.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 4 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (equirect 4096×2048 generate → KTX2 4096×2048 (High) / 2048×1024 (Low), seamless left-right wrap, horizon at vertical centre) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each sky wraps without a visible seam, matches the location light/mood column of style bible §2.2, and the night sky is dark enough that lantern light remains the key light.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.245 Owner approval: Briar Glen environment concepts open
    • mw-e37.249 Owner approval: Briarwood and Mooring's Watch concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.280Generate location skies and backdrops via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 4 prompt files of e37-asset-skies-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-skies-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: equirect 4096×2048 generate → KTX2 4096×2048 (High) / 2048×1024 (Low), seamless left-right wrap, horizon at vertical centre. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 4 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (equirect 4096×2048 generate → KTX2 4096×2048 (High) / 2048×1024 (Low), seamless left-right wrap, horizon at vertical centre), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.279 Write location skies and backdrops prompts (4 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.281Owner approval: location skies and backdropsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 4 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-skies-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each sky wraps without a visible seam, matches the location light/mood column of style bible §2.2, and the night sky is dark enough that lantern light remains the key light. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each sky wraps without a visible seam, matches the location light/mood column of style bible §2.2, and the night sky is dark enough that lantern light remains the key light.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-skies-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.280 Generate location skies and backdrops via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3needs-human
  • mw-e37.282Integrate approved location skies and backdropsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/texture/<asset-id>/, build KTX2 with mips (UASTC for any normal map), register each texture in the stylized material library with its vertex-colour blend partner, add CREDITS rows and approval records, and swap the grey-box materials in the consuming areas.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e24-town-greybox, e25-briarwood-greybox, e27-world-clock. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e24-town-lighting-audio, e25-wilds-lighting-audio.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 4 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given Briar Glen and the Briarwood, when the world clock is stepped through day, dusk and night via the debug console, then the matching final sky loads with no seam visible in a 360° Playwright capture and no console errors.
    • AC-5 perf Given the sky textures, when e32-perf-budgets runs, then each sky is ≤ 4096×2048 on High and ≤ 2048×1024 on Low and resident texture memory stays ≤ 256 MB on Low.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.281 Owner approval: location skies and backdrops open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:textureepic:e37milestone:m3
  • mw-e37.283Write named cast portraits prompts (19 assets)blockedP1M3task

    Description

    Why

    Dialogue is text-only in the MVP, so portraits carry every character's voice and warmth; they also become the likeness reference for the 3D NPCs and hero creatures.

    What

    Write one prompt file per asset in assets/prompts/portrait/<asset-id>.md (category: portrait) from template npc-portrait.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Portraits for the Briar Glen cast (Mirela Thorne, Captain Brannoc Hale, Harrow Vane, Odette "Dot" Farrow, Hollis Pell, Tansy Pell aged 12, Juniper Fenn, Oswin Brand, Duggan Marl), the six missing (Moss Greaves, Ettie Lark, Rowan Tate, Harlan Burr, Mina Coles, Fitch — also shown on the missing-persons board), and the Knot's talkers: Brother Horn (grey muzzle, bronze-wired horns, soft sad eyes), Clatter (rotted habit, apologetic), Mother Kettleback (copper kettle hat) and the Sleepless Abbot Corvin Ashgrove (lantern-lit dream-fog, courteous).

    Asset ids (19):

    • portrait-npc-mirela-bookseller
    • portrait-npc-hale-captain
    • portrait-npc-vane-mine-owner
    • portrait-npc-dot-innkeeper
    • portrait-npc-hollis-baker
    • portrait-npc-tansy-pell
    • portrait-npc-juniper-fletcher
    • portrait-npc-oswin-smith
    • portrait-npc-duggan-foreman
    • portrait-npc-moss-sleeper
    • portrait-npc-ettie-sleeper
    • portrait-npc-rowan-sleeper
    • portrait-npc-harlan-sleeper
    • portrait-npc-mina-sleeper
    • portrait-npc-fitch-sleeper
    • portrait-npc-horn-warden
    • portrait-npc-clatter-skeleton
    • portrait-npc-kettleback-matriarch
    • portrait-npc-abbot-corvin

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-portraits-cast-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Portraits are approved before the 3D NPC/creature concepts so the turnarounds match these faces. The dialogue portrait frame is part A's ui-frame-dialogue-portrait-01.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 19 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate → 512²/256² PNG → KTX2 UASTC, bust framing with head-room, softly blurred location-coloured background) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: every character matches their story bible §5 description, the set reads as one painter, faces are expressive but natural, Horn reads intimidating-then-sad (never a monster) and the abbot gentle rather than sinister.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:portraitepic:e37milestone:m3
  • mw-e37.284Generate named cast portraits via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 19 prompt files of e37-asset-portraits-cast-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-portraits-cast-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate → 512²/256² PNG → KTX2 UASTC, bust framing with head-room, softly blurred location-coloured background. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 19 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate → 512²/256² PNG → KTX2 UASTC, bust framing with head-room, softly blurred location-coloured background), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.283 Write named cast portraits prompts (19 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:portraitepic:e37milestone:m3
  • mw-e37.285Owner approval: named cast portraitsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 19 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-portraits-cast-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every character matches their story bible §5 description, the set reads as one painter, faces are expressive but natural, Horn reads intimidating-then-sad (never a monster) and the abbot gentle rather than sinister. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 19 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every character matches their story bible §5 description, the set reads as one painter, faces are expressive but natural, Horn reads intimidating-then-sad (never a monster) and the abbot gentle rather than sinister.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-portraits-cast-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.284 Generate named cast portraits via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:portraitepic:e37milestone:m3needs-human
  • mw-e37.286Integrate approved named cast portraitsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e22-dialogue-ui, e24-npc-schedules, e14-clatter, e14-mother-kettleback, e14-horn-befriend-help, e13-abbot-encounter, e26-horns-hall-fold.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 19 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given each named character's dialogue opened via the dialogue preview runner, when the dialogue UI renders, then the final portrait shows in ui-frame-dialogue-portrait-01 with no placeholder flags and no console errors.
    • AC-5 perf Given the portrait atlas, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and portraits stream with their location package rather than the initial download.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e13.16 Build the Cradle encounter with fight, trick, persuade and join paths open
    • mw-e14.3 Bring Mother Kettleback to life: trade, Duggan crate and carrying fees open
    • mw-e14.5 Build Clatter: the apologetic skeleton who can remember his name open
    • mw-e14.6 Befriend and help Brother Horn without fighting open
    • mw-e22.10 Build accessible dialogue UI with choices, tags and history done
    • mw-e24.13 Place Briar Glen's NPCs on day/night schedules in progress
    • mw-e26.16 Stage Horn's Hall and the Fold, the reveal and the wake-up point open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.285 Owner approval: named cast portraits open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:portraitepic:e37milestone:m3
  • mw-e37.291Write story and loot item icons prompts (29 assets)blockedP1M3task

    Description

    Why

    Story items and everyday loot need icons that match their world models and read in the inventory at 64 px; part A covered only the class kits.

    What

    Write one prompt file per asset in assets/prompts/icon-item/<asset-id>.md (category: icon-item) from template item-icon.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Story items (the Vesperine Hours, horn-coin, Horn's ring, the Vesper Bell tongue, Deepworks ledger, rusted watch key, Tansy's ribbon, Anselm's psalter, Mortimer's tooth, goblin kettle helm, "friend below" note, gallery key, Fold horn-key, Hornfolk fragment, Vane's mine key, the Horn of Horn) and common loot/consumables (healing draught, Juniper's salve, wakeful tea, sleep-draught, bread loaf, oil flask, iron and brass keys, the slice skeleton key, silver ornament, goblin trinket, candle stub, folded note).

    Asset ids (29):

    • icon-item-vesperine-hours-01
    • icon-item-horn-coin-01
    • icon-item-horn-ring-01
    • icon-item-vesper-bell-tongue-01
    • icon-item-deepworks-ledger-01
    • icon-item-rusted-watch-key-01
    • icon-item-tansy-ribbon-01
    • icon-item-psalter-anselm-01
    • icon-item-mortimer-tooth-01
    • icon-item-goblin-kettle-helm-01
    • icon-item-friend-below-note-01
    • icon-item-gallery-key-01
    • icon-item-fold-horn-key-01
    • icon-item-hornfolk-fragment-01
    • icon-item-mine-key-vane-01
    • icon-item-horn-of-horn-01
    • icon-item-healing-draught-01
    • icon-item-salve-juniper-01
    • icon-item-wakeful-tea-01
    • icon-item-sleep-draught-01
    • icon-item-bread-loaf-01
    • icon-item-oil-flask-01
    • icon-item-key-iron-01
    • icon-item-key-brass-01
    • icon-item-skeleton-key-01
    • icon-item-silver-ornament-01
    • icon-item-goblin-trinket-01
    • icon-item-candle-stub-01
    • icon-item-note-folded-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-icons-world-items-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Covers the "loot/world item icons" hand-off from e37-asset-icons-items-kit-prompts; coins reuse part A's icon-item-coin-01 / icon-item-gold-coin-01. The loot list (draughts, salve, tea, bread, oil, keys, ornament, trinket, candle, note) is inferred from systems/world beads and the story bible — confirm against the item data when e18-loot-tables content lands. icon-item-gallery-key-01 and icon-item-skeleton-key-01 also serve the m1 slice (which ships on placeholders).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 29 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: every icon is identifiable at 64 px, the three keys and two draughts are distinguishable by shape not colour alone, and story items carry their canon marks (horn-coin ox, Lantern Court seal on the Hours, Vane mark on the key) without legible text.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.112 Owner approval: kit item icons open
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.292Generate story and loot item icons via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 29 prompt files of e37-asset-icons-world-items-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-icons-world-items-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 29 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate → 256²/128²/64² transparent, object ~80 % fill, ink drop shadow down-right), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.291 Write story and loot item icons prompts (29 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.293Owner approval: story and loot item iconsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 29 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-icons-world-items-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every icon is identifiable at 64 px, the three keys and two draughts are distinguishable by shape not colour alone, and story items carry their canon marks (horn-coin ox, Lantern Court seal on the Hours, Vane mark on the key) without legible text. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 29 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every icon is identifiable at 64 px, the three keys and two draughts are distinguishable by shape not colour alone, and story items carry their canon marks (horn-coin ox, Lantern Court seal on the Hours, Vane mark on the key) without legible text.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-icons-world-items-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.292 Generate story and loot item icons via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:iconepic:e37milestone:m3needs-human
  • mw-e37.294Integrate approved story and loot item iconsblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e17-inventory-ui, e17-item-schema, e17-consumables-quickslots, e18-loot-tables.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 29 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the inventory with every item in this set granted via the debug console, when opened, then all 29 icons render from the atlas with no placeholder flags.
    • AC-5 perf Given the rebuilt icon atlas, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e17.10 Build inventory screen with category tabs, inspect and actions done
    • mw-e17.2 Define item definition schema and content validator done
    • mw-e17.6 Use consumables from inventory and assignable quick slots done
    • mw-e18.1 Implement loot table schema and deterministic seeded roller done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.293 Owner approval: story and loot item icons open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:iconepic:e37milestone:m3
  • mw-e37.295Select CC0 kit pieces for Briar Glen exterior props (10 models)blockedP1M3task

    Description

    Why

    The Market Green is the systemic playground: stalls break, barrels hide, washing lines burn, lamps can be doused — every piece carries a legibility cue (style bible §7).

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Market stalls (breakable), crates, hay cart, water trough, washing line (flammable), sacks, hedges/fences, lamp posts, window lanterns and the lamplighter pole.

    Kit brief ids (2):

    • prop-town-market-set-01
    • prop-town-lighting-set-01

    Target model ids (10):

    • model-prop-market-stall-01
    • model-prop-crate-01
    • model-prop-hay-cart-01
    • model-prop-water-trough-01
    • model-prop-washing-line-01
    • model-prop-sack-pile-01
    • model-prop-fence-hedge-01
    • model-prop-lamp-post-01
    • model-prop-window-lantern-01
    • model-prop-lamplighter-pole-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-town-exterior-kit-kit-recolour)

    Notes

    Barrels and wardrobes used for hiding are not duplicated: the town reuses model-prop-barrel-hide-01 and model-prop-wardrobe-hide-01 from e37-asset-thief-props-* (part A owns them).

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 2 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 10 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.245 Owner approval: Briar Glen environment concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.296Recolour Briar Glen exterior props from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-town-exterior-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 10 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.295 Select CC0 kit pieces for Briar Glen exterior props (10 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.297Owner approval: Briar Glen exterior props kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 10 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-town-exterior-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every interactive prop shows its legibility cue (breakable, flammable, hideable, dousable) at 10 m and the set reads as one palette with the approved Briar Glen concepts. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every interactive prop shows its legibility cue (breakable, flammable, hideable, dousable) at 10 m and the set reads as one palette with the approved Briar Glen concepts.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-town-exterior-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.296 Recolour Briar Glen exterior props from CC0 kits open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.298Integrate approved Briar Glen exterior propsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e24-town-systemic-objects, e24-town-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e24-town-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 10 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given Briar Glen, when the debug console spawns each exterior prop and the thief hides, breaks and douses, then the final models load with their legibility cues and no console errors.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e24.3 Place systemic objects and hiding spots throughout Briar Glen open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.297 Owner approval: Briar Glen exterior props kit turntables open
    • mw-e37.53 Integrate approved thief props open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.299Select CC0 kit pieces for Briar Glen interior props (20 models)blockedP1M3task

    Description

    Why

    Seven named interiors (inn, bookshop, forge, fletchery, bakery, Watch House, Vane House) need furniture that feels lived-in and consistent without bespoke modelling for every chair.

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Generic furniture and trade kit: inn bar, tavern tables, chairs, beds, hearth; crooked bookshelves, rolling ladder, lectern; anvil, bellows, weapon racks; arrow bins, herb racks, salve jars; bread ovens, dough troughs; desks, cell bars; Vane's fine furniture and balcony railings. Story-specific pieces (red shelf, curtain, bell mould, strongbox, drain stone, missing-persons board, cellar kettle, lending shelf) come from e37-asset-props-town-story-*.

    Kit brief ids (7):

    • prop-inn-set-01
    • prop-bookshop-set-01
    • prop-forge-set-01
    • prop-fletchery-set-01
    • prop-bakery-set-01
    • prop-watch-house-set-01
    • prop-vane-house-set-01

    Target model ids (20):

    • model-prop-inn-bar-01
    • model-prop-table-tavern-01
    • model-prop-chair-01
    • model-prop-bed-01
    • model-prop-hearth-01
    • model-prop-shelf-crooked-01
    • model-prop-bookshop-ladder-01
    • model-prop-lectern-01
    • model-prop-anvil-01
    • model-prop-bellows-01
    • model-prop-weapon-rack-01
    • model-prop-arrow-bin-01
    • model-prop-herb-rack-01
    • model-prop-salve-jars-01
    • model-prop-bread-oven-01
    • model-prop-dough-trough-01
    • model-prop-desk-01
    • model-prop-cell-bars-01
    • model-prop-furniture-fine-set-01
    • model-prop-balcony-railing-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-town-interiors-kit-kit-recolour)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 7 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 20 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.245 Owner approval: Briar Glen environment concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.300Recolour Briar Glen interior props from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-town-interiors-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 20 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.299 Select CC0 kit pieces for Briar Glen interior props (20 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.301Owner approval: Briar Glen interior props kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 20 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-town-interiors-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each interior set reads as its owner (Dot's cosy inn, Mirela's crooked shop, Vane's cold wealth) while sharing one palette, and liftable/breakable pieces carry their cues. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 20 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each interior set reads as its owner (Dot's cosy inn, Mirela's crooked shop, Vane's cold wealth) while sharing one palette, and liftable/breakable pieces carry their cues.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-town-interiors-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.300 Recolour Briar Glen interior props from CC0 kits open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.302Integrate approved Briar Glen interior propsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e24-sleeping-ox, e24-lamplit-stacks, e24-trade-row, e24-watch-house-jail, e24-vane-house. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e24-town-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 20 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given each Briar Glen interior, when Playwright loads it, then final interior props render with no placeholder models, the bookshop ladder and jail bars keep their colliders, and no console errors occur.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e24.4 Build the Sleeping Ox inn: common room, rooms, cellar and rest open
    • mw-e24.5 Author the Lamplit Stacks bookshop on the e21 authoring template open
    • mw-e24.7 Build the Forge, Fletchery & Simples and Bakery with merchant stock open
    • mw-e24.8 Build the Watch House and a jail cell whose drain leads out open
    • mw-e24.9 Build Vane House as an infiltration target with strongbox and ledger open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.301 Owner approval: Briar Glen interior props kit turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.303Select CC0 kit pieces for wilderness props (15 models)blockedP1M3task

    Description

    Why

    The Briarwood needs dense, instanced vegetation and a handful of set-dressing pieces for the millpond and Mooring's Watch without breaking the draw-call budget.

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Oak and holly trees (instanced LODs + impostors), bramble clumps, fern clusters, fallen logs, a hollow oak, rock set; sluice gate, drowned cart, woodcutter's hut contents, the lost lantern; armour stands (Hollow Sentinel posts), tower bell and cord, keeper's log, goblin lookout junk. The rotatable signal mirror comes from e37-asset-props-set-piece-hero-*.

    Kit brief ids (3):

    • prop-forest-set-01
    • prop-millpond-set-01
    • prop-watchtower-set-01

    Target model ids (15):

    • model-prop-tree-oak-01
    • model-prop-tree-holly-01
    • model-prop-bramble-01
    • model-prop-fern-cluster-01
    • model-prop-log-fallen-01
    • model-prop-oak-hollow-01
    • model-prop-rock-set-01
    • model-prop-sluice-gate-01
    • model-prop-cart-drowned-01
    • model-prop-hut-contents-01
    • model-prop-lantern-lost-01
    • model-prop-armour-stand-01
    • model-prop-tower-bell-cord-01
    • model-prop-keeper-log-01
    • model-prop-goblin-lookout-junk-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-wilds-kit-kit-recolour)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 3 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 15 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.249 Owner approval: Briarwood and Mooring's Watch concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.304Recolour wilderness props from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-wilds-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Trees get LOD1 + billboard impostor baked by the pipeline. The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 15 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.303 Select CC0 kit pieces for wilderness props (15 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.305Owner approval: wilderness props kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 15 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-wilds-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: vegetation reads as oak/holly/bramble in the Briarwood palette with impostors that do not pop at 40 m, climbable and flammable pieces carry their cues, and the tower bell cord reads as pullable. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 15 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then vegetation reads as oak/holly/bramble in the Briarwood palette with impostors that do not pop at 40 m, climbable and flammable pieces carry their cues, and the tower bell cord reads as pullable.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-wilds-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.304 Recolour wilderness props from CC0 kits open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.306Integrate approved wilderness propsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e25-briarwood-greybox, e25-millpond-drowned-lane, e25-mooring-watch-greybox, e25-mooring-watch-encounters. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e25-wilds-art-dress.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 15 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given the Briarwood and Mooring's Watch, when Playwright flies the debug camera along the priory road, then final vegetation and props render with impostor transitions and no console errors.
    • AC-4 perf Given the Briarwood with final vegetation, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low with instancing enabled.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e25.5 Build the millpond and drowned lane with a Hushling and a lost lantern open
    • mw-e25.6 Block out Mooring's Watch: courtyard, tower floors, roof and tunnel done
    • mw-e25.7 Place the Hollow Sentinels and goblin lookout with class resolutions open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.305 Owner approval: wilderness props kit turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.307Select CC0 kit pieces for dungeon props (19 models)blockedP1M3task

    Description

    Why

    Mine supports that break, bone piles that scatter and candle racks that burn are systemic dungeon furniture; they come from kits so the budget goes to hero pieces.

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Mine supports (breakable), rails, carts, winch, cage lift, oil lamps, rubble; pews, altar, candle racks, bell frame; scriptorium lecterns, loose pages, candle store, ruined bookshelves; bone piles (physics), bone niches, holy-water font, Clatter's pale mushrooms. Singing-monk statues and the Vesper Bell come from e37-asset-props-set-piece-hero-*.

    Kit brief ids (4):

    • prop-mine-shoring-set-01
    • prop-priory-set-01
    • prop-scriptorium-set-01
    • prop-ossuary-set-01

    Target model ids (19):

    • model-prop-mine-support-01
    • model-prop-mine-rail-01
    • model-prop-mine-cart-01
    • model-prop-winch-01
    • model-prop-cage-lift-01
    • model-prop-oil-lamp-01
    • model-prop-rubble-set-01
    • model-prop-pew-01
    • model-prop-altar-01
    • model-prop-candle-rack-01
    • model-prop-bell-frame-01
    • model-prop-lectern-scriptorium-01
    • model-prop-loose-pages-01
    • model-prop-candle-store-01
    • model-prop-bookshelf-ruined-01
    • model-prop-bone-pile-01
    • model-prop-bone-niche-01
    • model-prop-holy-water-font-01
    • model-prop-mushroom-pale-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-dungeon-kit-kit-recolour)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 4 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 19 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.253 Owner approval: Deepworks and Bellwater Priory concepts open
    • mw-e37.257 Owner approval: Knot environment concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.308Recolour dungeon props from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-dungeon-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 19 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.307 Select CC0 kit pieces for dungeon props (19 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.309Owner approval: dungeon props kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 19 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-dungeon-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: breakable supports and physics bone piles carry their cues, the priory pieces share the sandstone/gilt palette, and nothing on the bone props reads as gore. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 19 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then breakable supports and physics bone piles carry their cues, the priory pieces share the sandstone/gilt palette, and nothing on the bone props reads as gore.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-dungeon-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.308 Recolour dungeon props from CC0 kits open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.310Integrate approved dungeon propsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e26-deepworks-greybox, e25-supply-tunnel, e26-priory-greybox, e26-priory-scriptorium, e26-ossuary-galleries. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-mine-priory, e26-art-dress-knot.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 19 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given the Deepworks, priory and Ossuary, when the knight smashes a support and a bone pile, then the final fracture pieces and physics bones spawn, and no console errors occur.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e25.9 Make the collapsed supply tunnel a class-gated shortcut to the mine open
    • mw-e26.13 Populate the Ossuary: Forgotten habits, Clatter's garden, the psalter open
    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    • mw-e26.7 Build the scriptorium with book mimics, tallow ooze and abbot letters open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.309 Owner approval: dungeon props kit turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.311Select CC0 kit pieces for puzzle reskin and ending props (9 models)blockedP1M3task

    Description

    Why

    The e15 puzzle prefabs must look like they belong to the priory and the Knot, and each ending changes the world with a few telling props (bread at the mine gate, an epilogue lantern).

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Area reskins of e15 prefabs — mirrors, statues, scales plates, braziers, chimes, water basin — keeping their collider/socket contracts; ending props: bread basket at the mine gate, epilogue lantern, rebuilt mine headframe.

    Kit brief ids (2):

    • prop-puzzle-reskins-01
    • prop-ending-variants-01

    Target model ids (9):

    • model-prop-puzzle-mirror-01
    • model-prop-puzzle-statue-01
    • model-prop-puzzle-scales-plate-01
    • model-prop-puzzle-brazier-01
    • model-prop-puzzle-chime-01
    • model-prop-puzzle-water-basin-01
    • model-prop-bread-basket-01
    • model-prop-lantern-epilogue-01
    • model-prop-mine-headframe-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-puzzle-endings-kit-kit-recolour)

    Notes

    Reskins must not change prefab collider sizes or socket names (e15-prefab-pieces contract); the puzzle solver replays are the regression check.

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 2 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 9 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.253 Owner approval: Deepworks and Bellwater Priory concepts open
    • mw-e37.257 Owner approval: Knot environment concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.312Recolour puzzle reskin and ending props from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-puzzle-endings-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 9 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.311 Select CC0 kit pieces for puzzle reskin and ending props (9 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.313Owner approval: puzzle reskin and ending props kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 9 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-puzzle-endings-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each reskin keeps the silhouette and legibility cue of its grey-box prefab (a player who solved it in grey-box recognises it) and the ending props read at a glance in epilogue framing. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 9 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each reskin keeps the silhouette and legibility cue of its grey-box prefab (a player who solved it in grey-box recognises it) and the ending props read at a glance in epilogue framing.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-puzzle-endings-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.312 Recolour puzzle reskin and ending props from CC0 kits open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.314Integrate approved puzzle reskin and ending propsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e26-dungeon-puzzles, e26-ending-states, e15-prefab-pieces. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-mine-priory, e26-art-dress-knot.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 9 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given the Frozen Channel, Sunbeam, Scales and Dark Crossing puzzles, when their solution replays run with final reskins, then every replay passes and no console errors occur.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e15.4 Ship reusable puzzle prefabs built only from world components done
    • mw-e26.15 Place the Frozen Channel, Sunbeam, Scales and Dark Crossing puzzles open
    • mw-e26.23 Build the four endings' level states across town and dungeon open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.313 Owner approval: puzzle reskin and ending props kit turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.315Select CC0 kit pieces for world-placed story item models (14 models)blockedP1M3task

    Description

    Why

    Story items lie in the world before they reach the inventory; their world model must match their icon so players recognise what they found.

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    World pickups matching the story item icons: the Vesperine Hours, horn-coin (tiny ox asleep on the back), Horn's ring, Deepworks ledger, rusted watch key, Tansy's ribbon, Anselm's psalter, Mortimer's tooth, a "friend below" note, the gallery key, the Fold horn-key, a Hornfolk fragment, Vane's mine key and the Horn of Horn. The bell tongue lives in e37-asset-props-set-piece-hero-*; the goblin kettle helm reuses the goblin helm attachment from e37-asset-creatures-goblins-*.

    Kit brief ids (1):

    • prop-story-items-set-01

    Target model ids (14):

    • model-prop-vesperine-hours-01
    • model-prop-horn-coin-01
    • model-prop-horn-ring-01
    • model-prop-deepworks-ledger-01
    • model-prop-rusted-watch-key-01
    • model-prop-tansy-ribbon-01
    • model-prop-psalter-anselm-01
    • model-prop-mortimer-tooth-01
    • model-prop-friend-below-note-01
    • model-prop-gallery-key-01
    • model-prop-fold-horn-key-01
    • model-prop-hornfolk-fragment-01
    • model-prop-mine-key-vane-01
    • model-prop-horn-of-horn-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-story-items-kit-kit-recolour)

    Notes

    Many pieces are simple (book, coin, key, ring) and match CC0 kit meshes; unique ones (Horn of Horn, horn-key) go to the gap-fill chain. prop-story-items-set-01 is a new brief id grouping these models.

    Budget: small props 50–400 tris, prop atlas, one shared material (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 1 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 14 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, prop atlas, one shared material (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.293 Owner approval: story and loot item icons open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.316Recolour world-placed story item models from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-story-items-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, prop atlas, one shared material (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 14 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, prop atlas, one shared material (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.315 Select CC0 kit pieces for world-placed story item models (14 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.317Owner approval: world-placed story item models kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 14 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-story-items-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each world model is recognisable as its approved icon from 3 m under the wayfinder highlight, and seals/marks follow style bible §5.3 (Lantern Court seal, Vane mark, Hornfolk runes) without legible text. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 14 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each world model is recognisable as its approved icon from 3 m under the wayfinder highlight, and seals/marks follow style bible §5.3 (Lantern Court seal, Vane mark, Hornfolk runes) without legible text.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-story-items-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.316 Recolour world-placed story item models from CC0 kits open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.318Integrate approved world-placed story item modelsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e17-world-pickup-drop, e18-placed-treasure, e26-vane-gallery-breach, e26-horns-hall-fold.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 14 models are under public/assets/model/ within small props 50–400 tris, prop atlas, one shared material (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given the debug console, when each story item is dropped into the world and picked up, then its final model renders with the wayfinder highlight and the matching icon appears in the inventory, with no console errors.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e17.7 Pick up, drop and throw items as physical world objects done
    • mw-e18.5 Support designer-placed and hidden treasure with discovery rules open
    • mw-e26.16 Stage Horn's Hall and the Fold, the reveal and the wake-up point open
    • mw-e26.4 Build Vane's sealed gallery, the ledger and the sealable breach open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.317 Owner approval: world-placed story item models kit turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.323Write Briar Glen story props concept prompts (2 images)blockedP1M3task

    Description

    Why

    The town's story is told through a few specific objects — the bounty board, the missing-persons list, the bell mould, Vane's strongbox, the red shelf — that no kit provides.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Notice board with bounty poster (500 → 800 crowns shown by a swappable decal; numbers rendered by the game font) as its own sheet; a story-prop sheet for the Vesper Bell mould, missing-persons board, jail drain stone and evidence chest, Vane's strongbox and ledger desk, the Stacks' red shelf, restricted-shelf curtain and Mortimer's rare shelf, the biscuit tin, the inn cellar kettle and lending shelf.

    Concept image ids (2):

    • prop-town-notice-board-01
    • prop-town-story-set-01

    Target model ids (13):

    • model-prop-notice-board-01
    • model-prop-bell-mould-01
    • model-prop-missing-persons-board-01
    • model-prop-drain-stone-01
    • model-prop-evidence-chest-01
    • model-prop-strongbox-vane-01
    • model-prop-ledger-desk-01
    • model-prop-red-shelf-01
    • model-prop-restricted-curtain-01
    • model-prop-rare-shelf-mortimer-01
    • model-prop-biscuit-tin-01
    • model-prop-cellar-kettle-01
    • model-prop-lending-shelf-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-props-town-story-3d-generate)

    Notes

    prop-town-story-set-01 is a new concept id grouping story pieces from the inn, bookshop, forge, Watch House and Vane House sets of the needs list.

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 2 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: each story prop is readable as itself at 5 m, the drain stone visibly differs from its neighbours (loose), the strongbox reads lockpickable, and no prop carries legible text.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.245 Owner approval: Briar Glen environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.324Generate Briar Glen story props concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 2 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-props-town-story-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 2 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.323 Write Briar Glen story props concept prompts (2 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.325Owner approval: Briar Glen story props flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 2 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-town-story-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each story prop is readable as itself at 5 m, the drain stone visibly differs from its neighbours (loose), the strongbox reads lockpickable, and no prop carries legible text. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each story prop is readable as itself at 5 m, the drain stone visibly differs from its neighbours (loose), the strongbox reads lockpickable, and no prop carries legible text.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-town-story-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.324 Generate Briar Glen story props concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.326Generate Briar Glen story props 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 13 target models: first try a CC0 kit match recoloured to the palette atlas; otherwise call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-props-town-story-turntable-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 13 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.325 Owner approval: Briar Glen story props flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.327Owner approval: Briar Glen story props turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 13 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-town-story-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each story prop is readable as itself at 5 m, the drain stone visibly differs from its neighbours (loose), the strongbox reads lockpickable, and no prop carries legible text. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 13 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each story prop is readable as itself at 5 m, the drain stone visibly differs from its neighbours (loose), the strongbox reads lockpickable, and no prop carries legible text.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-town-story-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.326 Generate Briar Glen story props 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.328Integrate approved Briar Glen story propsblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e24-town-greybox, e24-trade-row, e24-watch-house-jail, e24-vane-house, e24-lamplit-stacks, e24-sleeping-ox, e24-stacks-back-room. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e24-town-art-dress. Lower-priority consumers (e24-stacks-back-room) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 13 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given Briar Glen, when the thief loosens the drain stone, picks the strongbox and reads the notice board, then the final models load with their cues and the bounty decal swaps from 500 to 800 on the world fact, with no console errors.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e24.4 Build the Sleeping Ox inn: common room, rooms, cellar and rest open
    • mw-e24.5 Author the Lamplit Stacks bookshop on the e21 authoring template open
    • mw-e24.7 Build the Forge, Fletchery & Simples and Bakery with merchant stock open
    • mw-e24.8 Build the Watch House and a jail cell whose drain leads out open
    • mw-e24.9 Build Vane House as an infiltration target with strongbox and ledger open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.327 Owner approval: Briar Glen story props turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.329Write Rootcellar goblin camp props concept prompts (1 images)blockedP1M3task

    Description

    Why

    The goblins are people with a camp, not vermin (style bible §5.2); their furniture — a kettle throne, hammocks, alarm pots — is where that reads.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Mother Kettleback's kettle throne, hammocks, alarm pots (loud when knocked), Duggan's crate (a person-sized crate with air holes), junk piles, planted "goblin trinkets" stamped with the Vane Deepworks mark (pick crossed with a key), and a cookfire.

    Concept image ids (1):

    • prop-goblin-camp-set-01

    Target model ids (7):

    • model-prop-kettle-throne-01
    • model-prop-goblin-hammock-01
    • model-prop-alarm-pots-01
    • model-prop-duggan-crate-01
    • model-prop-goblin-junk-pile-01
    • model-prop-goblin-trinket-vane-01
    • model-prop-goblin-cookfire-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-props-goblin-camp-3d-generate)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 1 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: the camp reads lived-in and patched (warm greens, copper kettles), alarm pots read as noisy traps, and the Vane mark on the trinkets is visible on close inspection.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.253 Owner approval: Deepworks and Bellwater Priory concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.330Generate Rootcellar goblin camp props concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 1 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-props-goblin-camp-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 1 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.329 Write Rootcellar goblin camp props concept prompts (1 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.331Owner approval: Rootcellar goblin camp props flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 1 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-goblin-camp-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the camp reads lived-in and patched (warm greens, copper kettles), alarm pots read as noisy traps, and the Vane mark on the trinkets is visible on close inspection. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 1 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the camp reads lived-in and patched (warm greens, copper kettles), alarm pots read as noisy traps, and the Vane mark on the trinkets is visible on close inspection.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-goblin-camp-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.330 Generate Rootcellar goblin camp props concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.332Generate Rootcellar goblin camp props 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 7 target models: first try a CC0 kit match recoloured to the palette atlas; otherwise call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-props-goblin-camp-turntable-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 7 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.331 Owner approval: Rootcellar goblin camp props flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.333Owner approval: Rootcellar goblin camp props turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 7 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-goblin-camp-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the camp reads lived-in and patched (warm greens, copper kettles), alarm pots read as noisy traps, and the Vane mark on the trinkets is visible on close inspection. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 7 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the camp reads lived-in and patched (warm greens, copper kettles), alarm pots read as noisy traps, and the Vane mark on the trinkets is visible on close inspection.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-goblin-camp-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.332 Generate Rootcellar goblin camp props 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.334Integrate approved Rootcellar goblin camp propsblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e26-deepworks-encounters, e14-mother-kettleback, e14-rootcellar-society. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-mine-priory.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 7 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the goblin hall, when the thief knocks an alarm pot and opens Duggan's crate, then the final models load, the alarm noise event fires, and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e14.2 Make the Rootcellar clan talkable, bribable and forgiving of capture open
    • mw-e14.3 Bring Mother Kettleback to life: trade, Duggan crate and carrying fees open
    • mw-e26.3 Populate the Deepworks: goblin camp, miner Forgotten, mine hazards open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.333 Owner approval: Rootcellar goblin camp props turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.335Write Hornfolk and Knot props concept prompts (4 images)blockedP1M3task

    Description

    Why

    Hornfolk stonework (always covering its ears) is the Knot's visual voice, and the Fold/Cradle props carry the reveal and the finale.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    The Standing Horn menhir (hero landmark); Knot statuary sheet: Hornfolk ear-covering statues, carved landmark faces (two, turning inward near the Cradle), rune pillars, counterweighted portcullis, chapel bells; Fold sheet: moss beds, goblin bread, chalk tally wall (thick strokes by a big hand), the horn-key door; Cradle sheet: the abbot's four anchor lanterns (shootable, the only warm light) and dream-leak floating debris.

    Concept image ids (4):

    • prop-standing-horn-01
    • prop-knot-set-01
    • prop-fold-set-01
    • prop-cradle-set-01

    Target model ids (13):

    • model-prop-standing-horn-01
    • model-prop-statue-hornfolk-ears-01
    • model-prop-carved-face-landmark-01
    • model-prop-carved-face-landmark-02
    • model-prop-rune-pillar-01
    • model-prop-portcullis-counterweight-01
    • model-prop-chapel-bell-set-01
    • model-prop-moss-bed-01
    • model-prop-goblin-bread-01
    • model-prop-chalk-tally-wall-01
    • model-prop-fold-horn-door-01
    • model-prop-anchor-lantern-01
    • model-prop-dream-debris-set-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-props-hornfolk-knot-3d-generate)

    Notes

    The Standing Horn is placed by e25-standing-horn (P2) but also anchors the Hornfolk statue style, so it is produced here at P1.

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2); large statues 2–5 k. Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 4 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2); large statues 2–5 k) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: every Hornfolk statue covers its ears, the Fold props read warm and cared-for, anchor lanterns read as targets against the cold Cradle, and carved faces are readable as landmarks from 20 m.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.249 Owner approval: Briarwood and Mooring's Watch concepts open
    • mw-e37.257 Owner approval: Knot environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.336Generate Hornfolk and Knot props concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 4 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-props-hornfolk-knot-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 4 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.335 Write Hornfolk and Knot props concept prompts (4 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.337Owner approval: Hornfolk and Knot props flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 4 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-hornfolk-knot-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every Hornfolk statue covers its ears, the Fold props read warm and cared-for, anchor lanterns read as targets against the cold Cradle, and carved faces are readable as landmarks from 20 m. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every Hornfolk statue covers its ears, the Fold props read warm and cared-for, anchor lanterns read as targets against the cold Cradle, and carved faces are readable as landmarks from 20 m.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-hornfolk-knot-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.336 Generate Hornfolk and Knot props concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.338Generate Hornfolk and Knot props 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 13 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-props-hornfolk-knot-turntable-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2); large statues 2–5 k. API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 13 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2); large statues 2–5 k, or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.337 Owner approval: Hornfolk and Knot props flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.339Owner approval: Hornfolk and Knot props turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 13 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-hornfolk-knot-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: every Hornfolk statue covers its ears, the Fold props read warm and cared-for, anchor lanterns read as targets against the cold Cradle, and carved faces are readable as landmarks from 20 m. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 13 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then every Hornfolk statue covers its ears, the Fold props read warm and cared-for, anchor lanterns read as targets against the cold Cradle, and carved faces are readable as landmarks from 20 m.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-hornfolk-knot-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.338 Generate Hornfolk and Knot props 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.340Integrate approved Hornfolk and Knot propsblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e26-knot-outer-greybox, e26-chapel-of-echoes, e26-horns-hall-fold, e26-cradle-arena, e25-standing-horn. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-knot. Lower-priority consumers (e25-standing-horn) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 13 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2); large statues 2–5 k and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the Chapel, the Fold and the Cradle, when the portcullis trap fires, the horn-key door opens and an anchor lantern is shot, then the final models animate/break correctly and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e26.14 Build the Chapel of Echoes with the Chimes puzzle and portcullis trap open
    • mw-e26.16 Stage Horn's Hall and the Fold, the reveal and the wake-up point open
    • mw-e26.17 Stage the Cradle arena for the abbot confrontation open
    • mw-e26.9 Block out the Knot's Outer Ring, Ossuary Galleries and Chapel done
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.339 Owner approval: Hornfolk and Knot props turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.341Write set-piece hero props concept prompts (3 images)blockedP1M3task

    Description

    Why

    Three hero objects carry puzzles and the finale: the cracked Vesper Bell (and its tongue), the priory's rotatable singing-monk "Watchers", and Mooring's rotatable signal mirror.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Vesper Bell in three states — cracked and tongueless (as found), tongue rehung, mended (Frostglass/Alteration) — plus the bronze tongue as a world item with its warm rim; three singing-monk statue poses (mouths open, rotatable/topple-able); the signal mirror on its iron pivot.

    Concept image ids (3):

    • prop-vesper-bell-01
    • prop-priory-watcher-statues-01
    • prop-signal-mirror-01

    Target model ids (8):

    • model-prop-vesper-bell-cracked-01
    • model-prop-vesper-bell-tongued-01
    • model-prop-vesper-bell-mended-01
    • model-prop-vesper-bell-tongue-01
    • model-prop-statue-singing-monk-01
    • model-prop-statue-singing-monk-02
    • model-prop-statue-singing-monk-03
    • model-prop-signal-mirror-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-props-set-piece-hero-3d-generate)

    Notes

    prop-priory-watcher-statues-01 and prop-signal-mirror-01 are new concept ids split out of the priory and watchtower sets. The bell tongue icon is in e37-asset-icons-world-items-*.

    Budget: hero props 2–5 k tris (bell up to 6 k with LOD1 50 %), T2 1024² unique texture, ≤ 1 material each (style bible §13.2, §6.1 hero assets). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 3 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (hero props 2–5 k tris (bell up to 6 k with LOD1 50 %), T2 1024² unique texture, ≤ 1 material each (style bible §13.2, §6.1 hero assets)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: the bell's crack and missing tongue read from the foot of the Sounding Shaft as a dark bell-mouth, the mended bell is visibly whole, the Watchers sing with open mouths (the opposite of Hornfolk statues), and the mirror's facing direction is readable at 10 m.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.249 Owner approval: Briarwood and Mooring's Watch concepts open
    • mw-e37.253 Owner approval: Deepworks and Bellwater Priory concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.342Generate set-piece hero props concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 3 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-props-set-piece-hero-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 3 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.341 Write set-piece hero props concept prompts (3 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.343Owner approval: set-piece hero props flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 3 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-set-piece-hero-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the bell's crack and missing tongue read from the foot of the Sounding Shaft as a dark bell-mouth, the mended bell is visibly whole, the Watchers sing with open mouths (the opposite of Hornfolk statues), and the mirror's facing direction is readable at 10 m. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 3 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the bell's crack and missing tongue read from the foot of the Sounding Shaft as a dark bell-mouth, the mended bell is visibly whole, the Watchers sing with open mouths (the opposite of Hornfolk statues), and the mirror's facing direction is readable at 10 m.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-set-piece-hero-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.342 Generate set-piece hero props concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.344Generate set-piece hero props 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 8 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-props-set-piece-hero-turntable-approve)

    Notes

    Budget: hero props 2–5 k tris (bell up to 6 k with LOD1 50 %), T2 1024² unique texture, ≤ 1 material each (style bible §13.2, §6.1 hero assets). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 8 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets hero props 2–5 k tris (bell up to 6 k with LOD1 50 %), T2 1024² unique texture, ≤ 1 material each (style bible §13.2, §6.1 hero assets), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.343 Owner approval: set-piece hero props flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.345Owner approval: set-piece hero props turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 8 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-set-piece-hero-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the bell's crack and missing tongue read from the foot of the Sounding Shaft as a dark bell-mouth, the mended bell is visibly whole, the Watchers sing with open mouths (the opposite of Hornfolk statues), and the mirror's facing direction is readable at 10 m. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the bell's crack and missing tongue read from the foot of the Sounding Shaft as a dark bell-mouth, the mended bell is visibly whole, the Watchers sing with open mouths (the opposite of Hornfolk statues), and the mirror's facing direction is readable at 10 m.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-set-piece-hero-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.344 Generate set-piece hero props 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.346Integrate approved set-piece hero propsblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e26-priory-belfry, e26-vesper-bell-finale, e26-priory-choir, e25-signal-mirror. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-mine-priory.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 8 models are under public/assets/model/ within hero props 2–5 k tris (bell up to 6 k with LOD1 50 %), T2 1024² unique texture, ≤ 1 material each (style bible §13.2, §6.1 hero assets) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the belfry, choir and Mooring's Watch roof, when the bell is struck tongueless, the tongue is rehung, a Watcher is rotated and the mirror is turned, then the final models swap state correctly and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e25.8 Turn the signal mirror to light the priory's hidden choir door open
    • mw-e26.19 Ring the Vesper Bell: hang the tongue, mend it and wake the sleepers open
    • mw-e26.6 Place the Watchers statue puzzle in the priory choir open
    • mw-e26.8 Build the belfry and the sour-bell consequence of early ringing open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.345 Owner approval: set-piece hero props turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.347Write world prop gap-fill concept prompts (up to 3 images)blockedP1M3task

    Description

    Why

    CC0 kits will not cover every world prop; pieces the kit-select beads list as gaps still need approved, consistent models.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: prop) from prop-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Prop sheets for every piece listed in the gap lists of the P1 kit-select beads, grouped by region, then Claude-run image-to-3D. Ids below are reserved slots; the final ids are copied from the gap lists (one model id per gap piece, already named in the kit briefs).

    Concept image ids (up to 3):

    • prop-world-gapfill-sheet-01
    • prop-world-gapfill-sheet-02
    • prop-world-gapfill-sheet-03

    Target model ids (up to 15):

    • model-prop-<gap-piece>-01 … (up to 15 models, ids fixed by the kit briefs)

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-props-world-gapfill-3d-generate)

    Notes

    If the gap lists are empty this chain closes with a note. More than 15 gap pieces means a kit choice should be revisited before generating. The P2 cemetery/school kit does not feed this chain.

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the up to 3 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: each gap piece matches its kit-set neighbours in palette, bevel and texel density so it cannot be picked out as "the generated one".
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.295 Select CC0 kit pieces for Briar Glen exterior props (10 models) open
    • mw-e37.299 Select CC0 kit pieces for Briar Glen interior props (20 models) open
    • mw-e37.303 Select CC0 kit pieces for wilderness props (15 models) open
    • mw-e37.307 Select CC0 kit pieces for dungeon props (19 models) open
    • mw-e37.311 Select CC0 kit pieces for puzzle reskin and ending props (9 models) open
    • mw-e37.315 Select CC0 kit pieces for world-placed story item models (14 models) open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.348Generate world prop gap-fill concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all up to 3 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-props-world-gapfill-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the up to 3 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.347 Write world prop gap-fill concept prompts (up to 3 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.349Owner approval: world prop gap-fill flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the up to 3 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-world-gapfill-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each gap piece matches its kit-set neighbours in palette, bevel and texel density so it cannot be picked out as "the generated one". Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 3 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each gap piece matches its kit-set neighbours in palette, bevel and texel density so it cannot be picked out as "the generated one".
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-world-gapfill-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.348 Generate world prop gap-fill concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.350Generate world prop gap-fill 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the up to 15 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-props-world-gapfill-turntable-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the up to 15 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.349 Owner approval: world prop gap-fill flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.351Owner approval: world prop gap-fill turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the up to 15 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-world-gapfill-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each gap piece matches its kit-set neighbours in palette, bevel and texel density so it cannot be picked out as "the generated one". Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 15 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each gap piece matches its kit-set neighbours in palette, bevel and texel density so it cannot be picked out as "the generated one".
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-world-gapfill-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.350 Generate world prop gap-fill 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.352Integrate approved world prop gap-fillblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e24-town-greybox, e25-briarwood-greybox, e26-deepworks-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e24-town-art-dress, e25-wilds-art-dress, e26-art-dress-mine-priory.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all up to 15 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the areas that use gap pieces, when Playwright loads them, then every gap model renders from its final glb with no placeholder models and no console errors.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.351 Owner approval: world prop gap-fill turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.353Write named Briar Glen NPC characters concept prompts (9 images)blockedP1M3task

    Description

    Why

    The nine named townsfolk are met, followed, robbed and saved; they must be recognisable in the world as the faces in their portraits.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: character) from character-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Turnaround sheets matching the approved portraits for Mirela, Captain Hale, Harrow Vane, Dot, Hollis Pell, Tansy (child proportions, plus a nightclothes/barefoot sleepwalk variant texture), Juniper, Oswin and Duggan; Hale also gets a nightclothes variant (he sleepwalks at night per style bible §5.2). Bespoke heads on kit-compatible bodies where e37-3d-pipeline-decision recommends it.

    Concept image ids (9):

    • char-npc-mirela-01
    • char-npc-hale-01
    • char-npc-vane-01
    • char-npc-dot-01
    • char-npc-hollis-01
    • char-npc-tansy-01
    • char-npc-juniper-01
    • char-npc-oswin-01
    • char-npc-duggan-01

    Target model ids (9):

    • model-npc-mirela-01
    • model-npc-hale-01
    • model-npc-vane-01
    • model-npc-dot-01
    • model-npc-hollis-01
    • model-npc-tansy-01
    • model-npc-juniper-01
    • model-npc-oswin-01
    • model-npc-duggan-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-npcs-named-3d-generate)

    Notes

    Duggan is found in a goblin crate (e14-mother-kettleback). Sleepwalk and schedule clips are in e37-asset-anim-npcs-*.

    Budget: key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 9 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: each NPC is recognisable against their approved portrait at 10 m, silhouettes are distinct from each other and from the player classes, and Tansy reads as a 12-year-old child without caricature.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.285 Owner approval: named cast portraits open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.354Generate named Briar Glen NPC characters concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 9 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-npcs-named-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 9 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.353 Write named Briar Glen NPC characters concept prompts (9 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.355Owner approval: named Briar Glen NPC characters flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 9 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-npcs-named-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each NPC is recognisable against their approved portrait at 10 m, silhouettes are distinct from each other and from the player classes, and Tansy reads as a 12-year-old child without caricature. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 9 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each NPC is recognisable against their approved portrait at 10 m, silhouettes are distinct from each other and from the player classes, and Tansy reads as a 12-year-old child without caricature.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-npcs-named-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.354 Generate named Briar Glen NPC characters concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.356Generate named Briar Glen NPC characters 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 9 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig on the canonical humanoid skeleton via e37-animation-pipeline so shared clips retarget, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-npcs-named-turntable-approve)

    Notes

    Budget: key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 9 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.355 Owner approval: named Briar Glen NPC characters flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.357Owner approval: named Briar Glen NPC characters turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 9 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-npcs-named-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each NPC is recognisable against their approved portrait at 10 m, silhouettes are distinct from each other and from the player classes, and Tansy reads as a 12-year-old child without caricature. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 9 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each NPC is recognisable against their approved portrait at 10 m, silhouettes are distinct from each other and from the player classes, and Tansy reads as a 12-year-old child without caricature.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-npcs-named-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.356 Generate named Briar Glen NPC characters 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.358Integrate approved named Briar Glen NPC charactersblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e24-npc-schedules, e24-first-night, e24-lamplit-stacks, e14-mother-kettleback.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 9 models are under public/assets/model/ within key NPC 4–7 k tris, LOD1 50 %, T1–T2 atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given Briar Glen with NPC schedules running, when the world clock passes a full day in the debug console, then every named NPC renders with its final model, plays its schedule idles, and no console errors occur.
    • AC-4 perf Given the Market Green at its busiest schedule slot, when e32-perf-budgets runs, then skinned meshes on screen stay ≤ 10 and draw calls ≤ 150 on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e14.3 Bring Mother Kettleback to life: trade, Duggan crate and carrying fees open
    • mw-e24.13 Place Briar Glen's NPCs on day/night schedules in progress
    • mw-e24.14 Stage the first-night sleepwalk from the Ox to the mine gate open
    • mw-e24.5 Author the Lamplit Stacks bookshop on the e21 authoring template open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.357 Owner approval: named Briar Glen NPC characters turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.359Select CC0 kit pieces for crowd NPC models (8 models)blockedP1M3task

    Description

    Why

    Briar Glen needs a believable population and the six missing must be recognisable in the Fold — a CC0 modular character kit with recolours and hair/face swaps gives variety cheaply.

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/character/<brief-id>.md from character-reference-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Generic townsfolk set (8–12 recolour/outfit variants), two watch recruits (the teenagers), and the six missing — Moss Greaves, Ettie Lark, Rowan Tate, Harlan Burr, Mina Coles, Fitch — as kit variants in nightclothes, barefoot, matched to their approved portraits for sleeping poses.

    Kit brief ids (1):

    • char-npc-crowd-set-01

    Target model ids (8):

    • model-npc-townsfolk-set-01
    • model-npc-watch-recruit-set-01
    • model-npc-sleeper-moss-01
    • model-npc-sleeper-ettie-01
    • model-npc-sleeper-rowan-01
    • model-npc-sleeper-harlan-01
    • model-npc-sleeper-mina-01
    • model-npc-sleeper-fitch-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-npc-crowd-kit-kit-recolour)

    Notes

    char-npc-crowd-set-01 is a new kit-brief id. Sleeping poses and wake clips come from e37-asset-anim-npcs-*.

    Budget: background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 1 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 8 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.285 Owner approval: named cast portraits open
    • mw-e37.355 Owner approval: named Briar Glen NPC characters flat concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.360Recolour crowd NPC models from CC0 kitsblockedP1M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-npc-crowd-kit-kit-approve)

    Notes

    Budget: background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 8 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.359 Select CC0 kit pieces for crowd NPC models (8 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.361Owner approval: crowd NPC models kit turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 8 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-npc-crowd-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: crowd variants are distinguishable at 15 m, each sleeper is recognisable against their portrait (hair, build, nightclothes colour), sleepers read as ordinary warm-skinned people distinct from Hushlings, and the recruits read young and nervous. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then crowd variants are distinguishable at 15 m, each sleeper is recognisable against their portrait (hair, build, nightclothes colour), sleepers read as ordinary warm-skinned people distinct from Hushlings, and the recruits read young and nervous.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-npc-crowd-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.360 Recolour crowd NPC models from CC0 kits open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.362Integrate approved crowd NPC modelsblockedP1M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e24-npc-schedules, e26-horns-hall-fold.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 8 models are under public/assets/model/ within background NPC 2–4 k tris, LOD1 50 %, T1 shared atlas, 1 material, ≤ 65 bones on the canonical humanoid rig (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given Briar Glen by day and the Fold, when Playwright captures the market crowd and the six sleepers, then final crowd models render with distinct variants, sleepers lie on their moss beds, and no console errors occur.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e24.13 Place Briar Glen's NPCs on day/night schedules in progress
    • mw-e26.16 Stage Horn's Hall and the Fold, the reveal and the wake-up point open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.361 Owner approval: crowd NPC models kit turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.363Write Forgotten and Clatter creatures concept prompts (3 images)blockedP1M3task

    Description

    Why

    The Forgotten are the most common enemy and the m1/m2 combat test subject; posed mid-habit they say "a skeleton might remember", and Clatter is the one who does.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: creature) from creature-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Miner-Forgotten (pick, lamp-hook), monk-Forgotten (rotted Vesperine habit, staff and censer attachments) and Clatter (Brother Anselm Hobb: rotted habit, gardener's stoop, hunched apologetic silhouette). Cold eye-glow #9FD8E0, never red; negative space between ribs is the read.

    Concept image ids (3):

    • creature-forgotten-miner-01
    • creature-forgotten-monk-01
    • creature-clatter-01

    Target model ids (3):

    • model-creature-forgotten-miner-01
    • model-creature-forgotten-monk-01
    • model-creature-clatter-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-creatures-forgotten-3d-generate)

    Notes

    Asset ids use canon short names (style bible §5.2): the world needs list said creature-skeleton-miner-01 etc. Part A's Animate Bones spell reuses model-creature-forgotten-miner-01.

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 3 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: miner and monk variants read apart at 20 m by tool and habit, Clatter's stoop reads as a different (friendly) character in silhouette, and eye-glow is cold, not red.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e13.2 Write the MVP bestiary design sheet for all ten creatures open
    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.285 Owner approval: named cast portraits open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.364Generate Forgotten and Clatter creatures concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 3 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-creatures-forgotten-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 3 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.363 Write Forgotten and Clatter creatures concept prompts (3 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.365Owner approval: Forgotten and Clatter creatures flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 3 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-forgotten-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: miner and monk variants read apart at 20 m by tool and habit, Clatter's stoop reads as a different (friendly) character in silhouette, and eye-glow is cold, not red. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 3 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then miner and monk variants read apart at 20 m by tool and habit, Clatter's stoop reads as a different (friendly) character in silhouette, and eye-glow is cold, not red.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-forgotten-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.364 Generate Forgotten and Clatter creatures concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.366Generate Forgotten and Clatter creatures 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 3 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig on the canonical humanoid skeleton so Forgotten clips retarget; bones as separable collapse pieces for reassembly, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-creatures-forgotten-turntable-approve)

    Notes

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 3 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.365 Owner approval: Forgotten and Clatter creatures flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.367Owner approval: Forgotten and Clatter creatures turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 3 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-forgotten-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: miner and monk variants read apart at 20 m by tool and habit, Clatter's stoop reads as a different (friendly) character in silhouette, and eye-glow is cold, not red. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 3 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then miner and monk variants read apart at 20 m by tool and habit, Clatter's stoop reads as a different (friendly) character in silhouette, and eye-glow is cold, not red.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-forgotten-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.366 Generate Forgotten and Clatter creatures 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.368Integrate approved Forgotten and Clatter creaturesblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e13-forgotten-skeleton, e13-forgotten-habits, e14-clatter.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 3 models are under public/assets/model/ within standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the creature arena, when a miner, a monk and Clatter are spawned via the debug console, then final models load, collapse into separable bones on poise break, and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e13.1 Add the Forgotten skeleton with the e04 three-move set done
    • mw-e13.4 Add monk Forgotten and habit routines that ignore quiet players open
    • mw-e14.5 Build Clatter: the apologetic skeleton who can remember his name open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.367 Owner approval: Forgotten and Clatter creatures turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.369Write Rootcellar goblin creatures concept prompts (3 images)blockedP1M3task

    Description

    Why

    The Rootcellar clan is fully social — talk, trade, bribe, hire — so goblins must read as people with rank and personality, not vermin.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: creature) from creature-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Scavenger (nets, junk pack) and slinger (sling, pouch) with round heads, triangle ears and pear bodies; a set of rank kettle-helm attachments (also the world model for the goblin kettle helm item); Mother Kettleback, big for a goblin, with a copper kettle as armour and another as a hat.

    Concept image ids (3):

    • creature-goblin-scavenger-01
    • creature-goblin-slinger-01
    • creature-goblin-kettleback-01

    Target model ids (4):

    • model-creature-goblin-scavenger-01
    • model-creature-goblin-slinger-01
    • model-creature-goblin-kettle-helm-01
    • model-creature-goblin-kettleback-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-creatures-goblins-3d-generate)

    Notes

    Snig (P2) is in e37-asset-creatures-social-secondary-* and reuses the goblin rig.

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 3 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: scavenger and slinger read apart by silhouette, kettle helms signal rank at 15 m, clothing is patched and lived-in, and Mother Kettleback reads as the matriarch.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e13.2 Write the MVP bestiary design sheet for all ten creatures open
    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.285 Owner approval: named cast portraits open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.370Generate Rootcellar goblin creatures concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 3 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-creatures-goblins-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 3 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.369 Write Rootcellar goblin creatures concept prompts (3 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.371Owner approval: Rootcellar goblin creatures flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 3 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-goblins-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: scavenger and slinger read apart by silhouette, kettle helms signal rank at 15 m, clothing is patched and lived-in, and Mother Kettleback reads as the matriarch. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 3 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then scavenger and slinger read apart by silhouette, kettle helms signal rank at 15 m, clothing is patched and lived-in, and Mother Kettleback reads as the matriarch.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-goblins-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.370 Generate Rootcellar goblin creatures concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.372Generate Rootcellar goblin creatures 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 4 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-creatures-goblins-turntable-approve)

    Notes

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 4 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.371 Owner approval: Rootcellar goblin creatures flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.373Owner approval: Rootcellar goblin creatures turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 4 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-goblins-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: scavenger and slinger read apart by silhouette, kettle helms signal rank at 15 m, clothing is patched and lived-in, and Mother Kettleback reads as the matriarch. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then scavenger and slinger read apart by silhouette, kettle helms signal rank at 15 m, clothing is patched and lived-in, and Mother Kettleback reads as the matriarch.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-goblins-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.372 Generate Rootcellar goblin creatures 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.374Integrate approved Rootcellar goblin creaturesblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e13-rootcellar-goblins, e14-mother-kettleback, e14-rootcellar-society.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 4 models are under public/assets/model/ within standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the goblin hall, when scavengers, slingers and Mother Kettleback are spawned, then final models load with helm variants per rank and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e13.6 Add Rootcellar goblin combatants: slings, nets and loud alarms open
    • mw-e14.2 Make the Rootcellar clan talkable, bribable and forgiving of capture open
    • mw-e14.3 Bring Mother Kettleback to life: trade, Duggan crate and carrying fees open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.373 Owner approval: Rootcellar goblin creatures turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.375Write Brother Horn hero creature concept prompts (1 images)blockedP1M3task

    Description

    Why

    Brother Horn is the central encounter: terrifying at first read, sad and gentle on the second — the model must hold both (style bible §5.2).

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: creature) from creature-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Nine feet (≈ 2.75 m), grey-muzzled and old, horns chipped and bound in bronze wire, moss on his shoulders, a cloth bundle and a pouch of bread for the sleepers; soft face shapes with big expressive eyes and a heavy brow that can read sad; plus his stone-headed axe carved with his name in Hornfolk runes (separate held-weapon model).

    Concept image ids (1):

    • creature-horn-base-01

    Target model ids (2):

    • model-creature-horn-01
    • model-prop-horn-axe-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-creature-horn-3d-generate)

    Notes

    Asset id creature-horn-base-01 / model-creature-horn-01 follows the style bible §15.1 examples (the world needs list said creature-minotaur-base-01).

    Budget: hero creature ≤ 20 k tris, LOD1 50 %, LOD2 25 %, T3 2048² High / T2 Low, 1–2 materials, ≤ 80 bones (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 1 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (hero creature ≤ 20 k tris, LOD1 50 %, LOD2 25 %, T3 2048² High / T2 Low, 1–2 materials, ≤ 80 bones (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: Horn is enormous and intimidating in silhouette yet his face can read sad, the bronze-wired chipped horns and grey muzzle are visible at 10 m, and there are no red eyes, drool or gore.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e13.2 Write the MVP bestiary design sheet for all ten creatures open
    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.285 Owner approval: named cast portraits open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.376Generate Brother Horn hero creature concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 1 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-creature-horn-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 1 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.375 Write Brother Horn hero creature concept prompts (1 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.377Owner approval: Brother Horn hero creature flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 1 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creature-horn-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Horn is enormous and intimidating in silhouette yet his face can read sad, the bronze-wired chipped horns and grey muzzle are visible at 10 m, and there are no red eyes, drool or gore. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 1 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Horn is enormous and intimidating in silhouette yet his face can read sad, the bronze-wired chipped horns and grey muzzle are visible at 10 m, and there are no red eyes, drool or gore.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creature-horn-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.376 Generate Brother Horn hero creature concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.378Generate Brother Horn hero creature 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 2 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-creature-horn-turntable-approve)

    Notes

    Budget: hero creature ≤ 20 k tris, LOD1 50 %, LOD2 25 %, T3 2048² High / T2 Low, 1–2 materials, ≤ 80 bones (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 2 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets hero creature ≤ 20 k tris, LOD1 50 %, LOD2 25 %, T3 2048² High / T2 Low, 1–2 materials, ≤ 80 bones (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.377 Owner approval: Brother Horn hero creature flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.379Owner approval: Brother Horn hero creature turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 2 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creature-horn-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Horn is enormous and intimidating in silhouette yet his face can read sad, the bronze-wired chipped horns and grey muzzle are visible at 10 m, and there are no red eyes, drool or gore. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Horn is enormous and intimidating in silhouette yet his face can read sad, the bronze-wired chipped horns and grey muzzle are visible at 10 m, and there are no red eyes, drool or gore.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creature-horn-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.378 Generate Brother Horn hero creature 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.380Integrate approved Brother Horn hero creatureblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e13-horn-moveset, e14-horn-befriend-help.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 2 models are under public/assets/model/ within hero creature ≤ 20 k tris, LOD1 50 %, LOD2 25 %, T3 2048² High / T2 Low, 1–2 materials, ≤ 80 bones (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given Horn's Hall, when Horn is spawned and cycles idle, charge and yield via the debug console, then the final model and axe load with correct attach points and no console errors.
    • AC-4 perf Given Horn's Hall with Horn and the six sleepers visible, when e32-perf-budgets runs, then visible triangles stay ≤ 500 k and skinned meshes ≤ 10 on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e13.13 Add Brother Horn's creature data: charges, grabs and throws to stop open
    • mw-e14.6 Befriend and help Brother Horn without fighting open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.379 Owner approval: Brother Horn hero creature turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.381Write bestiary creatures concept prompts (7 images)blockedP1M3task

    Description

    Why

    Five creature types make up the systemic bestiary: each has a property the world can exploit (fire, light, noise, feeding) that its silhouette must advertise.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: creature) from creature-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Briar Wolf (lean grey horizontal wedge, silent, ears toward the mine); Hollow Sentinel (Mooring's garrison armour with glowing seams and barony tabard remnants); Loom Spider (pale, dog-sized, radial leg spikes, one ember warning colour); Tallow Ooze (wax blob with wicks, candle stubs and a snuffer visible inside) plus small, puddle and frozen variants; book, lectern and chest mimics, each an almost-perfect object with one tell.

    Concept image ids (7):

    • creature-briar-wolf-01
    • creature-hollow-sentinel-01
    • creature-loom-spider-01
    • creature-tallow-ooze-01
    • creature-mimic-book-01
    • creature-mimic-lectern-01
    • creature-mimic-chest-01

    Target model ids (10):

    • model-creature-briar-wolf-01
    • model-creature-hollow-sentinel-01
    • model-creature-loom-spider-01
    • model-creature-tallow-ooze-01
    • model-creature-tallow-ooze-small-01
    • model-creature-tallow-ooze-puddle-01
    • model-creature-tallow-ooze-frozen-01
    • model-creature-mimic-book-01
    • model-creature-mimic-lectern-01
    • model-creature-mimic-chest-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-creatures-bestiary-3d-generate)

    Notes

    Ids use canon short names (world needs list said creature-wolf-briar-01, creature-spider-loom-01, creature-sentinel-armour-01, creature-ooze-tallow-01). Ooze puddle is a mesh decal state; the frozen variant is matte and cracked.

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); ooze variants and mimics may be lighter (≤ 2 k). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 7 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); ooze variants and mimics may be lighter (≤ 2 k)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: each creature's family shape (wedge, hollow rectangles, radial spikes, soft blob, box/slab) reads at 20 m, disposition cues read (wolf head up/down), the ooze reads as wax not element, and each mimic's tell is findable by an attentive player.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e13.2 Write the MVP bestiary design sheet for all ten creatures open
    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.382Generate bestiary creatures concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 7 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-creatures-bestiary-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 7 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.381 Write bestiary creatures concept prompts (7 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.383Owner approval: bestiary creatures flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 7 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-bestiary-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each creature's family shape (wedge, hollow rectangles, radial spikes, soft blob, box/slab) reads at 20 m, disposition cues read (wolf head up/down), the ooze reads as wax not element, and each mimic's tell is findable by an attentive player. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 7 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each creature's family shape (wedge, hollow rectangles, radial spikes, soft blob, box/slab) reads at 20 m, disposition cues read (wolf head up/down), the ooze reads as wax not element, and each mimic's tell is findable by an attentive player.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-bestiary-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.382 Generate bestiary creatures concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.384Generate bestiary creatures 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 10 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-creatures-bestiary-turntable-approve)

    Notes

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); ooze variants and mimics may be lighter (≤ 2 k). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 10 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); ooze variants and mimics may be lighter (≤ 2 k), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.383 Owner approval: bestiary creatures flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.385Owner approval: bestiary creatures turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 10 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-bestiary-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each creature's family shape (wedge, hollow rectangles, radial spikes, soft blob, box/slab) reads at 20 m, disposition cues read (wolf head up/down), the ooze reads as wax not element, and each mimic's tell is findable by an attentive player. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each creature's family shape (wedge, hollow rectangles, radial spikes, soft blob, box/slab) reads at 20 m, disposition cues read (wolf head up/down), the ooze reads as wax not element, and each mimic's tell is findable by an attentive player.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-bestiary-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.384 Generate bestiary creatures 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.386Integrate approved bestiary creaturesblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e13-briar-wolves, e13-hollow-sentinels, e13-loom-spiders, e13-tallow-ooze, e13-mimics.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 10 models are under public/assets/model/ within standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); ooze variants and mimics may be lighter (≤ 2 k) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the creature arena, when each creature and ooze variant is spawned via the debug console, then final models load, the ooze swaps variants on melt/freeze, and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e13.10 Add Tallow Ooze that melts into fire puddles and shatters when frozen open
    • mw-e13.11 Add book, lectern and chest mimics with tells and feeding open
    • mw-e13.12 Add Hollow Sentinels bound to hold the tower until relieved open
    • mw-e13.7 Add Loom Spiders that weave readable webs and fear bright light open
    • mw-e13.8 Add silent Briar Wolf packs that can be fed, scared or remembered open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.385 Owner approval: bestiary creatures turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.387Write dream creatures concept prompts (2 images)blockedP1M3task

    Description

    Why

    Hushlings and the abbot are made of the Nightjar's dream: soft, fog-bodied and unsettling, and they must never be confused with real sleepwalkers.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: creature) from creature-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Hushling: child-sized grey fog figure, smooth eyeless face, head cocked to listen, fingers slightly too long, fraying into wisps below the knees (never reads as a real child); the Sleepless Abbot: tall tapering robe of lantern-lit dream-fog, hands folded, head inclined, the Vesper Bell's bronze tongue on his belt, mouth open like a choir statue when solid.

    Concept image ids (2):

    • creature-hushling-01
    • creature-abbot-01

    Target model ids (2):

    • model-creature-hushling-01
    • model-creature-abbot-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-creatures-dream-3d-generate)

    Notes

    Ids use canon short names (world needs list said creature-wraith-abbot-01). Fog bodies come from e37-asset-vfx-world-* (vfx-hushling-fog-body-01, vfx-abbot-fog-body-01).

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); fog bodies use the world VFX fog shader over a low-poly core. Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 2 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); fog bodies use the world VFX fog shader over a low-poly core) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: Hushlings read as dream creatures (eyeless, fraying, no clothing detail) and are distinct from sleepwalkers and from the abbot, and the abbot is courteous in posture, never skeletal or snarling.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e13.2 Write the MVP bestiary design sheet for all ten creatures open
    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.285 Owner approval: named cast portraits open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.388Generate dream creatures concepts via Codex CLIblockedP1M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 2 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-creatures-dream-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 2 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.387 Write dream creatures concept prompts (2 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.389Owner approval: dream creatures flat conceptsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 2 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-dream-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Hushlings read as dream creatures (eyeless, fraying, no clothing detail) and are distinct from sleepwalkers and from the abbot, and the abbot is courteous in posture, never skeletal or snarling. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Hushlings read as dream creatures (eyeless, fraying, no clothing detail) and are distinct from sleepwalkers and from the abbot, and the abbot is courteous in posture, never skeletal or snarling.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-dream-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.388 Generate dream creatures concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.390Generate dream creatures 3D models via image-to-3D APIblockedP1M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 2 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-creatures-dream-turntable-approve)

    Notes

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); fog bodies use the world VFX fog shader over a low-poly core. API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 2 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); fog bodies use the world VFX fog shader over a low-poly core, or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.389 Owner approval: dream creatures flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.391Owner approval: dream creatures turntablesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 2 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-dream-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Hushlings read as dream creatures (eyeless, fraying, no clothing detail) and are distinct from sleepwalkers and from the abbot, and the abbot is courteous in posture, never skeletal or snarling. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Hushlings read as dream creatures (eyeless, fraying, no clothing detail) and are distinct from sleepwalkers and from the abbot, and the abbot is courteous in posture, never skeletal or snarling.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-dream-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.390 Generate dream creatures 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.392Integrate approved dream creaturesblockedP1M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e13-hushlings, e13-abbot-wraith.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 2 models are under public/assets/model/ within standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2); fog bodies use the world VFX fog shader over a low-poly core and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the drowned lane and the Cradle, when a Hushling and the abbot are spawned, then final core meshes load with their fog-body shaders and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e13.15 Add the Sleepless Abbot wraith: solid only while singing open
    • mw-e13.9 Add blind Hushlings that hunt by sound and break at loud noises open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.391 Owner approval: dream creatures turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.399Write Forgotten and Clatter animations motion briefs (13 clips)blockedP1M3task

    Description

    Why

    The Forgotten's three-move set, crumble-and-reassemble and habit idles are how players learn to read and avoid them; Clatter's fidgets make him a person.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Miner three-move set (chop, 2-hit slash, lunge), collapse and reassemble, hauling idle; monk staff sweep, censer swing, sweeping and praying idles, a calm "settle" when the Vesper hymn is hummed; Clatter tending his mushrooms and an apologetic fidget.

    Clip ids (13):

    • anim-forgotten-chop-01
    • anim-forgotten-slash-double-01
    • anim-forgotten-lunge-01
    • anim-forgotten-collapse-01
    • anim-forgotten-reassemble-01
    • anim-forgotten-idle-haul-01
    • anim-forgotten-staff-sweep-01
    • anim-forgotten-censer-swing-01
    • anim-forgotten-idle-sweep-01
    • anim-forgotten-idle-pray-01
    • anim-forgotten-calm-settle-01
    • anim-clatter-idle-tend-01
    • anim-clatter-fidget-apologise-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    Attack windows must match the e04 three-move set timings used by e13-forgotten-skeleton.

    Rig: canonical humanoid skeleton (Forgotten models are rigged to it); collapse/reassemble use per-bone physics hand-off markers. Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 13 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.400Source and retarget Forgotten and Clatter animationsblockedP1M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-forgotten-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 13 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.367 Owner approval: Forgotten and Clatter creatures turntables open
    • mw-e37.399 Write Forgotten and Clatter animations motion briefs (13 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.401Owner approval: Forgotten and Clatter animationsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 13 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-forgotten-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: attack telegraphs read from the default camera, habit idles read as habits (sweeping, praying, hauling) at 15 m, collapse/reassemble has no pops, and Clatter's idles read apologetic rather than threatening. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 13 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then attack telegraphs read from the default camera, habit idles read as habits (sweeping, praying, hauling) at 15 m, collapse/reassemble has no pops, and Clatter's idles read apologetic rather than threatening.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-forgotten-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.400 Source and retarget Forgotten and Clatter animations open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.402Integrate approved Forgotten and Clatter animationsblockedP1M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e13-forgotten-skeleton, e13-forgotten-reassembly, e13-forgotten-habits, e14-clatter.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 13 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given the creature arena, when a miner attacks, collapses and reassembles, a monk sweeps and prays, and Clatter tends his garden, then final clips play with correct markers and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e13.1 Add the Forgotten skeleton with the e04 three-move set done
    • mw-e13.3 Forgotten crumble and reassemble unless bones are scattered or burned open
    • mw-e13.4 Add monk Forgotten and habit routines that ignore quiet players open
    • mw-e14.5 Build Clatter: the apologetic skeleton who can remember his name open
    • mw-e37.368 Integrate approved Forgotten and Clatter creatures open
    • mw-e37.401 Owner approval: Forgotten and Clatter animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.403Write goblin animations motion briefs (8 clips)blockedP1M3task

    Description

    Why

    Goblins fight with slings and nets, raise very loud alarms and flee when outnumbered; their bodies must also say "we can talk" in the camp.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Sling throw, net throw, flee, alarm-pot banging, idle chatter, cower, Mother Kettleback enthroned idle and a haggling gesture.

    Clip ids (8):

    • anim-goblin-sling-01
    • anim-goblin-net-throw-01
    • anim-goblin-flee-01
    • anim-goblin-alarm-bang-01
    • anim-goblin-idle-chatter-01
    • anim-goblin-cower-01
    • anim-kettleback-idle-throne-01
    • anim-kettleback-haggle-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    Rig: goblin creature rig from the approved goblin models (auto-rig), shared by scavenger, slinger, Kettleback and Snig. Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 8 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.404Source and retarget goblin animationsblockedP1M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-goblins-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 8 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.373 Owner approval: Rootcellar goblin creatures turntables open
    • mw-e37.403 Write goblin animations motion briefs (8 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.405Owner approval: goblin animationsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 8 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-goblins-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: sling and net wind-ups are readable telegraphs, flee and cower read as fear not attack, and camp idles read social. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then sling and net wind-ups are readable telegraphs, flee and cower read as fear not attack, and camp idles read social.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-goblins-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.404 Source and retarget goblin animations open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.406Integrate approved goblin animationsblockedP1M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e13-rootcellar-goblins, e14-mother-kettleback, e14-rootcellar-society.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 8 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given the goblin hall, when goblins are alerted, attack, raise the alarm and flee, and Kettleback trades, then final clips play with markers driving sling, net and alarm events, and no console errors occur.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e13.6 Add Rootcellar goblin combatants: slings, nets and loud alarms open
    • mw-e14.2 Make the Rootcellar clan talkable, bribable and forgiving of capture open
    • mw-e14.3 Bring Mother Kettleback to life: trade, Duggan crate and carrying fees open
    • mw-e37.374 Integrate approved Rootcellar goblin creatures open
    • mw-e37.405 Owner approval: goblin animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.407Write Brother Horn animations motion briefs (8 clips)blockedP1M3task

    Description

    Why

    Horn fights to stop, not to kill; every clip must feel heavy, effortful and reluctant, and the yield and carry clips carry the reveal.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Axe sweep, charge, grab-and-throw, stomp, yield kneel (axe laid flat, head bowed), circle-walk, resting with one eye open, carrying a sleeper gently.

    Clip ids (8):

    • anim-horn-axe-sweep-01
    • anim-horn-charge-01
    • anim-horn-grab-throw-01
    • anim-horn-stomp-01
    • anim-horn-yield-kneel-01
    • anim-horn-circle-walk-01
    • anim-horn-rest-one-eye-01
    • anim-horn-carry-sleeper-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    Grab-throw uses grab/release markers bound to the player; carry-sleeper attaches a sleeper model from e37-asset-npc-crowd-kit-*.

    Rig: Horn hero rig (≤ 80 bones) from model-creature-horn-01, axe attach bone. Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 8 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.408Source and retarget Brother Horn animationsblockedP1M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-horn-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 8 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.379 Owner approval: Brother Horn hero creature turntables open
    • mw-e37.407 Write Brother Horn animations motion briefs (8 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.409Owner approval: Brother Horn animationsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 8 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-horn-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Horn reads nine feet tall and heavy, attacks read as stopping not killing, the yield reads as choice not defeat, and the carry is gentle. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Horn reads nine feet tall and heavy, attacks read as stopping not killing, the yield reads as choice not defeat, and the carry is gentle.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-horn-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.408 Source and retarget Brother Horn animations open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.410Integrate approved Brother Horn animationsblockedP1M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e13-horn-moveset, e13-horn-encounter, e14-horn-befriend-help.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 8 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given Horn's Hall, when the Warden encounter runs its charge, grab-throw, stomp and yield beats and the befriend path plays rest and carry, then final clips play with correct markers and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e13.13 Add Brother Horn's creature data: charges, grabs and throws to stop open
    • mw-e13.14 Build the Warden boss encounter with yield, spare and Trial of Horns open
    • mw-e14.6 Befriend and help Brother Horn without fighting open
    • mw-e37.380 Integrate approved Brother Horn hero creature open
    • mw-e37.409 Owner approval: Brother Horn animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.411Write Briar Wolf and Loom Spider animations motion briefs (9 clips)blockedP1M3task

    Description

    Why

    Wolves that can be fed or scared and spiders that crawl walls and flee from light are read entirely through motion.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Wolf pack trot, lunge, eating (fed), backing away from fire (no howl until the ending); spider wall crawl, ceiling crawl, bite, web spit, flee from light.

    Clip ids (9):

    • anim-briar-wolf-trot-pack-01
    • anim-briar-wolf-lunge-01
    • anim-briar-wolf-eat-01
    • anim-briar-wolf-back-away-fire-01
    • anim-loom-spider-crawl-wall-01
    • anim-loom-spider-crawl-ceiling-01
    • anim-loom-spider-bite-01
    • anim-loom-spider-web-spit-01
    • anim-loom-spider-flee-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    Rig: quadruped wolf rig and multi-leg spider rig from the approved bestiary models (auto-rig). Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 9 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.412Source and retarget Briar Wolf and Loom Spider animationsblockedP1M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-beasts-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 9 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.385 Owner approval: bestiary creatures turntables open
    • mw-e37.411 Write Briar Wolf and Loom Spider animations motion briefs (9 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.413Owner approval: Briar Wolf and Loom Spider animationsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 9 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-beasts-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: wolf head height reads disposition (lowered threat, raised curious), backing from fire reads as fear, and spider wall/ceiling crawls have no foot sliding. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 9 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then wolf head height reads disposition (lowered threat, raised curious), backing from fire reads as fear, and spider wall/ceiling crawls have no foot sliding.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-beasts-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.412 Source and retarget Briar Wolf and Loom Spider animations open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.414Integrate approved Briar Wolf and Loom Spider animationsblockedP1M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e13-briar-wolves, e13-loom-spiders.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 9 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given the wolf den and the Outer Ring, when wolves are fed and scared with fire and a spider crawls, bites and flees a light, then final clips play with correct markers and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e13.7 Add Loom Spiders that weave readable webs and fear bright light open
    • mw-e13.8 Add silent Briar Wolf packs that can be fed, scared or remembered open
    • mw-e37.386 Integrate approved bestiary creatures open
    • mw-e37.413 Owner approval: Briar Wolf and Loom Spider animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.415Write Hushling and abbot animations motion briefs (7 clips)blockedP1M3task

    Description

    Why

    Hushlings drift and listen, the abbot conducts and sings; their motion sells that they are made of dream, not flesh.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Hushling drift, grasp, dissipate (torn apart by loud sound); abbot singing/conducting (solid), drifting (fog), stagger when a lantern breaks, fury.

    Clip ids (7):

    • anim-hushling-drift-01
    • anim-hushling-grasp-01
    • anim-hushling-dissipate-01
    • anim-abbot-sing-conduct-01
    • anim-abbot-drift-01
    • anim-abbot-stagger-01
    • anim-abbot-fury-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    Rig: Hushling and abbot core rigs from the approved dream models; fog-body VFX follow bone sockets. Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 7 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.416Source and retarget Hushling and abbot animationsblockedP1M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-dream-wraith-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 7 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.391 Owner approval: dream creatures turntables open
    • mw-e37.415 Write Hushling and abbot animations motion briefs (7 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.417Owner approval: Hushling and abbot animationsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 7 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-dream-wraith-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Hushlings never show footfalls and their head-snap-to-sound reads as hunting, and the abbot's singing pose reads solid while drift reads insubstantial. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 7 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Hushlings never show footfalls and their head-snap-to-sound reads as hunting, and the abbot's singing pose reads solid while drift reads insubstantial.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-dream-wraith-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.416 Source and retarget Hushling and abbot animations open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.418Integrate approved Hushling and abbot animationsblockedP1M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e13-hushlings, e13-abbot-wraith, e13-abbot-encounter.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 7 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given the drowned lane and the Cradle, when a Hushling hunts and is torn apart by a loud noise and the abbot sings, drifts, staggers and rages, then final clips play with correct markers and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e13.15 Add the Sleepless Abbot wraith: solid only while singing open
    • mw-e13.16 Build the Cradle encounter with fight, trick, persuade and join paths open
    • mw-e13.9 Add blind Hushlings that hunt by sound and break at loud noises open
    • mw-e37.392 Integrate approved dream creatures open
    • mw-e37.417 Owner approval: Hushling and abbot animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.419Write ooze, mimic and sentinel animations motion briefs (14 clips)blockedP1M3task

    Description

    Why

    The ooze, mimics and Hollow Sentinels are systemic toys whose tells and states are animation: a breathing mimic, a splitting ooze, a sentinel saluting and falling still.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Tallow Ooze crawl, engulf, split; per-mimic disguised breathing tell and bite (book, lectern, chest), the book mimic eating paper, a shared flee hop; Hollow Sentinel halberd sweep, shield charge, and salute-then-fall-still when relieved.

    Clip ids (14):

    • anim-tallow-ooze-crawl-01
    • anim-tallow-ooze-engulf-01
    • anim-tallow-ooze-split-01
    • anim-mimic-book-tell-01
    • anim-mimic-book-bite-01
    • anim-mimic-book-eat-paper-01
    • anim-mimic-lectern-tell-01
    • anim-mimic-lectern-bite-01
    • anim-mimic-chest-tell-01
    • anim-mimic-chest-bite-01
    • anim-mimic-flee-01
    • anim-hollow-sentinel-halberd-sweep-01
    • anim-hollow-sentinel-shield-charge-01
    • anim-hollow-sentinel-salute-still-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    Mortimer (P2) reuses the book mimic clips.

    Rig: ooze blend-shape/joint rig, one rig per mimic body (book, lectern, chest) and the humanoid-derived Hollow Sentinel rig. Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 14 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.420Source and retarget ooze, mimic and sentinel animationsblockedP1M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-constructs-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 14 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.385 Owner approval: bestiary creatures turntables open
    • mw-e37.419 Write ooze, mimic and sentinel animations motion briefs (14 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.421Owner approval: ooze, mimic and sentinel animationsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 14 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-constructs-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each mimic's breathing tell is subtle but findable within 10 s of watching, the ooze split reads clearly, and the sentinel salute reads as honour discharged. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 14 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each mimic's breathing tell is subtle but findable within 10 s of watching, the ooze split reads clearly, and the sentinel salute reads as honour discharged.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-constructs-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.420 Source and retarget ooze, mimic and sentinel animations open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.422Integrate approved ooze, mimic and sentinel animationsblockedP1M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e13-tallow-ooze, e13-mimics, e13-hollow-sentinels.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 14 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given the scriptorium, the Knot and Mooring's Watch, when an ooze engulfs and splits, each mimic tells and bites, and a sentinel attacks then is relieved, then final clips play with correct markers and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e13.10 Add Tallow Ooze that melts into fire puddles and shatters when frozen open
    • mw-e13.11 Add book, lectern and chest mimics with tells and feeding open
    • mw-e13.12 Add Hollow Sentinels bound to hold the tower until relieved open
    • mw-e37.386 Integrate approved bestiary creatures open
    • mw-e37.421 Owner approval: ooze, mimic and sentinel animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.423Write townsfolk and sleeper animations motion briefs (11 clips)blockedP1M3task

    Description

    Why

    Following Tansy's sleepwalk on the first night and finding the six sleepers breathing in the Fold are the MVP's key emotional beats; town schedules need a few work idles to feel alive.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Sleepwalk (serene, eyes open, barefoot), three sleeping poses with breathing (on back, on side, curled), waking and sitting up, plus schedule idles: talking, sitting, smith hammering, baker kneading, sweeping, lamplighting.

    Clip ids (11):

    • anim-humanoid-sleepwalk-01
    • anim-humanoid-sleep-pose-back-01
    • anim-humanoid-sleep-pose-side-01
    • anim-humanoid-sleep-pose-curled-01
    • anim-humanoid-wake-sit-up-01
    • anim-humanoid-npc-idle-talk-01
    • anim-humanoid-npc-sit-01
    • anim-humanoid-npc-work-hammer-01
    • anim-humanoid-npc-work-knead-01
    • anim-humanoid-npc-sweep-01
    • anim-humanoid-npc-lamplight-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    The wake clip also serves e26-vesper-bell-finale (sleepers wake). Tansy's hum is sfx-tansy-hum-sleepwalk-loop-01.

    Rig: canonical humanoid skeleton (named NPCs and crowd kit share it). Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 11 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.424Source and retarget townsfolk and sleeper animationsblockedP1M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-npcs-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 11 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.357 Owner approval: named Briar Glen NPC characters turntables open
    • mw-e37.361 Owner approval: crowd NPC models kit turntables open
    • mw-e37.423 Write townsfolk and sleeper animations motion briefs (11 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.425Owner approval: townsfolk and sleeper animationsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 11 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-npcs-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the sleepwalk reads serene and uncanny (never zombie-like), sleepers visibly breathe, and schedule idles read as the trade they depict at 15 m. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 11 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the sleepwalk reads serene and uncanny (never zombie-like), sleepers visibly breathe, and schedule idles read as the trade they depict at 15 m.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-npcs-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.424 Source and retarget townsfolk and sleeper animations open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.426Integrate approved townsfolk and sleeper animationsblockedP1M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e24-npc-schedules, e24-first-night, e26-horns-hall-fold.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 11 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given the first-night sequence and the Fold, when Tansy sleepwalks from the Ox to the mine gate and the six sleepers lie then wake, then final clips play with footstep markers and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e24.13 Place Briar Glen's NPCs on day/night schedules in progress
    • mw-e24.14 Stage the first-night sleepwalk from the Ox to the mine gate open
    • mw-e26.16 Stage Horn's Hall and the Fold, the reveal and the wake-up point open
    • mw-e37.358 Integrate approved named Briar Glen NPC characters open
    • mw-e37.362 Integrate approved crowd NPC models open
    • mw-e37.425 Owner approval: townsfolk and sleeper animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.427Write world and dream VFX prompts (10 assets)blockedP1M3task

    Description

    Why

    The dream leaking into the world, the fog-bodied creatures, the song's motes and a few set-piece effects are location-specific and not covered by the gameplay VFX sets.

    What

    Write one prompt file per asset in assets/prompts/vfx/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Cradle dream-leak loop, Hushling fog body, abbot fog body, abbot lantern anchor link (the tether between lantern and abbot), song-intensity motes, signal-mirror beam, follow-rune glow (light-reactive rune cue), sentinel binding dispel, Vesper Bell soundwave, and the priory pear-tree bloom.

    Asset ids (10):

    • vfx-dream-leak-loop-01
    • vfx-hushling-fog-body-01
    • vfx-abbot-fog-body-01
    • vfx-abbot-lantern-anchor-link-01
    • vfx-song-intensity-motes-01
    • vfx-signal-mirror-beam-01
    • vfx-rune-glow-follow-01
    • vfx-sentinel-binding-dispel-01
    • vfx-bell-soundwave-01
    • vfx-pear-tree-bloom-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-world-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    Generic ambient VFX (dust, embers, fireflies, leaves, fog volume) are part A's e37-asset-vfx-environment-ambient-* and are not duplicated.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 10 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (512² or 1024² flipbook sheets (4×4 or 8×8), alpha or additive on black, loopable where marked; shader masks greyscale 512²) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: dream effects use the Cradle palette (dream-fog #9C98C2, shimmer #CFC6F2) and read as unsettling beauty, the lantern link and rune glow read as gameplay cues, and nothing flashes faster than 3 Hz.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.389 Owner approval: dream creatures flat concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.428Generate world and dream VFX via Codex CLIblockedP1M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 10 prompt files of e37-asset-vfx-world-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-world-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 512² or 1024² flipbook sheets (4×4 or 8×8), alpha or additive on black, loopable where marked; shader masks greyscale 512². Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 10 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (512² or 1024² flipbook sheets (4×4 or 8×8), alpha or additive on black, loopable where marked; shader masks greyscale 512²), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.427 Write world and dream VFX prompts (10 assets) open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.429Owner approval: world and dream VFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 10 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-world-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: dream effects use the Cradle palette (dream-fog #9C98C2, shimmer #CFC6F2) and read as unsettling beauty, the lantern link and rune glow read as gameplay cues, and nothing flashes faster than 3 Hz. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then dream effects use the Cradle palette (dream-fog #9C98C2, shimmer #CFC6F2) and read as unsettling beauty, the lantern link and rune glow read as gameplay cues, and nothing flashes faster than 3 Hz.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-world-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.428 Generate world and dream VFX via Codex CLI open
    area:artasset:vfxepic:e37milestone:m3needs-human
  • mw-e37.430Integrate approved world and dream VFXblockedP1M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e29-vfx-framework, e26-cradle-arena, e13-hushlings, e13-abbot-wraith, e13-song-intensity, e25-signal-mirror, e26-knot-rune-navigation, e13-hollow-sentinels, e26-vesper-bell-finale, e26-priory-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-art-dress-knot.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 10 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Cradle, the drowned lane, Mooring's Watch roof and the belfry, when each effect is triggered via the debug console, then final textures render and VFX GPU time stays within its 2 ms share.
    • AC-5 perf Given the Cradle arena with dream-leak, fog bodies, lantern links and motes active, when e32-perf-budgets runs, then live particles stay ≤ 800 and full-screen transparent layers ≤ 2 on Low.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e13.12 Add Hollow Sentinels bound to hold the tower until relieved open
    • mw-e13.15 Add the Sleepless Abbot wraith: solid only while singing open
    • mw-e13.5 Drive creature behaviour from a global song-intensity world state open
    • mw-e13.9 Add blind Hushlings that hunt by sound and break at loud noises open
    • mw-e25.8 Turn the signal mirror to light the priory's hidden choir door open
    • mw-e26.11 Make the Knot loop unless you follow its runes open
    • mw-e26.17 Stage the Cradle arena for the abbot confrontation open
    • mw-e26.19 Ring the Vesper Bell: hang the tongue, mend it and wake the sleepers open
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.7 Magical material library: dissolve, glow, distortion, runes done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.429 Owner approval: world and dream VFX open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.78Write P2 spell VFX prompts (7 assets)blockedP2M3task

    Description

    Why

    Fire Wall, Arcane Sight, Snuff and Stasis are MVP-desirable spells; if they ship, they deserve final visuals.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Phase flipbooks for fire-wall, arcane-sight, snuff, stasis.

    Asset ids (7):

    • vfx-spell-fire-fire-wall-spawn-01
    • vfx-spell-fire-fire-wall-loop-01
    • vfx-spell-fire-fire-wall-end-01
    • vfx-spell-arcane-arcane-sight-overlay-01
    • vfx-spell-shadow-snuff-pulse-01
    • vfx-spell-time-stasis-lock-01
    • vfx-spell-time-stasis-release-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-spells-secondary-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    P2 because every spell here is P2; cut together with its spell. Stasis uses the time palette (desaturated area, clock-ring).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 7 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores, 12–24 fps) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each spell's phases read as one effect and match its school motion signature (§2.3).
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.79Generate P2 spell VFX via Codex CLIblockedP2M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 7 prompt files of e37-asset-vfx-spells-secondary-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-spells-secondary-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores, 12–24 fps. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 7 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² sheet, 4×4 or 8×8 exact grid, black background for additive cores, 12–24 fps), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.78 Write P2 spell VFX prompts (7 assets) open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.80Owner approval: P2 spell VFXblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 7 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-spells-secondary-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each spell's phases read as one effect and match its school motion signature (§2.3). Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 7 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each spell's phases read as one effect and match its school motion signature (§2.3).
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-spells-secondary-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.79 Generate P2 spell VFX via Codex CLI open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3needs-human
  • mw-e37.81Integrate approved P2 spell VFXblockedP2M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e29-spell-vfx-hooks, e08-spell-fire-wall, e08-spell-arcane-sight, e08-spell-snuff, e08-spell-stasis.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 7 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell sandbox, when each secondary spell is cast, then every phase plays from final textures with no console errors.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e08.16 Add Arcane Sight: reveal hidden mechanisms and magical properties open
    • mw-e08.19 Add Snuff: extinguish all light sources in a radius open
    • mw-e08.23 Add Stasis: freeze one object or creature in time open
    • mw-e08.4 Add Fire Wall: a persistent line of flame that blocks and burns open
    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.10 Spell VFX slots and templates for the spell pipeline done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.80 Owner approval: P2 spell VFX open
    area:artasset:vfxclass:sorcererepic:e37milestone:m3
  • mw-e37.98Write ambient environment VFX prompts (5 assets)blockedP2M3task

    Description

    Why

    Ambient motion makes the hand-painted world feel alive and warm without costing gameplay budget.

    What

    Write one prompt file per asset in assets/prompts/<category>/<asset-id>.md (category: vfx) from template vfx-flipbook-texture.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Dust motes in light shafts, torch embers, fireflies, falling leaves and a painted fog-volume noise texture.

    Asset ids (5):

    • vfx-env-dust-motes-01
    • vfx-env-torch-embers-01
    • vfx-env-fireflies-01
    • vfx-env-falling-leaves-01
    • vfx-env-fog-volume-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-vfx-environment-ambient-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    P2 to match e29-environment-fx. Location-specific ambient VFX from the world list are out of scope here.

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs.

    Acceptance criteria

    • AC-1 content Given the 5 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (512² sheets or single sprites, alpha background, loopable) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: ambient effects stay subtle (never mistaken for gameplay cues).
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.99Generate ambient environment VFX via Codex CLIblockedP2M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 5 prompt files of e37-asset-vfx-environment-ambient-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-vfx-environment-ambient-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 512² sheets or single sprites, alpha background, loopable. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 5 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (512² sheets or single sprites, alpha background, loopable), then dimensions, transparency/background and grid layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    • mw-e37.98 Write ambient environment VFX prompts (5 assets) open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.100Owner approval: ambient environment VFXblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 5 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-vfx-environment-ambient-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: ambient effects stay subtle (never mistaken for gameplay cues). Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 5 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then ambient effects stay subtle (never mistaken for gameplay cues).
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-vfx-environment-ambient-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.99 Generate ambient environment VFX via Codex CLI open
    area:artasset:vfxepic:e37milestone:m3needs-human
  • mw-e37.101Integrate approved ambient environment VFXblockedP2M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/UI logic (owned by the consuming beads)

    Notes

    Consumers: e29-environment-fx.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 5 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the style-target diorama, when ambient VFX are enabled, then final textures render and VFX GPU time stays within its 2 ms share.
    • AC-5 perf Given the rebuilt atlases/textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the UI/fonts download share stays ≤ 4 MB where applicable.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e29.1 Data-driven VFX framework with pooling and particle budgets done
    • mw-e29.14 Ambient environment VFX: dust motes, embers, fireflies, fog open
    • mw-e37.100 Owner approval: ambient environment VFX open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:vfxepic:e37milestone:m3
  • mw-e37.221Write harbour gull and rat models concept prompts (2 images)blockedP2M3task

    Description

    Why

    Gulls that steal shinies and rats that give you away are ambient life, not creature types (story bible §8), but they make the harbour feel criminal and alive.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: creature) from creature-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Harbour gull (white-grey, carries a stolen shiny with the pickup glint) and wharf rat (small, dark, scatters from light).

    Concept image ids (2):

    • creature-ambient-gull-01
    • creature-ambient-rat-01

    Target model ids (2):

    • model-ambient-gull-01
    • model-ambient-rat-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-ambient-life-gull-rat-3d-generate)

    Notes

    P2 to match e40-harbor-ambient-life. The Gull Shoot uses wooden gull targets (waterfront kit), so the P1 contest does not wait on this set.

    Budget: ambient critter ≤ 1.5 k tris, LOD1 50 %, T0–T1 shared atlas, ≤ 30 bones, instanced. Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 2 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (ambient critter ≤ 1.5 k tris, LOD1 50 %, T0–T1 shared atlas, ≤ 30 bones, instanced) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: the gull reads cheeky rather than menacing with its stolen shiny glinting, and the rat reads small and dark without being grotesque.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.149 Owner approval: Wendmouth environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.222Generate harbour gull and rat models concepts via Codex CLIblockedP2M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 2 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-ambient-life-gull-rat-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 2 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.221 Write harbour gull and rat models concept prompts (2 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.223Owner approval: harbour gull and rat models flat conceptsblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 2 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ambient-life-gull-rat-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the gull reads cheeky rather than menacing with its stolen shiny glinting, and the rat reads small and dark without being grotesque. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the gull reads cheeky rather than menacing with its stolen shiny glinting, and the rat reads small and dark without being grotesque.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ambient-life-gull-rat-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.222 Generate harbour gull and rat models concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.224Generate harbour gull and rat models 3D models via image-to-3D APIblockedP2M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 2 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-ambient-life-gull-rat-turntable-approve)

    Notes

    Budget: ambient critter ≤ 1.5 k tris, LOD1 50 %, T0–T1 shared atlas, ≤ 30 bones, instanced. API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 2 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets ambient critter ≤ 1.5 k tris, LOD1 50 %, T0–T1 shared atlas, ≤ 30 bones, instanced, or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.223 Owner approval: harbour gull and rat models flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.225Owner approval: harbour gull and rat models turntablesblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 2 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-ambient-life-gull-rat-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the gull reads cheeky rather than menacing with its stolen shiny glinting, and the rat reads small and dark without being grotesque. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the gull reads cheeky rather than menacing with its stolen shiny glinting, and the rat reads small and dark without being grotesque.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-ambient-life-gull-rat-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.224 Generate harbour gull and rat models 3D models via image-to-3D API open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.226Integrate approved harbour gull and rat modelsblockedP2M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e40-harbor-ambient-life.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 2 models are under public/assets/model/ within ambient critter ≤ 1.5 k tris, LOD1 50 %, T0–T1 shared atlas, ≤ 30 bones, instanced and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the rooftops, when gulls and rats are spawned via the debug console, then final instanced models load and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.225 Owner approval: harbour gull and rat models turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.19 Add harbour gulls that steal shiny things and rats that give you away open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.231Write Tereza's sabre duel animations motion briefs (5 clips)blockedP2M3task

    Description

    Why

    Tereza's first-blood duel is the knight's elegant set piece: a retired duellist who enjoyed it too much.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Guard stance, lunge, parry, riposte, and a yield salute when first blood is drawn.

    Clip ids (5):

    • anim-tereza-guard-01
    • anim-tereza-lunge-01
    • anim-tereza-parry-01
    • anim-tereza-riposte-01
    • anim-tereza-yield-salute-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    P2 to match e40-tereza-duel.

    Rig: canonical humanoid skeleton with the Saltmarch sabre socket. Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 5 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.232Source and retarget Tereza's sabre duel animationsblockedP2M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-tereza-duel-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 5 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.191 Owner approval: Saltmarch weapon and arrow turntables open
    • mw-e37.215 Owner approval: named harbour NPC characters turntables open
    • mw-e37.231 Write Tereza's sabre duel animations motion briefs (5 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.233Owner approval: Tereza's sabre duel animationsblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 5 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-tereza-duel-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the duel reads precise and elegant, lunge telegraphs match the e04 parry window, and the salute reads gracious. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 5 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the duel reads precise and elegant, lunge telegraphs match the e04 parry window, and the salute reads gracious.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-tereza-duel-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.232 Source and retarget Tereza's sabre duel animations open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.234Integrate approved Tereza's sabre duel animationsblockedP2M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e40-tereza-duel.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 5 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given the Tidemarket duel, when the knight duels Tereza to first blood, then final clips play with hit markers matching the parry window and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e37.216 Integrate approved named harbour NPC characters open
    • mw-e37.233 Owner approval: Tereza's sabre duel animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.11 Stage Tereza Maelo's first-blood duel open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.235Write gull and rat animations motion briefs (6 clips)blockedP2M3task

    Description

    Why

    Gulls snatching shinies and rats scattering from light are only readable through motion.

    What

    Write one motion brief per clip in assets/prompts/anim/<asset-id>.md from assets/prompts/_templates/animation-brief.md: clip id, target model and rig, source (CC0 library clip, or Meshy/Tripo auto-anim prompt), loop/one-shot, duration, root motion policy, sim marker events, consistency checklist and approval gate.

    Gull idle, fly, snatch and hoard; rat scurry and flee-from-light.

    Clip ids (6):

    • anim-ambient-gull-idle-01
    • anim-ambient-gull-fly-01
    • anim-ambient-gull-snatch-01
    • anim-ambient-gull-hoard-01
    • anim-ambient-rat-scurry-01
    • anim-ambient-rat-flee-01

    Scope

    • In: One brief per clip id
    • In: Sim marker list per clip (footstep, hit-open/close, grab/release, sfx, vfx, interrupt-ok)
    • Out: Retargeting tooling (e37-animation-pipeline)
    • Out: Base locomotion (idle/walk/run) — comes with the model's auto-rig step or the pipeline base library

    Notes

    P2 to match e40-harbor-ambient-life.

    Rig: gull and rat critter rigs from the approved ambient-life models. Timings must match the consuming beads' attack/interaction data.

    Acceptance criteria

    • AC-1 content Given the 6 clip ids, when the asset validator runs, then each has one brief whose id equals its filename stem and follows the anim-<rig-or-creature>-<action>-<nn> pattern.
    • AC-2 content Given each brief, when inspected, then it states target model, rig, source, frame count, loop flag, root-motion policy and the required sim marker events per animation-brief.md.
    • AC-3 content Given each brief sourcing from a library, when inspected, then the library licence is CC0 (Mixamo raw files never enter the repo); API-sourced briefs record provider and tier.
    • AC-4 content Edge: given a brief with no marker for a clip that emits noise or contact (footfall, hit, grab), when validated, then the validator fails naming the clip.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.236Source and retarget gull and rat animationsblockedP2M3task

    Description

    Why

    Claude produces every clip; the owner only approves.

    What

    Source or generate each clip per its brief (CC0 library, or the provider auto-anim API on the approved rigged model), retarget with e37-animation-pipeline, add markers, and render preview GIFs on the target model with e37-turntable-preview.

    Scope

    • In: Sourcing/generation, retarget, markers
    • In: Preview GIF per clip
    • Out: Owner approval (e37-asset-anim-ambient-life-approve)

    Notes

    glb clip on the target rig, 30 fps, in-place with root velocity curve unless the brief says otherwise, loop flag and event markers per the clip manifest. API keys only from env vars.

    Acceptance criteria

    • AC-1 integration Given the 6 briefs, when the batch completes, then each clip exists in assets/_incoming/<asset-id>/vN.glb with a sidecar (source, licence or provider/tier, date).
    • AC-2 content Given the clip manifest entries, when validated, then loop flags, durations (±1 frame) and event markers match each brief, and looping clips have first/last pose delta below the pipeline threshold.
    • AC-3 integration Given each clip, when previewed, then a GIF on the target model exists on the review page.
    • AC-4 integration Edge: given the animation API or library download hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.11 Character animation pipeline with retargeting to a shared humanoid rig open
    • mw-e37.225 Owner approval: harbour gull and rat models turntables open
    • mw-e37.235 Write gull and rat animations motion briefs (6 clips) open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.237Owner approval: gull and rat animationsblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the animation gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 6 preview GIFs and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: animation, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-anim-ambient-life-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the snatch reads as theft (shiny in beak), fly loops are seamless, and the rat flee reads as startled. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 6 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "animation".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the snatch reads as theft (shiny in beak), fly loops are seamless, and the rat flee reads as startled.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-anim-ambient-life-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.236 Source and retarget gull and rat animations open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.238Integrate approved gull and rat animationsblockedP2M3task

    Description

    Why

    Final clips replace placeholder poses without touching gameplay code.

    What

    Pack approved clips into the per-character clip sets via the clip manifest, add CREDITS + approval records, clear placeholder flags, and verify in-game.

    Scope

    • In: Clip manifest entries, CREDITS, approval records
    • Out: Animation state machine logic (consuming beads, e02-animation-system)

    Notes

    Consumers: e40-harbor-ambient-life.

    Acceptance criteria

    • AC-1 integration Given the approved clips, when the pipeline and validator run, then all 6 clips are in the runtime clip sets and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then every clip has a CREDITS row with source and licence, and an animation approval record.
    • AC-3 e2e Given the rooftops, when a gull snatches a dropped coin and a rat is lit by a lantern, then final clips play with correct markers and no console errors.
    • AC-4 integration Edge: given a clip missing its approval record, when the pipeline runs, then it is not packed and the placeholder pose remains.

    Waits on

    • mw-e02.20 Build layered animation state machine synced to sim timelines done
    • mw-e37.226 Integrate approved harbour gull and rat models open
    • mw-e37.237 Owner approval: gull and rat animations open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.19 Add harbour gulls that steal shiny things and rats that give you away open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.259Write optional Briar Glen and slice concepts prompts (4 assets)blockedP2M3task

    Description

    Why

    The restricted back room, the lychgate cemetery and the empty schoolhouse are MVP-desirable story spaces (P2 beads); the slice mood reference helps the m1 grey-box read as the same game.

    What

    Write one prompt file per asset in assets/prompts/environment/<asset-id>.md (category: environment) from template environment-concept.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Mirela's back room with *Nine Sleeps* on a locked lectern; the lychgate cemetery with Vesperine bell-marked graves and the Mooring family plot; the empty schoolroom with the rhyme on the slate (as brush-mark shapes, no legible text) and Tansy's reading corner; an optional mood reference for the m1 slice level.

    Asset ids (4):

    • env-lamplit-stacks-back-room-01
    • env-lychgate-cemetery-01
    • env-schoolhouse-empty-01
    • env-grey-box-slice-01

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-env-optional-concepts-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    P2 to match e24-stacks-back-room and e24-cemetery-schoolhouse. env-grey-box-slice-01 is optional and informs e01-slice-greybox-level only as a mood reference (the slice ships on grey-box art).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 4 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: each painting matches the approved Briar Glen concepts in palette and brushwork, keeps text as unreadable shapes, and the schoolhouse reads as absence (missing teacher) rather than threat.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.245 Owner approval: Briar Glen environment concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.260Generate optional Briar Glen and slice concepts via Codex CLIblockedP2M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 4 prompt files of e37-asset-env-optional-concepts-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-env-optional-concepts-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 4 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (16:9, 1536×864 generate, PNG, painterly concept — reference/mood target for grey-box and art-dress, not a runtime texture), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.259 Write optional Briar Glen and slice concepts prompts (4 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.261Owner approval: optional Briar Glen and slice conceptsblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 4 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-env-optional-concepts-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each painting matches the approved Briar Glen concepts in palette and brushwork, keeps text as unreadable shapes, and the schoolhouse reads as absence (missing teacher) rather than threat. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each painting matches the approved Briar Glen concepts in palette and brushwork, keeps text as unreadable shapes, and the schoolhouse reads as absence (missing teacher) rather than threat.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-env-optional-concepts-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.260 Generate optional Briar Glen and slice concepts via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3needs-human
  • mw-e37.262Integrate approved optional Briar Glen and slice conceptsblockedP2M3task

    Description

    Why

    Approved environment concepts are the art-dress target: the art-dress, lighting and style-consistency beads compare in-engine screenshots against them.

    What

    Promote approved versions to assets/source/environment/<asset-id>/, add assets/CREDITS.md rows and approval records, register each concept as the artReference of its area in the area content data, and add it to the art-dress checklist and e37-style-consistency-review comparison sheet.

    Scope

    • In: Source promotion, CREDITS rows + approval records in the same commit
    • In: Area artReference entries and the art-dress comparison sheet
    • Out: Art-dressing the areas (art-dress beads); concepts are not runtime assets

    Notes

    Consumers: e24-town-greybox, e24-stacks-back-room, e24-cemetery-schoolhouse. Lower-priority consumers (e24-stacks-back-room, e24-cemetery-schoolhouse) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when e37-asset-validator runs, then every id has a source folder, CREDITS row and a matching approval hash, and the validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 content Given the area content data for the back room, cemetery, schoolhouse and slice level, when schema-validated, then each area in this set names its concept id in artReference and the id resolves to an approved asset.
    • AC-4 integration Given the art-dress comparison sheet generator, when it runs, then each concept is paired with the latest Playwright screenshot of its area from the same camera preset.
    • AC-5 integration Edge: given an area whose artReference points at an id without an approval record, when CI runs, then the content check fails naming the area and id.

    Waits on

    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.261 Owner approval: optional Briar Glen and slice concepts open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:conceptepic:e37milestone:m3
  • mw-e37.287Write secondary and historical portraits prompts (4 assets)blockedP2M3task

    Description

    Why

    Snig and Mortimer are P2 social creatures, and the historical painted portraits (Sergeant Aldric Mooring, Ysolde Thorne) are optional in-world props that reward curiosity.

    What

    Write one prompt file per asset in assets/prompts/portrait/<asset-id>.md (category: portrait) from template npc-portrait.md, with the GPT STYLE PREAMBLE (style bible §14) plus its §14.1 category add-on pasted verbatim, the output spec, the bible consistency checklist, consuming bead(s) and an empty iteration log.

    Snig (small, quick, a stolen primer tucked away), Mortimer (a plump, smug book with a red ribbon tongue), and two in-world painted portraits in period frames: Sergeant Aldric Mooring (for Mooring's Watch) and Ysolde Thorne as a Vesperine novice (for the Lamplit Stacks).

    Asset ids (4):

    • portrait-npc-snig-goblin
    • portrait-npc-mortimer-mimic
    • portrait-npc-mooring-sergeant
    • portrait-npc-ysolde-novice

    Scope

    • In: One prompt file per asset id above
    • In: Consuming bead references and anchor/reference inputs (our own approved assets only)
    • In: Output spec per template
    • Out: Running the generator (see e37-asset-portraits-secondary-generate)
    • Out: Changing a preamble (bible bead + version bump only)

    Notes

    P2: optional portraits. The historical portraits are hung as framed picture props (texture on a frame model from the town kits).

    Prompts cite the locked style anchors from e37-asset-style-lock as reference inputs. Canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 4 asset ids listed in this bead, when the asset validator runs over assets/prompts/, then every id has exactly one prompt file whose asset id equals its filename stem and passes naming checks (<category>-<subject>-<variant>, ≤ 64 chars).
    • AC-2 content Given each prompt file, when the validator compares its preamble block with docs/art/style-bible.md §14, then it matches byte-for-byte and the correct §14.1 category add-on follows it.
    • AC-3 content Given each prompt file, when inspected, then it names its consuming bead(s), output spec (1024² generate → 512²/256² PNG → KTX2 UASTC, bust framing with head-room, softly blurred location-coloured background) and the filled consistency checklist, with no unfilled <…> placeholders.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt writes out the palette hexes, shape language and silhouette rules needed to meet the approval criterion: Snig and Mortimer match the approved cast portraits in style, and the two historical portraits read as old oil paintings in the world (varnish, frame) without legible text.
    • AC-5 content Edge: given a prompt that asks for text/letters, names an artist, studio or game, uses a non-canon name for a story-bible subject, or contains an API key pattern, when the validator runs, then it fails and names the file and line.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.285 Owner approval: named cast portraits open
    • mw-e37.5 Review and finalize image prompt templates open
    • mw-e39.1 Owner review and sign-off of the story bible; lock MVP canon done
    area:artasset:portraitepic:e37milestone:m3
  • mw-e37.288Generate secondary and historical portraits via Codex CLIblockedP2M3task

    Description

    Why

    Claude produces every image candidate so the owner only has to approve (contract §6).

    What

    Run e37-image-gen-runner (codex exec → gpt-image; fallback OpenAI Images API) for all 4 prompt files of e37-asset-portraits-secondary-prompts. Outputs land in assets/_incoming/<asset-id>/vN.png with a vN.json sidecar; Claude self-checks each candidate against its checklist, iterates, logs every iteration, then builds a batch review page for the owner.

    Scope

    • In: Batch generation in planned batches respecting subscription limits
    • In: Self-check + iteration log per asset
    • In: Batch review page (contact sheet) for the approval bead
    • Out: Owner approval (e37-asset-portraits-secondary-approve)
    • Out: Committing final assets (integrate bead)

    Notes

    Output spec: 1024² generate → 512²/256² PNG → KTX2 UASTC, bust framing with head-room, softly blurred location-coloured background. Record account tier in every sidecar — restrictive-tier outputs are placeholders only.

    Acceptance criteria

    • AC-1 integration Given the 4 prompt files, when the runner batch completes, then assets/_incoming/<asset-id>/vN.png and a vN.json sidecar (prompt path, tool, model, account tier, date) exist for every id.
    • AC-2 content Given each candidate, when checked against its output spec (1024² generate → 512²/256² PNG → KTX2 UASTC, bust framing with head-room, softly blurred location-coloured background), then dimensions, transparency/background and layout match or the iteration log records why it was regenerated.
    • AC-3 content Given the batch review page, when opened, then it shows every id with its latest version, the prompt path and the checklist result.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.
    • AC-5 integration Given all sidecars and iteration logs, when the secret scanner runs, then no API key or token is found.

    Waits on

    • mw-e37.287 Write secondary and historical portraits prompts (4 assets) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:portraitepic:e37milestone:m3
  • mw-e37.289Owner approval: secondary and historical portraitsblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the image gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the batch review page of 4 candidates and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: image, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-portraits-secondary-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Snig and Mortimer match the approved cast portraits in style, and the two historical portraits read as old oil paintings in the world (varnish, frame) without legible text. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "image".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Snig and Mortimer match the approved cast portraits in style, and the two historical portraits read as old oil paintings in the world (varnish, frame) without legible text.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-portraits-secondary-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.288 Generate secondary and historical portraits via Codex CLI open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:portraitepic:e37milestone:m3needs-human
  • mw-e37.290Integrate approved secondary and historical portraitsblockedP2M3task

    Description

    Why

    Final art replaces placeholders without touching gameplay code (contract §5: integration is a file swap).

    What

    Promote approved versions to assets/source/<category>/<asset-id>/, run the pipeline (atlas/KTX2 build as applicable), add assets/CREDITS.md rows and approval records, replace placeholder entries, and verify in-game.

    Scope

    • In: Source promotion, pipeline run, atlas rebuild
    • In: CREDITS rows + approval records in the same commit
    • In: Clearing placeholder flags for this set
    • Out: Gameplay/level logic (owned by the consuming beads)

    Notes

    Consumers: e22-dialogue-ui, e25-mooring-watch-encounters, e24-lamplit-stacks, e14-snig, e14-mortimer. Lower-priority consumers (e14-snig, e14-mortimer) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e37-asset-validator run, then runtime files exist under public/assets/ for all 4 ids and the validator (naming, budgets, licence, approval hash) is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool, model, account tier, date, prompt path and terms URL.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given Snig's and Mortimer's dialogues and the two framed portraits in the world, when rendered, then final portraits show with no placeholder flags and no console errors.
    • AC-5 perf Given the rebuilt textures, when e32-perf-budgets runs, then resident texture memory stays ≤ 256 MB on Low and the owning location package stays ≤ 25 MB.
    • AC-6 integration Edge: given an id in this set without an approval record, when the pipeline runs, then it refuses to promote that id, the placeholder stays in place, and the remaining-placeholder report lists it.

    Waits on

    • mw-e22.10 Build accessible dialogue UI with choices, tags and history done
    • mw-e24.5 Author the Lamplit Stacks bookshop on the e21 authoring template open
    • mw-e25.7 Place the Hollow Sentinels and goblin lookout with class resolutions open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.289 Owner approval: secondary and historical portraits open
    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    area:artasset:portraitepic:e37milestone:m3
  • mw-e37.319Select CC0 kit pieces for cemetery and schoolhouse props (7 models)blockedP2M3task

    Description

    Why

    The lychgate cemetery (Vesperine graves, the Mooring plot) and the empty schoolhouse are quiet lore spaces for the P2 story beads.

    What

    Bulk props come from CC0 kits recoloured to the palette, not from generation (contract §1, style bible §6.1 and §17.2). Write one kit brief per brief id in assets/prompts/prop/<brief-id>.md from prop-sheet.md (asset table, brief, target model list, output spec, consistency checklist, iteration log) — no image is generated. Instead Claude selects matching pieces from CC0-only kits, records source URL + licence file per piece, maps each piece to a target model id, plans the palette-atlas recolour (source colour → palette token hex from style bible §2.1/§2.2) and lists any piece no kit supplies as a gap for e37-asset-props-world-gapfill-*.

    Lychgate, Vesperine headstones with a small bell mark (two variants), the Mooring family plot, school desks, the slate board (rhyme rendered by the game font) and a stack of children's books.

    Kit brief ids (2):

    • prop-cemetery-set-01
    • prop-school-set-01

    Target model ids (7):

    • model-prop-lychgate-01
    • model-prop-headstone-vesperine-01
    • model-prop-headstone-vesperine-02
    • model-prop-mooring-plot-01
    • model-prop-school-desk-01
    • model-prop-slate-board-01
    • model-prop-books-children-01

    Scope

    • In: Kit brief per brief id; piece → model id mapping with licence
    • In: Recolour map and interaction sockets needed by consumers (breakable, liftable, hide)
    • In: Gap list handed to the gap-fill chain
    • Out: Download/recolour/import (e37-asset-props-cemetery-school-kit-kit-recolour)

    Notes

    P2 to match e24-cemetery-schoolhouse. Gaps here are sourced CC0-only or cut; the P1 gap-fill chain does not wait on this set.

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). Allowed sources: CC0 only (Kenney, Quaternius, KayKit-style packs verified CC0, OpenGameArt CC0) per style bible §16; no CC-BY-SA/NC, no "royalty-free, no redistribution".

    Acceptance criteria

    • AC-1 content Given the 2 brief ids, when the asset validator runs, then each has exactly one kit brief whose id equals its filename stem and passes naming checks.
    • AC-2 content Given the 7 target model ids, when the briefs are audited, then every id maps to exactly one CC0 source piece (kit, piece name, source URL, licence file path) or appears in the gap list.
    • AC-3 content Given each recolour map, when validated, then every target colour is a palette hex from style bible §2.1 or the location row in §2.2.
    • AC-4 content Given each brief, when inspected, then it records the §13.2 budget (small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2)) and which legibility cues from style bible §7 each interactive piece must carry.
    • AC-5 content Edge: given a piece whose licence is not CC0 (CC-BY-SA, NC, ND, unknown provenance), when the validator runs, then it fails naming the piece and brief.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.261 Owner approval: optional Briar Glen and slice concepts open
    • mw-e37.6 Spike: 3D sourcing — CC0 kits plus Meshy vs Tripo API bake-off open
    • mw-e37.7 Placeholder asset kit: CC0 stand-ins at correct scale and naming open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.320Recolour cemetery and schoolhouse props from CC0 kitsblockedP2M3task

    Description

    Why

    Kits only look like one game once they share the palette atlas and the stylized material (style bible §6).

    What

    Download the selected kits unmodified to assets/kits/<kit>/ with their licence files, derive each target model into assets/_incoming/<asset-id>/vN.glb (palette-atlas UV remap, merge to budget, pivots/colliders, interaction sockets and breakable fracture pieces where the brief asks), run automated validation, and render turntables/contact sheets with e37-turntable-preview.

    Scope

    • In: Kit download with licence, recolour, merge, sockets
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model, one contact sheet per brief
    • Out: Owner approval (e37-asset-props-cemetery-school-kit-kit-approve)

    Notes

    Budget: small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2). The palette remap is scripted in the model pipeline; e37-texture-atlas-build (P2) may later replace the script without changing ids.

    Acceptance criteria

    • AC-1 integration Given the approved briefs, when the recolour script runs, then each of the 7 model ids has a vN.glb + sidecar (kit, piece, source URL, licence, date) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and uses only the shared prop atlas material.
    • AC-3 integration Given assets/kits/, when audited, then every kit folder is byte-identical to its download and contains its licence file.
    • AC-4 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist, plus one contact sheet per brief on the review page.
    • AC-5 integration Edge: given a model whose sampled albedo colours fall outside the palette (ΔE > 3 from every palette hex), when validated, then it is flagged on the review page and not offered for approval.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.319 Select CC0 kit pieces for cemetery and schoolhouse props (7 models) open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.321Owner approval: cemetery and schoolhouse props kit turntablesblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the recoloured kit turntables and contact sheets of the 7 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-props-cemetery-school-kit-kit-recolour with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Vesperine headstones carry the bell mark (not text), the Mooring plot is findable as a landmark, and the schoolroom reads as abandoned mid-lesson. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 7 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Vesperine headstones carry the bell mark (not text), the Mooring plot is findable as a landmark, and the schoolroom reads as abandoned mid-lesson.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-props-cemetery-school-kit-kit-recolour with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.320 Recolour cemetery and schoolhouse props from CC0 kits open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.322Integrate approved cemetery and schoolhouse propsblockedP2M3task

    Description

    Why

    Final props replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs/impostors), bind to the stylized material, wire model ids into the content data of the consuming areas, add CREDITS rows (kit, licence, source URL) and approval records, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + turntable approval records
    • In: Placeholder swap
    • Out: Placement and level logic (consuming beads)
    • Out: Gap pieces (e37-asset-props-world-gapfill-integrate)

    Notes

    Consumers: e24-cemetery-schoolhouse.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 7 models are under public/assets/model/ within small props 50–400 tris, medium 400–2 k, large 2–5 k (LOD1 50 %), trees ≤ 3 k + impostor, prop atlas, one shared material per set (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (kit, piece, licence, source URL, date) and a turntable approval record.
    • AC-3 e2e Given the cemetery and schoolhouse, when Playwright loads them, then final props render with no placeholder models and no console errors.
    • AC-4 perf Given the owning area with these props placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low, with this set using one material.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e24.11 Build the lychgate cemetery and the empty schoolhouse open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.321 Owner approval: cemetery and schoolhouse props kit turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.393Write Snig and Mortimer creatures concept prompts (2 images)blockedP2M3task

    Description

    Why

    Snig (the pickpocketing goblin who wants to read) and Mortimer (the tame book mimic) are P2 social characters with a lot of charm per polygon.

    What

    Write one prompt file per concept image in assets/prompts/<category>/<asset-id>.md (category: creature) from creature-reference-sheet.md, flat front-facing on plain parchment so the image-to-3D API gets clean input, with the GPT STYLE PREAMBLE (style bible §14) verbatim, output spec and consistency checklist.

    Snig: small, quick, sticky-fingered, a stolen primer tucked somewhere, on the goblin rig; Mortimer: a plump, well-oiled, slightly smug book with a red ribbon tongue.

    Concept image ids (2):

    • creature-goblin-snig-01
    • creature-mimic-mortimer-01

    Target model ids (2):

    • model-creature-goblin-snig-01
    • model-creature-mimic-mortimer-01

    Scope

    • In: Concept/reference prompt per id above
    • In: Model output spec (tri budget, texture, bones) recorded in each prompt
    • Out: 3D generation (e37-asset-creatures-social-secondary-3d-generate)

    Notes

    P2 to match e14-snig and e14-mortimer. Clips reuse the goblin and mimic sets (e37-asset-anim-goblins-*, e37-asset-anim-constructs-*).

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2). Prompts cite the locked style anchors from e37-asset-style-lock; canon names and details follow docs/narrative/story-bible.md.

    Acceptance criteria

    • AC-1 content Given the 2 concept ids, when the asset validator runs, then each has exactly one prompt file whose id equals its filename stem and passes naming checks.
    • AC-2 content Given each prompt file, when compared with docs/art/style-bible.md §14 and §14.1, then the preamble and category add-on match byte-for-byte.
    • AC-3 content Given each prompt file, when inspected, then it records the §13.2 model budget (standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2)) and the silhouette/palette rules from §5 relevant to the asset.
    • AC-4 content Given the set, when reviewed against the bible, then every prompt spells out what the approval criterion needs: Snig reads smaller and quicker than other goblins with the primer visible, and Mortimer reads as a friendly version of the book mimic.
    • AC-5 content Edge: given a prompt asking for perspective views, cast shadows or busy backgrounds that break image-to-3D, or containing text requests, a non-canon name or an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e37.1 Review and sign off the visual style bible and GPT style preamble done
    • mw-e37.142 Lock approved style anchor images for all later image prompts open
    • mw-e37.289 Owner approval: secondary and historical portraits open
    • mw-e37.371 Owner approval: Rootcellar goblin creatures flat concepts open
    • mw-e37.383 Owner approval: bestiary creatures flat concepts open
    • mw-e37.5 Review and finalize image prompt templates open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.394Generate Snig and Mortimer creatures concepts via Codex CLIblockedP2M3task

    Description

    Why

    Image-to-3D quality depends on a clean, approved flat concept (style bible §17.2).

    What

    Run e37-image-gen-runner for all 2 concept prompts into assets/_incoming/<asset-id>/vN.png + sidecar; self-check against the checklist (silhouette at 64 px, palette, flat lighting) and iterate; build the review page.

    Scope

    • In: Concept generation and iteration log
    • In: Silhouette test renders (solid ink at 64 px) on the review page
    • Out: Owner approval (e37-asset-creatures-social-secondary-concept-approve)

    Notes

    Record account tier in every sidecar.

    Acceptance criteria

    • AC-1 integration Given the 2 prompts, when the batch completes, then every id has vN.png + vN.json (prompt path, tool, model, tier, date) in assets/_incoming/.
    • AC-2 content Given each candidate, when auto-checked, then it is front-facing on a plain parchment background with no cast shadows, or the iteration log records a regeneration.
    • AC-3 content Given the review page, when opened, then each candidate shows alongside its solid-ink 64 px silhouette.
    • AC-4 integration Edge: given the image runner hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e37.393 Write Snig and Mortimer creatures concept prompts (2 images) open
    • mw-e37.4 Image generation runner wrapping codex exec with Images API fallback open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.395Owner approval: Snig and Mortimer creatures flat conceptsblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the flat concept gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the 2 flat concept images and their silhouette tests and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: flat concept, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-social-secondary-concept-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Snig reads smaller and quicker than other goblins with the primer visible, and Mortimer reads as a friendly version of the book mimic. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "flat concept".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Snig reads smaller and quicker than other goblins with the primer visible, and Mortimer reads as a friendly version of the book mimic.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-social-secondary-concept-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.394 Generate Snig and Mortimer creatures concepts via Codex CLI open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.396Generate Snig and Mortimer creatures 3D models via image-to-3D APIblockedP2M3task

    Description

    Why

    The owner never does 3D work; Claude turns approved flats into game-ready models (contract §1).

    What

    For each of the 2 target models: call e37-3d-gen-api-client (Meshy or Tripo per e37-3d-pipeline-decision) with the approved flat, remesh/retopo to budget, rig/animate via API where applicable, download to assets/_incoming/<asset-id>/vN.glb, run automated validation, and render turntables with e37-turntable-preview.

    Scope

    • In: API jobs, retopo, rig
    • In: Automated budget/naming/licence validation
    • In: Turntable PNG strip + GIF per model
    • Out: Turntable approval (e37-asset-creatures-social-secondary-turntable-approve)

    Notes

    Budget: standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2). API keys only from MESHY_API_KEY / TRIPO_API_KEY env vars.

    Acceptance criteria

    • AC-1 integration Given the approved flats, when the API client runs, then each of the 2 model ids has a vN.glb + sidecar (provider, model version, tier, job id, date, source image hash) in assets/_incoming/.
    • AC-2 integration Given each glb, when validated, then it meets standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2), or the job is re-run with adjusted retopo settings and the iteration log says why.
    • AC-3 integration Given each glb, when e37-turntable-preview runs, then a PNG strip (8 angles) and a GIF exist for the review page.
    • AC-4 integration Edge: given an API job that fails or times out, when the client retries with back-off, then at most 3 attempts are made, no duplicate paid job is started for an id with a completed job, and the failure is reported per id.
    • AC-5 integration Given sidecars and logs, when the secret scanner runs, then no API key appears.

    Waits on

    • mw-e37.10 Headless turntable preview of a glb as PNG strip and GIF open
    • mw-e37.395 Owner approval: Snig and Mortimer creatures flat concepts open
    • mw-e37.9 Image-to-3D API client and CLI for the chosen provider open
    area:artasset:modelepic:e37milestone:m3
  • mw-e37.397Owner approval: Snig and Mortimer creatures turntablesblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the turntable gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the turntable strips/GIFs of the 2 models and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: turntable, version, SHA-256, approver, date, notes). Rejected items loop back to e37-asset-creatures-social-secondary-3d-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Snig reads smaller and quicker than other goblins with the primer visible, and Mortimer reads as a friendly version of the book mimic. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 2 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "turntable".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Snig reads smaller and quicker than other goblins with the primer visible, and Mortimer reads as a friendly version of the book mimic.
    • AC-3 manual Given each turntable, when compared with its approved flat concept, then proportions, palette and signature shapes match and there are no holes, floating geometry or smeared textures.
    • AC-4 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e37-asset-creatures-social-secondary-3d-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-5 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e37.396 Generate Snig and Mortimer creatures 3D models via image-to-3D API open
    area:artasset:modelepic:e37milestone:m3needs-human
  • mw-e37.398Integrate approved Snig and Mortimer creaturesblockedP2M3task

    Description

    Why

    Final models replace greybox stand-ins without touching gameplay code (contract §5).

    What

    Promote approved glbs through e37-model-import-pipeline (meshopt + KTX2, LODs), bind to the stylized material, wire into content data, add CREDITS rows and approval records for both gates, and swap out the placeholder models.

    Scope

    • In: Import pipeline, LODs, material binding
    • In: CREDITS + approval records (flat concept + turntable)
    • In: Placeholder swap
    • Out: Gameplay logic (consuming beads)

    Notes

    Consumers: e14-snig, e14-mortimer.

    Acceptance criteria

    • AC-1 integration Given the approved glbs, when the import pipeline and e37-asset-validator run, then all 2 models are under public/assets/model/ within standard creature 2–6 k tris, LOD1 50 %, LOD2 20 %, T1 512², 1 material, ≤ 65 bones (style bible §13.2) and the validator is green.
    • AC-2 content Given assets/CREDITS.md and assets/approvals.json, when audited, then every model has a CREDITS row (provider, tier, date, prompt path, terms URL) and approval records for both the flat-concept and turntable gates.
    • AC-3 e2e Given the Deepworks and the Lamplit Stacks, when Snig and Mortimer are spawned, then final models load on the shared rigs and no console errors occur.
    • AC-4 perf Given the owning area with these models placed, when e32-perf-budgets runs, then draw calls stay ≤ 150 and visible triangles ≤ 500 k on Low.
    • AC-5 integration Edge: given a model with a turntable approval but a changed file hash, when CI runs, then integration is refused and the placeholder remains.

    Waits on

    • mw-e14.4 Bring Snig to life: pocket-picking, reading lessons and vouching open
    • mw-e14.7 Add Mortimer, the tame book mimic who guards the rare shelf open
    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    • mw-e37.397 Owner approval: Snig and Mortimer creatures turntables open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    area:artasset:modelepic:e37milestone:m3
E38Audio Direction & Asset PipelineThe Vesper Bell sounds like one world — acoustic dark-folk music (hurdy-gurdy, nyckelharpa, low strings, wordless choir) that adapts to exploration, stealth, tension and combat, and tactile SFX whose loudness and character match the stealth/sound simulation — produced with Suno and a decided SFX source through a validated, licence-tracked pipeline.4/181 done · 2%

M1 Grey-box slice 5

  • mw-e38.2Spike: SFX sourcing — ElevenLabs Sound Effects API vs CC0openP1M1spike

    Description

    Why

    We need hundreds of SFX (footsteps × surfaces × gaits, 13 spell schools, creature states, UI) with clean licences for a public repo and consistent character.

    What

    Time-box 1 day. Question: which source (or hybrid) gives the best quality/consistency/licence-safety per hour for our SFX list? Claude produces the same 12-sound test set via (a) the ElevenLabs Sound Effects API with the SFX PREAMBLE (end-to-end, no owner generation work) and (b) CC0 libraries (Kenney, freesound CC0-only filter, OpenGameArt CC0), scores them, the owner listens at a recorded SFX-batch gate, and an ADR records the decision.

    Scope

    • In: 12-sound test set: stone walk ×3 round-robin, gravel run, wood door creak, sword parry metal, arrow release, fire cast, frost impact, skeleton collapse, goblin chatter, minotaur bellow (angry + calm), UI page turn
    • In: Scoring: fit to audio bible palette, dryness/cleanliness, round-robin variety, time per usable sound, licence clarity for a public repo, cost
    • In: Licence/terms review per source and tier
    • Out: Producing the full SFX set (later prompt/generate beads)
    • Out: Import pipeline (see e38-audio-import-pipeline)

    Notes

    Recommendation going in: ElevenLabs Sound Effects API as primary — official API lets Claude generate end-to-end from the template (text prompt, duration, prompt influence) and the owner only approves by listening; strongest for signature sounds (13 schools of magic, the minotaur's dual-character vocals, goblin gibberish, creature state sets). CC0 libraries as fallback/bulk (Kenney, freesound CC0-only, OpenGameArt CC0) for footsteps, UI, doors and ambience where they are better or cheaper. Use a paid ElevenLabs tier for shipping sounds (free tiers typically require attribution and/or restrict commercial use — verify at spike time). Avoid "royalty-free, no redistribution" libraries for files committed to a public repo. Key from ELEVENLABS_API_KEY env only. Feeds e38-sfx-gen-client.

    Acceptance criteria

    • AC-1 manual Given the 12-sound test set produced from each source, when scored with the rubric, then an ADR in docs/adr/ records per-sound scores, time spent, cost and the chosen approach per SFX category.
    • AC-2 manual Given each candidate source and tier, when licence terms are reviewed, then the ADR quotes the relevant clauses (with URL and date) on redistribution in a public repository and attribution.
    • AC-3 content Given the test sounds committed as placeholders, when validated, then each has a CREDITS row with source URL/tool, tier, date and licence.
    • AC-4 manual Given the minotaur angry and calm bellows, when played back-to-back, then the ADR records whether the chosen source can produce the "same creature, two emotions" requirement from audio bible §7.5.
    • AC-5 manual Edge: given a CC0 library sound whose licence metadata is ambiguous or later changed, when found, then it is excluded and the ADR notes the rule "CC0 confirmed on the file page at download time, screenshot or archived URL kept".

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    area:sfxasset:sfxepic:e38milestone:m1
  • mw-e38.3Review and finalize music, stinger and SFX prompt templatesblockedP1M1task

    Description

    Why

    Per-asset music and SFX prompt beads copy these templates; they must encode key/BPM family locking, loudness and loop rules so every asset arrives pipeline-ready.

    What

    Review assets/prompts/_templates/music-track.md, music-stinger.md and sfx.md against the signed-off audio bible and the SFX tool ADR; add one worked example each (music-briar-glen-day-explore, music-stinger-combat-start-d-dorian, sfx-foot-stone-walk-01..06).

    Scope

    • In: Template edits
    • In: Three worked examples
    • In: Suno UI field names updated to the current product
    • Out: Per-asset music/SFX prompt beads (later wave)

    Notes

    The SFX template must support both library sourcing (search brief + per-file provenance) and generation (SFX PREAMBLE).

    Acceptance criteria

    • AC-1 content Given the three audio templates, when inspected, then each contains asset id, consuming bead(s), filled prompt with preamble placeholder, output spec (key/BPM/length/loop/format/LUFS), consistency checklist, iteration log and provenance table.
    • AC-2 manual Given the worked music example, when run in Suno, then the result matches the requested key and BPM (verified with an analyser) and contains no vocals.
    • AC-3 manual Given the worked SFX example, when sourced per the ADR, then 6 round-robin footsteps pass the audio validator and the loudness ordering sneak < walk < run holds.
    • AC-4 manual Edge: given a Suno UI change that renames or removes a field referenced by a template (e.g. Exclude styles), when discovered, then the template documents the fallback (append negatives to Style).

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.2 Spike: SFX sourcing — ElevenLabs Sound Effects API vs CC0 open
    area:musicarea:sfxepic:e38milestone:m1
  • mw-e38.4Audio validator: loudness, true peak, loop seams, naming and licenceblockedP1M1task

    Description

    Why

    Loudness and loop quality are invisible in code review and easy to get wrong across many files and tools; a clicking loop or a 6 dB-hot SFX ruins feel.

    What

    As a developer, I want pnpm assets:validate to check audio against the audio bible so that CI rejects files outside loudness targets, with bad loop seams, wrong channel counts or missing credits. Checks: integrated LUFS and true peak per category (BS.1770 K-weighting, gating); leading silence for one-shots; mono for positional SFX; sidecar JSON schema (bpm, beatsPerBar, loop points); loop length = whole bars (± 1 ms); seam discontinuity (sample delta + short-window RMS jump); naming + CREDITS (reusing e37-asset-validator).

    Scope

    • In: Pure TS loudness meter (BS.1770-4) and loop analysis over decoded PCM
    • In: Category targets as data (shared with the bible)
    • In: Sidecar zod schema
    • In: CI integration
    • Out: Encoding/normalising (see e38-audio-import-pipeline)
    • Out: Runtime mixing (see e28-audio-engine)

    Notes

    Owner requirement: 100 % tested. Test fixtures: synthetic sines/noise with known LUFS (e.g. 1 kHz sine at −20 dBFS ≈ −20.0 LUFS mono per spec reference) and deliberately clicking loops.

    Acceptance criteria

    • AC-1 unit Given the EBU reference 1 kHz stereo sine at −23 dBFS, when measured, then integrated loudness is −23.0 ± 0.1 LUFS.
    • AC-2 unit Given a music file measured at −14 LUFS in the music-explore category (target −18 ± 1), when validated, then it fails with actual vs target.
    • AC-3 unit Given a loop whose end sample jumps by > 0.1 full-scale versus its start, or whose length is not a whole number of bars at its sidecar BPM, when validated, then it fails naming the seam or length error.
    • AC-4 unit Given a positional SFX file with 2 channels or > 10 ms leading silence, when validated, then it fails with the specific rule.
    • AC-5 unit Edge: given a silent file, a truncated/corrupt file or a sidecar with loopEnd ≤ loopStart, when validated, then each produces a clear error (no NaN loudness, no crash) and validation continues with other files.
    • AC-6 unit Given the validator source, when coverage runs, then lines, branches, functions and statements are all 100 %.

    Waits on

    • mw-e00.1 Scaffold TypeScript/Vite/pnpm repo with lint, typecheck and Vitest done
    • mw-e37.2 Asset validator: naming, budgets and licence entries in CI open
    area:sfxarea:toolsepic:e38milestone:m1
  • mw-e38.5Audio import pipeline: normalise, encode Opus/AAC, loop metadatablockedP1M1task

    Description

    Why

    Suno, SFX tools and libraries deliver inconsistent sample rates, levels and formats; the browser needs small Opus files with AAC fallback and sample-accurate loops.

    What

    As a developer, I want pnpm assets:build to ingest the owner's Suno takes from assets/_incoming/music/<asset-id>.wav (and generated/CC0 SFX from assets/_incoming/<asset-id>/), promote approved files to assets/source/, and process them into public/assets/audio/ so that every file is 48 kHz, loudness-normalised to its category target, trimmed, encoded (Opus .ogg + AAC .m4a) and accompanied by a sidecar JSON with loop points compensated for encoder pre-skip/priming, then validated.

    Scope

    • In: ffmpeg-based (pinned) node script: resample, trim, normalise (two-pass loudnorm), encode
    • In: Pre-skip/priming compensation for loop points
    • In: Audio manifest (asset id → URLs, duration, bytes, loop info)
    • In: Incremental cache
    • Out: Loudness/loop checking logic (see e38-audio-validator, invoked as final step)
    • Out: Playback (see e28-audio-engine)

    Notes

    Opus pre-skip is typically 312 samples at 48 kHz; read the actual value from the Ogg header. Bitrates per audio bible §5.2. Initial-load audio ≤ 8 MB.

    Acceptance criteria

    • AC-1 integration Given a 44.1 kHz WAV music source at −10 LUFS, when built, then outputs are 48 kHz Opus .ogg and AAC .m4a measuring within the category target ± 1 LU and ≤ its true-peak ceiling.
    • AC-2 integration Given a source with sidecar loop points, when built and decoded, then the decoded Opus loop region matches the source loop region sample-for-sample within ± 1 sample after pre-skip compensation.
    • AC-3 e2e Given a built loop played in the browser via the audio engine test page for 3 iterations, when recorded, then no seam discontinuity is detected by the validator's seam check.
    • AC-4 integration Given the built audio manifest, when summed for files tagged initial, then the total is ≤ 8 MB, otherwise the build fails.
    • AC-5 integration Edge: given a source that is clipped (true peak > 0 dBTP) or mostly silent, when built, then the build reports it and does not normalise silence upward beyond +20 dB gain.

    Waits on

    • mw-e38.4 Audio validator: loudness, true peak, loop seams, naming and licence open
    area:musicarea:toolsepic:e38milestone:m1
  • mw-e38.6Placeholder audio kit: CC0 stand-ins with final asset idsblockedP1M1task

    Description

    Why

    The m1 vertical slice needs feedback sounds (footsteps, hits, UI, a loop) to judge feel; final audio must not block gameplay.

    What

    Assemble CC0 placeholders named with their final asset ids: footsteps for stone/wood/dirt/grass (walk/run/sneak, 4 round-robins), melee hit/block/parry, bow draw/release, one spell cast/impact, door/lever/chest, skeleton/goblin vocals, UI set, one ambience bed and one placeholder music loop — processed by the import pipeline.

    Scope

    • In: CC0 selection (Kenney, freesound CC0-only)
    • In: Final-format ids + CREDITS rows flagged placeholder
    • In: Catalogue listing id → placeholder
    • Out: Final audio (per-asset beads)
    • Out: Audio engine wiring (Related: e28-audio-engine consumers)

    Notes

    Keep placeholder loudness on-target so mix decisions made in m1/m2 still hold when finals arrive.

    Acceptance criteria

    • AC-1 content Given the catalogue, when validated, then every placeholder has a final-format id, passes loudness/format checks and has a CC0 CREDITS row with placeholder: yes.
    • AC-2 integration Given the footstep set, when measured, then mean loudness orders sneak < walk < run for every surface.
    • AC-3 e2e Given the greybox testbed with the audio engine, when the player walks across each placeholder surface, then the matching surface sound plays (verified via the audio debug log).
    • AC-4 integration Edge: given an asset id referenced by content data with no placeholder or final file, when content validation runs, then it fails naming the missing id.

    Waits on

    • mw-e28.1 Web Audio engine: registry, buses, voice pool, positional audio done
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    area:musicarea:sfxepic:e38milestone:m1

M2 Class fantasies 17

  • mw-e38.7ElevenLabs Sound Effects API client for Claude-run SFX generationblockedP1M2task

    Description

    Why

    With an official API, Claude can generate SFX end-to-end from the template while the owner just listens and approves — SFX "generate" tasks become Claude-run.

    What

    As a developer, I want pnpm assets:gen-sfx <prompt-file> to call the ElevenLabs Sound Effects API with the SFX PREAMBLE + template prompt (duration, prompt influence, round-robin count), save each take to assets/_incoming/<asset-id>/vN.wav (or the API's format converted to WAV) with vN.json provenance, run the audio import pipeline and validator, and build a batch listening page/playlist for the owner's SFX-batch approval gate.

    Scope

    • In: Client in src/tools/assets/sfx-gen/ with HTTP behind an injectable interface
    • In: Round-robin generation (n takes per sound)
    • In: Retry/backoff on 429/5xx, character/credit usage recorded
    • In: Batch preview HTML listing takes with approve/reject commands
    • Out: Approval recording (see e37-asset-approval-log)
    • Out: CC0 library sourcing (manual/Claude-scripted per ADR)

    Notes

    Only if e38-sfx-tool-decision confirms ElevenLabs. Key only from ELEVENLABS_API_KEY env — never logged, committed or written to vN.json. 100 % coverage with HTTP mocked (no live calls in CI). Refuse to run if the prompt file preamble differs from audio bible §8.

    Acceptance criteria

    • AC-1 unit Given a filled SFX prompt file with round-robin count 4 and a mocked API returning audio, when gen-sfx runs, then 4 takes are saved as v1..v4 with vN.json provenance (tool, model, duration, date) and the validator is invoked on each.
    • AC-2 unit Given a prompt file whose SFX PREAMBLE differs from the audio bible, when run, then it refuses before any HTTP call.
    • AC-3 unit Given 429 then success, when called, then the client backs off (injected clock) and succeeds, recording attempts.
    • AC-4 integration Given a completed batch, when the preview page is generated, then it lists every take with its asset id, loudness and an approve/reject command line.
    • AC-5 unit Edge: given a missing ELEVENLABS_API_KEY or an error response body echoing headers, when logs are captured, then the key value never appears and the missing-key case exits non-zero with setup instructions.
    • AC-6 unit Given the client module, when coverage runs, then all four metrics are 100 %.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.2 Spike: SFX sourcing — ElevenLabs Sound Effects API vs CC0 open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    area:sfxarea:toolsasset:sfxepic:e38milestone:m2
  • mw-e38.8Spike: prove a key/BPM-locked Suno family with bar-synced cutsblockedP1M2spike

    Description

    Why

    Adaptive music (explore/stealth/tension/combat) is core to stealth feel, but Suno outputs full mixes of unpredictable key/length; we must prove a workable method before producing ~12 location families.

    What

    Time-box 1.5 days. Using the labyrinth family (E Phrygian, ~58/116 BPM), generate an explore anchor and derive stealth/tension/combat variants via Extend/Cover/audio-reference; test stem export/separation if available on the tier; cut loop points; prototype bar-synced crossfades + stingers in the audio engine test page. ADR records the method, success rate and Suno tier needed.

    Scope

    • In: One full family + 2 stingers
    • In: Key/BPM verification method
    • In: Stem evaluation
    • In: Transition prototype
    • In: Suno licence tier confirmation for shipping music
    • Out: Producing other location families
    • Out: Final music state mapping (see e38-music-state-data)

    Notes

    Fallbacks if derivation fails: (1) accept separate generations in the same key/BPM and mask transitions with stingers; (2) vertical-only approach using separated stems of one track; (3) use drone-only states. Generate shipping takes on a paid tier (audio bible §4).

    Acceptance criteria

    • AC-1 manual Given the labyrinth family, when analysed, then all four state tracks share the same key/mode and a BPM relationship of 1:1 or 1:2, and the ADR records how many generations were needed per usable track.
    • AC-2 e2e Given the transition prototype, when state switches explore→tension→combat→resolve are triggered at random times, then each transition begins on the next bar boundary (± 10 ms) and the validator seam check reports no clicks.
    • AC-3 manual Given stem export/separation on the current tier, when evaluated on the anchor track, then the ADR states whether stems are clean enough for vertical layering (yes/no with listening notes).
    • AC-4 manual Given the ADR, when read, then it states the required Suno tier, the terms URL and date consulted, and the per-family production recipe.
    • AC-5 manual Edge: given a derived variant that drifts in key or tempo, when detected, then the ADR documents the detection method and the chosen fallback.

    Waits on

    • mw-e28.1 Web Audio engine: registry, buses, voice pool, positional audio done
    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    area:musicasset:musicepic:e38milestone:m2needs-human
  • mw-e38.9Data-driven music state mapping from alert states with hysteresisblockedP1M2feature

    Description

    Why

    Music is a stealth cue: tension must start exactly when a creature investigates and never lie (audio bible §2.1). The rules belong in data so designers can tune them per location.

    What

    As a thief, I want the music to shift to tension only when a creature is actually investigating me so that the score is a trustworthy cue. Define a zod-validated music-state config per location (tracks per state, BPM/beatsPerBar, hysteresis delays, stingers, silence budget) and a pure sim-side selector: highest-priority creature alert state → music state, with enter-immediate / exit-after-delay hysteresis.

    Scope

    • In: Schema + data files in src/content/music/
    • In: Pure selector in src/sim (deterministic, injected clock)
    • In: Game-layer binding to the audio engine's transition API
    • Out: Audio engine transitions/crossfades (Related: e28-audio-engine)
    • Out: Alert state logic (see e11-alert-states)

    Notes

    Defaults from audio bible §2.1: combat enter next beat, exit after 4 s; tension exit after 6 s; silence 60–180 s after 1–2 explore loops.

    Acceptance criteria

    • AC-1 unit Given one creature transitioning Unaware → Investigating, when the selector runs, then the music state becomes tension on that tick.
    • AC-2 unit Given the last combat creature leaving Combat, when 3.9 s elapse the state is still combat, and when 4.0 s elapse it becomes resolve then tension/explore per the remaining creatures.
    • AC-3 unit Given rapid Searching ↔ Alerted flapping every 1 s, when the selector runs for 20 s, then the music state changes at most twice.
    • AC-4 content Given every location music config, when validated, then each referenced track id exists in the audio manifest and all tracks in a family share BPM and beatsPerBar.
    • AC-5 unit Edge: given a creature that loses track of the player (Searching → Unaware) while another is Suspicious, when evaluated, then music stays at the highest remaining state (stealth) rather than dropping to explore.

    Waits on

    • mw-e00.18 Load schema-validated content with a per-entry test harness done
    • mw-e11.7 Six-state alert machine: Unaware to Combat with timed decay done
    • mw-e28.1 Web Audio engine: registry, buses, voice pool, positional audio done
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:contentarea:musicclass:thiefepic:e38milestone:m2
  • mw-e38.10Audio style target: full soundscape for the style-target dioramablockedP1M2task

    Description

    Why

    Like the visual diorama, one finished sonic slice sets the benchmark for mix, reverb and palette before full production.

    What

    Give the style-target diorama its final-quality soundscape: golden-hour ambience bed + randomised one-shots, footsteps on each diorama surface, weak-wall draught, flammable rope bridge creak and burn, one spell (cast/loop/impact), one creature vocal set, the Briar Glen explore→tension→combat family and stingers, location reverb.

    Scope

    • In: Assets via the chosen SFX source and Suno per templates
    • In: Mix pass on the audio engine buses
    • In: Reference recording (video capture) committed for comparison
    • Out: Other locations
    • Out: Engine features (Related: e28-audio-engine)

    Notes

    Its reference capture becomes the mix benchmark for e38-mix-review.

    Acceptance criteria

    • AC-1 integration Given a 3-minute scripted diorama walkthrough capture, when measured, then master integrated loudness is −16 ± 2 LUFS and true peak ≤ −1 dBTP.
    • AC-2 manual Given the weak wall and the hidden well tunnel, when approached with eyes closed, then a listener can locate them by the draught/air cue within 5 m.
    • AC-3 integration Given all diorama audio assets, when validated, then each passes the audio validator and has a non-placeholder CREDITS row.
    • AC-4 manual Edge: given 6 simultaneous impact sounds plus combat music, when played, then no clipping occurs and the parry sound remains audible (voice-limiting/priority works).

    Waits on

    • mw-e37.15 Build the style-target diorama as the visual and performance benchmark open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicarea:sfxepic:e38milestone:m2
  • mw-e38.12Write knight combat SFX prompts (14 assets)blockedP1M2task

    Description

    Why

    Knight combat is proven by feel; a parry that rings and a heavy swing that whooms are half of that feel (souls-like weight).

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Light and heavy sword swings, wood/metal shield blocks, parry, guard break, riposte, shield bash, kick, dodge rolls (cloth, armour), charge-ready cue, stamina-exhausted cue and wall-recoil clang; ≥ 3 round-robin variants for swings/blocks.

    Asset ids (14):

    • sfx-knight-sword-swing-light-01
    • sfx-knight-sword-swing-heavy-01
    • sfx-knight-block-shield-wood-01
    • sfx-knight-block-shield-metal-01
    • sfx-knight-parry-metal-01
    • sfx-knight-guard-break-01
    • sfx-knight-riposte-01
    • sfx-knight-shield-bash-01
    • sfx-knight-kick-01
    • sfx-knight-dodge-roll-cloth-01
    • sfx-knight-dodge-roll-armor-01
    • sfx-knight-charge-ready-01
    • sfx-knight-stamina-exhausted-01
    • sfx-knight-wall-recoil-clang-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-knight-combat-generate)

    Notes

    m2 because the Forgotten (skeleton) fun validation and class-fantasy playtests judge combat feel; CC0 placeholders (e28-placeholder-sounds) keep gameplay unblocked. One of the sonic-lock anchor sets. Charge-ready and parry must be distinguishable for players relying on audio cues (captions via e28-sound-captions).

    Acceptance criteria

    • AC-1 content Given the 14 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:sfxasset:sfxclass:knightepic:e38milestone:m2
  • mw-e38.13Generate knight combat SFX via ElevenLabs or CC0blockedP1M2task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-knight-combat-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 14 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.12 Write knight combat SFX prompts (14 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxclass:knightepic:e38milestone:m2
  • mw-e38.14Owner approval: knight combat SFXblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 14 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-knight-combat-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: parry is unmistakable from a block and heavy swings sound heavier than light ones. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 14 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then parry is unmistakable from a block and heavy swings sound heavier than light ones.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-knight-combat-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.13 Generate knight combat SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxclass:knightepic:e38milestone:m2needs-human
  • mw-e38.15Integrate approved knight combat SFXblockedP1M2task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-combat-hit-audio, e04-melee-core, e04-parry-riposte, e04-shield-bash, e04-kick-verb, e04-heavy-charged, e04-weapon-reach, e04-dodge-iframes.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 14 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the combat sandbox, when the knight performs every move, then each cue plays the final sound (no placeholder flag) via the cue sheet with no console errors.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e04.12 Parry window and riposte critical attack done
    • mw-e04.13 Heavy and charged attacks with hyperarmor done
    • mw-e04.14 Shield bash interrupts, shoves and breaks bashable objects done
    • mw-e04.15 Weapon reach classes and swing-type wall recoil done
    • mw-e04.18 Kick verb shoves creatures and physics objects done
    • mw-e04.6 Knight light attack chain and shield block with guard break done
    • mw-e04.8 Dodge roll and backstep with invulnerability frames done
    • mw-e28.4 Combat impact audio matrix: hits, blocks, parries, whiffs done
    • mw-e38.14 Owner approval: knight combat SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxclass:knightepic:e38milestone:m2
  • mw-e38.16Write impact and Forgotten SFX prompts (15 assets)blockedP1M2task

    Description

    Why

    Every systemic material must sound different the way the sim treats it (audio bible §7.1), and the Forgotten (animated skeletons) are the first enemy the combat loop is validated against.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Impact matrix (blade-flesh, blade-bone, metal-metal, blunt-wood, claw, stone), destruction (stone wall, wood crate) and the Forgotten set (idle rattle loop, alert, attack telegraph, unblockable telegraph, hurt, poise break, collapse).

    Asset ids (15):

    • sfx-impact-blade-flesh-01
    • sfx-impact-blade-bone-01
    • sfx-impact-metal-metal-01
    • sfx-impact-blunt-wood-01
    • sfx-impact-claw-01
    • sfx-impact-stone-01
    • sfx-destruct-stone-wall-01
    • sfx-destruct-wood-crate-01
    • sfx-creature-forgotten-idle-rattle-loop-01
    • sfx-creature-forgotten-alert-01
    • sfx-creature-forgotten-attack-telegraph-01
    • sfx-creature-forgotten-unblockable-telegraph-01
    • sfx-creature-forgotten-hurt-bone-01
    • sfx-creature-forgotten-poise-break-01
    • sfx-creature-forgotten-collapse-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-impacts-forgotten-generate)

    Notes

    The Forgotten (canon name for skeletons, story bible) are listed in the gameplay needs because they are the m2 combat test enemy (e04-skeleton-fun-validation); all other creature vocal sets come from the world asset planner. Unblockable telegraph must be audibly distinct from the normal telegraph. Flesh hits are muffled thump + cloth — never wet gore.

    Acceptance criteria

    • AC-1 content Given the 15 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:sfxasset:sfxepic:e38milestone:m2
  • mw-e38.17Generate impact and Forgotten SFX via ElevenLabs or CC0blockedP1M2task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-impacts-forgotten-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 15 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.16 Write impact and Forgotten SFX prompts (15 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m2
  • mw-e38.18Owner approval: impact and Forgotten SFXblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 15 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-impacts-forgotten-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each material impact is identifiable blind and the unblockable telegraph is distinct from the normal one. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 15 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each material impact is identifiable blind and the unblockable telegraph is distinct from the normal one.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-impacts-forgotten-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.17 Generate impact and Forgotten SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m2needs-human
  • mw-e38.19Integrate approved impact and Forgotten SFXblockedP1M2task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-combat-hit-audio, e04-smash-breakables, e28-creature-audio-hooks, e04-creature-attack-hooks.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 15 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the combat sandbox with a Forgotten, when every impact material, destruction and Forgotten state is triggered, then final sounds play via cue sheets with no placeholder flags.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e04.17 Smash breakable walls and objects by impact force open
    • mw-e04.20 Creatures attack via the move system with readable telegraphs done
    • mw-e28.4 Combat impact audio matrix: hits, blocks, parries, whiffs done
    • mw-e28.8 Creature audio slots and audible attack telegraphs done
    • mw-e38.18 Owner approval: impact and Forgotten SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m2
  • mw-e38.20Write core footsteps prompts (20 assets)blockedP1M2task

    Description

    Why

    Footsteps are both feedback and a stealth rule: players learn that gravel is loud because it sounds loud (loudness must match the sim noise radius).

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Round-robin footstep sets (4–6 variants each) for stone, wood, dirt, grass, gravel and shallow water in sneak/walk/run gaits, plus light and heavy landings.

    Asset ids (20):

    • sfx-foot-stone-sneak
    • sfx-foot-stone-walk
    • sfx-foot-stone-run
    • sfx-foot-wood-sneak
    • sfx-foot-wood-walk
    • sfx-foot-wood-run
    • sfx-foot-dirt-sneak
    • sfx-foot-dirt-walk
    • sfx-foot-dirt-run
    • sfx-foot-grass-sneak
    • sfx-foot-grass-walk
    • sfx-foot-grass-run
    • sfx-foot-gravel-sneak
    • sfx-foot-gravel-walk
    • sfx-foot-gravel-run
    • sfx-foot-water-shallow-sneak
    • sfx-foot-water-shallow-walk
    • sfx-foot-water-shallow-run
    • sfx-foot-land-light
    • sfx-foot-land-heavy

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-footsteps-core-generate)

    Notes

    Each id is a round-robin set (-01…-04 minimum, per sfx template). Surface ids must equal e09-sound-propagation surface ids. m2 because the thief class gauntlet reads footstep loudness. CC0 sourcing (Kenney/freesound CC0) is acceptable and often better for footsteps. Sonic-lock anchor set.

    Acceptance criteria

    • AC-1 content Given the 20 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:sfxasset:sfxepic:e38milestone:m2
  • mw-e38.21Generate core footsteps via ElevenLabs or CC0blockedP1M2task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-footsteps-core-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 20 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.20 Write core footsteps prompts (20 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m2
  • mw-e38.22Owner approval: core footstepsblockedP1M2task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 20 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-footsteps-core-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: loudness ordering sneak < walk < run < land holds, and surfaces order carpet < grass < dirt < stone < wood-hollow < gravel/water when auditioned in sequence. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 20 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then loudness ordering sneak < walk < run < land holds, and surfaces order carpet < grass < dirt < stone < wood-hollow < gravel/water when auditioned in sequence.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-footsteps-core-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.21 Generate core footsteps via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m2needs-human
  • mw-e38.23Integrate approved core footstepsblockedP1M2task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-footsteps, e09-surface-acoustics, e02-footstep-events.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 20 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the stealth grey-box course, when the player walks every surface in every gait, then the final round-robin plays without immediate repeats and no placeholder flags remain.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e02.11 Emit footstep events tagged with surface material and gait done
    • mw-e09.4 Tag surfaces with acoustic materials that change footstep noise done
    • mw-e28.6 Surface-aware footsteps modulated by stance and armor done
    • mw-e38.22 Owner approval: core footsteps open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m2
  • mw-e38.64Lock approved reference sounds for all later SFX promptsblockedP1M2task

    Description

    Why

    SFX generated in many batches drift in loudness, room tone and weight; locked reference sounds keep the palette coherent (audio bible §7).

    What

    After the knight combat, impact/Forgotten and core footstep sets are approved, Claude proposes reference sounds per SFX category (impact, weapon, footstep, creature, magic-to-follow, UI) with measured loudness; the owner confirms. Recorded in assets/prompts/_sonic-anchors.json; later SFX prompt files cite them and the generate step loudness-matches against them.

    Scope

    • In: Reference proposal + owner confirmation
    • In: Sonic anchor registry
    • In: Validator rule for later SFX prompt files
    • Out: Music (Suno) — stingers follow the audio bible directly

    Notes

    Anchor sets: e38-asset-sfx-knight-combat-*, e38-asset-sfx-impacts-forgotten-*, e38-asset-sfx-footsteps-core-*.

    Acceptance criteria

    • AC-1 manual Given the approved anchor sets, when the owner reviews the proposal, then references for impact, weapon, footstep and creature categories are confirmed and recorded in assets/approvals.json with gate "sonic-lock".
    • AC-2 content Given assets/prompts/_sonic-anchors.json, when validated, then every reference id resolves to an approved sound whose SHA-256 matches its approval record.
    • AC-3 integration Given a later SFX prompt file without its category references, when the asset validator runs, then it fails naming the file.
    • AC-4 integration Edge: given a new candidate whose integrated loudness deviates > 3 LU from its category reference, when the generate step runs, then it is flagged on the listening page rather than silently accepted.

    Waits on

    • mw-e38.14 Owner approval: knight combat SFX open
    • mw-e38.18 Owner approval: impact and Forgotten SFX open
    • mw-e38.22 Owner approval: core footsteps open
    • mw-e38.4 Audio validator: loudness, true peak, loop seams, naming and licence open
    area:sfxasset:sfxepic:e38milestone:m2needs-human

M3 MVP content 155

  • mw-e38.11Audio consistency and mix review gate before MVP content lockblockedP1M3task

    Description

    Why

    Suno sessions and mixed SFX sources drift in timbre and level; a gate catches it before external playtests (m4).

    What

    Structured listening review per location against the audio bible and the audio style target: music family transitions, leitmotif presence (Glen, Labyrinth, Minotaur and its reveal variant), footstep loudness ordering vs sim, spell school distinctness (blind identification test), creature state readability, loudness report across all assets.

    Scope

    • In: Loudness/format report across all audio
    • In: Blind school-identification test
    • In: Findings file docs/audio/reviews/ with fix beads
    • Out: Fixing assets (filed as beads)

    Notes

    Run informally at m2 exit, formally before m3 content lock.

    Acceptance criteria

    • AC-1 integration Given all runtime audio, when the report script runs, then it lists per-file LUFS/true peak/category and flags any out-of-target file (expected zero at gate pass).
    • AC-2 manual Given 13 spell-cast sounds played in random order to 3 listeners with the school list, when identified, then ≥ 70 % of identifications are correct.
    • AC-3 manual Given the minotaur encounter and reveal, when reviewed, then the minotaur motif and its reveal variant are both present and recognisable by the reviewer.
    • AC-4 manual Edge: given a failing asset on the MVP critical path, when triaged, then it is fixed before m3 or explicitly waived by the owner with a reason in the review file.

    Waits on

    • mw-e38.10 Audio style target: full soundscape for the style-target diorama open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicarea:sfxepic:e38milestone:m3needs-human
  • mw-e38.24Write extra footsteps and armour prompts (18 assets)blockedP1M3task

    Description

    Why

    Stealth-relevant surfaces (creaky boards, grates, carpet, leaves, broken glass) and armour weight make noise a readable, plannable rule.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Round-robin footsteps for creaky/hollow wood, metal grate, carpet, leaves and glass shards in three gaits, plus plate/chain/leather armour movement layers played on top of footsteps.

    Asset ids (18):

    • sfx-foot-wood-hollow-sneak
    • sfx-foot-wood-hollow-walk
    • sfx-foot-wood-hollow-run
    • sfx-foot-metal-grate-sneak
    • sfx-foot-metal-grate-walk
    • sfx-foot-metal-grate-run
    • sfx-foot-carpet-sneak
    • sfx-foot-carpet-walk
    • sfx-foot-carpet-run
    • sfx-foot-leaves-sneak
    • sfx-foot-leaves-walk
    • sfx-foot-leaves-run
    • sfx-foot-glass-shards-sneak
    • sfx-foot-glass-shards-walk
    • sfx-foot-glass-shards-run
    • sfx-armor-plate-layer
    • sfx-armor-chain-layer
    • sfx-armor-leather-layer

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-footsteps-extra-armor-generate)

    Notes

    glass-shards is not in the audio bible §7.3 surface list — add it to e09-surface-acoustics or drop these ids. Armour layers: input said chain/plate; audio bible says plate/leather/cloth — this set uses plate, chain, leather; reconcile at prompt time. Remaining bible surfaces (mud, snow-ice, straw, bone-litter) are location-driven and left to the world asset planner.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock.

    Acceptance criteria

    • AC-1 content Given the 18 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.25Generate extra footsteps and armour via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-footsteps-extra-armor-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 18 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.24 Write extra footsteps and armour prompts (18 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.26Owner approval: extra footsteps and armourblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 18 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-footsteps-extra-armor-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the extra surfaces respect the sim loudness ordering and the knight's plate layer is clearly the loudest. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 18 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the extra surfaces respect the sim loudness ordering and the knight's plate layer is clearly the loudest.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-footsteps-extra-armor-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.25 Generate extra footsteps and armour via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.27Integrate approved extra footsteps and armourblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-footsteps, e09-surface-acoustics, e04-armor-weight.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 18 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the stealth grey-box course, when the knight and thief walk the extra surfaces, then final footsteps and armour layers play with no placeholder flags.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e04.16 Armor weight sets roll class, stamina regen, poise and noise done
    • mw-e09.4 Tag surfaces with acoustic materials that change footstep noise done
    • mw-e28.6 Surface-aware footsteps modulated by stance and armor done
    • mw-e38.26 Owner approval: extra footsteps and armour open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.28Write bow and arrow SFX prompts (15 assets)blockedP1M3task

    Description

    Why

    The archer's rhythm lives in the draw creak and the focused-release chime; trick-arrow payloads must be recognisable by ear.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Draw creak loop, release twang, focused-window chime, flyby, impacts (wood, stone, flesh, metal), metal ricochet, pickup, and payload sounds for fire, water, rope, noise and blunt arrows.

    Asset ids (15):

    • sfx-bow-draw-creak-loop-01
    • sfx-bow-release-twang-01
    • sfx-bow-focused-chime-01
    • sfx-arrow-flyby-01
    • sfx-arrow-impact-wood-01
    • sfx-arrow-impact-stone-01
    • sfx-arrow-impact-flesh-01
    • sfx-arrow-impact-metal-01
    • sfx-arrow-ricochet-metal-01
    • sfx-arrow-pickup-01
    • sfx-arrow-fire-ignite-01
    • sfx-arrow-water-splash-01
    • sfx-arrow-rope-unfurl-01
    • sfx-arrow-noise-rattle-01
    • sfx-arrow-blunt-thud-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-bow-arrows-generate)

    Notes

    Draw creak loop needs a seamless loop point (sidecar). Focused chime must be audible over combat music at the SFX bus level.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock.

    Acceptance criteria

    • AC-1 content Given the 15 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxclass:archerepic:e38milestone:m3
  • mw-e38.29Generate bow and arrow SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-bow-arrows-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 15 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.28 Write bow and arrow SFX prompts (15 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxclass:archerepic:e38milestone:m3
  • mw-e38.30Owner approval: bow and arrow SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 15 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-bow-arrows-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the focused chime is clearly audible in a busy mix and each payload is identifiable blind. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 15 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the focused chime is clearly audible in a busy mix and each payload is identifiable blind.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-bow-arrows-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.29 Generate bow and arrow SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxclass:archerepic:e38milestone:m3needs-human
  • mw-e38.31Integrate approved bow and arrow SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-bow-audio, e05-draw-timing, e05-arrow-retrieval, e05-fire-arrow, e05-water-arrow, e05-rope-arrow, e05-noise-arrow, e05-blunt-arrow.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 15 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the archery range, when every arrow type is drawn, released and lands on each material, then final sounds play via cue sheets with no placeholder flags.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e05.10 Rope arrows anchor into wood and create climbable ropes open
    • mw-e05.11 Noise arrows create sound events that lure creatures open
    • mw-e05.12 Blunt arrows knock objects, press switches and stun open
    • mw-e05.4 Focused release window and rhythm bonus for well-timed shots open
    • mw-e05.7 Stuck arrows persist and can be retrieved or looted done
    • mw-e05.8 Fire arrows ignite flammable things; dip arrows in open flame open
    • mw-e05.9 Water arrows douse fires, extinguish lights and wet surfaces open
    • mw-e28.7 Bow audio: draw creak, release, flyby and payload cues open
    • mw-e38.30 Owner approval: bow and arrow SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxclass:archerepic:e38milestone:m3
  • mw-e38.32Write stealth action SFX prompts (20 assets)blockedP1M3task

    Description

    Why

    Stealth is a conversation through sound: a coin that clinks draws a guard, a dropped body is heard, an alarm bell changes the whole level.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Lockpick pin click/fail/break, pickpocket rustle, takedown choke, backstab, body drop, coin impact, bottle shatter, splash, candle snuff, torch douse, alarm bell, guard shout, cough in smoke, smoke-bomb pop and trap triggers (bear trap, tripwire, noisemaker, caltrops).

    Asset ids (20):

    • sfx-thief-lockpick-pin-click-01
    • sfx-thief-lockpick-fail-01
    • sfx-thief-lockpick-break-01
    • sfx-thief-pickpocket-rustle-01
    • sfx-thief-takedown-choke-01
    • sfx-thief-backstab-01
    • sfx-body-drop-thud-01
    • sfx-coin-impact-stone-01
    • sfx-bottle-shatter-01
    • sfx-splash-throwable-01
    • sfx-light-candle-snuff-01
    • sfx-light-torch-douse-01
    • sfx-alarm-bell-01
    • sfx-guard-shout-alert-01
    • sfx-cough-smoke-01
    • sfx-smoke-bomb-pop-01
    • sfx-trap-bear-snap-01
    • sfx-trap-tripwire-twang-01
    • sfx-trap-noisemaker-rattle-01
    • sfx-trap-caltrops-scatter-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-stealth-actions-generate)

    Notes

    No voice for MVP: guard shout and cough are non-verbal vocalisations (no words). Relative loudness must match each event's sim noise radius. Smoke-bomb pop added (implied by smoke bombs). Takedown choke is non-graphic.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock.

    Acceptance criteria

    • AC-1 content Given the 20 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxclass:thiefepic:e38milestone:m3
  • mw-e38.33Generate stealth action SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-stealth-actions-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 20 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.32 Write stealth action SFX prompts (20 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxclass:thiefepic:e38milestone:m3
  • mw-e38.34Owner approval: stealth action SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 20 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-stealth-actions-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: no sound contains intelligible words, and loud world events (bell, shatter) are clearly louder than thief actions. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 20 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then no sound contains intelligible words, and loud world events (bell, shatter) are clearly louder than thief actions.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-stealth-actions-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.33 Generate stealth action SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxclass:thiefepic:e38milestone:m3needs-human
  • mw-e38.35Integrate approved stealth action SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e10-lockpicking, e10-pickpocketing, e10-takedowns, e10-body-carry-hide, e10-thrown-distractions, e10-extinguish-lights, e10-smoke-escape, e10-trap-disarm, e11-communication.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 20 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the thief grey-box challenge, when every thief action and trap fires, then final sounds play via cue sheets with no placeholder flags.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e10.12 Detect and disarm world traps; failures trigger them open
    • mw-e10.13 Smoke bombs and flash powder break line of sight for escapes open
    • mw-e10.2 Throw objects to create noise distractions guards investigate open
    • mw-e10.3 Extinguish and relight light sources to reshape the shadows open
    • mw-e10.4 Backstabs and non-lethal takedowns on unaware targets open
    • mw-e10.5 Carry and hide unconscious or dead bodies open
    • mw-e10.7 Pick locks as an in-world, interruptible, noisy action open
    • mw-e10.8 Pickpocket and plant items on creatures from behind open
    • mw-e11.12 Allies share alerts by shouts, sight signals and alarm devices open
    • mw-e38.34 Owner approval: stealth action SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxclass:thiefepic:e38milestone:m3
  • mw-e38.36Write UI SFX prompts (14 assets)blockedP1M3task

    Description

    Why

    Menus should feel like handling a field journal — paper, leather, brass (audio bible §7.6) — and critical HUD states (lock-on, low health) need audio.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Menu open/close (leather flap), hover, confirm (brass click), cancel, page turn, coin clink, item pickup, equip, quest update (soft chime), journal quill scratch, error/deny (wooden knock), lock-on tick and low-health heartbeat loop.

    Asset ids (14):

    • sfx-ui-menu-open-01
    • sfx-ui-menu-close-01
    • sfx-ui-hover-01
    • sfx-ui-confirm-01
    • sfx-ui-cancel-01
    • sfx-ui-page-turn-01
    • sfx-ui-coin-01
    • sfx-ui-item-pickup-01
    • sfx-ui-equip-01
    • sfx-ui-quest-update-01
    • sfx-ui-journal-quill-01
    • sfx-ui-error-deny-01
    • sfx-ui-lockon-01
    • sfx-ui-low-health-heartbeat-loop-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-ui-core-generate)

    Notes

    All ≤ 400 ms except the heartbeat loop; UI loudness target −20 LUFS short-term ±2, never louder than combat. The verb-learned fanfare is a music stinger (e38-asset-music-stingers-*).

    Prompts cite the locked reference sounds from e38-asset-sonic-lock.

    Acceptance criteria

    • AC-1 content Given the 14 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.37Generate UI SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-ui-core-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 14 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.36 Write UI SFX prompts (14 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.38Owner approval: UI SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 14 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-ui-core-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: UI sounds stay pleasant after 50 repetitions and never mask combat cues. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 14 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then UI sounds stay pleasant after 50 repetitions and never mask combat cues.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-ui-core-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.37 Generate UI SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.39Integrate approved UI SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e17-inventory-ui, e17-equipment-ui, e23-journal-ui, e20-shop-ui, e07-book-reader-ui, e02-lock-on, e28-cue-sheets.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 14 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the inventory, journal, shop and combat sandbox, when every UI action and lock-on fires, then final sounds play with no placeholder flags.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e02.16 Lock on to and cycle between targets with camera framing done
    • mw-e07.9 Read books in a page-turning reader with a study action open
    • mw-e17.10 Build inventory screen with category tabs, inspect and actions done
    • mw-e17.11 Add equipment paper-doll view with verb and stealth comparison open
    • mw-e20.10 Build shop UI with merchant identity, buy/sell and price breakdown done
    • mw-e23.6 Build in-character journal for quests, rumors and notes done
    • mw-e28.3 Data-driven cue sheets map sim events to sounds done
    • mw-e38.38 Owner approval: UI SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.40Write elemental spell SFX prompts (13 assets)blockedP1M3task

    Description

    Why

    Elemental spells change the world; each must sound organic and match its school palette (audio bible §7.4).

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Phase sounds for ember, firebolt, flame-jet, frostglass, wellspring, gust, thunderclap, arc-lash.

    Asset ids (13):

    • sfx-spell-fire-ember-cast-01
    • sfx-spell-fire-ember-impact-01
    • sfx-spell-fire-firebolt-cast-01
    • sfx-spell-fire-firebolt-impact-01
    • sfx-spell-fire-flame-jet-loop-01
    • sfx-spell-frost-frostglass-cast-01
    • sfx-spell-frost-frostglass-impact-01
    • sfx-spell-frost-frostglass-shatter-01
    • sfx-spell-conjuration-wellspring-cast-01
    • sfx-spell-conjuration-wellspring-splash-01
    • sfx-spell-storm-gust-whoosh-01
    • sfx-spell-storm-thunderclap-boom-01
    • sfx-spell-storm-arc-lash-crackle-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-spells-elemental-generate)

    Notes

    Storm harshness is capped (audio bible §7.4). Flame Jet loop needs a seamless loop point.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock.

    Acceptance criteria

    • AC-1 content Given the 13 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.41Generate elemental spell SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-spells-elemental-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 13 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.40 Write elemental spell SFX prompts (13 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.42Owner approval: elemental spell SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 13 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-spells-elemental-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each spell's phases sound like one spell and its school is identifiable blind. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 13 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each spell's phases sound like one spell and its school is identifiable blind.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-spells-elemental-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.41 Generate elemental spell SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3needs-human
  • mw-e38.43Integrate approved elemental spell SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e06-spell-cue-binding, e08-spell-ember, e08-spell-firebolt-flame-jet, e08-spell-frostglass, e08-spell-wellspring, e08-spell-gust, e08-spell-thunderclap, e08-spell-arc-lash.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 13 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell sandbox, when each elemental spell is cast, then every phase plays its final sound with no placeholder flags.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e06.17 Bind spell events to placeholder VFX and SFX cues open
    • mw-e08.2 Add Ember: precise ignition of flammable things done
    • mw-e08.3 Add Firebolt and its Flame Jet follow-on verb open
    • mw-e08.5 Add Frostglass: freeze targets and create temporary ice surfaces open
    • mw-e08.6 Add Wellspring: conjure a burst of water that soaks an area open
    • mw-e08.7 Add Gust: blast creatures back, clear gas and propel objects open
    • mw-e08.8 Add Thunderclap: a violent shockwave that breaks and deafens open
    • mw-e08.9 Add Arc Lash: lightning that chains through conductive and wet open
    • mw-e38.42 Owner approval: elemental spell SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.44Write arcane and mystic spell SFX prompts (22 assets)blockedP1M3task

    Description

    Why

    The sorcerer's kinetic, illusion, light and life spells need distinct sonic identities so a player can hear what was cast.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Phase sounds for mage-hand, telekinetic-throw, blink, levitate, gravity-well, mirror-self, wisp-light, prism-ray, grasping-vines, animate-bones, polymorph.

    Asset ids (22):

    • sfx-spell-arcane-mage-hand-grab-01
    • sfx-spell-arcane-mage-hand-hold-loop-01
    • sfx-spell-arcane-mage-hand-release-01
    • sfx-spell-arcane-telekinetic-throw-launch-01
    • sfx-spell-arcane-telekinetic-throw-catch-01
    • sfx-spell-arcane-blink-depart-01
    • sfx-spell-arcane-blink-arrive-01
    • sfx-spell-gravity-levitate-loop-01
    • sfx-spell-gravity-gravity-well-loop-01
    • sfx-spell-gravity-gravity-well-collapse-01
    • sfx-spell-illusion-mirror-self-spawn-01
    • sfx-spell-illusion-mirror-self-dispel-01
    • sfx-spell-light-wisp-light-spawn-01
    • sfx-spell-light-wisp-light-hum-loop-01
    • sfx-spell-light-prism-ray-loop-01
    • sfx-spell-nature-grasping-vines-erupt-01
    • sfx-spell-nature-grasping-vines-creak-01
    • sfx-spell-necromancy-animate-bones-assemble-01
    • sfx-spell-necromancy-animate-bones-rattle-01
    • sfx-spell-necromancy-animate-bones-crumble-01
    • sfx-spell-alteration-polymorph-poof-01
    • sfx-spell-alteration-polymorph-critter-cluck-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-spells-arcane-mystic-generate)

    Notes

    Loops (hold, levitate, gravity well, wisp hum, prism) need seamless loop points. Polymorph critter cluck matches the critter model.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock.

    Acceptance criteria

    • AC-1 content Given the 22 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.45Generate arcane and mystic spell SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-spells-arcane-mystic-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 22 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.44 Write arcane and mystic spell SFX prompts (22 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.46Owner approval: arcane and mystic spell SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 22 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-spells-arcane-mystic-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each spell's phases sound like one spell and its school is identifiable blind. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 22 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each spell's phases sound like one spell and its school is identifiable blind.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-spells-arcane-mystic-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.45 Generate arcane and mystic spell SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3needs-human
  • mw-e38.47Integrate approved arcane and mystic spell SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e06-spell-cue-binding, e08-spell-mage-hand, e08-spell-telekinetic-throw, e08-spell-blink, e08-spell-levitate, e08-spell-gravity-well, e08-spell-mirror-self, e08-spell-wisp-light, e08-spell-prism-ray, e08-spell-grasping-vines, e08-spell-animate-bones, e08-spell-polymorph.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 22 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell sandbox, when each spell in the set is cast, then every phase plays its final sound with no placeholder flags.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e06.17 Bind spell events to placeholder VFX and SFX cues open
    • mw-e08.10 Add Mage Hand: grab, move and use distant objects done
    • mw-e08.11 Add Telekinetic Throw & Catch: hurl objects, creatures and arrows open
    • mw-e08.12 Add Blink: teleport several metres through open space open
    • mw-e08.13 Add Levitate: float the caster or an object upward slowly open
    • mw-e08.14 Add Gravity Well: pull creatures and loose objects to a point open
    • mw-e08.15 Add Mirror Self: an illusory double that draws attention open
    • mw-e08.17 Add Wisp Light: a floating orb that lights darkness and repels open
    • mw-e08.18 Add Prism Ray: a light beam that reflects off reflective surfaces open
    • mw-e08.20 Add Grasping Vines: roots burst up and restrain creatures open
    • mw-e08.21 Add Animate Bones: raise nearby remains as a temporary servant open
    • mw-e08.22 Add Polymorph: temporarily turn a creature into a harmless animal open
    • mw-e38.46 Owner approval: arcane and mystic spell SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.52Write school default SFX prompts (26 assets)blockedP1M3task

    Description

    Why

    Spells without bespoke sound (NPC casts, data-only spells, miscasts) must still sound like their school.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    One default cast and one default impact per school following the audio bible §7.4 palette.

    Asset ids (26):

    • sfx-spell-fire-default-cast-01
    • sfx-spell-frost-default-cast-01
    • sfx-spell-storm-default-cast-01
    • sfx-spell-arcane-default-cast-01
    • sfx-spell-illusion-default-cast-01
    • sfx-spell-alteration-default-cast-01
    • sfx-spell-conjuration-default-cast-01
    • sfx-spell-necromancy-default-cast-01
    • sfx-spell-nature-default-cast-01
    • sfx-spell-light-default-cast-01
    • sfx-spell-shadow-default-cast-01
    • sfx-spell-gravity-default-cast-01
    • sfx-spell-time-default-cast-01
    • sfx-spell-fire-default-impact-01
    • sfx-spell-frost-default-impact-01
    • sfx-spell-storm-default-impact-01
    • sfx-spell-arcane-default-impact-01
    • sfx-spell-illusion-default-impact-01
    • sfx-spell-alteration-default-impact-01
    • sfx-spell-conjuration-default-impact-01
    • sfx-spell-necromancy-default-impact-01
    • sfx-spell-nature-default-impact-01
    • sfx-spell-light-default-impact-01
    • sfx-spell-shadow-default-impact-01
    • sfx-spell-gravity-default-impact-01
    • sfx-spell-time-default-impact-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-school-defaults-generate)

    Notes

    Miscasts reuse the default impact with pipeline pitch/filter variants rather than separate generations.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock.

    Acceptance criteria

    • AC-1 content Given the 26 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.53Generate school default SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-school-defaults-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 26 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.52 Write school default SFX prompts (26 assets) open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.54Owner approval: school default SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 26 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-school-defaults-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: all 13 schools are distinguishable blind in a shuffled playlist. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 26 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then all 13 schools are distinguishable blind in a shuffled playlist.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-school-defaults-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.53 Generate school default SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3needs-human
  • mw-e38.55Integrate approved school default SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e06-spell-cue-binding, e06-botched-casts.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 26 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell sandbox, when a data-only spell of each school is cast, then the school default sounds play with no placeholder flags.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e06.13 Resolve botched casts into data-driven miscast outcomes open
    • mw-e06.17 Bind spell events to placeholder VFX and SFX cues open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.54 Owner approval: school default SFX open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.60Write gameplay music stingers Suno prompts (11)blockedP1M3task

    Description

    Why

    Stingers mark the story beats of play — being spotted, escaping, discovering a secret, learning a verb — and tie gameplay to the musical identity (audio bible §2.3).

    What

    Write one prompt file per stinger in assets/prompts/music/<asset-id>.md from _templates/music-stinger.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key (or neutral), BPM, length, output spec.

    Key-neutral stealth stingers (suspicious, detected, combat start, lost them), discovery, four class-ident capability-unlock fanfares, quest complete and death.

    Asset ids (11):

    • music-stinger-suspicious
    • music-stinger-detected
    • music-stinger-combat-start
    • music-stinger-lost-them
    • music-stinger-discovery
    • music-stinger-capability-unlock-knight
    • music-stinger-capability-unlock-archer
    • music-stinger-capability-unlock-sorcerer
    • music-stinger-capability-unlock-thief
    • music-stinger-quest-complete
    • music-stinger-death

    Scope

    • In: One Suno prompt per stinger
    • In: Motif references per audio bible §1.4
    • Out: Pasting into Suno (e38-asset-music-stingers-generate, owner)

    Notes

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min/stinger) and drops the chosen take in assets/_incoming/music/. Location-keyed combat-start/victory variants and the Brother Horn reveal (music-stinger-horn-reveal) belong to the location music set (world planner); these are key-neutral. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 11 ids, when the asset validator runs, then each has one prompt file matching music-stinger-<event>-<key?> naming.
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte.
    • AC-3 content Given each prompt, when inspected, then length is within audio bible §2.3 for its stinger type and key/BPM are stated (or "key-neutral").
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words or names a real artist, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.61Owner generates gameplay music stingers in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per stinger) — contract §1.

    What

    For each prompt of e38-asset-music-stingers-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 11 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.60 Write gameplay music stingers Suno prompts (11) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.62Owner approval: gameplay music stingersblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loudness-normalised) stingers played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-stingers-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each stinger fits its moment and the four class idents are recognisably one family with different characters. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 11 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each stinger fits its moment and the four class idents are recognisably one family with different characters.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-stingers-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.61 Owner generates gameplay music stingers in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.63Integrate approved gameplay music stingers into adaptive musicblockedP1M3task

    Description

    Why

    Stingers only matter when they fire at the right moment on the music bus.

    What

    Trim, fade tails, normalise to stinger loudness, encode Opus + AAC with sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data / stinger table.

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e28-adaptive-music, e09-alert-barks, e19-capabilities-screen, e38-music-state-data.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then each stinger is −16 LUFS ±1 (short-term max), ≤ −1.0 dBTP, transient within 20 ms of start and tail ≤ 2 s, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each stinger has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given the stealth course and capabilities screen, when a guard cycles suspicious→detected→lost and a verb is learned, then the final stingers play on the music bus without clipping.
    • AC-4 integration Edge: given a stinger without an approval record, when the build runs, then its placeholder remains and the report lists it.

    Waits on

    • mw-e09.13 Text barks and audio stingers on alert state transitions open
    • mw-e19.12 Build capabilities screen and "new verb learned" feedback open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.62 Owner approval: gameplay music stingers open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.65Write River Wend and barge music Suno prompts (7)blockedP1M3task

    Description

    Why

    The river is connective tissue: open and flowing on the towpath, a gentle journey on the barge, and faintly wrong at the humming Weeping Adit.

    What

    Write one prompt file per track in assets/prompts/music/<asset-id>.md from _templates/music-track.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    River Wend family (B Dorian 84 BPM 6/8: explore, stealth, tension, combat), the barge journey (D Dorian 76, main theme on harp and low whistle, linear), and the Weeping Adit (C♯ Aeolian 56/free-time, bridging to the Deepworks: drone explore with the Nightjar song faint on the water, stealth).

    Asset ids (7):

    • music-river-wend-explore
    • music-river-wend-stealth
    • music-river-wend-tension
    • music-river-wend-combat
    • music-barge-journey
    • music-weeping-adit-explore
    • music-weeping-adit-stealth

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-river-generate, owner)

    Notes

    Ids follow audio bible §3 (music-barge-journey; the needs list said music-barge-ride). music-weeping-adit is a bible track not in the needs list.

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 7 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.66Owner generates River Wend and barge music in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-river-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 7 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.65 Write River Wend and barge music Suno prompts (7) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.67Owner approval: River Wend and barge musicblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-river-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the river family is key/tempo-locked and open-sounding, the barge journey quotes the main theme recognisably, and the Adit bridges into the Deepworks key with a faint Nightjar quote. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 7 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the river family is key/tempo-locked and open-sounding, the barge journey quotes the main theme recognisably, and the Adit bridges into the Deepworks key with a faint Nightjar quote.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-river-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.66 Owner generates River Wend and barge music in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.68Integrate approved River Wend and barge music into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Cut bar-aligned loop points, add -end tails, normalise to the §5.1 targets, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data (family → states).

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e25-barge-travel, e25-weeping-adit. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e25-river-art-audio.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then explore/stealth tracks are −18 LUFS ±1 (≤ −1.5 dBTP) and tension/combat/boss tracks −16 LUFS ±1 (≤ −1.0 dBTP), loop regions are whole bars ≥ 60 s with sample-accurate seams, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given the quay, towpath and the Weeping Adit, when the player explores, sneaks and fights, then the river family switches on bar boundaries, the Adit track cross-fades into the Deepworks family, and the barge card plays the journey track, with no clipping.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e25.13 Build the Weeping Adit: the flooded sixth way into the lower Deepworks open
    • mw-e25.15 Ride Mags Oakum's barge between Briar Glen Quay and Wendmouth open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.67 Owner approval: River Wend and barge music open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.69Write Wendmouth music families Suno prompts (12)blockedP1M3task

    Description

    Why

    Wendmouth's "Harbour colour" (shanty-inflected, no accordion, no pirate cliché) and "The Tide" motif make the harbour sound like a different mood of the same band (audio bible §1.1, §1.4).

    What

    Write one prompt file per track in assets/prompts/music/<asset-id>.md from _templates/music-track.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    Wendmouth day (A Mixolydian 112 6/8: explore — establishes "The Tide" — tension, combat/brawl), Wendmouth night (A Dorian 90: explore, stealth = heist variant of "The Tide" on pizzicato cello and muted dulcimer, tension, combat), the Drowned Gull (diegetic, D Mixolydian 120), the Tidefair festive loop (A Mixolydian 120 6/8) and the Undertow (D Phrygian 70: explore, stealth, tension).

    Asset ids (12):

    • music-wendmouth-day-explore
    • music-wendmouth-day-tension
    • music-wendmouth-day-combat
    • music-wendmouth-night-explore
    • music-wendmouth-night-stealth
    • music-wendmouth-night-tension
    • music-wendmouth-night-combat
    • music-drowned-gull-explore
    • music-tidefair-explore
    • music-undertow-explore
    • music-undertow-stealth
    • music-undertow-tension

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-wendmouth-generate, owner)

    Notes

    music-wendmouth-day-explore is the motif anchor for "The Tide"; later harbour cues cite it. The needs list's music-heist-bay-nine is covered by the bible's night stealth (heist) layer rather than a separate family; ids follow audio bible §3 (music-drowned-gull, not -tavern).

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 12 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.70Owner generates Wendmouth music families in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-wendmouth-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 12 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.69 Write Wendmouth music families Suno prompts (12) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.71Owner approval: Wendmouth music familiesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-wendmouth-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: "The Tide" is recognisable in the day explore track and its heist variant, there is no accordion, concertina, lyrics or pirate cliché, and the Gull is rowdier than the Sleeping Ox. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then "The Tide" is recognisable in the day explore track and its heist variant, there is no accordion, concertina, lyrics or pirate cliché, and the Gull is rowdier than the Sleeping Ox.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-wendmouth-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.70 Owner generates Wendmouth music families in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.72Integrate approved Wendmouth music families into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Cut bar-aligned loop points, add -end tails, normalise to the §5.1 targets, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data (family → states).

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e40-drowned-gull, e40-tidefair-strength, e40-undertow, e40-bonded-warehouse. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e40-harbor-lighting-audio.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then explore/stealth tracks are −18 LUFS ±1 (≤ −1.5 dBTP) and tension/combat/boss tracks −16 LUFS ±1 (≤ −1.0 dBTP), loop regions are whole bars ≥ 60 s with sample-accurate seams, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given Wendmouth by day and night, the Gull, the Tidefair and the Undertow, when states change and the warehouse heist starts, then the matching tracks switch on bar boundaries and the heist stealth layer plays, with no clipping.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.71 Owner approval: Wendmouth music families open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    • mw-e40.12 Build the Undertow black market and its smugglers' tunnels open
    • mw-e40.4 Build the Bonded Warehouse: bay nine, skylights, hoists and manifests open
    • mw-e40.6 Build the Drowned Gull: arm-wrestling, dice, drinking and the trapdoor open
    • mw-e40.7 Stage the Tidefair arm-wrestling bout and the Gull brawl open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.73Write harbour and Tidefair stingers Suno prompts (12)blockedP1M3task

    Description

    Why

    Tidefair contests, the customs confiscation, a perfect heist and the Tern sailing are beats that need a musical punctuation mark in the harbour key.

    What

    Write one prompt file per stinger/cue in assets/prompts/music/<asset-id>.md from _templates/music-stinger.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    Tidefair start (1–2 s fiddle flourish), win (3–4 s "The Tide" fragment with stomp) and lose (2–3 s gracious deflating fiddle slide); customs-confiscate; heist-perfect ("The Tide" heist variant resolving); tern-sails (Act III departure); combat-start and combat-victory in the new keys (b-dorian = River Wend; a-mixolydian = Wendmouth day; a-dorian = Wendmouth night).

    Asset ids (12):

    • music-stinger-tidefair-start
    • music-stinger-tidefair-win
    • music-stinger-tidefair-lose
    • music-stinger-customs-confiscate
    • music-stinger-heist-perfect
    • music-stinger-tern-sails
    • music-stinger-combat-start-b-dorian
    • music-stinger-combat-start-a-mixolydian
    • music-stinger-combat-start-a-dorian
    • music-stinger-combat-victory-b-dorian
    • music-stinger-combat-victory-a-mixolydian
    • music-stinger-combat-victory-a-dorian

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-harbour-stingers-generate, owner)

    Notes

    music-stinger-tidefair-start is added from audio bible §2.3 (the needs list had only win/lose).

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 12 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.71 Owner approval: Wendmouth music families open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.74Owner generates harbour and Tidefair stingers in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-harbour-stingers-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 12 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.73 Write harbour and Tidefair stingers Suno prompts (12) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.75Owner approval: harbour and Tidefair stingersblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-harbour-stingers-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each stinger sits in its family key, Tidefair lose is comic not sad, and heist-perfect and tidefair-win quote "The Tide" recognisably. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each stinger sits in its family key, Tidefair lose is comic not sad, and heist-perfect and tidefair-win quote "The Tide" recognisably.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-harbour-stingers-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.74 Owner generates harbour and Tidefair stingers in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.76Integrate approved harbour and Tidefair stingers into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Trim, fade tails, normalise to stinger loudness, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data / stinger table.

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e40-tidefair-strength, e40-tidefair-shoot-pockets, e40-customs-house, e40-crate-heist, e40-gilded-tern.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then each stinger is −16 LUFS ±1 (short-term max), ≤ −1.0 dBTP, transient within 20 ms of start and tail ≤ 2 s, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given the Tidefair contests, Cray confiscating a book, a perfect heist and the Act III fact, when each fires, then its stinger plays once on the music bus in key, and river/harbour combat uses the keyed combat stingers, with no clipping.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.75 Owner approval: harbour and Tidefair stingers open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    • mw-e40.14 Build the Gilded Tern: rigging, hold, cabin, locked berth, departure open
    • mw-e40.20 Place The Crate for Mr. S— heist with all six solution routes open
    • mw-e40.3 Build the Customs House, its strongroom and Cray's book confiscation open
    • mw-e40.7 Stage the Tidefair arm-wrestling bout and the Gull brawl open
    • mw-e40.8 Stage the Tidefair Gull Shoot and the Pocket Race open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.77Write River Wend ambience prompts (6 assets)blockedP1M3task

    Description

    Why

    The river is heard before it is seen — reeds, herons, the weir's roar (which may mask noise), the lock's creaks and the Adit's night hum (rumour 16).

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Quay bed (barge creaks, the grind and knock of dressed blocks being landed), riverbank flow bed (audio only — no flow sim), towpath day (herons, reeds, hooves and tow-rope creak), Millweir spill roar, Kestrel Lock (gate creaks, sluice rush, windlass, quiet cottage), and the Weeping Adit drip with a faint hum at night.

    Asset ids (6):

    • amb-river-wend-quay-01
    • amb-river-wend-bank-01
    • amb-river-wend-towpath-01
    • amb-millweir-spill-01
    • amb-kestrel-lock-01
    • amb-weeping-adit-drip-hum-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-amb-river-generate)

    Notes

    Ids follow audio bible §7.7 (amb-river-wend-*; the needs list said amb-river-quay-01, amb-river-flow-bank-01, amb-towpath-day-01). If the weir is a noise-masking zone its radius must match e09-sound-propagation. The Adit hum uses the Nightjar motif anchor.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 6 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each bed, when inspected, then it states loop length ≥ 30 s, stereo, the randomised one-shots kept out of the bed, and the §7.7 gameplay role (draught, water, song) it carries.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (ambience −24 LUFS ± 2, ≤ −3.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.78Generate River Wend ambience via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout, loop-seam preview).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-amb-river-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds. Loop beds are stitched from multiple generations where the API limits clip length.

    Acceptance criteria

    • AC-1 integration Given the 6 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then beds are stereo, ≥ 30 s, loop seams pass the discontinuity check, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    • mw-e38.77 Write River Wend ambience prompts (6 assets) open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.79Owner approval: River Wend ambienceblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 6 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-amb-river-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each bed identifies its place, the weir roar is continuous and seamless, and the Adit hum is faint enough to be a rumour rather than a cue. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 6 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each bed identifies its place, the weir roar is continuous and seamless, and the Adit hum is faint enough to be a rumour rather than a cue.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-amb-river-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.78 Generate River Wend ambience via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.80Integrate approved River Wend ambienceblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets / ambience zone data, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-cue-sheets, e25-quay-stone-stair, e25-millweir-sluice-walk, e25-weeping-adit, e25-towpath-kestrel-lock. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e25-river-art-audio. Ambience zones are e28-ambience (P2); these beds bind through the cue sheets.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 6 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the river, when the player walks from the quay along the towpath to the lock and visits the weir and the Adit by night, then each final bed plays and cross-fades with no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e25.11 Build Briar Glen Quay and the Stone Stair slipway down from the mine open
    • mw-e25.12 Build the Millweir and its sluice walk to the Briarwood far bank open
    • mw-e25.13 Build the Weeping Adit: the flooded sixth way into the lower Deepworks open
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e28.3 Data-driven cue sheets map sim events to sounds done
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    • mw-e38.79 Owner approval: River Wend ambience open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.81Write Wendmouth ambience prompts (10 assets)blockedP1M3task

    Description

    Why

    Wendmouth must be louder and busier than any Briar Glen bed (audio bible §7.7): gulls, halyards, crowds, cranes, the bell buoy.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Harbour day (wordless crowd, gulls, rigging creak, surf, crane winches), harbour night, the Drowned Gull murmur (rowdy walla, dice, tankards, waves under the floor), Tidemarket bustle, Undertow cellar, Bonded Warehouse at night, the Tern's hold, breakwater surf, a gull loop and wharf-rat scurry beds.

    Asset ids (10):

    • amb-wendmouth-harbour-day-01
    • amb-wendmouth-harbour-night-01
    • amb-drowned-gull-murmur-01
    • amb-wendmouth-tidemarket-01
    • amb-wendmouth-undertow-01
    • amb-wendmouth-bonded-warehouse-night-01
    • amb-wendmouth-gilded-tern-hold-01
    • amb-wendmouth-breakwater-surf-01
    • amb-wendmouth-gulls-01
    • amb-wendmouth-wharf-rats-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-amb-harbour-generate)

    Notes

    Ids use the amb-wendmouth-* pattern from audio bible §7.7 (needs list said amb-tidemarket-bustle-01, amb-undertow-cellar-01, etc.); amb-drowned-gull-* follows the bible tavern row.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 10 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each bed, when inspected, then it states loop length ≥ 30 s, stereo, the randomised one-shots kept out of the bed, and the §7.7 gameplay role (draught, water, song) it carries.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (ambience −24 LUFS ± 2, ≤ −3.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.82Generate Wendmouth ambience via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout, loop-seam preview).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-amb-harbour-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds. Loop beds are stitched from multiple generations where the API limits clip length.

    Acceptance criteria

    • AC-1 integration Given the 10 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then beds are stereo, ≥ 30 s, loop seams pass the discontinuity check, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    • mw-e38.81 Write Wendmouth ambience prompts (10 assets) open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.83Owner approval: Wendmouth ambienceblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 10 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-amb-harbour-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: harbour beds are clearly louder and busier than Briar Glen beds, crowd walla has no intelligible words, the warehouse at night is quiet enough for a heist, and beds loop seamlessly. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then harbour beds are clearly louder and busier than Briar Glen beds, crowd walla has no intelligible words, the warehouse at night is quiet enough for a heist, and beds loop seamlessly.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-amb-harbour-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.82 Generate Wendmouth ambience via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.84Integrate approved Wendmouth ambienceblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets / ambience zone data, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-cue-sheets, e40-harbor-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e40-harbor-lighting-audio. Ambience zones are e28-ambience (P2); these beds bind through the cue sheets.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 10 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given Wendmouth, when the player walks from the Stone Wharf through the Tidemarket into the Undertow, the Gull and the Tern by day and night, then each final bed plays with no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e28.3 Data-driven cue sheets map sim events to sounds done
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    • mw-e38.83 Owner approval: Wendmouth ambience open
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.85Write river set-piece SFX prompts (10 assets)blockedP1M3task

    Description

    Why

    The Stone Stair slide, weir sluice, lock cycle and the Adit current are mechanisms the player operates or survives; each must say what changed.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Stone Stair block-slide rumble, heavy sluice gate, lock paddle and windlass, lock gate strain, lock chamber fill loop, Adit current push loop, Adit barge winch, barge horn, barge pole plunge, towpath hooves and harness jingle.

    Asset ids (10):

    • sfx-stone-stair-slide-01
    • sfx-sluice-gate-heavy-01
    • sfx-lock-paddle-01
    • sfx-lock-gate-strain-01
    • sfx-lock-chamber-fill-loop-01
    • sfx-adit-current-push-loop-01
    • sfx-adit-winch-barge-01
    • sfx-barge-horn-01
    • sfx-barge-pole-plunge-01
    • sfx-towpath-hooves-harness-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-river-setpiece-generate)

    Notes

    Barge pole and hooves are added from audio bible §7.9 River row.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 10 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.86Generate river set-piece SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-river-setpiece-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 10 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    • mw-e38.85 Write river set-piece SFX prompts (10 assets) open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.87Owner approval: river set-piece SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 10 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-river-setpiece-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each mechanism sound reads its state change, the Adit current loop sounds forceful without implying a flow sim, and the barge horn is distinct from every bell. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each mechanism sound reads its state change, the Adit current loop sounds forceful without implying a flow sim, and the barge horn is distinct from every bell.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-river-setpiece-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.86 Generate river set-piece SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.88Integrate approved river set-piece SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e25-quay-stone-stair, e25-millweir-sluice-walk, e25-towpath-kestrel-lock, e25-weeping-adit, e25-barge-travel.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 10 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the river locations, when the Stone Stair is slid, the sluice opened, the lock cycled and the Adit swum, then final sounds play with the right noise events and no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e25.11 Build Briar Glen Quay and the Stone Stair slipway down from the mine open
    • mw-e25.12 Build the Millweir and its sluice walk to the Briarwood far bank open
    • mw-e25.13 Build the Weeping Adit: the flooded sixth way into the lower Deepworks open
    • mw-e25.14 Build the towpath and Kestrel Lock with the keeper's cottage open
    • mw-e25.15 Ride Mags Oakum's barge between Briar Glen Quay and Wendmouth open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    • mw-e38.87 Owner approval: river set-piece SFX open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.89Write harbour mechanism and ship SFX prompts (18 assets)blockedP1M3task

    Description

    Why

    Cranes, nets, seals, strongrooms, sea-doors and the Tern are the heist's moving parts; bells and buoys give the harbour its low, slightly sad pulse.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Crane winch loop and jib swing, cargo net cut and drop-splash, customs stamp, seal break and re-stamp, strongroom door, skylight, hoist beam creak, Gull trapdoor, sea-door, Tern anchor chain, sails unfurl, ship's bell, tide change, bell buoy and breakwater fog bell.

    Asset ids (18):

    • sfx-crane-winch-loop-01
    • sfx-crane-jib-swing-01
    • sfx-cargo-net-cut-01
    • sfx-cargo-net-drop-splash-01
    • sfx-customs-stamp-01
    • sfx-customs-seal-break-01
    • sfx-customs-seal-restamp-01
    • sfx-strongroom-door-01
    • sfx-skylight-open-01
    • sfx-hoist-beam-creak-01
    • sfx-trapdoor-gull-01
    • sfx-sea-door-01
    • sfx-tern-anchor-chain-01
    • sfx-tern-sails-unfurl-01
    • sfx-tern-ship-bell-01
    • sfx-tide-change-01
    • sfx-bell-buoy-01
    • sfx-fog-bell-breakwater-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-harbour-mechanisms-generate)

    Notes

    Net cut, ship's bell, bell buoy and fog bell are added from audio bible §7.9.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 18 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.90Generate harbour mechanism and ship SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-harbour-mechanisms-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 18 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    • mw-e38.89 Write harbour mechanism and ship SFX prompts (18 assets) open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.91Owner approval: harbour mechanism and ship SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 18 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-harbour-mechanisms-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the net cut reads as fibrous snap plus falling load, seal break vs re-stamp are distinguishable, and harbour bells are thinner and shorter than the Vesper Bell with no minor-third bloom. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 18 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the net cut reads as fibrous snap plus falling load, seal break vs re-stamp are distinguishable, and harbour bells are thinner and shorter than the Vesper Bell with no minor-third bloom.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-harbour-mechanisms-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.90 Generate harbour mechanism and ship SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.92Integrate approved harbour mechanism and ship SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e40-stone-wharf, e40-customs-house, e40-bonded-warehouse, e40-drowned-gull, e40-breakwater-sea-door, e40-gilded-tern, e40-crate-heist.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 18 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Stone Wharf, warehouse, customs house and breakwater, when a crane swings, a net is cut, a seal is broken and re-stamped, the sea-door opens and the Tern sails, then final sounds play with correct noise events and no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    • mw-e38.91 Owner approval: harbour mechanism and ship SFX open
    • mw-e40.14 Build the Gilded Tern: rigging, hold, cabin, locked berth, departure open
    • mw-e40.15 Build the breakwater, sunken figurehead, sea-door and harbour tides open
    • mw-e40.2 Build the Stone Wharf with working cranes, cargo nets, crates and block yards open
    • mw-e40.20 Place The Crate for Mr. S— heist with all six solution routes open
    • mw-e40.3 Build the Customs House, its strongroom and Cray's book confiscation open
    • mw-e40.4 Build the Bonded Warehouse: bay nine, skylights, hoists and manifests open
    • mw-e40.6 Build the Drowned Gull: arm-wrestling, dice, drinking and the trapdoor open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.93Write harbour contest, alarm and gull SFX prompts (25 assets)blockedP1M3task

    Description

    Why

    Contests, brawls and the watch's non-verbal alarms carry the harbour's hijinks; gulls and rats are its ambient mischief.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Arm-wrestle strain loop and table slam, four brawl punches, crowd cheer and groan, wooden gull target hit, regatta oars loop and starting clapper, dice roll, tankard slam; watch wooden rattle and handbell, smuggler whistle, bosun's pipe, thrown-off-pier splash and surfacing gasp; four gull cries, gull snatch "ha-ha", rat startle squeal.

    Asset ids (25):

    • sfx-arm-wrestle-strain-loop-01
    • sfx-arm-wrestle-slam-01
    • sfx-brawl-punch-01
    • sfx-brawl-punch-02
    • sfx-brawl-punch-03
    • sfx-brawl-punch-04
    • sfx-crowd-cheer-01
    • sfx-crowd-groan-01
    • sfx-wooden-gull-hit-01
    • sfx-regatta-oars-loop-01
    • sfx-regatta-start-clapper-01
    • sfx-dice-roll-01
    • sfx-tankard-slam-01
    • sfx-watch-rattle-01
    • sfx-watch-handbell-01
    • sfx-smuggler-whistle-01
    • sfx-bosun-pipe-01
    • sfx-thrown-off-pier-splash-01
    • sfx-surface-gasp-01
    • sfx-gull-cry-01
    • sfx-gull-cry-02
    • sfx-gull-cry-03
    • sfx-gull-cry-04
    • sfx-gull-snatch-01
    • sfx-rat-squeal-startle-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-harbour-contests-life-generate)

    Notes

    Audio bible §7.9 replaces the needs list's sfx-watch-whistle-01 with the watch's wooden rattle and handbell (sfx-watch-rattle-01, sfx-watch-handbell-01) and the regatta start bell with a wooden clapper (sfx-regatta-start-clapper-01); sfx-bosun-pipe-01 is added for the Tern crew.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 25 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.94Generate harbour contest, alarm and gull SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-harbour-contests-life-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 25 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    • mw-e38.93 Write harbour contest, alarm and gull SFX prompts (25 assets) open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.95Owner approval: harbour contest, alarm and gull SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 25 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-harbour-contests-life-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: crowd sounds carry emotion with no words, the watch, smuggler and crew alarms are instantly distinguishable, brawl hits read comic not brutal, and the rat startle is loud enough to matter as a noise event. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 25 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then crowd sounds carry emotion with no words, the watch, smuggler and crew alarms are instantly distinguishable, brawl hits read comic not brutal, and the rat startle is loud enough to matter as a noise event.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-harbour-contests-life-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.94 Generate harbour contest, alarm and gull SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.96Integrate approved harbour contest, alarm and gull SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e40-contest-framework, e40-tidefair-strength, e40-tidefair-shoot-pockets, e40-drowned-gull, e40-harbor-opposition, e40-harbor-crowds, e40-tidefair-regatta, e40-harbor-ambient-life. Lower-priority consumers (e40-tidefair-regatta, e40-harbor-ambient-life) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 25 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Tidefair and the Drowned Gull, when a bout, a brawl, the Gull Shoot and a watch alarm run, then final sounds play with correct noise events and no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    • mw-e38.95 Owner approval: harbour contest, alarm and gull SFX open
    • mw-e40.16 Fill the harbour with pickpocketable crowds that give stealth cover open
    • mw-e40.18 Add the harbour watch, Low Tide Company and Tern crew as humans open
    • mw-e40.5 Run data-defined contests with entry, scoring, cheating and bets done
    • mw-e40.6 Build the Drowned Gull: arm-wrestling, dice, drinking and the trapdoor open
    • mw-e40.7 Stage the Tidefair arm-wrestling bout and the Gull brawl open
    • mw-e40.8 Stage the Tidefair Gull Shoot and the Pocket Race open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.97Write Saltmarch weapon, arrow and tool SFX prompts (12 assets)blockedP1M3task

    Description

    Why

    Imported gear must sound foreign and its gameplay-relevant noise must match the sim: a whistling arrow is a lure, glass shatter tears Hushlings, glue-soled boots are quieter than any gait.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Saltmarch sabre ring (thinner, higher than local steel), harpoon-spear haft thrum, sharkskin brigandine rasp layer (quieter than leather), arrows: whistling shriek, netting thwump, tar slap, glass-headed shatter, grapple clink and pay-out; Undertow tools: smoke pearl pop-hiss, glue-soled boot peel, skeleton-key ring jingle, tide-silk rope whisper.

    Asset ids (12):

    • sfx-saltmarch-sabre-ring-01
    • sfx-harpoon-spear-thrum-01
    • sfx-armor-sharkskin-layer
    • sfx-arrow-whistling-01
    • sfx-arrow-netting-01
    • sfx-arrow-tar-01
    • sfx-arrow-glass-shatter-01
    • sfx-arrow-grapple-01
    • sfx-smoke-pearl-01
    • sfx-glue-boots-peel-01
    • sfx-key-ring-jingle-01
    • sfx-tide-silk-rope-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-saltmarch-imports-generate)

    Notes

    Ids follow part A patterns (sfx-armor-<material>-layer, sfx-arrow-*). No duplicates of part A arrow or armour sounds.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 12 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.98Generate Saltmarch weapon, arrow and tool SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-saltmarch-imports-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 12 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    • mw-e38.97 Write Saltmarch weapon, arrow and tool SFX prompts (12 assets) open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.99Owner approval: Saltmarch weapon, arrow and tool SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 12 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-saltmarch-imports-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the whistling arrow is gameplay-loud and glass shatter is loud enough for its Hushling rule, the brigandine layer sits between cloth and leather, and glue-soled boots are quieter than any sneak step. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the whistling arrow is gameplay-loud and glass shatter is loud enough for its Hushling rule, the brigandine layer sits between cloth and leather, and glue-soled boots are quieter than any sneak step.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-saltmarch-imports-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.98 Generate Saltmarch weapon, arrow and tool SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.100Integrate approved Saltmarch weapon, arrow and tool SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e40-tidemarket, e40-undertow, e28-bow-audio, e28-footsteps, e04-armor-weight.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 12 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the stealth grey-box course, when each import is equipped and used, then final sounds play with noise radii matching the sim and no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e04.16 Armor weight sets roll class, stamina regen, poise and noise done
    • mw-e28.6 Surface-aware footsteps modulated by stance and armor done
    • mw-e28.7 Bow audio: draw creak, release, flyby and payload cues open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    • mw-e38.99 Owner approval: Saltmarch weapon, arrow and tool SFX open
    • mw-e40.10 Author the Tidemarket: Tereza's arms stall and the foreign book cart open
    • mw-e40.12 Build the Undertow black market and its smugglers' tunnels open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.102Owner generates main theme and motif anchor in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-anchors-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 3 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.101 Write main theme and motif anchor Suno prompts (3) done
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.103Owner approval: main theme and motif anchorblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-anchors-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each anchor states its motif clearly enough to be recognised when quoted in other tracks, the hymn is calm and plainchant-like, and the Nightjar's song is seductive rather than scary. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 3 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each anchor states its motif clearly enough to be recognised when quoted in other tracks, the hymn is calm and plainchant-like, and the Nightjar's song is seductive rather than scary.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-anchors-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.102 Owner generates main theme and motif anchor in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.104Integrate approved main theme and motif anchor into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Cut bar-aligned loop points, add -end tails, normalise to the §5.1 targets, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data (family → states).

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e01-title-new-game-flow.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then explore/stealth tracks are −18 LUFS ±1 (≤ −1.5 dBTP) and tension/combat/boss tracks −16 LUFS ±1 (≤ −1.0 dBTP), loop regions are whole bars ≥ 60 s with sample-accurate seams, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given the title screen, when it loads, then music-title-main-theme loops seamlessly on the music bus; the two motif anchors are present in the music registry for derived tracks.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e01.2 Title screen flows into class select, spawn and continue done
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.105Write Briar Glen music family Suno prompts (10)blockedP1M3task

    Description

    Why

    Briar Glen day, night, the inn, the bookshop and the first-night sleepwalk are the most-heard music in the game and establish "warm but uneasy".

    What

    Write one prompt file per track in assets/prompts/music/<asset-id>.md from _templates/music-track.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    Day family (D Dorian 88 BPM 6/8: explore, tension, combat), night family (D Aeolian 72 BPM: explore with faint Nightjar fragments on still nights, stealth, tension, combat), the Sleeping Ox (diegetic, G Mixolydian 108), the Lamplit Stacks (A Lydian 70, magic motif) and the first-night sleepwalk (the Nightjar's song hummed, following Tansy).

    Asset ids (10):

    • music-briar-glen-day-explore
    • music-briar-glen-day-tension
    • music-briar-glen-day-combat
    • music-briar-glen-night-explore
    • music-briar-glen-night-stealth
    • music-briar-glen-night-tension
    • music-briar-glen-night-combat
    • music-sleeping-ox-explore
    • music-lamplit-stacks-explore
    • music-first-night-sleepwalk

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-briar-glen-generate, owner)

    Notes

    Ids follow the audio bible §3 family roots (the world needs list said music-briar-glen-tavern / -bookshop); music-first-night-sleepwalk is new.

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 10 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.106Owner generates Briar Glen music family in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-briar-glen-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 10 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.105 Write Briar Glen music family Suno prompts (10) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.107Owner approval: Briar Glen music familyblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-briar-glen-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each family shares key and tempo so bar-synced cuts are seamless, day feels safe and warm, night uneasy, and the sleepwalk quotes the Nightjar's song recognisably. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each family shares key and tempo so bar-synced cuts are seamless, day feels safe and warm, night uneasy, and the sleepwalk quotes the Nightjar's song recognisably.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-briar-glen-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.106 Owner generates Briar Glen music family in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.108Integrate approved Briar Glen music family into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Cut bar-aligned loop points, add -end tails, normalise to the §5.1 targets, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data (family → states).

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e24-sleeping-ox, e24-lamplit-stacks, e24-first-night. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e24-town-lighting-audio.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then explore/stealth tracks are −18 LUFS ±1 (≤ −1.5 dBTP) and tension/combat/boss tracks −16 LUFS ±1 (≤ −1.0 dBTP), loop regions are whole bars ≥ 60 s with sample-accurate seams, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given Briar Glen, when the world clock passes day→night and a guard escalates suspicious→combat, then the matching family tracks cross-fade on bar boundaries and the inn/bookshop tracks play indoors, with no clipping.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e24.14 Stage the first-night sleepwalk from the Ox to the mine gate open
    • mw-e24.4 Build the Sleeping Ox inn: common room, rooms, cellar and rest open
    • mw-e24.5 Author the Lamplit Stacks bookshop on the e21 authoring template open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.107 Owner approval: Briar Glen music family open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.109Write wilderness music families Suno prompts (7)blockedP1M3task

    Description

    Why

    The wilderness music must feel open and old, cooler as you go deeper, with enough stealth support for the wolf den and the watchtower.

    What

    Write one prompt file per track in assets/prompts/music/<asset-id>.md from _templates/music-track.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    Briarwood family (A Aeolian 80 BPM: explore, stealth, tension, combat) and Mooring's Watch family (E Aeolian 76 BPM: explore, tension, combat).

    Asset ids (7):

    • music-briarwood-explore
    • music-briarwood-stealth
    • music-briarwood-tension
    • music-briarwood-combat
    • music-moorings-watch-explore
    • music-moorings-watch-tension
    • music-moorings-watch-combat

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-wilds-generate, owner)

    Notes

    Ids follow audio bible §3 (music-briarwood, music-moorings-watch; needs list said music-forest, music-watchtower).

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 7 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.110Owner generates wilderness music families in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-wilds-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 7 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.109 Write wilderness music families Suno prompts (7) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.111Owner approval: wilderness music familiesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-wilds-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each family is key/tempo-locked, the Briarwood feels open and hushed (no wolf howls), and Mooring's Watch feels windswept and dutiful. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 7 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each family is key/tempo-locked, the Briarwood feels open and hushed (no wolf howls), and Mooring's Watch feels windswept and dutiful.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-wilds-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.110 Owner generates wilderness music families in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.112Integrate approved wilderness music families into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Cut bar-aligned loop points, add -end tails, normalise to the §5.1 targets, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data (family → states).

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: . Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e25-wilds-lighting-audio.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then explore/stealth tracks are −18 LUFS ±1 (≤ −1.5 dBTP) and tension/combat/boss tracks −16 LUFS ±1 (≤ −1.0 dBTP), loop regions are whole bars ≥ 60 s with sample-accurate seams, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given the Briarwood and Mooring's Watch, when the player sneaks past wolves and fights at the tower, then explore/stealth/tension/combat tracks switch on bar boundaries with 4 s / 6 s hysteresis and no clipping.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.111 Owner approval: wilderness music families open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.113Write mine and priory music families Suno prompts (8)blockedP1M3task

    Description

    Why

    The mine is sparse and tense below the Bell Line; the priory is choral and melancholy — the Vesper hymn's home.

    What

    Write one prompt file per track in assets/prompts/music/<asset-id>.md from _templates/music-track.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    Deepworks family (C♯ Phrygian 64 BPM: sparse explore, stealth, tension, combat, quoting the Knot motif below the Bell Line) and Bellwater Priory family (F Dorian 60 BPM, choir: explore, stealth, tension, combat, quoting the Vesper hymn).

    Asset ids (8):

    • music-deepworks-explore
    • music-deepworks-stealth
    • music-deepworks-tension
    • music-deepworks-combat
    • music-bellwater-priory-explore
    • music-bellwater-priory-stealth
    • music-bellwater-priory-tension
    • music-bellwater-priory-combat

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-deepworks-priory-generate, owner)

    Notes

    Ids follow audio bible §3 (music-deepworks, music-bellwater-priory; needs list said music-old-mine, music-monastery).

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 8 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.114Owner generates mine and priory music families in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-deepworks-priory-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 8 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.113 Write mine and priory music families Suno prompts (8) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.115Owner approval: mine and priory music familiesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-deepworks-priory-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the Deepworks leaves room for silence and ambience, the priory quotes the Vesper hymn recognisably, and both families cut seamlessly between states. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the Deepworks leaves room for silence and ambience, the priory quotes the Vesper hymn recognisably, and both families cut seamlessly between states.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-deepworks-priory-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.114 Owner generates mine and priory music families in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.116Integrate approved mine and priory music families into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Cut bar-aligned loop points, add -end tails, normalise to the §5.1 targets, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data (family → states).

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: . Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-dungeon-lighting-audio.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then explore/stealth tracks are −18 LUFS ±1 (≤ −1.5 dBTP) and tension/combat/boss tracks −16 LUFS ±1 (≤ −1.0 dBTP), loop regions are whole bars ≥ 60 s with sample-accurate seams, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given the Deepworks and the priory, when goblins are alerted and the Forgotten engage, then state tracks switch on bar boundaries and the silence budget returns to ambience after 1–2 explore loops.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.115 Owner approval: mine and priory music families open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.117Write Knot, Fold and Cradle music Suno prompts (8)blockedP1M3task

    Description

    Why

    The Knot's never-resolving turn, the Fold's tender reveal and the Cradle's drifting lullaby are the emotional spine of Act II–III.

    What

    Write one prompt file per track in assets/prompts/music/<asset-id>.md from _templates/music-track.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    Knot family (E Phrygian 58 BPM: drone explore, stealth, tension, combat), the Fold (E Lydian 66: Horn's reveal harmony), the Cradle (explore drone and tension with the Nightjar's song drifting out of tune), and a Nightjar-song stem layered by song.intensity (0–3).

    Asset ids (8):

    • music-knot-explore
    • music-knot-stealth
    • music-knot-tension
    • music-knot-combat
    • music-knot-fold-explore
    • music-knot-cradle-explore
    • music-knot-cradle-tension
    • music-knot-stem-song

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-knot-generate, owner)

    Notes

    Ids follow audio bible §3 and the music-<family>-stem-<layer> pattern (needs list said music-labyrinth, music-labyrinth-heart, music-labyrinth-stem-song).

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 8 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.118Owner generates Knot, Fold and Cradle music in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-knot-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 8 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.117 Write Knot, Fold and Cradle music Suno prompts (8) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.119Owner approval: Knot, Fold and Cradle musicblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-knot-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the Knot motif never resolves, the Fold is unmistakably warm and tender, the Cradle is beautiful-uneasy, and the song stem layers over every Knot state without clashing. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the Knot motif never resolves, the Fold is unmistakably warm and tender, the Cradle is beautiful-uneasy, and the song stem layers over every Knot state without clashing.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-knot-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.118 Owner generates Knot, Fold and Cradle music in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.120Integrate approved Knot, Fold and Cradle music into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Cut bar-aligned loop points, add -end tails, normalise to the §5.1 targets, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data (family → states).

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e13-song-intensity, e26-horns-hall-fold, e26-cradle-arena. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-dungeon-lighting-audio.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then explore/stealth tracks are −18 LUFS ±1 (≤ −1.5 dBTP) and tension/combat/boss tracks −16 LUFS ±1 (≤ −1.0 dBTP), loop regions are whole bars ≥ 60 s with sample-accurate seams, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given the Knot, when song.intensity is stepped 0→3 via the debug console and the player enters the Fold and the Cradle, then the song stem gain follows intensity, the Fold track takes over on entry, and nothing clips.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e13.5 Drive creature behaviour from a global song-intensity world state open
    • mw-e26.16 Stage Horn's Hall and the Fold, the reveal and the wake-up point open
    • mw-e26.17 Stage the Cradle arena for the abbot confrontation open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.119 Owner approval: Knot, Fold and Cradle music open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.121Write boss, climb and finale music Suno prompts (8)blockedP1M3task

    Description

    Why

    The Warden fight (sorrow, not menace), the abbot confrontation (song versus hymn), the Climb and the bell-ringing finale are the MVP's set pieces.

    What

    Write one prompt file per track in assets/prompts/music/<asset-id>.md from _templates/music-track.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    Warden boss (E Phrygian 112 half-time: intro, loop A, loop B leaning toward the reveal harmony), abbot boss (E Phrygian/Locrian 100 in 3/4: intro, loop A, loop B braiding the Nightjar song with the inverted hymn), the Sounding Shaft climb (132, rising E Phrygian → D Dorian) and the Vespers finale (the bell rung, the song falters).

    Asset ids (8):

    • music-boss-warden-intro
    • music-boss-warden-loop-a
    • music-boss-warden-loop-b
    • music-boss-abbot-intro
    • music-boss-abbot-loop-a
    • music-boss-abbot-loop-b
    • music-sounding-shaft-climb
    • music-vespers-finale

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-bosses-climb-generate, owner)

    Notes

    Ids follow audio bible §3 (music-boss-warden family; the needs list said music-boss-minotaur). music-vespers-finale is new.

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 8 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.122Owner generates boss, climb and finale music in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-bosses-climb-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 8 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.121 Write boss, climb and finale music Suno prompts (8) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.123Owner approval: boss, climb and finale musicblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-bosses-climb-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the Warden music is weighty and sad rather than menacing, the abbot music audibly braids song and hymn, the climb drives upward, and the finale resolves into the hymn. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the Warden music is weighty and sad rather than menacing, the abbot music audibly braids song and hymn, the climb drives upward, and the finale resolves into the hymn.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-bosses-climb-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.122 Owner generates boss, climb and finale music in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.124Integrate approved boss, climb and finale music into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Cut bar-aligned loop points, add -end tails, normalise to the §5.1 targets, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data (family → states).

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e13-horn-encounter, e13-abbot-encounter, e26-sounding-shaft-climb, e26-vesper-bell-finale. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-dungeon-lighting-audio.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then explore/stealth tracks are −18 LUFS ±1 (≤ −1.5 dBTP) and tension/combat/boss tracks −16 LUFS ±1 (≤ −1.0 dBTP), loop regions are whole bars ≥ 60 s with sample-accurate seams, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given the Warden and Cradle encounters and the climb, when each is started via the debug console, then boss intro → loop A → loop B transitions land on bar boundaries and the finale track plays on the bell-rung fact, with no clipping.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e13.14 Build the Warden boss encounter with yield, spare and Trial of Horns open
    • mw-e13.16 Build the Cradle encounter with fight, trick, persuade and join paths open
    • mw-e26.18 Build the Sounding Shaft climb with defenders and chase variants open
    • mw-e26.19 Ring the Vesper Bell: hang the tongue, mend it and wake the sleepers open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.123 Owner approval: boss, climb and finale music open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.125Write ending beds and credits Suno prompts (5)blockedP1M3task

    Description

    Why

    Each of the four endings needs its own epilogue bed so the player feels what their choices made; the credits close on the main theme.

    What

    Write one prompt file per track in assets/prompts/music/<asset-id>.md from _templates/music-track.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    Epilogue beds for "Vespers Rung" (hymn resolved, warm), "The Last Warden" (the Horn motif, alone), "The Hireling's Silence" (prosperous but hollow, a faint song on still nights), "The Long Vespers" (the lullaby, a doorway not a grave), and the credits (D Dorian → D Lydian 84, class idents woven in).

    Asset ids (5):

    • music-ending-vespers-rung
    • music-ending-last-warden
    • music-ending-hirelings-silence
    • music-ending-long-vespers
    • music-credits

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-endings-generate, owner)

    Notes

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 5 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.126Owner generates ending beds and credits in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-endings-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 5 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.125 Write ending beds and credits Suno prompts (5) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.127Owner approval: ending beds and creditsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-endings-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each ending bed is distinct in emotion yet one family, none is despairing, and the credits resolve the main theme. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 5 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each ending bed is distinct in emotion yet one family, none is despairing, and the credits resolve the main theme.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-endings-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.126 Owner generates ending beds and credits in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.128Integrate approved ending beds and credits into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Cut bar-aligned loop points, add -end tails, normalise to the §5.1 targets, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data (family → states).

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e26-ending-states.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then explore/stealth tracks are −18 LUFS ±1 (≤ −1.5 dBTP) and tension/combat/boss tracks −16 LUFS ±1 (≤ −1.0 dBTP), loop regions are whole bars ≥ 60 s with sample-accurate seams, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given each ending state forced via the debug console, when the epilogue plays, then the matching bed plays under the slides and the credits track follows, with no clipping.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e26.23 Build the four endings' level states across town and dungeon open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.127 Owner approval: ending beds and credits open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.129Write world stingers and cues Suno prompts (20)blockedP1M3task

    Description

    Why

    Location-keyed combat stingers mask state cuts in key (audio bible §2.3), and five story beats plus the diegetic hymn hum need their own cues.

    What

    Write one prompt file per stinger/cue in assets/prompts/music/<asset-id>.md from _templates/music-stinger.md: Style field = SUNO STYLE PREAMBLE (audio bible §4.1) verbatim + tags, Exclude styles, structure-only Lyrics, key/mode, BPM, metre, length, loop plan and output spec.

    Combat-start (1–2 s) and combat-victory (3–5 s) stingers in each location key (d-dorian = Briar Glen day; d-aeolian = Briar Glen night; a-aeolian = Briarwood; e-aeolian = Mooring's Watch; cs-phrygian = Deepworks; f-dorian = Bellwater Priory; e-phrygian = the Knot and bosses); story stingers fold-reveal (Horn motif reveal variant, 6–10 s), song-swell (Nightjar fragment rising and detuning, 3–6 s), vespers-rung (bell toll + hymn cadence, 6–10 s), horn-sighting (distant Horn in the Outer Ring) and sour-bell (early tongueless strike); and music-hymn-vesper-hum, a short loopable voice-neutral hum of the Vesper hymn derived from the hymn anchor (the player hums it; Clatter and Mirror Self reuse it).

    Asset ids (20):

    • music-stinger-combat-start-d-dorian
    • music-stinger-combat-start-d-aeolian
    • music-stinger-combat-start-a-aeolian
    • music-stinger-combat-start-e-aeolian
    • music-stinger-combat-start-cs-phrygian
    • music-stinger-combat-start-f-dorian
    • music-stinger-combat-start-e-phrygian
    • music-stinger-combat-victory-d-dorian
    • music-stinger-combat-victory-d-aeolian
    • music-stinger-combat-victory-a-aeolian
    • music-stinger-combat-victory-e-aeolian
    • music-stinger-combat-victory-cs-phrygian
    • music-stinger-combat-victory-f-dorian
    • music-stinger-combat-victory-e-phrygian
    • music-stinger-fold-reveal
    • music-stinger-song-swell
    • music-stinger-vespers-rung
    • music-stinger-horn-sighting
    • music-stinger-sour-bell
    • music-hymn-vesper-hum

    Scope

    • In: One Suno prompt per id
    • In: Motif references per audio bible §1.4 and family key/BPM per §3
    • Out: Pasting into Suno (e38-asset-music-stingers-world-generate, owner)

    Notes

    Part A's key-neutral music-stinger-combat-start stays the fallback; these keyed variants replace it per location. music-stinger-fold-reveal is the "Brother Horn reveal" part A referred to as music-stinger-horn-reveal. music-stinger-horn-sighting and music-stinger-sour-bell are extra world beats from the needs list. The hymn hum may alternatively be produced from the anchor by Claude (pitch/formant processing) if Suno takes contain syllables.

    Music is human-in-the-loop: the owner pastes each Suno prompt (≈ 1 min per track) and drops the chosen take in assets/_incoming/music/. Family members share key/mode and BPM (audio bible §2.2); derived tracks use the approved motif anchors as audio reference where the Suno tier allows. Not gated by the sonic lock (different medium). Paid Suno tier required for distribution.

    Acceptance criteria

    • AC-1 content Given the 20 ids, when the asset validator runs, then each has one prompt file matching audio bible §6 music naming (music-<location>-<time?>-<state>, music-stinger-<event>-<key?>, music-<family>-stem-<layer>).
    • AC-2 content Given each prompt, when compared with docs/audio/audio-bible.md §4.1, then the Style field starts with the preamble byte-for-byte and the Exclude field matches the bible list.
    • AC-3 content Given each prompt, when inspected, then key/mode and BPM equal the audio bible §3 family row (or §2.3 stinger row), length is within §4 / §2.3 limits and the leitmotif it must carry is named.
    • AC-4 content Edge: given a prompt whose Lyrics field contains singable words, or which names a real artist, composer or game, when validated, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.130Owner generates world stingers and cues in SunoblockedP1M3task

    Description

    Why

    Suno has no official API; the owner pastes Claude's prompts (≈ 1 min per track) — contract §1.

    What

    For each prompt of e38-asset-music-stingers-world-prompts, the owner pastes Style/Exclude/Lyrics into Suno (paid tier, Instrumental on; for music-hymn-vesper-hum only, use a wordless hum (no words); reject takes with intelligible syllables), picks the best take and drops the WAV at assets/_incoming/music/<asset-id>.wav.

    Scope

    • In: Owner Suno session
    • In: Dropping takes in the incoming folder
    • Out: Any audio editing (Claude does it in the integrate bead)

    Notes

    Record Suno tier and date in a one-line note per take (Claude turns it into the sidecar).

    Acceptance criteria

    • AC-1 manual Given the 20 prompts, when the owner finishes the session, then a WAV exists at assets/_incoming/music/<asset-id>.wav for every id.
    • AC-2 manual Given each take, when chosen, then it was generated on a paid Suno tier (recorded in the note).
    • AC-3 integration Edge: given a missing or unreadable WAV, when Claude's intake check runs, then it lists the missing ids and does not block the ids that are present.

    Waits on

    • mw-e38.129 Write world stingers and cues Suno prompts (20) open
    • mw-e38.8 Spike: prove a key/BPM-locked Suno family with bar-synced cuts open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.131Owner approval: world stingers and cuesblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the music take gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the processed (trimmed, loop-pointed, loudness-normalised) takes played in context and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: music take, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-music-stingers-world-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each keyed stinger sits in its family key, victory stingers quote the main theme, story stingers are recognisable motif statements, and the hymn hum loops cleanly and sounds hummable. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 20 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "music take".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each keyed stinger sits in its family key, victory stingers quote the main theme, story stingers are recognisable motif statements, and the hymn hum loops cleanly and sounds hummable.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-music-stingers-world-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.130 Owner generates world stingers and cues in Suno open
    area:musicasset:musicepic:e38milestone:m3needs-human
  • mw-e38.132Integrate approved world stingers and cues into adaptive musicblockedP1M3task

    Description

    Why

    Music only matters when it plays in the right state, in key, on the bar (audio bible §2).

    What

    Trim, fade tails, normalise to stinger loudness, encode Opus + AAC with loop/BPM/key sidecars, add CREDITS (Suno tier + date) and approval records, and bind ids in the music state data / stinger table.

    Scope

    • In: Post-processing, encode, CREDITS, approval records, data binding
    • Out: Adaptive music controller logic (e28-adaptive-music)

    Notes

    Consumers: e26-horns-hall-fold, e13-song-intensity, e26-vesper-bell-finale, e26-outer-ring-encounters, e26-priory-belfry, e14-hum-vesper-hymn.

    Acceptance criteria

    • AC-1 integration Given the approved takes, when processed, then each stinger is −16 LUFS ±1 (short-term max), ≤ −1.0 dBTP, transient within 20 ms of start and tail ≤ 2 s, and e38-audio-validator is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with Suno tier, date and prompt path, plus an approval record.
    • AC-3 e2e Given each location, when combat starts and ends, then its keyed stingers fire on the music bus in key; and given the Fold entry, a song swell, the bell rung, a Horn sighting, an early bell strike and a player hum, then each story cue plays once without clipping.
    • AC-4 integration Edge: given an id without an approval record, when the build runs, then its placeholder remains and the remaining-placeholder report lists it.

    Waits on

    • mw-e13.5 Drive creature behaviour from a global song-intensity world state open
    • mw-e14.1 Let the player hum the Vesper hymn after reading the Vesperine Hours open
    • mw-e26.12 Populate the Outer Ring: spiders, first Forgotten, Horn sighting open
    • mw-e26.16 Stage Horn's Hall and the Fold, the reveal and the wake-up point open
    • mw-e26.19 Ring the Vesper Bell: hang the tongue, mend it and wake the sleepers open
    • mw-e26.8 Build the belfry and the sour-bell consequence of early ringing open
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e38.131 Owner approval: world stingers and cues open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    area:musicasset:musicepic:e38milestone:m3
  • mw-e38.133Write Briar Glen and wilderness ambience prompts (15 assets)blockedP1M3task

    Description

    Why

    Ambience carries place and gameplay (audio bible §7.7): the town that falls silent past midnight, the wood without wolf howls, water you can hear before you see.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Briar Glen: day market, night (crickets, a distant dog, no wolves, the Nightjar faint on still nights), the Sleeping Ox murmur, Brand's Forge hammering, the Lamplit Stacks quiet (clock, pages, Mortimer's rustle), Glen Well cistern drips, cemetery wind. Wilderness: Briarwood day, Briarwood night (the wolves' silence), Briarwood night with howls (ending variant only), millpond water, drowned lane at night (faint mimic whisper), Standing Horn hum, Mooring's Watch wind and banner remnants, Deepworks gate exterior.

    Asset ids (15):

    • amb-briar-glen-day-market-01
    • amb-briar-glen-night-01
    • amb-sleeping-ox-murmur-01
    • amb-brand-forge-hammering-01
    • amb-lamplit-stacks-quiet-01
    • amb-glen-well-cistern-drips-01
    • amb-cemetery-wind-01
    • amb-briarwood-day-01
    • amb-briarwood-night-silent-01
    • amb-briarwood-night-howls-01
    • amb-millpond-water-01
    • amb-drowned-lane-night-01
    • amb-standing-horn-hum-01
    • amb-moorings-watch-wind-01
    • amb-deepworks-gate-exterior-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-amb-surface-generate)

    Notes

    ElevenLabs clips are short: beds ≥ 30 s are stitched from several generations with crossfaded seams, or sourced from CC0 beds; memorable events (dog bark, bird call) are separate randomised one-shots. Replaces part A placeholders (amb-placeholder-*). amb-briarwood-night-howls-01 is used only by the ending states (e26-ending-states).

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 15 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each bed, when inspected, then it states loop length ≥ 30 s, stereo, the randomised one-shots kept out of the bed, and the §7.7 gameplay role (draught, water, song) it carries.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (ambience −24 LUFS ± 2, ≤ −3.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.134Generate Briar Glen and wilderness ambience via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout, loop-seam preview).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-amb-surface-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds. Loop beds are stitched from multiple generations where the API limits clip length.

    Acceptance criteria

    • AC-1 integration Given the 15 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then beds are stereo, ≥ 30 s, loop seams pass the discontinuity check, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.133 Write Briar Glen and wilderness ambience prompts (15 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.135Owner approval: Briar Glen and wilderness ambienceblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 15 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-amb-surface-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each bed identifies its place with eyes closed, loops without an audible seam over 3 minutes, and the Briarwood night bed is audibly missing wildlife compared with day. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 15 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each bed identifies its place with eyes closed, loops without an audible seam over 3 minutes, and the Briarwood night bed is audibly missing wildlife compared with day.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-amb-surface-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.134 Generate Briar Glen and wilderness ambience via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.136Integrate approved Briar Glen and wilderness ambienceblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets / ambience zone data, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-cue-sheets, e24-town-greybox, e25-briarwood-greybox, e25-mooring-watch-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e24-town-lighting-audio, e25-wilds-lighting-audio. Ambience zone playback is e28-ambience (P2); these P1 beds are bound through the cue sheets so they play even if ambience zones are cut — flag if that changes.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 15 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given Briar Glen and the wilderness, when the player walks from the Market Green through the Briarwood to the mine gate by day and night, then the matching final beds play and cross-fade with no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e24.2 Block out Briar Glen in grey-box with every named building shell done
    • mw-e25.1 Block out the Briarwood with paths, clearings and the priory road done
    • mw-e25.6 Block out Mooring's Watch: courtyard, tower floors, roof and tunnel done
    • mw-e28.3 Data-driven cue sheets map sim events to sounds done
    • mw-e38.135 Owner approval: Briar Glen and wilderness ambience open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.137Write Deepworks, priory and Knot ambience prompts (12 assets)blockedP1M3task

    Description

    Why

    Dungeon ambience is most of what the player hears (silence budget, audio bible §2.1) and it hides gameplay cues: draughts at weak walls, the song rising toward the Cradle.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Deepworks drips, winch creaks, distant goblin camp; priory nave wind, scriptorium candles, belfry wind with the cracked bell's occasional hum; the Knot's hum, Ossuary bone rattles, Chapel of Echoes, the Fold's warm breathing (sleepers), Sounding Shaft updraft, and the Cradle dream bed carrying the Nightjar's song low and drifting.

    Asset ids (12):

    • amb-deepworks-drips-01
    • amb-deepworks-creaks-01
    • amb-deepworks-goblin-camp-01
    • amb-bellwater-nave-wind-01
    • amb-bellwater-scriptorium-candles-01
    • amb-bellwater-belfry-wind-01
    • amb-knot-hum-01
    • amb-knot-ossuary-bones-01
    • amb-knot-chapel-echoes-01
    • amb-knot-fold-breathing-01
    • amb-knot-sounding-shaft-updraft-01
    • amb-knot-cradle-dream-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-amb-dungeon-generate)

    Notes

    Ids use canon location names (audio bible §6 example amb-deepworks-drips-01; the needs list said amb-old-mine-*, amb-priory-*, amb-fold-*, amb-cradle-*). The Cradle bed is built from the approved Nightjar motif anchor. Replaces part A placeholder amb-placeholder-dungeon-drips-loop-01.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 12 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each bed, when inspected, then it states loop length ≥ 30 s, stereo, the randomised one-shots kept out of the bed, and the §7.7 gameplay role (draught, water, song) it carries.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (ambience −24 LUFS ± 2, ≤ −3.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.138Generate Deepworks, priory and Knot ambience via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout, loop-seam preview).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-amb-dungeon-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds. Loop beds are stitched from multiple generations where the API limits clip length.

    Acceptance criteria

    • AC-1 integration Given the 12 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then beds are stereo, ≥ 30 s, loop seams pass the discontinuity check, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.137 Write Deepworks, priory and Knot ambience prompts (12 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.139Owner approval: Deepworks, priory and Knot ambienceblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 12 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-amb-dungeon-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each bed identifies its space, the Fold bed sounds warm and alive against the cold Knot, and the Cradle bed carries the Nightjar motif recognisably without becoming music. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each bed identifies its space, the Fold bed sounds warm and alive against the cold Knot, and the Cradle bed carries the Nightjar motif recognisably without becoming music.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-amb-dungeon-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.138 Generate Deepworks, priory and Knot ambience via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.140Integrate approved Deepworks, priory and Knot ambienceblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets / ambience zone data, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-cue-sheets, e26-deepworks-greybox, e26-priory-greybox, e26-knot-outer-greybox, e26-knot-inner-greybox. Art-dress / lighting-audio beads that wait on this integrate (top-level edges): e26-dungeon-lighting-audio. Ambience zones are e28-ambience (P2); see the note on e38-asset-amb-surface-integrate.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 12 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Deepworks, priory and Knot, when the player walks from the winch house to the Cradle, then each final bed plays in its space and cross-fades with no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e26.10 Block out the Fold, Horn's Hall, Sounding Shaft foot and the Cradle done
    • mw-e26.2 Block out the Deepworks: winch house, galleries, goblin hall, breach done
    • mw-e26.5 Block out Bellwater Priory: nave, choir, scriptorium, belfry, crypt done
    • mw-e26.9 Block out the Knot's Outer Ring, Ossuary Galleries and Chapel done
    • mw-e28.3 Data-driven cue sheets map sim events to sounds done
    • mw-e38.139 Owner approval: Deepworks, priory and Knot ambience open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.141Write bell and chime SFX prompts (10 assets)blockedP1M3task

    Description

    Why

    The Vesper Bell is the game's signature sound (audio bible §7.8): tongueless it is a gameplay-loud mistake, rung it is "wrong and beautiful", mended it is true; the chapel chimes are a sound puzzle.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Tongueless sour strike (wakes the Forgotten, draws Hushlings and Horn), cracked ring with tongue (beating, sour partials, long bloom), mended true ring, the tongue being hung, Mooring's Watch "watch ended" iron bell, and five pitched chapel chimes for the Chimes puzzle.

    Asset ids (10):

    • sfx-vesper-bell-sour-01
    • sfx-vesper-bell-ring-01
    • sfx-vesper-bell-ring-true-01
    • sfx-vesper-bell-tongue-hang-01
    • sfx-watchtower-bell-watch-ended-01
    • sfx-chapel-chime-01
    • sfx-chapel-chime-02
    • sfx-chapel-chime-03
    • sfx-chapel-chime-04
    • sfx-chapel-chime-05

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-bells-generate)

    Notes

    Asset id sfx-vesper-bell-tongue-hang-01 follows audio bible §7.8 (sfx-vesper-bell-<variant>-<nn>; needs list said sfx-bell-tongue-hang-01). Chimes may be synthesised or tuned in the pipeline to guarantee pitch; the bell ring is paired with the vespers-rung stinger. Bells are stereo-positional with long tails, an intentional exception to the dry-SFX rule.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 10 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.142Generate bell and chime SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-bells-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 10 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.141 Write bell and chime SFX prompts (10 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.143Owner approval: bell and chime SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 10 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-bells-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the three Vesper Bell states are instantly distinguishable (harsh clank, beautiful-wrong, true), the watch-ended bell reads as a signal, and the five chimes are distinct, in tune with each other and matched to the puzzle order. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 10 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the three Vesper Bell states are instantly distinguishable (harsh clank, beautiful-wrong, true), the watch-ended bell reads as a signal, and the five chimes are distinct, in tune with each other and matched to the puzzle order.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-bells-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.142 Generate bell and chime SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.144Integrate approved bell and chime SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e26-priory-belfry, e26-vesper-bell-finale, e25-mooring-watch-encounters, e26-chapel-of-echoes, e15-sequence-sound-puzzles.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 10 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the belfry and the Chapel of Echoes, when the bell is struck tongueless, rung and mended, and the chimes puzzle is solved by replay, then the final sounds play positionally with correct noise events and the replay passes.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e15.5 Support ordered, timed and sound-clue puzzle mechanisms done
    • mw-e25.7 Place the Hollow Sentinels and goblin lookout with class resolutions open
    • mw-e26.14 Build the Chapel of Echoes with the Chimes puzzle and portcullis trap open
    • mw-e26.19 Ring the Vesper Bell: hang the tongue, mend it and wake the sleepers open
    • mw-e26.8 Build the belfry and the sour-bell consequence of early ringing open
    • mw-e38.143 Owner approval: bell and chime SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.145Write town and wilderness set-piece SFX prompts (9 assets)blockedP1M3task

    Description

    Why

    Surface mechanisms (sluice, well, drain stone, signal mirror, mine gate) and two story beats (Tansy's hum, the death beat) need sounds players remember.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Sluice gate, the well stone landing twice (the hollow cistern tell), the jail drain stone, signal mirror pivot creak and glint "ting", horn-coin clink (heavier than silver), mine gate boards breaking, Tansy's hummed sleepwalk loop (the Nightjar's song, voice-neutral hum), and the m1 death beat.

    Asset ids (9):

    • sfx-sluice-gate-01
    • sfx-well-stone-double-land-01
    • sfx-jail-drain-stone-01
    • sfx-signal-mirror-rotate-01
    • sfx-signal-mirror-glint-01
    • sfx-horn-coin-clink-01
    • sfx-mine-gate-boards-break-01
    • sfx-tansy-hum-sleepwalk-loop-01
    • sfx-death-beat-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-setpiece-surface-generate)

    Notes

    sfx-signal-mirror-glint-01 and sfx-horn-coin-clink-01 are added from audio bible §7.8 signature sounds. Tansy's hum is built from the Nightjar motif anchor (ElevenLabs hum or processed anchor).

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 9 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.146Generate town and wilderness set-piece SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-setpiece-surface-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 9 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.145 Write town and wilderness set-piece SFX prompts (9 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.147Owner approval: town and wilderness set-piece SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 9 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-setpiece-surface-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each mechanism sound tells the player what changed (the double-landing well stone reveals the hollow below), Tansy's hum is recognisably the Nightjar's song, and the death beat is weighty but not despairing. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 9 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each mechanism sound tells the player what changed (the double-landing well stone reveals the hollow below), Tansy's hum is recognisably the Nightjar's song, and the death beat is weighty but not despairing.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-setpiece-surface-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.146 Generate town and wilderness set-piece SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.148Integrate approved town and wilderness set-piece SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e25-millpond-drowned-lane, e24-glen-well-cistern, e24-watch-house-jail, e25-signal-mirror, e25-mine-gate-approach, e24-first-night, e01-death-respawn-loop.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 9 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given Briar Glen and the wilderness, when the well stone is dropped, the drain stone lifted, the sluice opened, the mirror turned, the gate boards broken and Tansy followed, then final sounds play with the right noise events and no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e01.8 Run the player death and respawn loop done
    • mw-e24.10 Hide the cistern route under the Glen Well open
    • mw-e24.14 Stage the first-night sleepwalk from the Ox to the mine gate open
    • mw-e24.8 Build the Watch House and a jail cell whose drain leads out open
    • mw-e25.10 Build the boarded mine gate with every class's way in open
    • mw-e25.5 Build the millpond and drowned lane with a Hushling and a lost lantern open
    • mw-e25.8 Turn the signal mirror to light the priory's hidden choir door open
    • mw-e38.147 Owner approval: town and wilderness set-piece SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.149Write dungeon mechanism and story-beat SFX prompts (12 assets)blockedP1M3task

    Description

    Why

    Dungeon mechanisms, collapses and the subtle loop-shift cue are how the Deepworks and the Knot talk back; the sleepers waking is the payoff.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Cage lift, mine support collapse, gas explosion, portcullis drop, the Knot loop shift (a subtle cue when runes loop you back), shortcut door unbar, the Fold horn-key door, breach seal, statue rotation (stone on stone), Cradle dream pulse, the sleepers waking, and waking in the Fold after death.

    Asset ids (12):

    • sfx-mine-cage-lift-01
    • sfx-mine-support-collapse-01
    • sfx-mine-gas-explosion-01
    • sfx-portcullis-drop-01
    • sfx-knot-loop-shift-01
    • sfx-shortcut-door-unbar-01
    • sfx-fold-door-horn-key-01
    • sfx-breach-seal-01
    • sfx-statue-rotate-stone-01
    • sfx-cradle-dream-pulse-01
    • sfx-sleepers-wake-01
    • sfx-wake-in-fold-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-setpiece-dungeon-generate)

    Notes

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 12 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.150Generate dungeon mechanism and story-beat SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-setpiece-dungeon-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 12 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.149 Write dungeon mechanism and story-beat SFX prompts (12 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.151Owner approval: dungeon mechanism and story-beat SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 12 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-setpiece-dungeon-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: collapses and explosions are weighty without harshness, the loop-shift cue is subtle enough to be missed by a careless player but learnable, and the sleepers-wake sound is warm and relieving. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then collapses and explosions are weighty without harshness, the loop-shift cue is subtle enough to be missed by a careless player but learnable, and the sleepers-wake sound is warm and relieving.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-setpiece-dungeon-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.150 Generate dungeon mechanism and story-beat SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.152Integrate approved dungeon mechanism and story-beat SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e26-deepworks-encounters, e26-shortcuts-loops, e26-knot-rune-navigation, e26-vane-gallery-breach, e26-priory-choir, e26-cradle-arena, e26-horns-hall-fold, e26-chapel-of-echoes, e26-vesper-bell-finale, e01-contextual-respawn.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 12 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Deepworks and the Knot, when the cage lift runs, a support collapses, the portcullis drops, a rune loop resets the player and the sleepers wake, then final sounds play with the right noise events and no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e01.12 Wake in context after death instead of reloading open
    • mw-e26.11 Make the Knot loop unless you follow its runes open
    • mw-e26.14 Build the Chapel of Echoes with the Chimes puzzle and portcullis trap open
    • mw-e26.16 Stage Horn's Hall and the Fold, the reveal and the wake-up point open
    • mw-e26.17 Stage the Cradle arena for the abbot confrontation open
    • mw-e26.19 Ring the Vesper Bell: hang the tongue, mend it and wake the sleepers open
    • mw-e26.20 Wire dungeon shortcuts: crypt, cistern, cage lift and one-way doors open
    • mw-e26.3 Populate the Deepworks: goblin camp, miner Forgotten, mine hazards open
    • mw-e26.4 Build Vane's sealed gallery, the ledger and the sealable breach open
    • mw-e26.6 Place the Watchers statue puzzle in the priory choir open
    • mw-e38.151 Owner approval: dungeon mechanism and story-beat SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.153Write Forgotten habit, Clatter and goblin SFX prompts (20 assets)blockedP1M3task

    Description

    Why

    The Forgotten give themselves away by their habits before you see them, and goblins are people whose gibberish carries emotion (audio bible §7.5).

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Forgotten reassembly, sweeping loop, censer chain loop, pick tapping, murmured prayer breath loop (unintelligible), the calm settle when the hymn is hummed; Clatter's hesitant fidget rattle and flat tuneless hum; goblin chatter (four emotional takes of processed gibberish), alarm pots, alert, hurt, flee, sling whirl, net throw, kettle-helm clank, and Mother Kettleback's lower, rounder voice.

    Asset ids (20):

    • sfx-creature-forgotten-reassemble-01
    • sfx-creature-forgotten-sweep-loop-01
    • sfx-creature-forgotten-censer-loop-01
    • sfx-creature-forgotten-pick-tap-01
    • sfx-creature-forgotten-prayer-breath-loop-01
    • sfx-creature-forgotten-calm-01
    • sfx-creature-clatter-fidget-01
    • sfx-creature-clatter-hum-flat-loop-01
    • sfx-creature-goblin-chatter-01
    • sfx-creature-goblin-chatter-02
    • sfx-creature-goblin-chatter-03
    • sfx-creature-goblin-chatter-04
    • sfx-creature-goblin-alarm-pot-01
    • sfx-creature-goblin-alert-01
    • sfx-creature-goblin-hurt-01
    • sfx-creature-goblin-flee-01
    • sfx-creature-goblin-sling-whirl-01
    • sfx-creature-goblin-net-throw-01
    • sfx-creature-goblin-kettle-helm-clank-01
    • sfx-creature-kettleback-voice-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-creatures-forgotten-goblins-generate)

    Notes

    Builds on part A's Forgotten set (e38-asset-sfx-impacts-forgotten-*: idle rattle, alert, telegraphs, hurt, poise break, collapse) — none duplicated. Ids follow audio bible §6 sfx-creature-<creature>-<vocal>-<nn> (needs list said sfx-forgotten-*, sfx-goblin-*).

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 20 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.154Generate Forgotten habit, Clatter and goblin SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-creatures-forgotten-goblins-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 20 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.153 Write Forgotten habit, Clatter and goblin SFX prompts (20 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.155Owner approval: Forgotten habit, Clatter and goblin SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 20 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-creatures-forgotten-goblins-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: habit sounds identify what a Forgotten is doing before it is seen, the calm settle audibly slows the rattle, goblin chatter carries emotion with no intelligible words, and alarm pots are the loudest sound in the set. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 20 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then habit sounds identify what a Forgotten is doing before it is seen, the calm settle audibly slows the rattle, goblin chatter carries emotion with no intelligible words, and alarm pots are the loudest sound in the set.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-creatures-forgotten-goblins-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.154 Generate Forgotten habit, Clatter and goblin SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.156Integrate approved Forgotten habit, Clatter and goblin SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-creature-audio-hooks, e13-forgotten-habits, e13-forgotten-reassembly, e14-clatter, e13-rootcellar-goblins, e14-mother-kettleback.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 20 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Ossuary and the goblin hall, when Forgotten perform habits and are calmed by the hum and goblins chatter, raise the alarm and flee, then final sounds play from the creature audio slots with no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e13.3 Forgotten crumble and reassemble unless bones are scattered or burned open
    • mw-e13.4 Add monk Forgotten and habit routines that ignore quiet players open
    • mw-e13.6 Add Rootcellar goblin combatants: slings, nets and loud alarms open
    • mw-e14.3 Bring Mother Kettleback to life: trade, Duggan crate and carrying fees open
    • mw-e14.5 Build Clatter: the apologetic skeleton who can remember his name open
    • mw-e28.8 Creature audio slots and audible attack telegraphs done
    • mw-e38.155 Owner approval: Forgotten habit, Clatter and goblin SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.157Write Brother Horn SFX prompts (12 assets)blockedP1M3task

    Description

    Why

    The same creature must sound terrifying and sad (audio bible §7.5): effortful and reluctant in the fight, soft and lowing in the reveal.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Charge bellow, four heavy hoof footsteps on stone, grab, snorts, stone axe scrape, effortful hurt, low Hornfolk throat-song hum (calm loop), a gentle lowing call, and the yield exhale.

    Asset ids (12):

    • sfx-creature-horn-bellow-charge-01
    • sfx-creature-horn-footstep-heavy-01
    • sfx-creature-horn-footstep-heavy-02
    • sfx-creature-horn-footstep-heavy-03
    • sfx-creature-horn-footstep-heavy-04
    • sfx-creature-horn-grab-01
    • sfx-creature-horn-snort-01
    • sfx-creature-horn-axe-scrape-01
    • sfx-creature-horn-hurt-01
    • sfx-creature-horn-throat-song-loop-01
    • sfx-creature-horn-lowing-call-01
    • sfx-creature-horn-yield-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-creatures-horn-generate)

    Notes

    Ids follow audio bible §6 (sfx-creature-horn-bellow-02 example; needs list said sfx-horn-*).

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 12 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.158Generate Brother Horn SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-creatures-horn-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 12 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.157 Write Brother Horn SFX prompts (12 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.159Owner approval: Brother Horn SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 12 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-creatures-horn-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: combat sounds are huge but reluctant rather than bloodthirsty, the throat-song and lowing read as gentle, and footsteps convey nine feet of weight. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then combat sounds are huge but reluctant rather than bloodthirsty, the throat-song and lowing read as gentle, and footsteps convey nine feet of weight.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-creatures-horn-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.158 Generate Brother Horn SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.160Integrate approved Brother Horn SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-creature-audio-hooks, e13-horn-moveset, e14-horn-befriend-help.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 12 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given Horn's Hall, when the Warden encounter and the befriend path run, then final Horn sounds play from his audio slots, footsteps follow animation markers, and no placeholder flags remain.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e13.13 Add Brother Horn's creature data: charges, grabs and throws to stop open
    • mw-e14.6 Befriend and help Brother Horn without fighting open
    • mw-e28.8 Creature audio slots and audible attack telegraphs done
    • mw-e38.159 Owner approval: Brother Horn SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.161Write bestiary SFX prompts (22 assets)blockedP1M3task

    Description

    Why

    Each systemic creature needs a sonic tell the player can act on: the pant of a silent pack, the skitter of spiders, the drilled march of a sentinel, a mimic's breath.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Briar Wolf pack pant, growl, fear whimper, eating (no howls); Loom Spider skitter loop, web spit, hiss, light recoil, silk-spin loop; Hollow Sentinel armour clank, salute, halting march step, hollow resonance loop; Tallow Ooze squelch, melt sizzle, frozen shatter, candle-stub clatter; mimic breath tell, bite, book page-snap, chest hinge groan, lectern creak.

    Asset ids (22):

    • sfx-creature-briar-wolf-pack-pant-01
    • sfx-creature-briar-wolf-growl-01
    • sfx-creature-briar-wolf-whimper-01
    • sfx-creature-briar-wolf-eat-01
    • sfx-creature-loom-spider-skitter-loop-01
    • sfx-creature-loom-spider-web-spit-01
    • sfx-creature-loom-spider-hiss-01
    • sfx-creature-loom-spider-light-recoil-01
    • sfx-creature-loom-spider-silk-spin-loop-01
    • sfx-creature-hollow-sentinel-clank-01
    • sfx-creature-hollow-sentinel-salute-01
    • sfx-creature-hollow-sentinel-march-01
    • sfx-creature-hollow-sentinel-resonance-loop-01
    • sfx-creature-tallow-ooze-squelch-01
    • sfx-creature-tallow-ooze-melt-01
    • sfx-creature-tallow-ooze-frozen-shatter-01
    • sfx-creature-tallow-ooze-wick-clatter-01
    • sfx-creature-mimic-breath-tell-01
    • sfx-creature-mimic-bite-01
    • sfx-creature-mimic-book-page-snap-01
    • sfx-creature-mimic-chest-hinge-groan-01
    • sfx-creature-mimic-lectern-creak-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-creatures-bestiary-generate)

    Notes

    Ids follow audio bible §6 with canon short names (needs list said sfx-wolf-*, sfx-loom-spider-*, sfx-sentinel-*, sfx-tallow-ooze-*, sfx-mimic-*).

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 22 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.162Generate bestiary SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-creatures-bestiary-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 22 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.161 Write bestiary SFX prompts (22 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.163Owner approval: bestiary SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 22 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-creatures-bestiary-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each creature is identifiable by sound alone, wolves never howl, the ooze sounds waxy rather than elemental, and the mimic breath tell is quiet but audible within 3 m. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 22 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each creature is identifiable by sound alone, wolves never howl, the ooze sounds waxy rather than elemental, and the mimic breath tell is quiet but audible within 3 m.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-creatures-bestiary-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.162 Generate bestiary SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.164Integrate approved bestiary SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-creature-audio-hooks, e13-briar-wolves, e13-loom-spiders, e13-hollow-sentinels, e13-tallow-ooze, e13-mimics.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 22 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the creature arena, when each creature cycles idle, alert, attack, hurt and flee via the debug console, then final sounds play from its audio slots with no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e13.10 Add Tallow Ooze that melts into fire puddles and shatters when frozen open
    • mw-e13.11 Add book, lectern and chest mimics with tells and feeding open
    • mw-e13.12 Add Hollow Sentinels bound to hold the tower until relieved open
    • mw-e13.7 Add Loom Spiders that weave readable webs and fear bright light open
    • mw-e13.8 Add silent Briar Wolf packs that can be fed, scared or remembered open
    • mw-e28.8 Creature audio slots and audible attack telegraphs done
    • mw-e38.163 Owner approval: bestiary SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.165Write Hushling and abbot SFX prompts (8 assets)blockedP1M3task

    Description

    Why

    Hushlings hunt by sound and mimic the missing; the abbot is gentle presence until he sings — both are the dread the audio bible asks for, quiet and specific.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Hushling whisper-grasp, dissipation (ripping air scattering into whispers), idle hum loop of the Nightjar's song, and the voice-mimic murmur (pitch-contoured, fog-filtered, familiar intonation, no intelligible words; the line appears as a caption); the abbot's sung Nightjar fragment loop (warm wordless male voice, solid state), interrupted-song cut, lantern-chain creak loop, and fog hush loop.

    Asset ids (8):

    • sfx-creature-hushling-whisper-grasp-01
    • sfx-creature-hushling-dissipate-01
    • sfx-creature-hushling-idle-hum-loop-01
    • sfx-creature-hushling-mimic-01
    • sfx-creature-abbot-sing-loop-01
    • sfx-creature-abbot-interrupt-01
    • sfx-creature-abbot-lantern-chain-loop-01
    • sfx-creature-abbot-fog-hush-loop-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-creatures-dream-generate)

    Notes

    Ids follow audio bible §6 (sfx-creature-hushling-mimic-01 is the bible example). Sung/hummed fragments are built from the Nightjar motif anchor.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 8 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.103 Owner approval: main theme and motif anchor open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.166Generate Hushling and abbot SFX via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-creatures-dream-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 8 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.165 Write Hushling and abbot SFX prompts (8 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.167Owner approval: Hushling and abbot SFXblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 8 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-creatures-dream-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the Hushling mimic murmur has a familiar voice's contour with no intelligible words, the hum stopping is noticeable as silence, and the abbot is never a wail. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the Hushling mimic murmur has a familiar voice's contour with no intelligible words, the hum stopping is noticeable as silence, and the abbot is never a wail.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-creatures-dream-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.166 Generate Hushling and abbot SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.168Integrate approved Hushling and abbot SFXblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-creature-audio-hooks, e13-hushlings, e13-abbot-wraith.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 8 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the drowned lane and the Cradle, when a Hushling idles, hunts, mimics and dissipates and the abbot sings and is interrupted, then final sounds play with captions for the mimic lines and no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e13.15 Add the Sleepless Abbot wraith: solid only while singing open
    • mw-e13.9 Add blind Hushlings that hunt by sound and break at loud noises open
    • mw-e28.8 Creature audio slots and audible attack telegraphs done
    • mw-e38.167 Owner approval: Hushling and abbot SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.173Write world surface footsteps prompts (12 assets)blockedP1M3task

    Description

    Why

    Mud lanes, frozen water, straw and the Ossuary's bone litter are location surfaces with their own noise radius (audio bible §7.3); bone litter is deliberately loud.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Round-robin footsteps (4–6 variants each) for mud, snow-ice (Frost-frozen surfaces), straw and bone-litter in sneak, walk and run gaits.

    Asset ids (12):

    • sfx-foot-mud-sneak
    • sfx-foot-mud-walk
    • sfx-foot-mud-run
    • sfx-foot-snow-ice-sneak
    • sfx-foot-snow-ice-walk
    • sfx-foot-snow-ice-run
    • sfx-foot-straw-sneak
    • sfx-foot-straw-walk
    • sfx-foot-straw-run
    • sfx-foot-bone-litter-sneak
    • sfx-foot-bone-litter-walk
    • sfx-foot-bone-litter-run

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-footsteps-world-generate)

    Notes

    Completes the audio bible §7.3 surface set left to the world planner by e38-asset-sfx-footsteps-extra-armor-prompts. Ids follow part A's footstep naming (sfx-foot-<surface>-<gait>, variants inside).

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 12 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.174Generate world surface footsteps via ElevenLabs or CC0blockedP1M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-footsteps-world-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 12 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.173 Write world surface footsteps prompts (12 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.175Owner approval: world surface footstepsblockedP1M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 12 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-footsteps-world-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: the four surfaces respect the sim loudness ordering (bone-litter among the loudest, straw soft-crunchy) and sneak < walk < run holds within each surface. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 12 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then the four surfaces respect the sim loudness ordering (bone-litter among the loudest, straw soft-crunchy) and sneak < walk < run holds within each surface.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-footsteps-world-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.174 Generate world surface footsteps via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.176Integrate approved world surface footstepsblockedP1M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-footsteps, e09-surface-acoustics, e02-footstep-events.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 12 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the stealth grey-box course with mud, frozen, straw and bone-litter strips, when the knight and thief walk them in each gait, then final footsteps play with no placeholder flags and noise events match the sim radii.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e02.11 Emit footstep events tagged with surface material and gait done
    • mw-e09.4 Tag surfaces with acoustic materials that change footstep noise done
    • mw-e28.6 Surface-aware footsteps modulated by stance and armor done
    • mw-e38.175 Owner approval: world surface footsteps open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.179Placeholder audio pack is at ~2000 of its 2048 KB budgetopenP1M3task

    Description

    Why

    PR #142 (mw-e04.20) left the generated placeholder SFX pack at about 2000 KB of its 2048 KB budget. The next few cue additions will fail CI.

    What

    Shrink the placeholders (lower sample rate/bit depth or shorter durations for placeholder-only sounds, or dedupe shared ones) or, if the budget itself is wrong for the placeholder phase, raise it with a recorded reason. Placeholders must still be keyed by final asset ids.

    Acceptance criteria

    • AC-1 content Given the placeholder audio pack, when CI's audio placeholder check runs, then the pack uses at most 60% of its budget and every cue still resolves to a sound.
    area:musicepic:e38milestone:m3
  • mw-e38.48Write P2 spell SFX prompts (6 assets)blockedP2M3task

    Description

    Why

    If Fire Wall, Arcane Sight, Snuff and Stasis ship, they need final sound.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Phase sounds for fire-wall, arcane-sight, snuff, stasis.

    Asset ids (6):

    • sfx-spell-fire-fire-wall-spawn-01
    • sfx-spell-fire-fire-wall-loop-01
    • sfx-spell-arcane-arcane-sight-cast-01
    • sfx-spell-shadow-snuff-hush-01
    • sfx-spell-time-stasis-lock-01
    • sfx-spell-time-stasis-release-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-spells-secondary-generate)

    Notes

    P2 because every spell here is P2; cut together with its spell.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock.

    Acceptance criteria

    • AC-1 content Given the 6 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.49Generate P2 spell SFX via ElevenLabs or CC0blockedP2M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-spells-secondary-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 6 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.48 Write P2 spell SFX prompts (6 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.50Owner approval: P2 spell SFXblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 6 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-spells-secondary-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each spell's phases sound like one spell and its school is identifiable blind. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 6 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each spell's phases sound like one spell and its school is identifiable blind.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-spells-secondary-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.49 Generate P2 spell SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3needs-human
  • mw-e38.51Integrate approved P2 spell SFXblockedP2M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e06-spell-cue-binding, e08-spell-fire-wall, e08-spell-arcane-sight, e08-spell-snuff, e08-spell-stasis.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 6 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the spell sandbox, when each secondary spell is cast, then every phase plays its final sound with no placeholder flags.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e06.17 Bind spell events to placeholder VFX and SFX cues open
    • mw-e08.16 Add Arcane Sight: reveal hidden mechanisms and magical properties open
    • mw-e08.19 Add Snuff: extinguish all light sources in a radius open
    • mw-e08.23 Add Stasis: freeze one object or creature in time open
    • mw-e08.4 Add Fire Wall: a persistent line of flame that blocks and burns open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.50 Owner approval: P2 spell SFX open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxclass:sorcererepic:e38milestone:m3
  • mw-e38.56Write IRs and placeholder ambience prompts (8 assets)blockedP2M3task

    Description

    Why

    SFX are delivered dry and the engine adds location reverb (audio bible §7.1); convincing spaces need good impulse responses.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Convolution impulse responses for cave, stone hall, wood interior, forest and open field, plus three placeholder ambience loops (dungeon drips, forest day, wind gust) until location ambience lands.

    Asset ids (8):

    • ir-cave-01
    • ir-stone-hall-01
    • ir-wood-interior-01
    • ir-forest-01
    • ir-open-field-01
    • amb-placeholder-dungeon-drips-loop-01
    • amb-placeholder-forest-day-loop-01
    • amb-placeholder-wind-gust-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / element / creature state) per sound
    • Out: Generation (e38-asset-sfx-irs-ambience-generate)

    Notes

    IRs cannot come from ElevenLabs: Claude synthesises them (scripted noise-decay IRs) or sources CC0-only IRs; no CC-BY-SA/NC sets. Final location ambience comes from the world asset planner; these ambience ids are placeholders only. P2 to match the reverb/ambience beads.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock.

    Acceptance criteria

    • AC-1 content Given the 8 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1.
    • AC-5 content Edge: given a prompt that requests intelligible speech, music, or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.57Generate IRs and placeholder ambience via ElevenLabs or CC0blockedP2M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-irs-ambience-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 8 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.56 Write IRs and placeholder ambience prompts (8 assets) open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.58Owner approval: IRs and placeholder ambienceblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 8 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-irs-ambience-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: each IR makes a dry test sound feel like its space without metallic ringing. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 8 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then each IR makes a dry test sound feel like its space without metallic ringing.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-irs-ambience-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.57 Generate IRs and placeholder ambience via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.59Integrate approved IRs and placeholder ambienceblockedP2M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, update cue sheets where ids changed, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-reverb-zones, e28-ambience.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 8 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given reverb zones in the greybox testbed, when the player crosses cave, hall, interior, forest and field volumes, then the matching IR is applied with no audio glitches.
    • AC-5 perf Given the audio needed at start, when e28-audio-perf budgets are measured, then it stays within the ≤ 8 MB initial audio share.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e28.12 Reverb zones per space: caves, halls, interiors, forest open
    • mw-e28.13 Ambient beds and randomised positional one-shots done
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.58 Owner approval: IRs and placeholder ambience open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.169Write Snig and Mortimer SFX prompts (4 assets)blockedP2M3task

    Description

    Why

    Snig's giggles and Mortimer's contented purr are small charm sounds for the P2 social characters.

    What

    Write one prompt file per asset (or round-robin set) in assets/prompts/sfx/<asset-id>.md from _templates/sfx.md, with the SFX PREAMBLE (audio bible §8) verbatim, the category add-on, sourcing (generated vs CC0), round-robin count, sim link, output spec and checklist.

    Mortimer's warning snap for shoplifters and contented page-rustle purr; Snig's giggle and quick chatter.

    Asset ids (4):

    • sfx-creature-mimic-mortimer-snap-01
    • sfx-creature-mimic-mortimer-purr-01
    • sfx-creature-goblin-snig-giggle-01
    • sfx-creature-goblin-snig-chatter-01

    Scope

    • In: One prompt file per asset id above
    • In: Sim link (surface id / noise radius / creature state / world fact) per sound
    • Out: Generation (e38-asset-sfx-creatures-social-secondary-generate)

    Notes

    P2 to match e14-snig and e14-mortimer; linked to the creature audio hooks only.

    Prompts cite the locked reference sounds from e38-asset-sonic-lock. Canon names follow docs/narrative/story-bible.md; no intelligible speech anywhere (text-only MVP).

    Acceptance criteria

    • AC-1 content Given the 4 asset ids, when the asset validator runs over assets/prompts/sfx/, then each has exactly one prompt file whose id equals its filename stem and matches audio bible §6 naming.
    • AC-2 content Given each prompt file, when the validator compares its preamble with docs/audio/audio-bible.md §8, then it matches byte-for-byte.
    • AC-3 content Given each repeated sound, when inspected, then its round-robin count is ≥ 3 (footsteps 4–6) and its sim link names the sim id it must match.
    • AC-4 content Given each prompt file, when inspected, then it states duration, mono/stereo, loop yes/no and loudness target from audio bible §5.1 (SFX one-shots peak −3 dBFS, ≤ −1.0 dBTP).
    • AC-5 content Edge: given a prompt that requests intelligible speech, music (unless the bible names a diegetic melody), or contains an API key pattern, when the validator runs, then it fails naming the file.

    Waits on

    • mw-e38.1 Review and sign off the audio bible with Suno and SFX preambles done
    • mw-e38.155 Owner approval: Forgotten habit, Clatter and goblin SFX open
    • mw-e38.163 Owner approval: bestiary SFX open
    • mw-e38.3 Review and finalize music, stinger and SFX prompt templates open
    • mw-e38.64 Lock approved reference sounds for all later SFX prompts open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.170Generate Snig and Mortimer SFX via ElevenLabs or CC0blockedP2M3task

    Description

    Why

    Claude produces every SFX candidate end-to-end so the owner only listens (audio bible §9.1).

    What

    Generate each prompt via e38-sfx-gen-client (or source CC0 per e38-sfx-tool-decision) into assets/_incoming/<asset-id>/vN.wav, run the audio import pipeline + validator, and build a listening page (playlist grouped by set, loudness readout).

    Scope

    • In: Generation/sourcing, trimming, normalisation via pipeline
    • In: Listening page for the approval bead
    • Out: Owner approval (e38-asset-sfx-creatures-social-secondary-approve)

    Notes

    Record API tier / CC0 source URL per candidate. Paid tier for shipping sounds.

    Acceptance criteria

    • AC-1 integration Given the 4 prompt files, when the batch completes, then every id (and every round-robin variant) has a vN.wav + sidecar (tool or source URL, licence, tier, date) in assets/_incoming/.
    • AC-2 integration Given the candidates, when e38-audio-validator runs, then leading silence ≤ 10 ms, positional sounds are mono, loops have clean seams, and LUFS/true peak are within audio bible §5.1 tolerances.
    • AC-3 content Given the listening page, when opened, then every id plays with its prompt path and loudness readout.
    • AC-4 integration Edge: given the SFX client hits a usage/rate limit or network error mid-batch, when the batch is re-run, then it resumes from the first id without a candidate, never regenerates an id that already has a candidate or an approval record, and logs the back-off without printing any API key.

    Waits on

    • mw-e38.169 Write Snig and Mortimer SFX prompts (4 assets) open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.171Owner approval: Snig and Mortimer SFXblockedP2M3task

    Description

    Why

    Every shipped asset needs an owner decision at the sfx batch gate; CI refuses final assets without one (contract §6).

    What

    The owner reviews the listening page of 4 sounds and approves or rejects each item with a note. Claude records every decision in assets/approvals.json (asset id, gate: sfx batch, version, SHA-256, approver, date, notes). Rejected items loop back to e38-asset-sfx-creatures-social-secondary-generate with the note appended to their iteration log.

    Scope

    • In: Owner decision per asset
    • In: Approval records written by Claude
    • In: Re-queue of rejected items
    • Out: Generation or editing by the owner — the owner never edits assets

    Notes

    Approval criteria: Mortimer's snap is a clear warning and his purr reads contented, and Snig sounds younger and quicker than other goblins. Batch reviews are designed to take ≤ 15 minutes of owner time.

    Acceptance criteria

    • AC-1 manual Given the review page, when the owner finishes the session, then each of the 4 ids has an approve or reject decision with notes recorded in assets/approvals.json for gate "sfx batch".
    • AC-2 manual Given the approved items viewed side by side, when the owner compares them, then Mortimer's snap is a clear warning and his purr reads contented, and Snig sounds younger and quicker than other goblins.
    • AC-3 integration Edge: given a rejected id, when its decision is recorded, then it is re-queued for e38-asset-sfx-creatures-social-secondary-generate with the owner note in its iteration log, and no already-approved id is regenerated.
    • AC-4 integration Given an approval record whose SHA-256 does not match the file promoted to assets/source/, when CI runs, then the approval check fails naming the id.

    Waits on

    • mw-e37.3 Record owner approval gates and block unapproved assets in CI open
    • mw-e38.170 Generate Snig and Mortimer SFX via ElevenLabs or CC0 open
    area:sfxasset:sfxepic:e38milestone:m3needs-human
  • mw-e38.172Integrate approved Snig and Mortimer SFXblockedP2M3task

    Description

    Why

    Final audio replaces placeholders by file swap under the same ids (audio bible §9.3).

    What

    Promote approved sources, encode Opus + AAC with sidecars via e38-audio-import-pipeline, add CREDITS rows and approval records, bind ids in the cue sheets, and clear placeholder flags.

    Scope

    • In: Encode, sidecar, CREDITS, approval records
    • In: Placeholder swap in the manifest
    • Out: Cue logic and mixing (consuming beads)

    Notes

    Consumers: e28-creature-audio-hooks, e14-snig, e14-mortimer. Lower-priority consumers (e14-snig, e14-mortimer) are referenced here but not linked, to avoid a priority inversion.

    Acceptance criteria

    • AC-1 integration Given the approved sources, when the import pipeline and e38-audio-validator run, then .ogg + .m4a + sidecar exist under public/assets/audio/ for all 4 ids and validation is green.
    • AC-2 content Given assets/CREDITS.md, when audited, then each id has a row with tool/source, licence, tier and date, and an approval record exists.
    • AC-3 integration Given the placeholder manifest, when integration completes, then no id in this set is flagged placeholder: true.
    • AC-4 e2e Given the Lamplit Stacks and the Deepworks, when Mortimer is approached by a shoplifter and Snig is met, then final sounds play with no placeholder flags.
    • AC-5 perf Given the owning location's audio package, when e28-audio-perf budgets are measured, then streamed audio stays within the location package target (≤ 25 MB total package) and the ≤ 8 MB initial audio share is not exceeded.
    • AC-6 integration Edge: given an id without an approval record, when the pipeline runs, then it is not promoted, the placeholder keeps playing, and the remaining-placeholder report lists it.

    Waits on

    • mw-e28.8 Creature audio slots and audible attack telegraphs done
    • mw-e38.171 Owner approval: Snig and Mortimer SFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.6 Placeholder audio kit: CC0 stand-ins with final asset ids open
    area:sfxasset:sfxepic:e38milestone:m3
  • mw-e38.178Probe the SFX PREAMBLE on a footstep, a spell cast and a UI clickblockedP2M3task

    Description

    Why

    The audio bible was signed off (mw-e38.1) before its SFX PREAMBLE was tested. Three contrasting sounds show whether the preamble produces the tactile, heavy, true palette of audio bible §7 before the SFX batches start.

    What

    Using the ElevenLabs client (mw-e38.7), generate a stone footstep, an Ember spell cast and a UI click from the audio bible §8 preamble. Run them through the loudness and naming rules (§5, §6), commit them as placeholders with CREDITS rows, and put them up for owner approval. Revise the preamble if they miss.

    Scope

    • In: 3 probe sounds, placeholder CREDITS rows, preamble revisions
    • Out: the SFX batches themselves

    Acceptance criteria

    • AC-1 manual Given the three probe sounds, when the owner reviews them, then they are approved as matching §7, or the preamble is revised and re-probed.
    • AC-2 content Given the committed probes, when validated, then each has a CREDITS row flagged placeholder: yes and meets the §5 loudness targets.

    Waits on

    • mw-e38.7 ElevenLabs Sound Effects API client for Claude-run SFX generation open
    area:musicarea:sfxepic:e38milestone:m3
  • mw-e38.180Placeholder SFX pack is at 2010 KB of its 2 MB budgetopenP2M3task

    Description

    Why

    PR #181 added a synthesised placeholder telegraph sound; the placeholder pack is now 2010 KB against its 2 MB budget, leaving almost no room for further placeholders until real SFX (ElevenLabs) land.

    What

    Shrink placeholders (shorter, lower sample rate/mono, shared synth recipes generated at runtime) or revisit the budget with the owner.

    Acceptance criteria

    AC-1 [ci] The placeholder pack is under 1.8 MB with all referenced cues still resolving.

    area:audioarea:musicepic:e38milestone:m3
E39Story & NarrativeThe MVP adventure "The Labyrinth Beneath Briar Glen" is a coherent, reactive story: the town, the Briarwood, the River Wend, Mooring's Watch, the Deepworks, Bellwater Priory, the Knot and the optional harbour town of Wendmouth are populated with memorable characters, class-flavoured dialogue, multi-resolution quests, rumours that lead somewhere, and books/item text that carry the lore. The minotaur twist lands, failure bends the story instead of ending it, and every class experiences the key beats differently.28/48 done · 58%

M3 MVP content 19

  • mw-e39.38Emit the main-quest events and set its facts from level scriptsin progressP2M3task

    Description

    mw-e39.4 stages wait on area/event objectives (enterArea briar-glen, mine-gate, knot-outer-ring, ossuary-galleries, horns-hall, the-fold, the-cradle, belfry; events horned-shape-seen, friend-note-found, abbot-revealed, bell-tongue-destroyed, recast-tongue-delivered, deepworks-entered-<route> x6) and on facts nothing writes yet: bell.rung (belfry scene), tern.sailed is written by the quest, crate.intercepted (Crate for Mr. S), bounty.outcome and horn.spoken-for (Vane/Hollis/Hale dialogue), epilogue.finished (slideshow). Needs mw-e23.3 bindings.

    Waits on

    • mw-e23.12 Event-bound quest objectives should count events from before their stage done
    • mw-e23.3 Bind quest objective kinds to sim events done
    area:narrativeepic:e39milestone:m3
  • mw-e39.18Write failure-state narratives: the Fold, jail, capture, sour bellblockedP1M3feature

    Description

    Why

    "Failure creates stories." Death, capture and botched actions should land the player somewhere new and be remembered.

    What

    As a player, I want failures to move the story sideways so that I keep playing instead of reloading. Content and fact wiring per bible §4.5 and §9: waking in the Fold after dying in the Knot (pre- and post-reveal text; goblin camp or Forgotten variants if Horn is dead), waking at the Sleeping Ox after a forest death, jail with the drain escape, goblin capture, ringing the tongueless bell, misfired Lull dream, NPCs remembering embarrassments; Wendmouth: thrown off the pier (breakwater sea-door), losing the drinking contest (wake in the Gilded Tern's hold), books confiscated at customs (customs strongroom).

    Scope

    • In: narrative/failure data: wake-up texts and conditions
    • In: facts: player.rescues.byHorn, player.jailed.count, player.captured.byGoblins, bell.rung.sour
    • In: NPC remark hooks for embarrassment facts
    • Out: respawn mechanics and save rules (Related: E01/E30)
    • Out: jail/escape level geometry (Related: E24)

    Notes

    Kettleback's "carrying fee" must never exceed what the player can pay (take a trinket if broke).

    Acceptance criteria

    • AC-1 unit Given a death in the Knot with horn.fate = alive and quest before the reveal, when the wake-up is resolved, then the eerie Fold text plays and player.rescues.byHorn increments by 1.
    • AC-2 unit Given horn.fate = dead, when a death in the Knot occurs, then the goblin-camp variant plays if goblins.standing ≥ wary, else the Forgotten variant.
    • AC-3 unit Edge: given the player has 0 gold, when Kettleback charges the carrying fee, then a trinket is taken instead, or waived if none, and no negative gold results.
    • AC-4 unit Given the bell is rung without its tongue, when resolved, then bell.rung.sour is set and the Hushling/Horn-approach encounter flag is raised.
    • AC-5 unit Given the player is caught by dockhands in Wendmouth, when resolved, then the thrown-off-the-pier text plays, the player is placed at the breakwater and harbor.seadoor.discovered is set; given restricted books are confiscated, then they move to the customs strongroom container, never destroyed.
    • AC-6 manual Given a playtest, when a tester dies in the Knot twice, then they describe the Fold wake-up as intriguing rather than as a punishment.

    Waits on

    • mw-e22.1 Turn witnessed crimes into settlement bounties with pay/jail/flee open
    • mw-e23.2 Implement quest state machine with branching and multi-resolution done
    • mw-e27.1 Store persistent world facts in a typed deterministic fact store done
    • mw-e39.3 Set narrative content layout, ID scheme and class-variant tagging done
    area:narrativeclass:allepic:e39milestone:m3size:s
  • mw-e39.14Write spellbook titles, authors and flavour textsopenP2M3feature

    Description

    Why

    For the sorcerer, books are progression; each spellbook should feel like a found object with a voice, not a stat card.

    What

    As a sorcerer, I want each spellbook to have a title, an author and a human detail so that buying or finding one feels special. Flavour for every MVP spell (~15–20), following bible §7.3 house style, plus Lantern Court seal status (licensed/restricted/forbidden), and damaged-copy variant text for books that teach misfiring versions.

    Scope

    • In: flavour fields on spellbook item data (title, author, blurb, seal status, damaged variant)
    • In: Nine Sleeps ch. 1 (Lull) forbidden flavour
    • Out: spell mechanics and the spell catalogue (Related: E08 spell catalogue)
    • Out: learning mechanics (e07-spellbook-learning)

    Notes

    School legality per bible §3.3. Keep each blurb ≤ 80 words and include one concrete, human or funny detail.

    Acceptance criteria

    • AC-1 unit Given the spellbook data, when validated, then every spell in the MVP catalogue has exactly one spellbook with title, author, blurb and seal status.
    • AC-2 unit Given each spellbook, when its seal status is compared with its school, then it matches the legality table in bible §3.3.
    • AC-3 unit Given each blurb, when measured, then it is ≤ 80 words.
    • AC-4 content Edge: given a book with a damaged variant, when validated, then the damaged text differs from the intact text and names the misfire flavour.
    • AC-5 manual Given a read-through, when the narrative designer reviews all blurbs, then none reads as a numeric stat description.

    Waits on

    • mw-e07.2 Learn spells by reading and studying book items done
    • mw-e39.3 Set narrative content layout, ID scheme and class-variant tagging done
    area:narrativeclass:sorcererepic:e39milestone:m3size:s
  • mw-e39.15Write item and creature description textopenP2M3feature

    Description

    Why

    Lore lives in item text (Dark Souls) and creatures are characters, not target dummies; descriptions should imply history and hint at non-combat options.

    What

    As a player, I want item and creature descriptions that hint at stories and weaknesses so that reading them helps me play. 1–3 sentence descriptions for every MVP key item, quest item, notable equipment and consumable; descriptions for Wendmouth imports (foreign weapons/armour, exotic arrows, Undertow thief tools) and the harbour's human factions (Low Tide Company, harbour watch, Tern crew); bestiary/inspect text for all 10 creature types in bible §8 (Wendmouth adds none), each hinting at at least one non-lethal or systemic option (fear of light, sound sensitivity, flammability, feeding).

    Scope

    • In: desc-* fields for items and creatures
    • In: bestiary entries with unlock tiers (seen / studied)
    • Out: creature stats/behaviour (Related: E12/E13)
    • Out: loot placement (Related: E18)

    Notes

    Voice examples in bible §7.4. Avoid numbers in flavour text; mechanics belong in tooltips.

    Acceptance criteria

    • AC-1 unit Given item and creature data, when validated, then every MVP item and each of the 10 creature types has a description of 1–3 sentences.
    • AC-2 content Given each creature entry, when reviewed against bible §8, then it hints at ≥ 1 non-combat or systemic interaction.
    • AC-3 unit Given all flavour text, when scanned, then it contains no digits (numbers belong in tooltips).
    • AC-4 unit Edge: given a creature at "seen" tier, when its bestiary entry is shown, then only the seen-tier text is returned and studied-tier hints stay hidden.

    Waits on

    • mw-e00.18 Load schema-validated content with a per-entry test harness done
    • mw-e39.3 Set narrative content layout, ID scheme and class-variant tagging done
    area:narrativeclass:allepic:e39milestone:m3size:m
  • mw-e39.29Horn dialogue follow-ups: failed Trial of Horns, trust after the abbot's gift, vouching rhyme verseopenP2M3task

    Description

    Left out of PR #433 (mw-e39.7): a failed Trial of Horns branch; Horn trusting the player less after accepting the abbot's gift; the public-vouching rhyme verse in ending lines. Owner to confirm canon for each before writing.

    area:narrativeepic:e39milestone:m3
  • mw-e39.30Consume harbour dialogue hooks: barge.ride-booked / barge.adit-route-offered travel, lock.gossip-paid, lowtide.job-offered, armwrestle.requestedopenP2M3task

    Description

    mw-e39.19 emits hooks nobody consumes yet: barge.ride-booked (route river-run or weeping-adit; fare gold or deal; night refused in dialogue), barge.adit-route-offered, lock.gossip-paid (Old Reed's toll, also reed.toll-paid), lowtide.job-offered, tidefair.gull-shoot-sponsored, undertow.access-granted / undertow.restricted-books-offered, armwrestle.requested (mw-e40.6 owns the match). Wire each to the travel, Kestrel Lock, Undertow, Tidefair systems once Wendmouth exists.

    area:narrativeepic:e39milestone:m3
  • mw-e39.31Wire commission.dropped consequences and the horn-coin item to Nell's dropopenP2M3task

    Description

    nell-drowned-gull sets commission.outcome (delivered/kept/faked) and emits commission.dropped, and reads commission.coin-held as a stand-in for the horn-coin item. Needed: the item pickup writing commission.coin-held, the buyer's reaction and epilogue reading commission.outcome (bible 4.3, thief commission).

    area:narrativeepic:e39milestone:m3
  • mw-e39.33Add the Wendmouth evidence items and Cray's romance novel, retire the stand-in factsopenP2M3task

    Description

    mw-e39.20 (cray-customs, quell-harbor-agent) reads the stand-in facts evidence.foundry-invoice, evidence.honest-manifest, evidence.dead-clerk-seal and cray.romance-brought; nothing writes them yet and no matching items exist. Needed: add the three evidence items and the romance novel (items, tagged plot-critical where they are quest evidence so Cray never confiscates them), have pickup set the stand-in facts or replace the facts with hasItem conditions in the dialogues, and have the Quell deal (quell.manifest-handed event) give the honest manifest item. Also add the plot-critical tag to the item schema if it does not exist (mw-e39.20 AC-5 test currently checks tags only when present).

    area:narrativeepic:e39milestone:m3
  • mw-e39.34Consume Cray's confiscation hook: take restricted spellbooks, never plot-critical itemsopenP2M3task

    Description

    mw-e39.20 emits cray.confiscate { scope: restricted-spellbooks, exclude: plot-critical,forbidden-plot, route: strongroom } from cray-customs when a sorcerer submits to the search. Nothing consumes it. Needed: take the player's restricted spellbooks into the customs-house strongroom (retrievable via Contraband Pages), skipping any item tagged plot-critical or forbidden-plot; also consume cray.books-released (release the impounded crate) and cray.seizure-opened / cray.writ-explained / cray.bribe-recorded for the quest and ledger.

    area:narrativeepic:e39milestone:m3
  • mw-e39.35Implement Tereza's first-blood duel (E04 knight combat hook)openP2M3task

    Description

    mw-e39.20 (tereza-arms-stall) emits tereza.duel-start { stakes: first-blood, arena: tidemarket } on accept or rematch. Needed: run a first-blood duel (E04 knight combat), then write tereza.duel.fought = true and tereza.duel.victor = player or tereza; the dialogue entries duel-won and duel-lost then set tereza.duel.result and clear fought. Also consume tereza.under-counter-opened / tereza.shop-requested for the Tidemarket stock (mw-e40.10).

    area:narrativeepic:e39milestone:m3
  • mw-e39.36Wire Wendmouth scene hooks for Quell and Hesketh (crate, departure, shanghai, crew, boarding)openP2M3task

    Description

    mw-e39.20 emits quell.crate-opened, quell.manifest-handed, quell.departs, quell.collapsed, quell.guard-job-offered, hesketh.crew-signed, hesketh.board-requested, hesketh.shanghai-scene { outcome: work|released } and reads/writes quell.left and hesketh.shanghaied. Needed when the Wendmouth scene exists: gate Quell's presence (and his office note, speaker narrator) on quell.left; have the Drowned Gull drinking-contest loss set hesketh.shanghaied and run the hold scene; consume crew signing and Tereza-vouched boarding (travel to the Tern); open bay nine's crate on quell.crate-access.

    area:narrativeepic:e39milestone:m3
  • mw-e39.37Manual narrative consistency read of all content against the bibleblockedP2M3task

    Description

    Follow-up to mw-e39.24 (PR #436): the narrative lint landed, but its AC-6 manual full-content read against story-bible.md was not done. Read all dialogue, facts, notes and books once the Wendmouth dialogue (#434/#435) and Horn (#433) land; fix contradictions in a PR.

    Waits on

    • mw-e39.16 Write opening, first-night and ending/epilogue text done
    • mw-e39.17 Write class-specific arrivals, routes and signature beats done
    • mw-e39.18 Write failure-state narratives: the Fold, jail, capture, sour bell open
    • mw-e39.4 Script the main quest graph with four endings as quest data done
    • mw-e39.7 Write Brother Horn's dialogue across all Warden resolutions done
    • mw-e39.9 Write the Sleepless Abbot's notes, temptations and Cradle dialogue done
    area:narrativeepic:e39milestone:m3
  • mw-e39.39Play the Gilded Tern sailing in world at Act III startopenP2M3task

    Description

    mw-e39.4 sets tern.sailed when Act III begins (warden to second-reveal). Nothing consumes it: the Wendmouth scene should move the Tern out of the pool and the epilogue harbor-tern-ox slide reads it.

    area:narrativeepic:e39milestone:m3
  • mw-e39.41Write Horn befriend triggers and priory crypt unseal from the main questopenP2M3task

    Description

    Dialogue facts name the main quest as writer: horn.hymn-hummed, horn.ring-held, horn.name-stone-held, clatter.vouched, horn.weapon-lowered, horn.trial-won (+horn.befriended); horn.crypt-open should unseal world.priory-crypt.unsealed. Not done in mw-e39.4: they need gesture, item and duel systems.

    area:narrativeepic:e39milestone:m3
  • mw-e39.43Consume the abbot's dialogue hooks and write his scene facts (abbot.in-cradle, abbot.wraith-down, tongue, dreamer mark effects)openP2M3task

    Description

    abbot-cradle (mw-e39.9) emits events nothing consumes yet and reads facts nothing writes yet. Hooks: abbot.reveal-spoken, abbot.help-accepted {class}, abbot.lull-taught (sorcerer; Lull spell E08/E06), abbot.fight-begun (start the wraith fight, E13), abbot.trick-sprung {method: thief|sorcerer|archer}, abbot.persuaded, abbot.joined, abbot.fate-set {fate}. Facts to write from scenes: abbot.in-cradle (Cradle scene, E26), abbot.wraith-down (wraith combat, E13), abbot.tongue-recovered read by the belfry climb. Also: dreamer.marked consequences (Hushlings ignore the player, the song heard in town) belong to the creature and ambience systems. Done: each hook has a consumer and a test, or a documented decision not to.

    area:narrativeepic:e39milestone:m3
  • mw-e39.46Hook up The Crate for Mr. S— to the Wendmouth levelopenP2M3task

    Description

    quest-crate-for-mr-s (mw-e39.21) completes through enterArea (bonded-warehouse, undertow) and event objectives that Wendmouth does not emit yet: crate-bay-opened, crate-ballast-swapped, crate-resealed, crate-seized, crate-net-cut, crate-fished-out, bay-nine-brawl-won, crate-diverted, crate-collected. The level must emit them from the route obstacles (route-matrix bay-nine, customs-strongroom, gilded-tern), write heist.alarm on the watchman's alarm, and read cray.arrival.flagged, lowtide.standing, tern.sails-with-ballast. Related: mw-e40.20.

    area:narrativeepic:e39milestone:m3
  • mw-e39.45Resolve book and scroll textKeys: text for spell tomes and scrolls, and the reader lookupopenP3M3task

    Description

    Story-book page text resolves through bookPageText (src/content/types/readable.ts), but spell tomes and scrolls (mage-hand, ember, scroll-of-ember/firebolt/mage-hand) point at keys (book.mage-hand.page-1, book.scroll-of-ember.text) that resolve nowhere. The spellbook-flavour text (bible 7.3) must land in a text home (extend the book content type or a sibling) and the reader UI (mw-e07.9) must call the lookup. Out of scope of mw-e39.13.

    area:narrativeepic:e39milestone:m3
  • mw-e39.47Items for the Crate for Mr. S—: name-stone, honest manifest, Mr. S—'s sealed letteropenP3M3task

    Description

    The quest writes stand-in facts (namestone.obtained, horn.name-stone-held, manifest.honest.obtained, evidence.honest-manifest). Replace with real items (name-stone, manifest, the sealed letter, ballast, customs-seal stamp, forged manifest) and an optional letter fact; Mr. S—'s letter is unreadable beyond one line in the MVP (bible 6.1 quest 6).

    area:narrativeepic:e39milestone:m3
  • mw-e39.48Cray and Nell dialogue reactions to the crate outcomeopenP3M3task

    Description

    Read crate.method, cray.arrival.flagged, lowtide.standing and heist.undetected in cray-customs and nell-drowned-gull (Cray's arrival branch after the force brawl; Nell hostile under lowtide.standing = hostile; talk of the ballast after an undetected heist).

    area:narrativeepic:e39milestone:m3

M4 Fun validation 1

  • mw-e39.25Run a playtest narrative-comprehension check and fix gapsopenP1M4task

    Description

    Why

    A twist no one notices is not a twist. The story must be understandable without a wiki, through play alone.

    What

    As the narrative designer, I want observed playtests with a short comprehension questionnaire so that I know which beats land and which need clearer delivery. 5+ testers (mix of classes) play through; afterwards they answer: who was taking people and why, what Horn is, who the "friend below" was, what the bell does, what their class did differently. Findings become fix beads or immediate text edits.

    Scope

    • In: docs/narrative/playtest-comprehension.md (script, questionnaire, results)
    • In: text fixes for beats scoring < 60% comprehension
    • Out: fun/feel validation (Related: E35 MVP fun validation)
    • Out: telemetry dashboards (Related: E34)

    Notes

    Do not prompt testers about the twist during play; observe only. Record at least one tester per class.

    Acceptance criteria

    • AC-1 manual Given ≥ 5 testers covering all 4 classes, when the questionnaire is scored, then results per question are recorded in docs/narrative/playtest-comprehension.md.
    • AC-2 manual Given the results, when ≥ 4 of 5 testers explain the minotaur twist and the bell solution in their own words, then the check passes; otherwise fixes are made and the check repeated with new testers.
    • AC-3 manual Given the results, when any beat scores < 60% comprehension, then a text fix or a follow-up bead is created and linked in the results doc.
    • AC-4 content Edge: given a tester reaches an ending the designer did not expect, when analysed, then the fact trail is recorded and checked against the ending rules in e39-main-quest-data.

    Waits on

    • mw-e39.16 Write opening, first-night and ending/epilogue text done
    • mw-e39.24 Add narrative lint for names, canon facts and dangling IDs done
    • mw-e39.4 Script the main quest graph with four endings as quest data done
    area:narrativearea:qaepic:e39milestone:m4needs-humansize:s
E40Wendmouth HarborWendmouth, the rowdy harbour town at the mouth of the River Wend, is an optional-but-rewarding MVP level where shenanigans ensue: sneakiness is richly rewarded (customs house, bonded warehouse, manifests, rooftops, rigging, crowds, the Undertow), every other class gets hijinks (brawls, arm-wrestling, duels, the Gull Shoot, the Regatta, freezing the harbour pool), and everyone can equip themselves better than in Briar Glen (the Tidemarket and the Undertow). The Crate for Mr. S— heist, the Tidefair and Contraband Pages play out here.2/26 done · 8%

M3 MVP content 23

  • mw-e40.26Link the towpath and the barge to the Wendmouth Stone Wharfin progressP1M3task

    Description

    Planned world-map edges towpath-lock-wharf and barge-lock-wharf (bible 3.1, 3.6; mw-e24.1): the always-open towpath from Kestrel Lock and the morning barge arrive at the Stone Wharf; Wendmouth stays optional for the main quest.

    Acceptance criteria

    AC-1 integration Given the player at Kestrel Lock, when they walk the towpath or ride the barge in the morning, then the Stone Wharf loads. AC-2 content edges list their transitions and the main quest still never needs them (world:validate AC-5).

    area:contentepic:e40milestone:m3
  • mw-e40.2Build the Stone Wharf with working cranes, cargo nets, crates and block yardsblockedP1M3feature

    Description

    Why

    The wharf is the harbour's toybox: swinging loads, cuttable nets and crate and block-yard mazes for every class.

    What

    As a player, I want cranes I can operate, nets I can cut and crates and stone blocks I can climb or hide behind so that the wharf invites hijinks.

    The great stepped glenstone quay where stone barges unload: two treadwheel cranes on stone piers (operable winch + jib rotation, suspended loads on ropes), cargo nets (rope supports: cuttable, flammable, shootable), block yards of dressed glenstone in rows (climbable, hiding spots), stacked crates (climbable, hiding spots, pushable), the Lantern Court notice board, the open flagstones marked for Tidefair events, and at the far end the Silver Quay behind an iron gate and imperial guards (a non-enterable set piece: seen, not entered).

    Scope

    • In: Crane mechanisms, net/rope entities, crate stacks and block yards with material presets, Tidefair space markers, the gated Silver Quay backdrop
    • Out: Tidefair event logic (Tidefair items)
    • Out: Heist hoist sequence (e40-crate-heist)

    Notes

    Everything via properties: a net drops when its supporting rope is cut, burnt or shot — never scripted per weapon.

    Acceptance criteria

    • AC-1 integration Given a loaded cargo net hanging from a crane, when its rope is severed by any means, then the load falls under physics and lands or splashes into the water volume below.
    • AC-2 integration Given the crane jib rotated with a load swinging, when the load strikes a creature, then impulse damage applies via the damage model.
    • AC-3 integration Given a crate stack pushed over, when it collapses onto the only walkway, then a climb or push route over the debris remains (edge: no softlock).

    Waits on

    • mw-e03.10 Simulate movable, throwable and stackable physics objects in sim done
    • mw-e03.13 Support hanging objects on ropes that burn, cut or snap done
    • mw-e05.13 Shootable triggers and cuttable ropes activate mechanisms done
    • mw-e09.8 Hiding places: wardrobes, barrels, tall grass and shadowed alcoves open
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:contentepic:e40milestone:m3
  • mw-e40.3Build the Customs House, its strongroom and Cray's book confiscationblockedP1M3feature

    Description

    Why

    Inspector Cray is the MVP's only on-screen Lantern Court official; confiscation turns carrying books into a story.

    What

    As a sorcerer, I want a customs inspector who confiscates restricted books I carry openly so that smuggling them becomes my own heist.

    Customs House: cargo scale, Cray's office (the well-read shelf, confiscated romances), the manifest copy of bay nine, the strongroom of confiscated goods (skylight/roof route, locked door). Inspection: at the barge berth and the customs gate, any book item with legality restricted and no writ in the player's visible inventory is moved to the strongroom as an owned-by-customs item (never forbidden-plot items). Recovery: buy back with a writ, steal back (a crime via e22-crime-bounty), or charm back (Contraband Pages).

    Scope

    • In: Interior, strongroom container, inspection trigger + legality check, writ condition, confiscation facts
    • Out: Contraband Pages quest graph (e39-side-quests-harbor)
    • Out: Cray dialogue (e39-dialogue-harbor-trade)
    • Out: Crime/bounty rules (e22-crime-bounty)

    Notes

    Related: e21-stolen-forbidden-stock (P2) for reselling recovered restricted books. Stowaway arrivals (e25-barge-travel) and sneaking past the gate skip inspection.

    Acceptance criteria

    • AC-1 integration Given the player carries a restricted book without a writ, when inspected, then the book moves to the strongroom container and fact customs.confiscated.<bookId> is set.
    • AC-2 integration Given a book flagged as a plot item, when inspected, then it is never confiscated (edge).
    • AC-3 integration Given a confiscated book stolen back from the strongroom while witnessed, when reported, then a Wendmouth crime is recorded via e22-crime-bounty.
    • AC-4 integration Given the player holds a writ fact, when inspected, then nothing is confiscated and Cray's disposition is unchanged.

    Waits on

    • mw-e07.1 Define book item schema: spell, language, condition, legality done
    • mw-e17.3 Implement inventory model with stacks, keys, books and quest items done
    • mw-e18.3 Add lootable containers that persist their contents done
    • mw-e22.1 Turn witnessed crimes into settlement bounties with pay/jail/flee open
    • mw-e39.22 Script harbour side quests The Tidefair and Contraband Pages done
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:contentclass:sorcererepic:e40milestone:m3
  • mw-e40.4Build the Bonded Warehouse: bay nine, skylights, hoists and manifestsblockedP1M3feature

    Description

    Why

    The warehouse is the thief's showcase: a sealed bay, a watchman and a desk full of paper.

    What

    As a thief, I want a warehouse with skylights, hoist beams and a manifest desk so that I can case it and choose my way in.

    Sealed bays; bay nine (Vane Deepworks) with a customs-seal entity (intact / broken / re-sealed, stamp-verifiable); skylights (climb, rope-arrow anchor); hoist beams (traversable, can lower crates); the night watchman's patrol and lantern; the manifest desk (swap or forge the bay nine manifest); Jasper Quell's office (foundry invoice, honest manifest, Mr. S— letters).

    Scope

    • In: Interior, seal state entity, skylight and beam routes, watchman patrol data, manifest desk and Quell's office items
    • Out: Heist outcomes (e40-crate-heist)
    • Out: Quell dialogue (e39-dialogue-harbor-trade)

    Notes

    The seal records who stamped it; the dead clerk E. Ardley's stamp is evidence (bible canon).

    Acceptance criteria

    • AC-1 integration Given the watchman's night patrol, when the stealth replay enters via a skylight, then bay nine can be reached with the watchman never exceeding Suspicious.
    • AC-2 integration Given the bay nine seal broken, when re-sealed with the customs-seal stamp item, then the seal reads intact to inspection; without the stamp it reads broken.
    • AC-3 integration Given the watchman finds a broken seal on his round, when perceived, then he raises the alarm and the harbour watch investigates (edge: failure creates pursuit, not reload).
    • AC-4 content Given the obstacle registry, when validated, then bay nine declares >= 3 class routes.

    Waits on

    • mw-e05.10 Rope arrows anchor into wood and create climbable ropes open
    • mw-e09.9 Guards notice world anomalies: bodies, open doors, dark torches open
    • mw-e10.7 Pick locks as an in-world, interruptible, noisy action open
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e11.9 Patrol routes, guard posts and idle routines authored as data done
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:contentclass:thiefepic:e40milestone:m3
  • mw-e40.6Build the Drowned Gull: arm-wrestling, dice, drinking and the trapdoorblockedP1M3feature

    Description

    Why

    Nell's tavern is the harbour's social hub, the thief's drop point and a place where losing lands you somewhere new.

    What

    As a player, I want a rowdy tavern where I can arm-wrestle Big Oona, drink, gamble, start or end a brawl and find the trapdoor to the Undertow so that Wendmouth's people become my allies or rivals.

    Interior on the breakwater end: arm-wrestling table (contest), dice table, drinking contest (losing wakes you shanghaied in the Gilded Tern's hold via a wake-in-place rule), brawl trigger (non-lethal brawling), the thief commission drop with Nell (deliver the coin, keep it, or deliver a fake), and the trapdoor (found by search or granted by Nell's trust).

    Scope

    • In: Interior, contest instances (arm-wrestling, dice, drinking), brawl trigger, drop interaction facts, trapdoor, wake rule
    • Out: Nell and Oona dialogue (e39-dialogue-harbor-folk)
    • Out: Tidefair brawl (e40-tidefair-strength)

    Notes

    Brawls use non-lethal damage tags: knocked-out, never killed, for everyone involved.

    Acceptance criteria

    • AC-1 integration Given the player loses the drinking contest, when it resolves, then they wake in the Tern's hold, fact tern.shanghaied is set and no reload occurs.
    • AC-2 integration Given the thief delivers a fake horn-coin to Nell, when evaluated, then commission.fakeDelivered is set and the payout still occurs.
    • AC-3 integration Given a brawl started in the tavern, when it ends, then no participant has died and the watch is not called (dockhands settle it).
    • AC-4 integration Given the trapdoor is found without Nell's trust, when used, then the Undertow is reachable but Nell's disposition drops one band (edge).

    Waits on

    • mw-e01.12 Wake in context after death instead of reloading open
    • mw-e22.9 Start conversations with NPCs in-world and handle interruptions done
    • mw-e39.19 Write dialogue for Mags Oakum, Nell Gannet, Big Oona and Old Reed done
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    • mw-e40.5 Run data-defined contests with entry, scoring, cheating and bets done
    area:contentepic:e40milestone:m3
  • mw-e40.7Stage the Tidefair arm-wrestling bout and the Gull brawlblockedP1M3feature

    Description

    Why

    Knights get hijinks too: beat Big Oona, then survive the free-for-all when someone loses badly.

    What

    As a knight, I want to arm-wrestle and brawl at the Tidefair so that strength and timing win me coin and friends.

    Arm-wrestling: a timed hold contest scored from stamina management and timed pushes (reuses e04 stamina). The Gull brawl: a non-lethal free-for-all on the wharf using melee and hit reactions with a knockout tag; environment pushes into the water are allowed. Both run on the contest framework with cheat rules (magic, dirty tricks) and a lose-gracefully branch (Oona buys you a drink).

    Scope

    • In: Two contest definitions, arm-wrestle input/stamina binding, brawl non-lethal rules, participants
    • Out: Combat systems (E04)
    • Out: Quest rewards (e39-side-quests-harbor)

    Notes

    Any class may enter; knights have the flavour advantage (poise, stamina).

    Acceptance criteria

    • AC-1 integration Given the arm-wrestling contest, when the player outlasts Oona's stamina, then contest win fires and the Tidefair reputation fact increments.
    • AC-2 integration Given the brawl, when any participant reaches 0 health, then they are knocked out (not killed) and leave the brawl.
    • AC-3 integration Given the player is shoved into the harbour during the brawl, when they surface, then they are out of the contest and may climb back via a ladder (edge).

    Waits on

    • mw-e04.5 Stamina pool governs attacks, blocks, dodges and sprint done
    • mw-e04.7 Sim-chosen hit reactions: flinch, stagger, knockback, knockdown done
    • mw-e40.18 Add the harbour watch, Low Tide Company and Tern crew as humans open
    • mw-e40.2 Build the Stone Wharf with working cranes, cargo nets, crates and block yards open
    • mw-e40.5 Run data-defined contests with entry, scoring, cheating and bets done
    area:contentclass:knightepic:e40milestone:m3
  • mw-e40.8Stage the Tidefair Gull Shoot and the Pocket RaceblockedP1M3feature

    Description

    Why

    Archers win shooting contests and thieves lift ribbons from five marks — one of them the Inspector.

    What

    As an archer, I want to hit wooden gulls on a swinging boom and then the live gull that stole the ribbon; as a thief, I want to lift a ribbon from each of five marked contestants without being caught.

    Gull Shoot: boom-mounted targets on a swinging rope (moving-target scoring), then a live harbour gull target that flees to the rooftops. Pocket Race: five marked NPCs wandering the wharf crowd (one is Cray), each carrying a ribbon; caught = out.

    Scope

    • In: Two contest definitions, swinging boom prop, live-gull chase target, five marked contestants
    • Out: Archery and pickpocket mechanics (E05/E10)

    Notes

    Sabotage is possible: cut the boom rope, or plant a ribbon on a rival. Both have consequences via cheat rules.

    Acceptance criteria

    • AC-1 integration Given the boom swinging, when an arrow hits a wooden gull, then the hit scores and the gull drops.
    • AC-2 integration Given the Pocket Race, when the player lifts all five ribbons unseen, then they win; if Cray notices a lift, then she files a note (fact cray.noticedThief) but does not arrest.
    • AC-3 integration Given the live gull flees to a rooftop, when the player follows, then its hoard location becomes reachable and the ribbon is retrievable (edge: prize never lost).

    Waits on

    • mw-e05.3 Bow draw, aim and release firing selected arrow type in progress
    • mw-e10.8 Pickpocket and plant items on creatures from behind open
    • mw-e40.16 Fill the harbour with pickpocketable crowds that give stealth cover open
    • mw-e40.2 Build the Stone Wharf with working cranes, cargo nets, crates and block yards open
    • mw-e40.5 Run data-defined contests with entry, scoring, cheating and bets done
    area:contentepic:e40milestone:m3
  • mw-e40.10Author the Tidemarket: Tereza's arms stall and the foreign book cartblockedP1M3feature

    Description

    Why

    Everyone can equip themselves better in Wendmouth than in Briar Glen; the Tidemarket is where.

    What

    As a player of any class, I want an import market with foreign steel, light armour, exotic arrows and rare spellbooks so that the trip downriver upgrades my kit.

    Merchant data on e20: Tereza Maelo's arms stall (curved Saltmarch sabres, harpoon-spears, lacquered round shields, sharkskin brigandine; an under-the-counter tier gated by duel/Tidefair facts); exotic arrows as foreign variants of MVP arrow types (whistling = noise, grapple = rope; data only); spice/silk/oddities stall. Foreign bookseller's cart authored on the e21 bookshop template (Storm, Illusion and Gravity texts; restricted ones subject to customs).

    Scope

    • In: Covered market interior, three merchant files, one bookshop file, under-the-counter conditions
    • Out: Arrow mechanics (E05)
    • Out: Merchant dialogue (e39-dialogue-harbor-trade)
    • Out: Tereza's duel (e40-tereza-duel)

    Notes

    Related: e05-trick-arrows-extended (P3) — netting, tar and glass-headed arrows appear only if that lands. Mirela pays well for anything the cart won't sell (Related: e24-lamplit-stacks buyback).

    Acceptance criteria

    • AC-1 content Given the Tidemarket stock, when compared with all Briar Glen merchants, then every class has >= 2 purchasable items not sold in Briar Glen.
    • AC-2 content Given the foreign book cart, when pnpm validate:bookshops runs, then it passes and no unique book is duplicated with the Lamplit Stacks.
    • AC-3 integration Given the under-the-counter tier, when neither the duel nor a Tidefair win fact is set, then it is hidden (edge); with either, it appears.
    • AC-4 content Given the arrow stock, when validated, then every arrow item references an existing e05 arrow type.

    Waits on

    • mw-e04.16 Armor weight sets roll class, stamina regen, poise and noise done
    • mw-e05.1 Data schema for arrow types and property-based payloads done
    • mw-e20.2 Define merchant schema with identity, specialty and stock rules done
    • mw-e20.4 Implement merchant buy/sell transactions with persistent stock done
    • mw-e21.9 Provide a bookshop authoring template, validator and fixture shop open
    • mw-e39.20 Write dialogue for Inspector Cray, Tereza Maelo, Quell and Hesketh done
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:contentepic:e40milestone:m3
  • mw-e40.12Build the Undertow black market and its smugglers' tunnelsblockedP1M3feature

    Description

    Why

    The Undertow sells what the Tidemarket can't — the thief's best tools — and links the harbour underground.

    What

    As a thief, I want a black market in the smugglers' cellars with tunnels to the tavern and the harbour wall so that I can equip myself and move unseen.

    Cellars beneath the fish market; tunnels to the Drowned Gull trapdoor and the breakwater sea-door; Nell Gannet's fence/merchant data: smuggler thief tools (tide-silk rope, glue-soled boots, smoke pearls, skeleton-key ring, customs-seal stamp), fenced goods, and the dockhand disguise kit item. Access: trust, the trapdoor, or the sea-door.

    Scope

    • In: Cellar scene, tunnels, fence merchant data, thief tool item data (on e10 tool schema)
    • Out: Tool mechanics (E10)
    • Out: Disguise behaviour (e40-dockhand-disguises)

    Notes

    Tool items reuse existing verbs: tide-silk rope → rope anchor, glue-soled boots → quieter footsteps on wet surfaces, smoke pearls → smoke escape, skeleton-key ring → lockpick bonus, customs-seal stamp → re-seal action.

    Acceptance criteria

    • AC-1 content Given Nell's merchant file, when validated, then isFence is true and every tool references an existing capability or tool type.
    • AC-2 integration Given the player enters by the sea-door, when first arriving, then the Undertow merchants are Wary rather than Hostile and trade is allowed after one exchange (edge).
    • AC-3 integration Given the customs-seal stamp bought, when used on a broken seal, then the seal reads intact (ties to e40-bonded-warehouse).

    Waits on

    • mw-e10.1 Define thief tool item data: lockpicks, throwables, smoke, traps open
    • mw-e10.13 Smoke bombs and flash powder break line of sight for escapes open
    • mw-e20.2 Define merchant schema with identity, specialty and stock rules done
    • mw-e20.6 Support fences and merchant reactions to stolen goods open
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:contentclass:thiefepic:e40milestone:m3
  • mw-e40.13Build a continuous rooftop and net-loft route across the waterfrontopenP1M3feature

    Description

    Why

    Climbers should cross the whole harbour above the crowd — and archers need rigging-shot vantages.

    What

    As a thief, I want a roof route from the Stone Wharf to the breakwater via net lofts so that I can reach skylights, the customs roof and the Tern's rigging line unseen.

    Connected roofs and net lofts (hanging nets climbable and flammable), plank bridges, gull-hoard ledges, archer vantage points over the pool and the Tern's rigging.

    Scope

    • In: Roof surfaces with acoustic tags, climbable nets, plank bridges, vantage points
    • Out: Climbing mechanics (E10/E02)

    Notes

    Tarred roofs are quiet; tin roofs are loud (acoustic tags).

    Acceptance criteria

    • AC-1 integration Given the rooftop replay, when a thief crosses from the Stone Wharf to the breakwater, then they never touch street navmesh.
    • AC-2 integration Given a climbable net ignited, when it burns, then the route segment closes and an alternative segment remains (edge).
    • AC-3 integration Given an archer at a vantage point, when aiming at the Tern's hoist rope, then it is within effective bow range and unobstructed.

    Waits on

    • mw-e02.12 Mantle onto and grab ledges detected from world geometry done
    • mw-e09.4 Tag surfaces with acoustic materials that change footstep noise done
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:contentclass:thiefepic:e40milestone:m3
  • mw-e40.14Build the Gilded Tern: rigging, hold, cabin, locked berth, departureopenP1M3feature

    Description

    Why

    The merchantman is the heist's destination, a shanghai wake point and a ship you can climb.

    What

    As a player, I want to board the three-masted Tern by lighter, swim, rigging line, a frozen pool, Tereza's favour or signing on as crew so that the ship becomes a playground.

    Ship at anchor in the pool: climbable rigging and yards, deck, hold (crates, shanghai wake spot), Captain Hesketh's cabin, the locked berth of Mr. S—'s agent (never opens in the MVP; interact hooks), crew patrols. World variant: when Act III begins the Tern is gone (fact tern.sailed) with or without Vane's crate.

    Scope

    • In: Ship scene/area, rigging climb routes, hold and cabin, locked berth, boarding routes, sailed variant
    • Out: Crew behaviour (e40-harbor-opposition)
    • Out: Hesketh dialogue (e39-dialogue-harbor-trade)

    Notes

    The pool is standing water: freezing it at night makes a walkable path to the hull (bible sorcerer route).

    Acceptance criteria

    • AC-1 integration Given the pool frozen by any cold stimulus at night, when walked, then the Tern's hull ladder is reachable on foot.
    • AC-2 integration Given fact act3.started, when the harbour loads, then the Tern is absent and tern.sailed is set; the crate outcome is recorded as shipped if not resolved.
    • AC-3 integration Given the player is on board when Act III starts, when the harbour next loads, then they are placed on the wharf, never stranded at sea (edge).
    • AC-4 content Given the obstacle registry, when validated, then boarding the Tern declares >= 4 class routes.

    Waits on

    • mw-e02.14 Wade and swim in water and slide on frozen surfaces done
    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e10.9 Climb tagged surfaces, ledges and ropes with stamina done
    • mw-e27.8 Spawn fact-gated entity variants so the world reacts to choices done
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:contentepic:e40milestone:m3
  • mw-e40.15Build the breakwater, sunken figurehead, sea-door and harbour tidesblockedP1M3feature

    Description

    Why

    Getting thrown off the pier should land you somewhere new: the figurehead and the smugglers' sea-door.

    What

    As a player, I want being thrown off the pier to wash me up by a secret door so that failure in Wendmouth opens a route.

    Stone breakwater, the sunken figurehead (debunks the sea-serpent rumour 18 by diving), the smugglers' sea-door into the Undertow tunnels. Harbour tide: two standing-water levels scheduled on the world clock (high/low); low tide exposes the sea-door and the crate-drop spot. Wake rule: "thrown off the pier" (subdued in Wendmouth) → surface at the breakwater.

    Scope

    • In: Breakwater area, figurehead dive spot, sea-door, two-state tide schedule, wake rule content
    • Out: Flowing water / waves (not planned)

    Notes

    Tide is two scheduled water-level states, not simulation.

    Acceptance criteria

    • AC-1 integration Given the player is subdued by dockhands or the watch in Wendmouth, when resolved, then they surface at the breakwater and harbor.thrownOffPier increments.
    • AC-2 integration Given low tide on the clock schedule, when the harbour loads, then the sea-door is above water and enterable; at high tide it is reachable only by swimming (edge).
    • AC-3 integration Given the player dives to the figurehead, when reached, then rumour 18 resolves as false.

    Waits on

    • mw-e01.12 Wake in context after death instead of reloading open
    • mw-e02.14 Wade and swim in water and slide on frozen surfaces done
    • mw-e22.11 Add rumor system that points players to places and secrets done
    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:contentepic:e40milestone:m3
  • mw-e40.16Fill the harbour with pickpocketable crowds that give stealth coverblockedP1M3feature

    Description

    Why

    Pickpocketable crowds make the thief's playground; market days should feel packed.

    What

    As a thief, I want dense market-day crowds I can blend into and pick pockets from so that sneaking in plain sight is rewarded.

    Crowd NPC sets on schedule windows (market days denser), each with a small pocket loot table; crowd volumes reduce the player's visibility score while moving at walk speed inside them; bumping a crowd NPC at run speed emits a noise/complaint.

    Scope

    • In: Crowd schedule data, pocket loot tables, crowd-cover visibility modifier volumes, bump barks
    • Out: Disguises (e40-dockhand-disguises)
    • Out: Pickpocket mechanics (e10-pickpocketing)

    Notes

    Crowd cover is a visibility modifier volume on e09-visibility-model inputs, not a new stealth system.

    Acceptance criteria

    • AC-1 integration Given the player walking inside a crowd volume, when a watchman's visibility score is computed, then it is reduced by the configured crowd factor versus open ground.
    • AC-2 integration Given a crowd NPC pickpocketed unseen, when checked, then an item from its pocket table is taken and no crime is recorded.
    • AC-3 perf Given a market-day crowd of 40 agents on the Stone Wharf, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent) and p95 <= 16.7 ms at 1080p on the Low preset on an Intel Iris Xe / base M1 8 GB class machine, with p99 <= 33.3 ms (30 fps floor) during worst-case combat (edge: crowd LOD).

    Waits on

    • mw-e09.2 Compute player visibility from light, stance, motion and distance done
    • mw-e10.8 Pickpocket and plant items on creatures from behind open
    • mw-e18.1 Implement loot table schema and deterministic seeded roller done
    • mw-e24.13 Place Briar Glen's NPCs on day/night schedules in progress
    • mw-e40.1 Block out Wendmouth harbour in grey-box with every named place done
    area:contentclass:thiefepic:e40milestone:m3
  • mw-e40.18Add the harbour watch, Low Tide Company and Tern crew as humansblockedP1M3feature

    Description

    Why

    Wendmouth adds no creature types: its opposition is human and social — bribe, trick, drink with, out-brawl.

    What

    As a player, I want harbour people who arrest, throw me off the pier or brawl instead of killing me so that getting caught in Wendmouth is a story.

    Human creature data on e12: harbour watch (non-lethal by default; arrest via e22-crime-bounty or subdue → thrown off pier), Low Tide Company smugglers (clubs, knives, nets, whistles; alarms via whistles), Tern crew (deck patrols, belaying-pin clubs). Factions and relationships (Low Tide vs watch), bribe/drink affordances, retreat/surrender.

    Scope

    • In: Three human archetypes as creature data, move sets, faction table entries, affordances, subdue outcomes
    • Out: Crime/bounty (e22-crime-bounty)
    • Out: Dialogue (e39-dialogue-harbor-folk, e39-dialogue-harbor-trade)

    Notes

    Readability rules apply to human attacks too. Knives are lethal only if the player draws steel first (escalation fact).

    Acceptance criteria

    • AC-1 content Given the three human archetypes, when validated, then they pass CreatureDef and all moves pass readability.
    • AC-2 integration Given the watch subdues the player without a bounty, when resolved, then the player is thrown off the pier (breakwater wake) rather than jailed.
    • AC-3 integration Given a Low Tide smuggler blows a whistle, when heard by allies within range, then they converge on the whistle location.
    • AC-4 integration Given the player bribes a watchman with enough coin, when accepted, then that watchman ignores trespass for 10 game minutes (edge: expires).

    Waits on

    • mw-e04.20 Creatures attack via the move system with readable telegraphs done
    • mw-e11.12 Allies share alerts by shouts, sight signals and alarm devices open
    • mw-e11.13 Combat behaviour: engage, space, select attacks and share targets done
    • mw-e12.1 Define zod creature schema with senses, locomotion, attacks and needs done
    • mw-e12.8 Faction table and relationship queries between creatures done
    • mw-e22.1 Turn witnessed crimes into settlement bounties with pay/jail/flee open
    • mw-e22.12 Let players give gifts and bribes that shift disposition open
    • mw-e40.15 Build the breakwater, sunken figurehead, sea-door and harbour tides open
    area:contentepic:e40milestone:m3
  • mw-e40.20Place The Crate for Mr. S— heist with all six solution routesblockedP1M3feature

    Description

    Why

    The harbour's centrepiece: a stealth-first heist that every class can solve its own way.

    What

    As a player of any class, I want to take Vane's relic crate by heist, paper, net, force, ice or leverage so that I win the name-stone and the manifest my way.

    Wire the bible §6.1 quest 6 routes into the level: heist (case, roof/skylight entry, dodge the watchman, swap contents for ballast, re-seal with the stamp); paper (swap/forge the manifest so Cray seizes the crate legally, needing Quell's honest manifest or the dead clerk's seal); net (cut the net mid-hoist so the crate drops into the harbour, fish it out at low tide before the Low Tide Company); force (dockside brawl with Nell's crew and the watch; Cray arrives at the end); ice (freeze the pool at night and take it from the hold, or Gust the hoist so it lands on the wharf); leverage (confront Quell with the foundry invoice). Outcomes: name-stone, manifest, sealed letter facts.

    Scope

    • In: Hoist sequence timing, crate entity with contents state, route wiring, outcome facts, low-tide retrieval spot
    • Out: Quest graph (e39-harbor-heist-quest)
    • Out: Disguise entry (Related: e40-dockhand-disguises, P2)

    Notes

    Crate contents per canon: 40 horn-coins, 3 carved stones, 1 name-stone. The name-stone is a befriend-Horn trigger (Related: e14-horn-befriend-help).

    Acceptance criteria

    • AC-1 integration Given each of the six routes, when its replay runs, then the crate outcome fact is set to the route id and the name-stone is obtainable.
    • AC-2 integration Given the perfect heist (contents swapped, seal re-stamped, no alert), when the Tern sails, then heist.perfect is set and no one in Wendmouth reacts.
    • AC-3 integration Given the crate dropped into the harbour, when the Low Tide Company reaches it first at low tide, then the crate moves to the Undertow and remains obtainable there (edge: failure relocates).
    • AC-4 integration Given Act III starts before any route resolves, when evaluated, then crate.shipped is set and the customs manifest copy still proves the shipments.

    Waits on

    • mw-e39.21 Script the heist side quest The Crate for Mr. S— done
    • mw-e40.12 Build the Undertow black market and its smugglers' tunnels open
    • mw-e40.14 Build the Gilded Tern: rigging, hold, cabin, locked berth, departure open
    • mw-e40.15 Build the breakwater, sunken figurehead, sea-door and harbour tides open
    • mw-e40.18 Add the harbour watch, Low Tide Company and Tern crew as humans open
    • mw-e40.2 Build the Stone Wharf with working cranes, cargo nets, crates and block yards open
    • mw-e40.3 Build the Customs House, its strongroom and Cray's book confiscation open
    • mw-e40.4 Build the Bonded Warehouse: bay nine, skylights, hoists and manifests open
    area:contentclass:allepic:e40milestone:m3
  • mw-e40.21Declare Wendmouth obstacles and class routes in the registryblockedP1M3feature

    Description

    Why

    Sneakiness is richly rewarded, but every class must get its hijinks; the audit has to see the harbour.

    What

    As a player of any class, I want every harbour obstacle to offer my class a route so that Wendmouth plays to my fantasy.

    Registry entries and replays for: customs strongroom, bay nine, boarding the Tern, the Undertow entry, the crate (six routes), and the Tidefair (one event per class flavour). Obstacles are marked mandatory within their quest (the town itself is optional).

    Scope

    • In: Registry entries, route affordances added where missing, replays
    • Out: Audit gate (e16-route-audit)

    Notes

    Target 4 classes for bay nine and the Tern.

    Acceptance criteria

    • AC-1 content Given the registry, when validated, then every E40 quest-mandatory obstacle has >= 3 class routes and bay nine and the Tern have 4.
    • AC-2 integration Given each declared route, when replayed, then the obstacle exit fact is set.
    • AC-3 integration Given an obstacle whose only thief route needs the P2 disguise, when audited without it, then >= 3 other routes still pass (edge).

    Waits on

    • mw-e16.2 Declare obstacles and class routes as validated content data open
    • mw-e40.13 Build a continuous rooftop and net-loft route across the waterfront open
    • mw-e40.20 Place The Crate for Mr. S— heist with all six solution routes open
    area:contentclass:allepic:e40milestone:m3
  • mw-e40.22Place Wendmouth rumours, lore texts, secrets and treasureblockedP1M3feature

    Description

    Why

    Rumours 13–18 must lead somewhere; every vaulted warehouse and net loft should hide something.

    What

    As a curious player, I want harbour gossip that points at real places so that talking in Wendmouth leads to mischief.

    Bind rumours 13–18 to sources (Mags, Nell, Old Reed, Tidemarket gossip) with produced resolve facts; place the Lantern Court notice, the bay nine manifest copies, the foundry invoice, Mr. S—'s sealed letter; 10–14 treasures incl. smugglers' stashes and gull hoards.

    Scope

    • In: Rumour source bindings, fact producers, lore/treasure placements
    • Out: Texts (e39-harbor-rumors-texts)

    Notes

    River rumour 16 resolves in e25-weeping-adit; 18 in e40-breakwater-sea-door.

    Acceptance criteria

    • AC-1 content Given rumours 13–18, when validated, then each has >= 1 source and a resolvesWhen fact produced by placed content (no warnings).
    • AC-2 integration Given rumour 15 heard, when the player enters the Undertow, then it resolves.
    • AC-3 integration Given a stash looted, when saved and reloaded, then it stays empty (edge).

    Waits on

    • mw-e18.5 Support designer-placed and hidden treasure with discovery rules open
    • mw-e22.11 Add rumor system that points players to places and secrets done
    • mw-e39.23 Write harbour rumours and in-world texts (manifest, notice, tolls) done
    • mw-e40.12 Build the Undertow black market and its smugglers' tunnels open
    • mw-e40.3 Build the Customs House, its strongroom and Cray's book confiscation open
    area:contentepic:e40milestone:m3
  • mw-e40.23Art-dress Wendmouth with glenstone harbour assets and the TernblockedP1M3feature

    Description

    Why

    Colossal glenstone quays, vaulted warehouses, net lofts and a three-master: Wendmouth must look loud, cheerful and built like a city next to quiet Briar Glen.

    What

    As a player, I want Wendmouth to look like a crooked, salt-weathered port built from the valley's stone so that arriving feels like a change of air.

    Monumental glenstone harbour kit (stepped quays, mason-marked block breakwater, vaulted warehouses, columned Customs House, treadwheel cranes on stone piers, block yards) with timber net lofts and sheds perched on the stone, props, the Gilded Tern hero model, crowd variants, water surface materials; keep collision and gameplay ids intact.

    Scope

    • In: Art swap for the harbour, the Tern, interiors, crowd visuals
    • Out: Asset creation (E37)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item.

    Acceptance criteria

    • AC-1 integration Given the dressed harbour, when all E40 route and heist replays run, then they pass unchanged.
    • AC-2 perf Given the Stone Wharf on market day with the Tern in view, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent) and draw calls <= 1500.
    • AC-3 manual Given the art review, when compared to the style bible, then interactable affordances (climbable nets, cuttable ropes) remain legible against dressing (edge).

    Waits on

    • mw-e37.13 Shared stylized lit material with ramp, rim and wet/emissive masks open
    • mw-e37.14 Legibility kit: visual cues for every exploitable world property open
    • mw-e37.150 Integrate approved Wendmouth environment concepts open
    • mw-e37.158 Integrate approved Wendmouth tileables and trims open
    • mw-e37.200 Integrate approved waterfront and Tidefair props open
    • mw-e37.204 Integrate approved harbour interior props open
    • mw-e37.210 Integrate approved harbour heist and story props open
    • mw-e37.8 Model import pipeline: glTF optimise, meshopt and KTX2 compression open
    • mw-e40.16 Fill the harbour with pickpocketable crowds that give stealth cover open
    • mw-e40.21 Declare Wendmouth obstacles and class routes in the registry open
    area:artepic:e40milestone:m3
  • mw-e40.24Light and score Wendmouth for market day, night and the tavernblockedP1M3feature

    Description

    Why

    Loud and cheerful by day, lantern-lit and sneaky by night: the harbour's mood changes the play.

    What

    As a player, I want Wendmouth to sound busy by day and to have dark pools of shadow at night so that both hijinks and heists feel right.

    Lighting per phase (dock lanterns, ship lamps, lighthouse sweep on the breakwater), music cues (harbour day/night, Drowned Gull diegetic, Tidefair, heist tension), ambience bindings (gulls, rigging creak, surf), reverb zones for cellars.

    Scope

    • In: Lighting, music bindings, ambience/reverb bindings
    • Out: Audio assets (E38)

    Notes

    Related: final assets come from E37/E38 per-asset prompt/generate/integrate beads created by the asset-prompt wave from plan/world-asset-needs.md; those integrate beads should block this item. Gameplay never waits on this item. Related: e28-ambience, e28-reverb-zones and e29-environment-fx are P2 in the combat plan; bind ambience beds, reverb zones and fog/firefly FX here when they land, otherwise ship lighting + music only.

    Acceptance criteria

    • AC-1 integration Given the clock crosses dusk, when the phase event fires, then lighting blends to night within 5 s and music switches to the harbour night cue.
    • AC-2 integration Given night lighting, when sampled along the warehouse heist routes, then >= 40% of each route has light <= 0.3 (edge: stealth viable).
    • AC-3 perf Given night with all lanterns lit and the Tern's lamps, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).

    Waits on

    • mw-e27.12 Run a deterministic in-game clock with time-of-day and schedules done
    • mw-e28.11 Adaptive music controller with layered stems and stingers done
    • mw-e37.242 Integrate approved river and harbour VFX open
    • mw-e38.5 Audio import pipeline: normalise, encode Opus/AAC, loop metadata open
    • mw-e38.72 Integrate approved Wendmouth music families into adaptive music open
    • mw-e38.84 Integrate approved Wendmouth ambience open
    • mw-e38.9 Data-driven music state mapping from alert states with hysteresis open
    • mw-e40.23 Art-dress Wendmouth with glenstone harbour assets and the Tern open
    area:audioepic:e40milestone:m3
  • mw-e40.9Stage the Tidefair Regatta rowing race on the harbour poolblockedP2M3feature

    Description

    Why

    The sorcerer's hijinks: "no magic" is a rule nobody enforces until Cray walks by.

    What

    As a sorcerer, I want to win a rowing race by gusting my sail or freezing a rival's oars so that magic creates comedy.

    Boats are kinematic course-followers on the standing-water pool (no flow sim): speed from a rowing input rhythm, plus force stimuli on the sail (any impulse), minus frozen oars (frozen property halts a boat for 3 s). Cheat rule: magic observed by Cray disqualifies.

    Scope

    • In: Boat kinematic course entity, rowing input, stimulus responses, contest definition
    • Out: Boat physics or flowing water (not planned)

    Notes

    True extra: cut first if schedule slips.

    Acceptance criteria

    • AC-1 integration Given a force impulse applied to the player's sail, when evaluated, then boat speed rises by the impulse-derived boost for its duration.
    • AC-2 integration Given a rival's oars frozen by any cold stimulus, when evaluated, then that boat halts for 3 s.
    • AC-3 integration Given Cray perceives a cast during the race, when detected, then the player is disqualified and fact cray.regattaCheat is set (edge).

    Waits on

    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    • mw-e06.8 Apply spell forces: impulse, knockback, pull and lift done
    • mw-e40.2 Build the Stone Wharf with working cranes, cargo nets, crates and block yards open
    • mw-e40.5 Run data-defined contests with entry, scoring, cheating and bets done
    area:contentclass:sorcererepic:e40milestone:m3
  • mw-e40.11Stage Tereza Maelo's first-blood duelblockedP2M3feature

    Description

    Why

    A retired duellist looking for a reason not to be: a knight's signature Wendmouth moment.

    What

    As a knight, I want to accept Tereza's first-blood duel so that winning unlocks her under-the-counter stock and her respect.

    Duel mode: non-lethal, first clean hit landed wins; Tereza uses a fast parry-heavy sabre move set (readability rules apply); dirty tricks count as a loss of honour (fact).

    Scope

    • In: Duel encounter state, Tereza combat moves as creature data, outcome facts
    • Out: Stall stock (e40-tidemarket)

    Notes

    Any class may duel; knights receive the challenge unprompted.

    Acceptance criteria

    • AC-1 content Given Tereza's move data, when validated, then every move passes the readability rule.
    • AC-2 integration Given the player lands the first clean hit, when resolved, then tereza.duelWon is set and combat ends immediately with no further damage.
    • AC-3 integration Given the player uses a thrown distraction or poison during the duel, when detected, then tereza.dishonoured is set and the stock stays hidden (edge).

    Waits on

    • mw-e04.12 Parry window and riposte critical attack done
    • mw-e04.20 Creatures attack via the move system with readable telegraphs done
    • mw-e40.10 Author the Tidemarket: Tereza's arms stall and the foreign book cart open
    area:contentclass:knightepic:e40milestone:m3
  • mw-e40.17Let dockhand disguises fool the watch and warehouse crewsblockedP2M3feature

    Description

    Why

    A dockhand disguise from the Undertow is the classic heist entry.

    What

    As a thief, I want a dockhand disguise that lets me walk into restricted wharf areas so that I can case the warehouse in daylight.

    Disguise data for the dockhand faction look: accepted by harbour watch and warehouse crew until suspicious behaviour (running, climbing, entering bay nine, picking locks in view) exposes it.

    Scope

    • In: Disguise definition, restricted-area rules, exposure behaviours for harbour factions
    • Out: Disguise system (e10-disguises)

    Notes

    Related: e40-crate-heist lists the disguise as one heist entry when this lands.

    Acceptance criteria

    • AC-1 integration Given the disguise worn, when the player walks through the warehouse yard by day, then the watchman stays Unaware.
    • AC-2 integration Given the disguised player climbs in view, when perceived, then the disguise is exposed and crime.disguise.exposed fires.
    • AC-3 integration Given Nell's crew sees the disguise, when perceived, then they recognise it and do not report (edge: faction-specific).

    Waits on

    • mw-e10.10 Disguises that fool factions until behaviour gives you away open
    • mw-e40.12 Build the Undertow black market and its smugglers' tunnels open
    • mw-e40.16 Fill the harbour with pickpocketable crowds that give stealth cover open
    area:contentclass:thiefepic:e40milestone:m3
  • mw-e40.19Add harbour gulls that steal shiny things and rats that give you awayblockedP2M3feature

    Description

    Why

    Ambient life with systemic hooks: gulls with criminal records and rats that squeal at the worst moment.

    What

    As a player, I want gulls that snatch unattended shiny items and rats that scatter from light so that the harbour feels alive and mischievous.

    Gulls: ambient agents that grab unattended items tagged shiny and fly to rooftop hoards (followable, lootable). Wharf rats: flee light, emit a startle noise event when a sneaking player passes within 1.5 m.

    Scope

    • In: Two ambient agent definitions (not creature types), hoard containers, startle noise rule
    • Out: Creature roster (stays at 10 types)

    Notes

    Not counted as creature types (bible §8).

    Acceptance criteria

    • AC-1 integration Given an unattended shiny item on the wharf, when a gull reaches it, then it is carried to the nearest hoard container.
    • AC-2 integration Given a sneaking player passes within 1.5 m of a rat, when evaluated, then a startle noise event is emitted that nearby watchers can hear.
    • AC-3 integration Given a gull carrying a quest item, when it lands, then the item is placed in a reachable hoard (edge: quest items never lost).

    Waits on

    • mw-e03.15 Query light level at any position from all light sources in sim done
    • mw-e09.3 Propagate noise events through rooms, doors and walls with occlusion done
    • mw-e12.4 Spawn data-defined creatures into the sim and grey-box scenes done
    • mw-e40.13 Build a continuous rooftop and net-loft route across the waterfront open
    area:contentepic:e40milestone:m3

M4 Fun validation 1

  • mw-e40.25Perf-pass and playtest Wendmouth on both presetsblockedP1M4task

    Description

    Why

    Crowds, water, a ship and a brawl in one scene are a perf risk; hijinks must be discovered, not explained.

    What

    Perf suite runs on market day, the Tidefair brawl and night heist scenes on reference and low-tier machines; a 5-tester playtest (one per class plus one free): do they find a hijink and a gear upgrade unprompted within 30 minutes? Findings in docs/playtests/wendmouth.md with beads.

    Scope

    • In: Perf captures and fixes, playtest, findings
    • Out: Global perf (E32)

    Notes

    Related: e32-reference-runbook.

    Acceptance criteria

    • AC-1 perf Given market day with 40 crowd agents on the Stone Wharf, when measured, then frame time p95 <= 16.7 ms (steady 60 fps) on the reference machine (MacBook Pro M1 Pro, Chrome, High preset, 1440p-equivalent).
    • AC-2 perf Given the Tidefair brawl on Low, when measured, then p95 <= 16.7 ms at 1080p on the Low preset on an Intel Iris Xe / base M1 8 GB class machine, with p99 <= 33.3 ms (30 fps floor) during worst-case combat.
    • AC-3 perf Given a warm cache, when arriving by barge, then the harbour is playable in <= 3 s and heap stays <= 1.5 GB.
    • AC-4 manual Given 5 testers, when playing 30 minutes in Wendmouth, then >= 4 buy or earn a gear upgrade and >= 4 attempt a hijink or heist unprompted.

    Waits on

    • mw-e32.1 Build automated perf budget suite against the hardware baseline done
    • mw-e32.6 Implement Low/High graphics presets and dynamic resolution open
    • mw-e40.24 Light and score Wendmouth for market day, night and the tavern open
    area:perfepic:e40milestone:m4
E41CI & Release AutomationA PR gets a trustworthy verdict in about 6 minutes, only gates that must run per PR run per PR, the rest run nightly and5/22 done · 23%

Unscheduled 17

  • mw-e41.4Skip heavy jobs for docs, beads, site and script-only PRsopenP1task

    Description

    Why

    Bead-export, docs and site PRs run the full 12-minute pipeline although nothing they touch can break it.

    What

    Add a changes job that classifies the diff and gate the heavy jobs on it. Required checks stay green through an always-running aggregator (the e2e-smoke pattern), because a required check skipped by a path filter blocks merging.

    Scope

    • In: ci.yml, a classifier script with tests under scripts/
    • Out: merge queue (separate bead)

    Notes

    Default to the full pipeline on any doubt: unknown paths run everything.

    Acceptance criteria

    • AC-1 e2e Given a PR that changes only .beads, docs, site or plan files, then unit, coverage, e2e, playthrough and build are skipped and e2e-smoke and the other required checks still report success.
    • AC-2 unit Given a list of changed paths, when classified, then src, e2e, tests, package or lockfile, vite and playwright config and workflow changes select the full pipeline.
    • AC-3 e2e Given a skipped required check, then the PR is still mergeable.

    Waits on

    • mw-e41.1 Rebalance e2e: isolate cross-browser audio and shard chromium by duration done
  • mw-e41.11Deploy every main build to a playable preview URLblockedP1task

    Description

    Why

    The vertical slice is complete (PR 210) but the game itself is deployed nowhere; publish-site only ships the landing page and backlog.

    What

    Reuse the build artifact, sync it to S3 under /play/next/, invalidate that prefix, and run a Playwright smoke against the live URL.

    Scope

    • In: new workflow, infra/site.yml, a deployed-URL smoke spec
    • Out: tagged release (see the release bead); custom domain changes

    Notes

    Reuse the existing OIDC role pattern from publish-site and its pull_request_target safety rules.

    Acceptance criteria

    • AC-1 e2e Given a merge to main, then the dist artifact is published under a /play/next/ prefix behind CloudFront with immutable hashed assets cached and index.html short-cached.
    • AC-2 e2e Given the deployed URL, then a smoke spec boots the title screen with no console errors.
    • AC-3 unit Given infra/site.yml, then the OIDC role can write only that prefix.

    Waits on

    • mw-e41.3 Build dist once and reuse it in e2e, playthrough and perf jobs open
  • mw-e41.12Release gate: run the full nightly suite against a release candidateopenP1task

    Description

    Why

    Moving gates off PRs only works if something still enforces them before a release goes out.

    What

    A reusable workflow shared by the nightly run and the release workflow, so the release gate is the same code that runs nightly.

    Scope

    • In: .github/workflows, docs/ci-gates.md
    • Out: tagging and publishing (see the release bead)

    Notes

    Owner-run reference-machine perf measurements (mw-e32) stay a manual release checklist item.

    Acceptance criteria

    • AC-1 e2e Given workflow_dispatch with a ref, then it runs the release tier (cross-browser audio, bench, perf budgets, playthrough, e2e) and reports one pass or fail.
    • AC-2 unit Given docs/ci-gates.md, then the release gate lists exactly the nightly and release tier jobs.
    • AC-3 e2e Given a failing gate, then the release workflow does not create a tag.

    Waits on

    • mw-e41.5 Define per-PR, nightly and release gates and move the slow ones off PRs done
  • mw-e41.13Cut tagged releases with a dist zip and notes from the changelogblockedP1task

    Description

    Why

    There is no version, tag or release notes (package.json is 0.0.0); the changelog check already forces a note per user-facing PR, so the notes exist and only need compiling.

    What

    A release workflow and script: verify the gate, roll the changelog, tag, create the GitHub release with the dist zip, and publish to versioned and latest prefixes.

    Scope

    • In: release workflow, changelog roll script with tests, docs/releasing.md
    • Out: auto-publishing on every merge (previews cover that)

    Notes

    Date-based versions fit a game with no API consumers; revisit if semver is wanted.

    Acceptance criteria

    • AC-1 e2e Given workflow_dispatch on main with the release gate green, then a date-based tag vYYYY.MM.DD.N and a GitHub release are created.
    • AC-2 unit Given CHANGELOG.md, when releasing, then the Unreleased section becomes the dated version section and a fresh Unreleased section remains.
    • AC-3 e2e Given the release, then it attaches the dist zip and publishes the build to /play/<tag>/ and /play/latest/.

    Waits on

    • mw-e41.11 Deploy every main build to a playable preview URL open
    • mw-e41.12 Release gate: run the full nightly suite against a release candidate open
  • mw-e41.14Build ci-status: a concise CI summary for agentsopenP1task

    Description

    Why

    Agents currently dig through gh run view --log with grep to learn why CI failed; it is slow, lossy and floods context.

    What

    A pnpm ci:status CLI (PR or run id) that summarizes status, behind-main state, failing tests, flakes and artifact links, with fixtures-based tests of the parsers.

    Scope

    • In: scripts/ci-status*.ts, package.json, CLAUDE.md pointer
    • Out: any CI mutation

    Notes

    Reads Playwright JSON from the flake report artifact when present; falls back to log parsing.

    Acceptance criteria

    • AC-1 unit Given a PR number, when its branch is behind main, then the first line says so.
    • AC-2 unit Given a failed run, then output lists each failing job, step and test title with the first assertion line, and marks flaky versus failed.
    • AC-3 unit Given a green run, then output is one line and never contains raw logs.
  • mw-e41.15Build ship: update, wait, squash merge and clean up in one commandblockedP1task

    Description

    Why

    The manual post-PR checklist (up to date, checks, merge, close beads, delete branch, remove worktree) is repeated about 100 times a week and easy to partly skip.

    What

    A pnpm ship CLI implementing the working agreement: merge once green, never force, stop on anything unexpected.

    Scope

    • In: scripts/ship*.ts with injectable gh and bd runners for tests
    • Out: PR creation (see pr-open)

    Notes

    Honours the owner working agreement of 2026-09-27 (agent merges after CI passes).

    Acceptance criteria

    • AC-1 unit Given a PR behind main, then ship rebases or merges main and stops with a message if CI must re-run.
    • AC-2 unit Given green checks, then ship squash merges with branch deletion and closes every Closes bead with the PR number.
    • AC-3 unit Given the merge, then it removes the worktree and local branch and runs git fetch --prune.
    • AC-4 unit Given red checks or a missing Closes line, then ship refuses and prints why.

    Waits on

    • mw-e41.14 Build ci-status: a concise CI summary for agents open
  • mw-e41.6Run only baseline-producing jobs on push to mainopenP2task

    Description

    Why

    With up-to-date branches required, the squash commit's tree equals the tree CI already tested, so re-running everything on push finds nothing new (3 of 29 recent main runs failed on flakes nobody could act on).

    What

    Limit push-to-main CI to coverage-gate and the perf baseline upload. Revisit if a merge queue lands, where the queue run replaces both.

    Scope

    • In: ci.yml triggers and job conditions
    • Out: nightly gates

    Notes

    Coverage ratchet and perf compare download artifacts from the latest successful main push run, so those runs must remain.

    Acceptance criteria

    • AC-1 e2e Given a squash merge to main, then only the jobs that upload the coverage and perf baselines run.
    • AC-2 e2e Given the next PR, then coverage-ratchet still finds a baseline from main.

    Waits on

    • mw-e41.5 Define per-PR, nightly and release gates and move the slow ones off PRs done
  • mw-e41.7Cut e2e retries to 1 and emit a flake report on every runopenP2task

    Description

    Why

    retries: 2 triples the cost of every failing test (a 30 s timeout costs 90 s) and hides flakes: a green run with '3 flaky' in a log is invisible.

    What

    Reduce retries, add the Playwright JSON reporter, parse it into the job summary and upload it with 14-day retention.

    Scope

    • In: playwright.config.ts, ci.yml, a report script with tests
    • Out: nightly aggregation (see the flake aggregator bead)

    Notes

    Pair with mw-e00.33 and the wall-clock assertion bead: fewer retries only works once the known flakes are fixed or moved.

    Acceptance criteria

    • AC-1 e2e Given CI, then Playwright retries is 1.
    • AC-2 e2e Given a run with a flaky test, then the job summary lists it and a JSON report artifact records spec, title, status and duration.
    • AC-3 unit Given Playwright JSON output, when parsed, then flaky, failed and slowest tests are extracted.
  • mw-e41.9Adopt a GitHub merge queue and drop the rebase-and-rerun cycleblockedP2task

    Description

    Why

    Branch protection has strict: true, so each merge forces every open PR to rebase and re-run about 12 minutes of CI. About 100 PRs merge per week.

    What

    Enable the merge queue, add merge_group triggers, and update repo-settings.env, configure-repo.sh and docs/repo-settings.md.

    Scope

    • In: workflows, repo settings scripts and docs
    • Out: changing the squash-only policy

    Notes

    Owner must enable the setting. Once the queue run is the pre-merge verification, the main-push bead can shrink further.

    Acceptance criteria

    • AC-1 e2e Given the CI and security workflows, then they trigger on merge_group and required checks report there.
    • AC-2 unit Given scripts/repo-settings.env and verify-repo-settings.sh, then the merge queue is expected and verified.
    • AC-3 e2e Given two PRs queued together, then neither needs a manual rebase to merge.

    Waits on

    • mw-e41.4 Skip heavy jobs for docs, beads, site and script-only PRs open
  • mw-e41.10Export beads from a post-merge bot instead of in the next PRopenP2task

    Description

    Why

    66 of the last 100 merged PRs touched .beads/issues.jsonl, a likely conflict hotspot that also forces extra export commits and rebases.

    What

    A workflow on push to main that runs bd export and commits the result (or a guarded alternative if branch protection forbids bot pushes), and update the workflow docs in CLAUDE.md.

    Scope

    • In: workflow, CLAUDE.md and AGENTS.md workflow step
    • Out: changing the Dolt sync model

    Notes

    Verify the conflict claim first by counting rebase conflicts in recent PRs; the bot needs a token that can bypass the required checks or a merge-queue-compatible path.

    Acceptance criteria

    • AC-1 e2e Given a merge to main that closes beads, then .beads/issues.jsonl on main is regenerated without a human PR.
    • AC-2 unit Given a feature PR, then it does not need to touch .beads/issues.jsonl.
    • AC-3 e2e Given the publish-site workflow, then it runs after the export lands.
  • mw-e41.16Build wt-new: claim a bead and create a ready worktreeopenP2task

    Description

    Why

    Every task starts with the same fetch, worktree, install and claim steps; a script makes the required worktree workflow one command.

    What

    A pnpm wt:new CLI with injectable runners and tests.

    Scope

    • In: scripts/wt-new*.ts
    • Out: cleanup (ship handles it)

    Notes

    Node 24 is required (engine-strict); the script should select it or fail with the PATH hint.

    Acceptance criteria

    • AC-1 unit Given a bead id, then wt-new claims it, fetches origin/main and creates .claude/worktrees/<branch> from it.
    • AC-2 unit Given the new worktree, then dependencies are installed with the shared store and the bead's acceptance criteria are printed.
    • AC-3 unit Given an existing worktree for the bead, then it reports the path instead of creating another.
  • mw-e41.17Build pr-open: generate the PR body with Closes lines and changelog noteopenP2task

    Description

    Why

    pr-lint and changelog failures are the most common avoidable PR check failures.

    What

    A pnpm pr:open CLI that rebases on main, builds the body from commits and bead titles, and creates the PR with the required attribution.

    Scope

    • In: scripts/pr-open*.ts
    • Out: merging (ship)

    Notes

    Reuse scripts/pr-body-lint.ts and changelog-check.ts so rules are not duplicated.

    Acceptance criteria

    • AC-1 unit Given commits referencing bead ids, then the body has one Closes line per bead.
    • AC-2 unit Given the generated body, then scripts/pr-body-lint.ts accepts it.
    • AC-3 unit Given user-facing path changes without a changelog entry, then pr-open warns before creating the PR.
  • mw-e41.18Add pnpm check: lint, format, typecheck, exclusions and affected tests in parallelopenP2task

    Description

    Why

    lint (90 s) and coverage:exclusions failures are cheap to catch locally but cost a CI cycle.

    What

    A parallel local gate matching CI's fast checks.

    Scope

    • In: scripts/check*.ts, package.json, pre-push hook wiring
    • Out: e2e

    Notes

    Keep it under about 60 s on the reference machine.

    Acceptance criteria

    • AC-1 unit Given a change, then pnpm check runs lint, format:check, typecheck, coverage:exclusions and vitest --changed in parallel and prints one summary.
    • AC-2 unit Given a failure, then the exit code is non-zero and the failing command output is shown once.
    • AC-3 e2e Given the pre-push hook, then it can call pnpm check.
  • mw-e41.20Nightly flake aggregator that files beads for repeat offendersblockedP2task

    Description

    Why

    Without aggregation, flakes only cost time; nothing turns them into work.

    What

    A step in the nightly workflow that downloads recent flake report artifacts, aggregates them, and files or updates beads.

    Scope

    • In: nightly workflow step, scripts/flake-aggregate*.ts
    • Out: auto-quarantine of tests

    Notes

    Needs bead creation from CI; decide between a committed report file and a GitHub issue per test.

    Acceptance criteria

    • AC-1 unit Given 14 days of flake reports, then tests flaking in at least 3 runs are listed with counts.
    • AC-2 e2e Given a new repeat offender, then one bead is filed or updated and none are duplicated.
    • AC-3 unit Given a fixed test with no flakes for 14 days, then it drops off the list.

    Waits on

    • mw-e41.5 Define per-PR, nightly and release gates and move the slow ones off PRs done
    • mw-e41.7 Cut e2e retries to 1 and emit a flake report on every run open
  • mw-e41.3Build dist once and reuse it in e2e, playthrough and perf jobsopenP3task

    Description

    Why

    Five jobs (three e2e shards, playthrough, perf) each run vite build through the Playwright webServer, and the build job builds a sixth time.

    What

    Upload dist from the build job, download it in the e2e jobs, and make the webServer command skip the build when a dist directory is supplied.

    Scope

    • In: ci.yml, playwright.config.ts, playwright.perf.config.ts
    • Out: changing build output or bundle budgets

    Notes

    Saves roughly 20-30 s per job. Keep the local default (build then preview) so pnpm e2e works unchanged.

    Acceptance criteria

    • AC-1 e2e Given a PR run, then vite build runs once in the build job and its dist artifact is downloaded by every job that serves the app.
    • AC-2 e2e Given the Playwright config in CI, then webServer runs vite preview only and no job other than build runs vite build.
    • AC-3 e2e Given a local run, then pnpm e2e still builds and serves the app without extra steps.
  • mw-e41.19Select affected e2e specs from changed source filesopenP3task

    Description

    Why

    Local and agent runs of 44 e2e specs take minutes; most changes touch one area.

    What

    A maintained path-to-spec map and a pnpm e2e:affected command, usable locally and by path-aware CI.

    Scope

    • In: scripts/e2e-affected*.ts, e2e/affected-map.json
    • Out: skipping specs in required CI

    Notes

    Fail safe: unmapped paths run everything.

    Acceptance criteria

    • AC-1 unit Given changed files under src/ui, then only specs mapped to that area plus smoke are selected.
    • AC-2 unit Given a change outside the map, then all specs are selected.
    • AC-3 unit Given the map, then every spec file is covered by at least one area.

    Waits on

    • mw-e41.1 Rebalance e2e: isolate cross-browser audio and shard chromium by duration done
  • mw-e41.21Build flake-check: run a spec repeatedly under CI-like constraintsblockedP3task

    Description

    Why

    Agents need to tell a flake from a regression before pushing.

    What

    A pnpm flake:check CLI wrapping Playwright and Vitest repeat runs with CI-equivalent settings.

    Scope

    • In: scripts/flake-check*.ts
    • Out: fixing flakes

    Notes

    Complements mw-e00.33 (CPU-stress reproduction for unit tests).

    Acceptance criteria

    • AC-1 unit Given a spec path and N, then it runs N times with CI retries and worker settings and reports pass rate and failures.
    • AC-2 unit Given a non-zero failure rate, then the exit code is non-zero.

    Waits on

    • mw-e41.7 Cut e2e retries to 1 and emit a flake report on every run open
E42Open Valley & Town EconomyA grand-feeling valley outside the start: a cliff overlook above Briar Glen and the mountain (backdrop art, tight walkable paths), a bridge over the Wend to enter the village, a river that sinks armoured players, shops (clothes, staves, swords, armor, helmets, scrolls, potions, ingredients, breakable jars, arrows, bows, food, knives, gloves, inn bed), and enough varied skeletons whose gold and gear drops fund real purchases.33/42 done · 79%

M3 MVP content 9

  • mw-ju8.15Add a shop.deal sim command so buys, sells and buybacks replay deterministicallyopenP2M3task

    Description

    Why

    The shop UI (mw-e20.10) calls Shops.buy/sell/buyBack directly while the sim is paused, so deals are not in the replay log and pack events lag until the next sim step.

    What

    A shop.deal command (merchant id, op, line/instance id, count) handled in the sim step, so deals are recorded, replayed and emit events on the same tick. UI submits the command instead of calling Shops directly.

    Acceptance

    • AC-1 integration Given a recorded buy then sell, when replayed, then crowns, pack and merchant state hash match the live run.
    • AC-2 unit Given the command, when stepped, then shop.bought fires on that tick.
    area:contentarea:simepic:e42milestone:m3
  • mw-ju8.27Run 50 area transitions in the memory-leak harness (mw-e01.11 AC-5)openP2M3task

    Description

    mw-e01.11 AC-5: 50 back-and-forth area transitions, heap growth after GC <= 5%. The leak harness (mw-e32.12) does not exist yet. Until then src/game/transit/transit.integration.test.ts has an in-process stand-in (50 round trips, carried state does not grow). Transitions reload the page, so the harness should reload-cycle valley-01 <-> valley-02 via ?scene= and the tp console gate crossing.

    area:contentepic:e42milestone:m3
  • mw-ju8.30Walk on ice and slide: freeze water under a swimmer, ice sliding, melt drop (mw-e02.14 AC-3/4/5)openP2M3task

    Description

    mw-e02.14 shipped wading, swimming, sinking, breath, drowning and wetness (src/sim/character/water.ts). Three of its acceptance criteria need the e03 freeze/melt simulation, which does not exist yet (no frozen-water state: only the waterSurface/frozen/friction properties; mw-e03.7 and mw-e03.6 are open), so they are left. AC-3 unit Given a water volume transitions to frozen while the player swims on the surface, when resolved, then the player is placed on top of the ice rather than embedded in it. The water hook (waterTraversal) reads static scene regions (waterVolumes); it needs to read the live water-surface entity/volume from e03.6 (a frozen surface becomes a walkable collider, the volume's surface drops out) and lift a swimmer to the ice top. AC-4 unit Given a frozen surface (or friction < 0.2), when the player stops input at run speed, then they slide >= 2.0 m (vs <= 0.5 m on stone). The controller (src/sim/character/controller.ts locomotion step 2) uses a fixed accelTime/decelTime; it needs the ground's friction property (via the ground collider's owner, as src/sim/climb/surfaces.ts ownerOfCollider does) to scale accel/decel. This part is not blocked by e03.7: ice material already has friction 0.05. AC-5 unit Given the player stands on ice that melts, when the tick runs, then the player drops into the water volume and state becomes wading/swimming. Needs the melt transition from e03.7 restoring the water volume so waterTraversal picks the character up on the next tick.

    Waits on

    • mw-e03.6 Simulate water volumes, splashes, wetness and drying done
    • mw-e03.7 Freeze water and wet objects into ice and melt them with heat done
    area:contentarea:simepic:e42milestone:m3
  • mw-ju8.32Climb out of the water onto banks, and a quick drop-armor action (mw-e02.14 follow-ups)openP2M3task

    Description

    mw-e02.14 lets a swimmer or sinker leave the water only where the bottom comes up to wading depth (valley-03 got a ramp up each bank for this). Needed: (1) a swimmer next to a bank edge within reach of the ledge hook mantles out of the water (the ledge hook does not run while the water hook has the character: mode 'swim' is exclusive), with a stamina cost; (2) a quick 'drop armor' action that unequips body armor and shield in one press so a sinking character can shed the load (the load class is already read every tick, so unequipping floats it up: it works today through the inventory screen); (3) price drowning in the damage model (e04): the placeholder is 10 blunt per second tagged environment+drowning, and armor currently absorbs it. AC-1 unit Given a swimmer at the surface beside a 1.5 m bank, when it presses jump toward it, then it mantles onto the bank. AC-2 unit Given a sinking character, when drop armor is pressed, then its armor and shield are unequipped and it rises to the surface.

    area:contentarea:simepic:e42milestone:m3
  • mw-ju8.39Playtest: a first-time player finds the sorcery teacher under the bridge at night (mw-ju8.14 AC-3)openP2M3task

    Description

    mw-ju8.14 AC-3 manual: given a first-time player exploring at night, when they look around Briar Glen, then Idris Quillon is findable without a guide. Route: lane riverbank-path gap past the Bridge Watch post (lit alley) -> under-the-bridge; hinted by Dot/Mirela rumours 19-20 (story bible 6.2; no dialogue system yet, so rumours are not yet playable). Check: is the gap and lantern noticeable; does the player think to go at dusk; do rumours need to ship first. Teacher present 18:00-05:00 only (time set 1 22:00 in the debug console).

    area:contentepic:e42milestone:m3needs-human
  • mw-ju8.41Playtest: Forgotten archer, shield-bearer and brute attacks read clearlyopenP2M3task

    Description

    Split from the manual ACs of mw-ju8.23, mw-ju8.24 and mw-ju8.25 (bespoke hand-keyed clips, 2026-11-07). In ?scene=skeleton-pen (or wherever each spawns), watch each Forgotten variant attack: archer draw/aim/loose and shove, shield-bearer raise/hold/bash/counter with the shield covering the torso while guarding, brute's slow lift-hold-slam overhead and wide low sweep. Note any pose that reads wrong (sweep axes are the least certain).

    Acceptance criteria

    AC-1 manual the owner can name each attack from its pose at mid range, or files a note per clip that reads wrong.

    area:contentepic:e42milestone:m3needs-human
  • mw-ju8.28True in-place area loading (no page reload per crossing)openP3M3task

    Description

    Area transitions (mw-e01.11, #242) reload the page per crossing because main.ts builds exactly one scene per boot (~650 lines of per-scene setup). It works and guarantees nothing leaks, but is not seamless. Refactor main.ts scene setup into load/unload so a crossing swaps the scene in place, keeping the carry/arrival code. AC-1 integration Given a crossing, then no page reload occurs and the carry/arrival state is identical. AC-2 perf reference-mode area-transition budget improves.

    area:contentarea:gameepic:e42milestone:m3
  • mw-ju8.31Swim and wade animation clips, underwater camera tint and muffled audio (mw-e02.14 placeholders)openP3M3task

    Description

    mw-e02.14 reuses the nearest clips: wading plays the run clip at 60% speed, swimming and sinking publish the locomotion state 'swim', which the grey-box humanoid graph (src/content/data/anim-graph/greybox-humanoid.json) does not map, so the body keeps its previous pose. Needed: a swim (float/stroke) clip and a dive clip, a wade clip with legs through water, and a sinking pose, wired to the 'swim' state (and a dive weight from SwimTraversal.diving). Also: an underwater camera tint or fog and low-pass audio while the head is under (CharacterBreath / breath fraction < 1 and depth > headHeight), swimming stroke and underwater footstep sets, and a surface-ripple VFX. AC-1 e2e Given the player swimming in the river, then the animation probe reports a swim state with a clip, not the held previous pose.

    area:artarea:contentepic:e42milestone:m3
  • mw-ju8.33Creature-versus-creature engagement: Bridge Watch guards fight monsters in-sceneopenP3M3task

    Description

    Follow-up to mw-ju8.12: faction hostility (bridge-watch vs unaligned) is data only because AI targets only the player. Add creature targets to perception/awareness so guards engage hostile-faction creatures, give guards a melee attack, and retaliation when attacked.

    area:contentepic:e42milestone:m3
Other work81/171 done · 47%

M1 Grey-box slice 2

  • mw-7kfProps that fall below the scene fall for ever; burning ones trail heat chunks through the voidopenP2M1task

    Description

    Found by mw-e03.52. A physics prop that leaves the room (a crate past the floor edge) falls without limit: only quest-critical objects with a recovery anchor (mw-e17.14) get a kill plane. A burning one holds flame cells all the way down and each leaves about 80 awake element-field chunks, so 24 such crates cost 2,000 chunks and ~25 ms per tick (before mw-e03.52's kernel speed-up, 40-60 ms). Decide a kill plane for ordinary props (despawn or sleep them; a burning one should go out or be destroyed) and add it. This changes sim results, so it needs its own bead and replay re-blessing. Discovered from mw-e03.52.

    area:simepic:e03milestone:m1
  • mw-548Verify Rapier deterministic state hashes match on x86 in CIopenP2M1task

    Description

    Why

    ADR-0001 checks Rapier determinism only across browsers on one Apple Silicon machine. Cross-architecture equality (x86 vs arm64) is untested, and saves and replays depend on it.

    What

    Add a CI job that runs spikes/determinism (node-run) on ubuntu x86_64 and compares the final hash with the committed arm64 hash.

    Scope

    • In: CI job, expected-hash file
    • Out: production physics wiring

    Acceptance criteria

    • AC-1 integration Given the committed 600-step script, when run on an x86_64 CI runner, then the final hash equals the arm64 hash recorded in ADR-0001, or the job fails with both hashes printed.
    area:simepic:e00milestone:m1

M2 Class fantasies 5

  • mw-1jqClimbing is quiet and silhouetted: -10 dB vs walk on walls, contrast rule against lit backdropsopenP2M2task

    Description

    Left out of mw-e10.9 (stamina, difficulty, ropes and falls shipped there). The e10.9 text says climbing is quiet (-10 dB vs walk) but you are silhouetted on walls (contrast rule). Today a climber emits no footstep noise at all (the controller is airborne) and the stealth visibility model has no wall-backdrop term. Add a climbing movement noise (walk level minus 10 dB per metre climbed) and a visibility contrast term for a climber against a lit wall. AC: unit tests pinning the dB and the contrast term.

    area:simepic:e10milestone:m2
  • mw-6z6Apply shock damage and stagger to actors from the shocked eventopenP2M2task

    Description

    mw-e03.8 emits a shocked event (src/sim/electricity/rules.ts: entity, intensity = held charge, hops, origin) every tick an entity holds shockCharge or more, liquid layers excepted, and names no actor kind. The damage model should consume it for creatures (damage scaled by intensity and tick length, stagger), and ignore inanimate entities. Damage numbers were out of scope for mw-e03.8.

    area:simepic:e04milestone:m2size:s
  • mw-dzcSpawn charge receivers from scene data (chargeReceiver on a scene spawn)openP2M2task

    Description

    mw-e03.8 added makeChargeReceiver and ChargeReceiverComponent (src/sim/mechanisms/charge-receivers.ts) but scenes can only spawn light receivers (scene schema lightReceiver, src/sim/mechanisms/scene.ts). Add a chargeReceiver spawn field (threshold, mode) mirroring lightReceiver, call syncChargeReceiverNodes at scene start, regenerate schemas/docs. AC: a scene spawn with chargeReceiver and a conductive material becomes a receiver that drives its bound lever node when charged.

    area:simepic:e03milestone:m2size:s
  • mw-w4pTeach damaged spells that misfire from damaged booksblockedP2M2feature

    Description

    Why

    docs/design/books.md and the story bible (3.3) say a damaged book (missing pages) teaches a damaged spell that misfires. mw-e07.2's study runtime ignores book.condition and teaches the normal spell.

    What

    Carry a damaged flag from a damaged book into the learned spell (per-spell known state), have the miscast system (mw-e06.13) misfire it, and let restoring a book or finding the missing pages repair it. Hook: StudyRules completion (src/sim/magic/study.ts #complete) and BookStudyDef.

    Waits on

    • mw-e06.13 Resolve botched casts into data-driven miscast outcomes open
    • mw-e07.3 Model comprehension so hard books teach unstable spells first open
    area:simclass:sorcererepic:e07milestone:m2
  • mw-ikhGive the testbed room lever a live switch state and convert testbed-room-lever to a live goalopenP3M2task

    Description

    From mw-e15.2/e15.3. The example puzzle testbed-room-lever (src/content/data/puzzle/testbed-room-lever.json) still reads the stand-in fact testbed.room-lever.thrown because the testbed's room-lever prop has no switch or signal state a goal can read. Giving it one (a switch spawn field and a signal graph, or a lever property) makes the testbed a mechanisms scene, which moves the testbed replay hashes and the testbed e2e, and the rule is no new props in the shared testbed, so it needs its own decision: either give the lever a switch and rebless, or move the example puzzle to the mechanism-room scene (which already has north-lever with a switch state) and delete the stand-in fact.

    Acceptance criteria

    AC-1 unit The example puzzle's goal reads the lever's live state (signal or property) instead of the stand-in fact, and pulling, Mage Hand and a crate impact each solve it. AC-2 integration The testbed replay hashes are re-recorded once, with the reason in the PR, or the puzzle lives on a scene that needs no re-record.

    area:simepic:e15milestone:m2

M3 MVP content 12

  • mw-sbaWire the Act I main-quest triggers: horned shape on night one, follow Tansy to the mine gate, friend-note foundin progressP2M3task

    Description

    Split from mw-e39.38. Quest objectives with no built source yet: event horned-shape-seen (night-one Tansy/horned shape beat in Briar Glen: needs a night-time scripted encounter emitting it), enterArea mine-gate (follow-tansy; the mine road and gate exterior are mw-e25.23/mw-e25.10, add a player-filtered volume node mine-gate to the mine gate scene), event friend-note-found (the friend-below notes are mw-e39.42: each should emit friend-note-found on first read), enterArea briar-glen for return-to-briar-glen (needs a mine-road/Market Green return volume that is not visited before the morning-after stage, since early visits are remembered). Add the volumes as signal graphs like src/content/data/signal-graph/briar-glen-arrival.json.

    area:narrativeepic:e39milestone:m3
  • mw-0ml8Replace the riverbank-wharf-link stopgap with the real towpath once Kestrel Lock existsopenP2M3task

    Description

    mw-e40.26 linked under-the-bridge straight to the Wendmouth Stone Wharf (edge riverbank-wharf-link, transitions under-the-bridge/towpath-down and wendmouth-harbour/towpath-gate) because Briar Glen Quay, the Millweir and Kestrel Lock have no scenes. When mw-e25.24 and mw-e25.14 build them, move the wharf transition to Kestrel Lock (edge towpath-lock-wharf, bead mw-e40.26 planned edge), remove the stopgap edge and the east towpath strip in under-the-bridge, and move Old Reed to the lock if the owner agrees. AC-1 integration the towpath from Kestrel Lock loads the Stone Wharf; AC-2 content riverbank-wharf-link is gone and tests updated.

    area:contentepic:e40milestone:m3
  • mw-4l3zBarge travel from Kestrel Lock to the Stone Wharf (barge-lock-wharf)openP2M3task

    Description

    The barge-lock-wharf edge (mornings only, travel: barge) stays planned: it needs mw-e25.15's travel service and the Kestrel Lock scene. The harbour's barge-berth arrival is ready; add the arrive-from-<scene> spawn and transition when the service exists.

    area:contentepic:e40milestone:m3
  • mw-5wgEmit main-quest Knot and Cradle events and facts: knot-outer-ring, ossuary-galleries, horns-hall, the-fold, the-cradle, bell-tongue-destroyed, recast-tongue-delivered, bell.rungopenP2M3task

    Description

    Split from mw-e39.38. Area volumes (enterArea knot-outer-ring, ossuary-galleries, horns-hall, the-fold, the-cradle) belong to the E26 Knot scenes, which are not built: add a player-filtered volume node with the area id as its node id in each scene. The belfry area volume is done (signal-graph belfry-deck). bell-tongue-destroyed (destroying the tongue, mw-e39.43 / Cradle), recast-tongue-delivered (collecting the recast from Oswin Brand: a deliverItem or dialogue emit), and the fact bell.rung (belfry bell scene, mw-e26.8) have no source yet. Wendmouth: crate.intercepted is the crate heist (mw-e39.21), tern.sailed and epilogue.finished are mw-e39.39 / mw-e39.40; bounty.outcome and horn.spoken-for need Vane/Hollis/Hale and town testimony dialogue effects (mw-e39.41 for Horn).

    area:narrativeepic:e39milestone:m3
  • mw-6jvConsume the hub dialogue hooks: rumour trades, fence, jail sentence, well fallopenP2M3task

    Description

    mw-e39.5 (dot-sleeping-ox, mirela-stacks, hale-watch) emit hook events for systems that do not exist yet. Needed: rumor.told {rumor: N, source} (rumours 6, 8, 19 from Dot; 20 from Mirela) should become revealRumor effects once the rumour type and ids exist (mw-e22.11, e39-rumor-set), with Dot's drink/coin/swap trading and her rumour list; dot.fence-opened / dot.fence-trade (fence prices, shop rules); mirela.maps-offered, mirela.hours-offered, mirela.shelf-opened, mirela.thief-job-offered (bookshop stock, lending, the retrieval quest); hale.list-shared / hale.map-shared (a list item and map reveal); hale.scout-asked, hale.knight-asked, hale.boots-asked (side quest starts, with The Captain's Boots mw-e39.10 which also writes hale.sleepwalking.revealed, hale.secret.kept and hale.secret.exposed); jail.sentence {days} and hale.jailed written by the theft system (mw-e22.1, mw-e24.8); well.player-fell written when the player falls down the Glen Well; hale.testified for Act III. Facts are in src/content/data/fact/hub-dialogue.json.

    area:narrativeepic:e39milestone:m3
  • mw-164Deepworks blockout polish: ceilings, mine lamps, cage car visual and cage travelopenP2M3task

    Description

    Follow-up to mw-e26.2. The Deepworks greybox has no ceilings or lamps, and the cage lift is a stair run behind cage-gate (the door opens when the winch lever or shot pulley calls the cage down). Add: roofing/ceilings for the galleries, mine lamps and a dark-mine lighting pass, a visible cage car that travels top to bottom with the door, and a moving-platform ride in place of the stair run if the platform kit gains one. Acceptance: AC-1 content every gallery has a ceiling and light sources; AC-2 integration the cage car moves between cage-car-top and cage-car-bottom when called.

    area:contentepic:e26milestone:m3
  • mw-cw6Flaky CI: coverage-gate tests time out on slow runners (replay-content-hash at 5 s, scaffold AC-4 earlier)openP2M3bug

    Description

    coverage-gate runs the full suite under v8 coverage on a shared runner. tests/integration/replay-content-hash.test.ts AC-1 timed out at the default 5000 ms on PR #231 (a gear-catalogue PR that does not touch replay); scaffold AC-4 hit its 60 s limit on #224 and #226 (fixed in #227 by raising to 180 s). Fix: set a larger testTimeout when running under coverage (vitest config, e.g. 30 s for the coverage run), or give slow integration tests explicit timeouts; keep local runs strict. AC-1 integration Given a loaded runner, when coverage-gate runs, then no test fails on timeout alone.

    area:toolsmilestone:m3
  • mw-dm3Wire Mortimer's day-long ban and the ginger-biscuits item to Mirela's dialogueopenP2M3task

    Description

    mw-e39.5 (mirela-stacks) models Mortimer's ban as the fact mirela.banned and reads mirela.banned-days and mirela.biscuits-brought. Nothing writes them yet. Needed: (1) when Mortimer catches a shoplifter in the Lamplit Stacks, set mirela.banned true; (2) the game clock increments mirela.banned-days at each midnight while banned (the dialogue lifts the ban at >= 1 and resets it); (3) add the ginger-biscuits item (bible 5.1, 9) whose pickup/hold sets mirela.biscuits-brought (the dialogue clears it when given), or switch the dialogue option to hasItem; (4) restricted shelf stock reads mirela.restricted-access. Nine Sleeps must stay unsellable. Facts live in src/content/data/fact/hub-dialogue.json.

    area:contentepic:e39milestone:m3
  • mw-f25Emit the six deepworks-entered-<route> events from the mine entrancesopenP2M3task

    Description

    Split from mw-e39.38. The Getting in stage waits on events deepworks-entered-front-gate, -side-boarding, -winch-cage, -inner-bar, -supply-tunnel, -weeping-adit. None of the Deepworks levels exist (E26); the built entrances are only the supply-tunnel door in moorings-watch (sealed, mw-e25.9) and the Weeping Adit mouth (mw-e25.13). When each entrance is built, add a player-filtered volume past the threshold and emit the matching event (a signal-graph volume plus a receiver; or a level script emit effect), and set deepworks.route.

    area:narrativeepic:e39milestone:m3
  • mw-hl3yWire horned-shape-seen: the night-one Tansy and horned shape beat in Briar GlenopenP2M3task

    Description

    see-the-horned-shape (event horned-shape-seen, stage first-night) has no source. Needs a night-time scripted encounter in Briar Glen (Tansy walks up the street humming, a horned shape leads her to the mine gate) that emits horned-shape-seen via an emit effect or dialogue. No scripted-encounter mechanism exists yet for a timed scene beat; the stage falls through on time.day>=2 meanwhile.

    area:narrativeepic:e39milestone:m3
  • mw-ows1Gate the return-to-briar-glen area so early visits are not creditedopenP2M3task

    Description

    return-to-briar-glen (enterArea briar-glen, stage morning-after) must complete only for a return after the Vespers, but QuestRuntime.observe remembers enterArea visits to an inactive objective, and any volume named briar-glen is entered constantly. Findings: a signal graph cannot read facts or quest stage (no fact-reading node), a scene signals entry has no condition, and a sensor binds a spawn that must exist (spawnIf would break the binding). Options: (a) add a stage/fact gate to volume nodes in src/sim/signals (new node option, sim tests); (b) make the objective a fact objective written by a fact-gated receiver; (c) have the morning-after scene script emit an event. Also decide the volume's scene (lane town-end or Market Green).

    area:narrativeepic:e39milestone:m3
  • mw-t9yFind the ~100 ms frame hitch in valley-02 on the reference machineopenP3M3task

    Description

    Why

    mw-ju8.2's reference runs show valley-02 with exactly one frame of about 100 ms at High (102.4, 103.6, 105.2 ms in three runs) and about 80 ms at Low (83.6, 78.5, 83.0 ms). Valley-01 and valley-03 do not have it (max 4 to 5 ms). It is under the 200 ms long-task budget and does not move p95, but it is a visible stutter, repeatable, and specific to valley-02.

    What

    Find what valley-02 does in that frame (first use of a material, shadow or texture upload, the river region, or a physics or navmesh warm-up) and move it to load or remove it. Start by logging the frame index of the spike (?perf probe samples) and a Chrome performance trace.

    Acceptance criteria

    AC-1 perf Given valley-02 on the reference M1 Pro at High, when 1,800 frames are sampled after the warm-up, then the max frame interval is <= 33 ms (today one frame of ~100 ms).

    area:renderepic:e42milestone:m3

Unscheduled 71

  • mw-nh24Wire arrival volumes into rumour VISIT_TRIGGERS; add Millweir and bay-nine volumesin progressP3task

    Description

    mw-heoa added observed player volumes: briarwood, standing-horn (scene briarwood), mooring-watch (moorings-watch), glen-well, lamplit-stacks (briar-glen-green), weeping-adit (deepworks), breakwater (wendmouth-harbour). Add VISIT_TRIGGERS entries (place-briarwood -> briarwood, place-standing-horn -> standing-horn, place-mooring-watch -> mooring-watch, place-glen-well -> glen-well, place-lamplit-stacks -> lamplit-stacks, place-weeping-adit -> weeping-adit, place-breakwater -> breakwater) once PR 477 merges, with a test that a heard rumour resolves. Also: place-millweir has no scene (millweir-sluice graph is unused) so needs a volume when the Millweir scene exists; place-bay-nine could get its own volume inside bonded-warehouse.

  • mw-77xHANDOFF: thevesperbellopenP0task

    Description

    Lead session: dfb41a21 (main checkout) owns merging and beads export.

    Merged 2026-11-13/14: #448-#476. All beads closed.

    Open parents: mw-e39.38, mw-sba, mw-e40.26, mw-ily9 (needs mw-r5nw), mw-5wg, mw-e24.13 (needs mw-8stk), mw-e23.6 (AC-3 to AC-5 are mw-e23.6.1).

    Merge chain (background waiters, serial):

    • #477 mw-e22.11 rumour system: in the merge queue.
    • #478 mw-heoa arrival volumes: after #477.
    • #479 mw-1myt journal (Part of mw-e23.6): after #478.
    • #339 sword grip: DO NOT merge until the owner approves.

    No workers are running.

    Next once #477 merges:

    • mw-nh24 (wire the new volumes into VISIT_TRIGGERS)
    • mw-wbr7 (wire the rumour book into the journal Rumours tab)

    Both are small; one worker can do them together after #479.

    CI notes:

    • vitest testTimeout is 30 s on CI.
    • coverage-gate needs 100% branches on changed src/game, src/ui and src/tools files.
    • Debug ?scene= boots must not open blocking UI.
    • A scene's first signals entry lights its braziers.

    Owner action:

    • Delete the stale remote branch feat/note-reader.

    Waiting on owner:

    • #339 look
    • mw-ows1 gate
    • mw-hl3y timed encounters
    • Many PR-body content and tuning questions

    Updated: 2026-11-14, session dfb41a21

  • mw-0hwBind liquid volume drains and fills to signals and leversopenP2task

    Description

    mw-e03.6 ships setDrainOpen/setFillOpen on liquid volumes (src/sim/liquids) but no signal receiver, so a lever cannot open a basin drain yet.

    Acceptance criteria

    Given a drain bound to a lever signal, when the lever is pulled, then setDrainOpen runs and the level falls at the drain rate.

    area:simclass:allepic:e03
  • mw-1buFlaky bench recurred: light-field p95 over 0.5 ms on CIopenP2bug

    Description

    mw-64w was closed but the light-field AC-6 benchmark failed again on 2026-10-02 in PR #131's unit job (p95 0.517 ms vs 0.5 ms limit); it passed on rerun. Investigate whether the CI gate needs the same looser-CI/strict-local split used for line-of-sight (owner decision 2026-09-29), or whether the bench has noise that can be reduced. Related: mw-64w.

    Acceptance criteria

    • AC-1 perf Given 20 consecutive CI runs, when the light-field bench runs, then it never fails spuriously, while a real 2x regression still fails it.
  • mw-1iyMake wall-clock e2e budgets and the coverage-scaffold test robust on slow CIopenP2task

    Description

    Recurring CI flakes: title.spec AC-1 (10 s load), slice-saves AC-3 (3 s warm reload), slice-restart AC-3 (3 s, mw-e01.16), scenes AC-1 (5 s) and tests/toolchain/scaffold.test.ts AC-4 (60 s test timeout for a child coverage run). CI renders in software GL on 2-core runners, so wall-clock budgets written for the reference hardware (contract §1) sit at or over their limit; main's own runs hide 1-2 retried tests every time. Decide a policy (e.g. measure ticks/in-page timings with a documented CI factor, keep the real budgets in the perf-budget suite on the reference profile) and apply it; do not simply widen product budgets silently.

  • mw-3spInstall spells and fire in the headless game world and re-record the replaysopenP2task

    Description

    createGameWorld (src/tools/replay/testbed-player-scenario.ts) takes an opt-in magic flag (mw-e06.15); src/main.ts always installs the spell pipeline, mana, the element field and fire rules. Make the headless world match by default, run settleAuthoredFires after load, and re-record the replay fixtures (tests/integration/fixtures/*.replay.json, tests/replays) with the cause explained.

    area:game
  • mw-5ap5Hornfolk inscription fragments and the seal-dispel that open the Cradle's secret routeopenP2task

    Description

    mw-e26.10 AC-2: the secret sorcerer route (hornfolk-door, lock hornfolk-seal, edge horns-hall-cradle-secret) is greyboxed as a sealed door with the existing inscription-knot-carved-faces as the runes beside it. Missing: the Hornfolk inscription fragment items/texts (bible 4.2/7), a dedicated runes text for the door, the sorcerer's dispel (reading with fragments sets world.hornfolk-seal.dispelled and opens the door), and the capability for the edge (spell.mage-hand stands in).

    area:contentepic:e26
  • mw-5v5sPlace the Hollow Sentinels in Mooring's Watch and give the tower a bell cord shot, dispel and sneakopenP2task

    Description

    The Watch Still Stands is dialogue-driven (sentinel-watch, npc-hollow-sentinel, debug conversation room only). Needs: Sentinel creatures placed on the four armour stands (mw-e25.7), an interactable bell cord that an arrow can cut, spell.dispel (mw-e08), stealth detection for the thief's unseen walk, the old-words technique (mw-e04) behind the knight's relief, and a real fight for the smash route. Then bind the quest to those instead of the dialogue options.

  • mw-5v6Wall recoil presentation: stronger sparks and cut the swing animation shortopenP2task

    Description

    mw-e04.15 emits WallRecoil and PR #362 binds a placeholder clang and the deflect sparks. In ?scene=recoil-corridor the sparks read small and faint at the player camera's distance, and the knight's swing animation plays through to its end although the sim has ended the move and locked him for 30 ticks. Make the recoil read: bigger or brighter sparks, a short recoil animation or a stagger pose, maybe a camera nudge.

  • mw-7nsFrozen-solid actors become temporary physics objects (push off a ledge)openP2feature

    Description

    From mw-e03.24 Notes: frozen actors are immobile and brittle (shatter on a hard hit, Died/loot intact) but are not yet physics bodies, so they cannot be pushed or fall. Needs a feet-vs-centre placement conversion for creatures while a body exists and removal on thaw. Also: player frozen can still attack.

  • mw-8stkMeasure Market Green midday frame time with all scheduled townsfolk (mw-e24.13 AC-4)openP2task

    Description

    Ten townsfolk plus Vane, Mirela and Hale are at Market Green at 11:00-15:00. Add a perf scenario at 12:00 and record p95 <= 16.7 ms on the reference machine.

  • mw-47dpKnot outer greybox: lamps, ceilings and the Chapel acoustic volumeopenP2task

    Description

    The knot-outer blockout (mw-e26.9) has no ceilings or lamps (open dark fog above 4.5 m walls, 9 m in the Chapel) and no acoustic/reverb volume for the Chapel of Echoes. Add light-source spawns, ceilings where the camera allows and a sound-echo region for the nave. Beads mw-e26.14 (Chimes) and mw-e38.140 (ambience) build on it.

  • mw-d4nOwner decision: should the sword clang off corridor walls?openP2task

    Description

    mw-e04.15 (PR #362) ships wall recoil for the long reach class only. The bead text says medium and long, but with medium on, the knight's opening attack sword-light-1 (medium, horizontal) recoils in any corridor under 2.7 m wide (clear width, knight centred, facing along it), always on its first active tick, so a creature straight ahead is never hit (its arc starts about 55 degrees off to the right, so the blade is in the wall on tick 1 and the creature is reached on tick 2). That covers the slice's 1.8 m corridors, the testbed corridor and Briar Glen lane.

    Measured (real moves, Rapier colliders, headless):

    • sword-light-1: recoils at every width 1.0 to 2.7 m, never at 2.8 m and wider; with a creature 1.5 m ahead it recoils anyway and the creature is not hit at 1.0 to 2.7 m, and is hit on active tick 1 at 2.8 m and wider.
    • sword-light-2: recoils alone at 1.0 to 1.9 m, not at 2.0 m and wider; with a creature 1.5 m ahead the creature is hit first and nothing recoils.
    • sword-light-3, sword-heavy, charged heavy: vertical, never recoil. Riposte, roll attack, bash, kick: thrusts, never recoil.
    • halberd-sweep (long): recoils at every width up to 3.0 m (the widest tested).
    • Real scenes, mid-corridor facing along it: testbed corridor 1.8 m, slice 1.8 m, Briar Glen lane 1.8 m all recoil; 2.55 m and wider spots do not; doorways of 1.2 to 1.4 m do not, because the wall ends within 0.5 m of the blade.

    Options:

    1. Keep medium off (current data): the sword never clangs, only long weapons do.
    2. Turn medium on in src/content/data/reach-class/reach-classes.json (one word in wallRecoil.reaches), possibly also excluding the arc's start from the probe (for example only probing the blade once it is inside the forward cone, or skipping tick 1) so a swing at a creature straight ahead still lands in a corridor.

    Decide, then close this.

  • mw-d9nRain fills and puddles open ground; puddles evaporate; partial wetting in shallow liquidopenP2task

    Description

    mw-e03.6 puddles only wet fully submerged entities and never shrink; rain adds no liquid; entities standing in shallow liquid are not wetted.

    Acceptance criteria

    Puddles shrink at a documented rate and wet entities standing in them to the depth submerged; rain raises puddle depth.

    area:simclass:allepic:e03
  • mw-h63Break surface ice under heavy impacts and drop what stands on itopenP2feature

    Description

    Follow-up of mw-e03.7. Surface ice colliders (src/sim/liquids/ice.ts) only melt. The bead text says ice can be broken: a heavy impact or force stimulus on an ice cell should crack it (thickness vs. hit energy), remove the collider and wake what rests on it. Needs per-cell hit routing from physicsImpact / blunt and force stimuli.

    area:simepic:e03
  • mw-h97Per-load roll animation timing and armour absorption and poise tuningopenP2task

    Description

    From PR #356 (mw-e04.16): medium (40 ticks) and heavy (46 ticks) rolls reuse anim-knight-dodge-roll, tuned for 36 ticks, so they may look off. No shipped armour sets flat absorption or poise yet, so those AC-4 rules are unused in play; setting them on the mail hauberk changes the knight's numbers, so tune deliberately.

  • mw-hopjContest play input: gamepad and rebindable keys, plus grip/dice juiceopenP2task

    Description

    mw-opf6 ships keyboard-only play keys (F push or roll, H loaded die, N walk away) read directly from the window, not through the bindings system. Add bindable actions and gamepad buttons, glyph hints, and replay-log capture; sound and animation for the push and the dice.

    area:gameepic:e40
  • mw-ily9Place the Contraband Pages levels and events in the customs houseblockedP2task

    Description

    mw-e39.22 binds objectives to events the level must emit: books-lifted (the player takes the books from the strongroom via the roof hatch route; scene refs customs-roof-hatch, strongroom, confiscated-books), inspector-guise-passed and inspector-guise-blown (a borrowed inspector's coat or Mirror Self at the customs door; Cray knows every inspector). Also place note-impound-ledger on Cray's desk, note-tidefair-board on the Stone Wharf, and the area volumes customs-house and customs-strongroom may need tuning (wendmouth-harbour-areas graph). Relates to mw-e40.3.

    Waits on

    • mw-r5nw Emitters for the Contraband Pages customs events (books-lifted, inspector-guise-passed, inspector-guise-blown) open
  • mw-jrz3Place Duggan Marl, the Rootcellar camp and the crate so Framed in Brass is playable in the worldopenP2task

    Description

    Framed in Brass runs through kettleback-kitchen, duggan-testimony and vane-bounty, which are only reachable in the debug conversation room. Needs the camp, the crate, the goblin fight for the by-force route (goblins turn hostile), and Vane's house scene. The ledger readable in the sealed gallery and Quell's invoice are already placed or fact-based.

  • mw-ma8oTidefair rewards: Tereza's discount and under-counter stock, and a foreign spellbookopenP2task

    Description

    mw-e39.22 sets tereza.tidefair-discount and tereza.under-counter (tidefair.regarded) and tereza.tidefair-rewarded after an honest Tidefair win. The shop stock (E20/E21) must read tereza.tidefair-discount for prices and the under-counter list; the sorcerer's foreign spellbook trade is the existing story trade (tereza.spellbook-traded).

  • mw-mlvRead detectionSpeed and searchDuration difficulty multipliers in stealth/AIopenP2task

    Description

    mw-e31.10 added DifficultyConfig.searchDuration and Story/Veteran preset values, but no system reads detectionSpeed or searchDuration yet (damageTaken, damageDealt, parryWindow, dodgeWindow, fallDamage are wired). Scale awareness accumulation by detectionSpeed (e11 awareness) and the last-known-position Searching duration by searchDuration via scaleDifficulty (e09/e11). Add ACs under mw-e09.17. puzzleHints is read by mw-e15.11.

  • mw-n40fBuild the Market Green to priory road way (green-priory-road)openP2task

    Description

    The east-wall exit of briar-glen-green (exit-priory-road, lock road-not-open) is still a planned stub; the way into the Briarwood is the lane's woodside path. Decide where the green's priory road enters the Briarwood (the priory-road spot at the north end, or the town trail) and build the transitions both ways, then flip the green-priory-road edge to built.

  • mw-nm7Hiding spot follow-ups: solid spots, shared wardrobe and loot key, take bodies back outopenP2task

    Description

    From PR #359 (mw-e03.23): testbed hiding spots have no collider so you can walk through them; a spot and a lootable container cannot be one entity since Interact only fires the primary affordance, so a wardrobe with loot needs a secondary action; a stashed body cannot be taken out of a chest except by breaking it, and it is a kind and weight rather than a specific actor until corpses can be carried (mw-e10.5); a plain hideable entity with no spot prompts 'Nowhere to hide'.

  • mw-pqcLive spawn variant swaps skip drops, slain facts, presence and other startersopenP2task

    Description

    From PR #371 (mw-e27.8): a spawn brought in live by a fact change (SpawnVariants / watchSpawnVariants) does not get installSlainFacts, startCreatureDrops, presence re-sync, or registration with the mechanisms, carry and light starters; a signal graph bound to a gated spawn may misbehave while it is absent. The content check (checkVariants) blocks most gated features, but not all. Bring live swaps to parity with scene load, or extend the check.

    area:simepic:e27
  • mw-qbgwClass beat triggers still missing: night-one, mooring-watch, horn, climaxopenP2task

    Description

    mw-aw1y wired the class-beat narration at triggers that exist: arrival and first-journal (class pick), getting-in (enter-by-supply-tunnel / winch-cage / inner-bar objective complete, thief world.vane-house.roof-entered) and wendmouth (wendmouth.visited). Not wired for lack of a trigger (add one entry to BEAT_TRIGGERS in src/game/class-beats/class-beats.ts plus a class-beat.<beat>.shown fact in src/content/data/fact/class-beats.json each): night-one (mw-e25.2, player first spots Tansy), mooring-watch (mw-e25.7, mw-e25.8, no arrival volume/fact for the tower), horn (mw-e13.14, mw-e26.14, Warden trial), climax (mw-e26.19). Also the knight's getting-in text fires on the supply-tunnel objective (mw-e25.9) and the thief's on the roof fact only; mw-e24.12 rooftops share it. Discovered from mw-aw1y.

    area:narrativeepic:e39
  • mw-qfxValley-02 skeletons fight and kill each otheropenP2bug

    Description

    Found while checking PR #351: running valley-02 for 3 simulated minutes with an idle player, the player dies at tick 727, then skeletons fight each other: skel-valley-02-trail-miner is killed by entity 55's melee and entity 54's arrows (tick 3758), and skel-valley-02-ford-bearer is killed by 54's arrows (tick 6761). Not from environment damage. Not yet checked whether it starts with stray-arrow retaliation, whether it happens while the player is alive, or whether it predates #351 (the damage comes from attacks that #351 does not touch).

  • mw-r5nwEmitters for the Contraband Pages customs events (books-lifted, inspector-guise-passed, inspector-guise-blown)openP2task

    Description

    mw-ily9 found no source for the three events quest-contraband-pages binds. books-lifted: the confiscated books are stand-in facts, with no book items or strongroom container to take them from; needs impounded book items in a container at confiscated-books (strongroom) and a pickup-to-emit hook (item.pickedUp exists in sim). inspector-guise-passed/blown: no disguise system or Mirror Self spell exists; blocked by mw-e10.10 (disguises) and mw-e40.17; then Cray dialogue (or a customs-door volume) emits by whether the disguise holds. Scene refs already present: customs-roof-hatch, strongroom, confiscated-books, customs-strongroom volume.

  • mw-s14Night should affect stealth: the sim light field ignores the game clockopenP2task

    Description

    From mw-ju8.43 (PR #336): the lane's day and night look is render-only. The sim light field keeps the scene's static ambient and moon level, so guards see the player the same at noon and at night even though the screen is much darker. Decide whether time of day should feed the sim light field. If it does, stealth becomes clock-dependent and golden recordings need re-recording, or the recordings must pin the clock. AC-1 unit Given a scene with a day and night look, when the clock moves from 12:00 to 22:00, then the light level the stealth system reads at an unlit point falls by the look's ratio. AC-2 integration Same seed and clock give the same result, so replays stay deterministic. AC-3 manual Owner confirms sneaking at night feels different.

    area:simepic:e42
  • mw-t4sKnight has no distinct block pose: the shield does not raise on blockopenP2bug

    Description

    Found while checking mw-e8n (PR #216): the block animation shows no guard pose, the shield stays at the side. Animation clip data (not skin weights). Check the block clip / anim graph for the knight and give it a raised-shield pose; verify with in-game screenshots.

    area:artarea:render
  • mw-tqwShelter and occlusion for rain zonesopenP2task

    Description

    mw-e03.6 rain zones wet everything inside their box; roofs, awnings and overhangs should shield what is under them.

    Acceptance criteria

    Given an entity under a roof inside a rain zone, when it rains, then its wetness does not rise.

    area:simclass:allepic:e03
  • mw-tscfPlace the sleepwalking Hale: night route, Bell Line stones, mine-gate walk-in, bedpost and door bell (The Captain's Boots)openP2task

    Description

    The Captain's Boots narrates the night walk, the fetch from the mine gate, the tied bed and the door bell in hale-watch. Needs Hale moving at night (the Watch House door to the Bell Line stones along the fern path), a placed Hale at the barred mine gate while hale.walked-in holds (and absent from the Watch House), the Briarwood fern path as a real route (route.briarwood.revealed unlocking the priory shortcut), and the hand-bell and rope as placed things. Also an optional readable Vane-gains-authority effect when hale.secret.exposed.

  • mw-u2kWet or splashed liquid layers: water on oil layers and liquid layer fuel scalingopenP2task

    Description

    mw-e03.6 layer entities are ordinary objects: a water stimulus raising wetness on an oil layer puts it out, and an oil layer burns for its preset fuel regardless of depth.

    Acceptance criteria

    Oil fuel scales with layer depth; rain on an oil slick does not soak the layer entity.

    area:simclass:allepic:e03
  • mw-v645Place Snig, the Glen Well tunnel route and Mortimer so The Bookshop Burglar's trail is playableopenP2task

    Description

    The trail ends at the Glen Well (readable note) and Snig is met in snig-tunnels (caught-1), but his tunnels, the Rootcellar camp and the Stacks interior (Mortimer, the transom, the ink pot) are not placed, so the burglar quest binds to dialogue nodes and facts. Place Snig and Mortimer, build the well descent, and replace the stakeout dialogue stand-in with the real night encounter (a sorcerer's light as a real spell cast at the right moment).

  • mw-wmdvWire the Gull Shoot, Regatta and Pocket Race contests to the tidefair factsblockedP2task

    Description

    mw-e39.22 wrote quest-tidefair against facts the unbuilt contests must write. Each contest must set tidefair.results.<event> (won, lost, thrown, cheated) in its win/lose/disqualified/throwMatch effects, as drowned-gull-arm-wrestling now does, plus tidefair.cheated on a caught cheat: Gull Shoot and Pocket Race (mw-e40.8), Regatta (mw-e40.9). The regatta writes tidefair.regatta.magic-used (a spell cast during the race) and the scene writes tidefair.regatta.cray-present while Cray walks the quay (start, turn, finish): a won, magic-used, cray-present regatta is voided by the quest (fine branch in cray-customs). The pocket race writes tidefair.pocket.cray-lifted or cray-caught for Cray's ribbon. Done when each contest has data, the facts are written, and tests/integration/harbour-side-quests.test.ts has a contest-driven case per event.

    Waits on

    • mw-e40.8 Stage the Tidefair Gull Shoot and the Pocket Race open
    • mw-e40.9 Stage the Tidefair Regatta rowing race on the harbour pool open
  • mw-wmuElement look pass: wet reads only as darker, steam puff not seen on screen, drips show on frozen thingsopenP2task

    Description

    From PR #364 (mw-e29.8) screenshots: a wet crate reads as darker with faint drips, not clearly wet; the burning to wet steam puff was not visible in a screenshot (unit tests prove it is requested; the e2e check only asserts the VFX count did not drop); wet drips still spawn on a crate that is also frozen. Also a doused thing may show both vfx-extinguish-puff and the new steam puff. Tune or suppress lower-precedence effects, and capture the puff on screen. Feeds the owner's AC-5 playtest.

    area:renderepic:e29
  • mw-0ftCI: a cancelled duplicate changelog/pr-lint run blocks merging until rerunopenP3bug

    Description

    PRs #368 and #376: the pull_request 'labeled' event (no-changelog added at or after creation) starts a second changelog and pr-lint run; concurrency cancels one, and the cancelled check run keeps mergeStateStatus BLOCKED although the newest run passed. Rerunning the cancelled run clears it. Fix the workflow concurrency or cancel-in-progress settings so a superseded run does not leave a cancelled required check.

    area:tools
  • mw-3j7Arrow VFX look pass: fire flames read as flat triangles, trails grey, sparks and noise ring faintopenP3task

    Description

    From PR #348 (mw-e29.11) screenshots: fire-arrow flames appear as hard flat triangles and come from the tip rather than along the shaft; ribbon trails look grey at 0.3 alpha instead of the arrow's tint; water burst droplets small at camera distance; deflect sparks hard to tell from the dust puff; noise ring is a faint flat disc edge-on from low cameras. Demo: ?scene=testbed&arrows=demo. Trick arrows are not in play yet (quiver has standard, broadhead, blunt).

  • mw-4vrNoise from rope snaps, ice cracking, electrical and fire crackleopenP3task

    Description

    From PR #352 (mw-e03.25): docs/design/noise-events.md lists these as not emitted. A snapping rope and a shattering ice sheet would be useful stealth signals.

  • mw-4whRegenerate e2e shard weights for new specs (woodside-path, vertical-hall, npc-conversation, briar-glen-town)openP3chore

    Description

    Several long e2e specs were added in Nov 2026 and get the median weight in e2e/shards.json. Regenerate with pnpm e2e:shards:regenerate from recent main e2e-report artifacts so shards stay balanced.

  • mw-5qaLabel discriminated-union variants in generated content docsopenP3task

    Description

    pnpm content:docs flattens discriminated unions (spell delivery, spell effects[], fact) into one field list: rows from different variants share a path (e.g. effects[].impulse is an object for damage and a number for force), and the variant descriptions (.describe on each op/delivery) are dropped. Group rows per variant with its discriminator value and description. Found while shipping mw-e06.1 (PR #88).

    area:contentsize:s
  • mw-5ydRoute any future motion blur, head bob or chromatic aberration through the motion comfort settingsopenP3task

    Description

    mw-e31.7 added reduce-flashing and reduce-screen-effects but the game has no motion blur, head bob or chromatic aberration yet, so no setting exists for them. When one is added, add its off switch (and make reduce-screen-effects cover it) and send any new full-screen flash through FlashLimiter.admit (src/game/vfx/screen-feedback.ts).

  • mw-9jiCamera auto-centre keeps its pacing counter in a closure, not world state; non-default look settings are not recordedopenP3task

    Description

    From PR #379 (mw-e31.6): the look system's auto-centre idle counter lives in a closure inside playerLookSystem, so snapshots, hashes and restores do not include it. Look sensitivity, invert and auto-centre are read live from settings inside the sim and are not part of the recorded input, so a run recorded with non-default settings does not replay identically (replays use content defaults; same as hold/toggle in #377). Move the counter into a component and consider recording the active look settings with a replay.

    area:simepic:e31
  • mw-15u7Decide the Knot-side crypt edge: ossuary-crypt starts in the Ossuary but the passage stub stands off Horn's HallopenP3task

    Description

    mw-e26.10 built a sealed crypt passage stub in knot-inner (crypt-door, lock crypt-sealed). Edge ossuary-crypt (mw-e26.20) is from ossuary-galleries; no transition links knot-inner to bellwater-priory yet.

    area:narrativeepic:e26
  • mw-23rKnight tabard hem flaps beside the thigh at full stride (run/sprint)openP3task

    Description

    Left over after mw-e8n (PR #216): at full stride in run, sprint and walk poses a small ragged tabard hem flap lifts beside the swinging thigh. It reads as cloth, not a stretched ribbon. A cloth-specific weighting rule (or hem vertices pinned to the hip bone) would remove it. Low priority polish until real rigged character models land (mw-e37.21).

    area:artarea:render
  • mw-26tShow conduction on the debug overlay: graph nodes, edges, chargeopenP3task

    Description

    ConductionGraphCache (src/sim/electricity/network.ts) holds the cached graph and a builds counter; expose the nodes, edges and per-node charge in the debug overlay so storms and puddles can be tuned. Not needed for mw-e03.8 ACs.

    area:simepic:e03size:s
  • mw-36lSwap the vertical-hall greybox for the stealth course's vertical hall; add a thief rough-face and rope-tie e2eopenP3task

    Description

    mw-e10.9 AC-5 found no stealth course vertical hall, so it added ?scene=vertical-hall (ladder, rough face, rope hook, 5 m rafter platform). When mw-e10.17 builds the real course, point e2e/vertical-hall.spec.ts at it (or keep the hall as a climbing test room). Also cover in e2e: the thief climbs the rough face with a jump, and tying the rope at rafter-hook gives a rope everyone can climb.

    area:gameclass:thiefepic:e10
  • mw-44nStock or loot the climbing rope and give it its own iconopenP3task

    Description

    mw-e10.9 added the climbing-rope tool (placeholder icon shared with the rope arrow, not stocked: tests/integration/shop-row-content.test.ts lists it NOT_FOR_SALE). Decide where players get it (a shop line, loot tables, the thief kit), re-base its value in the economy pass, make icon-item-climbing-rope-01, and remove it from NOT_FOR_SALE.

    area:contentepic:e10
  • mw-99uvHollis's Bible as a placed pickup and the thief's stair in the bakery upstairsopenP3task

    Description

    mw-3n0f made the letter a real item (letter-anselm-hobb) given by Hollis's dialogue. Still to build: the Bible as a placed container upstairs in the Pell bakery, with a steal path that does not go through the dialogue option.

  • mw-at3Pick a gamepad button for the kick (mw-e04.18 left it unbound)openP3task

    Description

    The kick has a keyboard binding (K) but no pad button: every face, shoulder, stick and d-pad button is taken. Block + attack without a shield still kicks on pad. Decide with the owner (a chord such as LB+B, or a spare button) and bind it in DEFAULT_PAD_BINDINGS and docs/design/controls.md.

    area:gameepic:e04
  • mw-bnzOwnership: player's own items put in an owned chest read as stolen when taken back; refused return add not rolled backopenP3bug

    Description

    From PR #374 (mw-e27.9): an owned container treats everything in it as the owner's, so a player who puts their own item into Ottilie's back-box and takes it out records a theft. Track per-stack ownership instead. Also: a return clears the stolen flag and resolves the theft just before the container add; if the add is refused (9999 unit guard) it is not rolled back.

    area:simepic:e27
  • mw-bxxAt phone width the page title sits behind the vitals barsopenP3bug

    Description

    Seen in screenshots for PRs #378, #384 and #385 at 390 px: the 'The Vesper Bell' heading at top-left overlaps the player health, stamina and mana bars. Present before those changes. Hide or shrink the title during play on narrow screens, or move the bars.

    area:uiepic:e31
  • mw-bzsVoice volume slider does nothing: no voice bus in the audio engineopenP3bug

    Description

    Found during mw-e31.9 (PR #382): audio.voice exists in the settings schema and the options menu, but the engine has no voice bus, so the slider has no effect. Add a voice bus (for barks and dialogue lines) and route voice cues to it, or hide the slider until voice exists.

    area:audioepic:e31
  • mw-f90nMake The Glasswright's Primer a real book item with spell text and a Lamplit Stacks stock rowopenP3task

    Description

    From PR #463: the Primer is bundled inside crate-impounded-books; mirela.illusion-stocked is still a fact. Add a book item with its Illusion spell text (see mw-e39.45 for tome textKeys) and Mirela's stock row once the crate is delivered.

  • mw-fmr7Decide whether the Knot outer half splits into streamed scenes (Outer Ring / Ossuary / Chapel)openP3task

    Description

    mw-e26.9 built the three areas as ONE scene (knot-outer, ~125 x 260 m, ~210 placements) with named in-scene edges; the bead note suggests separate scenes or streamed chunks for memory. If the CI perf job (knot-outer-frame-p95-high) or load budgets say so, split at the Scales gate and the chapel door (each has two ways, so a split needs a transition per way).

  • mw-gf2hSorcerer memory-read on Clatter and the Tansy/Clatter family scene as real actionsopenP3task

    Description

    mw-3n0f follow-up: the sorcerer reading is still a dialogue option with a check; tansy.kin.known is set but no scene reads it yet (E29 / epilogue).

  • mw-jgpcSounding Shaft foot: climb, sounding-shaft-top volume and shaft-door contentopenP3task

    Description

    knot-inner has the shaft foot room (shaft-mouth marker) only. mw-e26.18 builds the climb; add the player volume sounding-shaft-top (mw-5wg) there.

    area:contentepic:e26
  • mw-k8pAdd Tansy's library card and the Pell bakery spare key as itemsopenP3task

    Description

    mw-e39.6 stand-ins: hollis-pell sets facts hollis.library-card-given (sorcerer) and hollis.spare-key-given (thief) and emits hollis.gave-library-card / hollis.gave-spare-key because no item exists for either. Add the two items (and a use for them: Mirela's library fine, the bakery back door) and swap the setFact effects for giveItem.

  • mw-kanInventory selection looks like focus; shop hint line cut off at 720 pxopenP3bug

    Description

    From PR #386 (mw-e31.11) screenshots: the inventory's orange selected item looks much like a focused item, so selection and focus are ambiguous when focus is on the tab strip; give selection its own non-colour mark. The shop's bottom hint line is cut off at 1280x720 (the panel scrolls).

    area:uiepic:e31
  • mw-mlfRope support load ignores what an actor wears and carriesopenP3task

    Description

    Found in mw-e03.13: a support span's load (src/sim/mechanisms/supports.ts, weighSpan) counts the weight property of what rests on it, but unlike pressure plates (weighPlate with gear and the carry ledger) not armour worn or objects carried, so a knight in plate on a rotten rope bridge weighs only his own weight property. Reuse the plates' gear and hold lookups.

    Acceptance criteria

    A bridge's load includes an actor's worn kilograms and the weight of what it carries, as a pressure plate's does.

    area:simepic:e03
  • mw-mmaPlaytest: blocked hits read apart from clean hits by visuals aloneopenP3task

    Description

    mw-e29.4 AC-5 (manual): in the combat sandbox three playtesters each say which hits were blocked versus clean from the visuals alone. Needs people; the effects ship in the mw-e29.4 PR.

    needs-human
  • mw-n37rKnot inner: lamps, ceilings, Horn's Hall statues and the Cradle's carved faces as artopenP3task

    Description

    knot-inner is a lampless, ceilingless blockout with markers for statues, moss beds, carved faces. Dress after mw-e37.258 and decide whether the inner half streams separately from knot-outer.

    area:contentepic:e26
  • mw-ol69Real items and a changing keeper's log for The Watch Still Stands rewardsopenP3task

    Description

    watch.key-held, watch.mirror-held and moorings.safe-base are fact stand-ins. Make Sergeant Mooring's watch-key and the signal mirror inventory items with icons (the mirror feeds the priory light puzzle mw-e25.8), make the tower a rest point and fast route to the mine, and add the closing line in the keeper's log (a text that reads differently once sentinels.relieved).

  • mw-qk2Quest authoring: locate file/line for quest validation issuesopenP3task

    Description

    Mirror dialogue-source.ts/json-locate.ts (PR #407) for quests: validateQuestText(file,text) and describeQuestIssue reporting file, objective/resolution/failure id and line for schema and validateQuestLogic issues. Out of scope of mw-e23.1; needs #407 merged.

    Waits on

    • mw-e23.1 Define quest authoring format with objectives and resolutions done
  • mw-qt6Decide what happens to arrows stuck in the playeropenP3task

    Description

    From PR #360 (mw-e05.7): arrows stuck in the player, from the player's own bow or a trap with no shooter, cannot be taken while alive. On death they do not drop or save; by code reading they follow the player as extra shafts until the 64 arrow cap removes the oldest or the page reloads (not checked visually). Enemy archers fire projectile attacks, which leave no arrow at rest. Decide whether they break, fall off or return to the quiver on death or after some time. Also: arrows in training dummies count as in a living body, so they cannot be taken back until it dies; decide if target practice should allow that.

    area:simepic:e05
  • mw-tmlvJail system: Snig in Hale's cell and the thief's jailbreak after The Bookshop Burglar turn-inopenP3task

    Description

    burglar.outcome turned-in sets burglar.snig-jailed and the cutting turns hostile. Bible 6.1: a thief can bust Snig out later. Needs the jail/cell system and the loose-stone hint in hale-watch; the jailbreak should reverse goblins.standing and open a Snig reunion.

  • mw-vauDecide where Old Reed stands: Kestrel Lock scene or Wendmouth towpath postopenP3task

    Description

    mw-e40.1 placed npc-reed at a toll board by the towpath arrival in wendmouth-harbour (spawn npc-reed, toll-board) because Kestrel Lock has no scene. Bible 5.14 puts him at Kestrel Lock. When the Kestrel Lock scene is built (mw-e25.14), move the spawn there and drop it from the harbour, or keep a toll post at the towpath gate if the owner prefers.

  • mw-vqzvPear tree graft and altar lay-down as world interactions (replace Juniper-dialogue and clatter-dialogue facts)openP3task

    Description

    mw-3n0f placed the pear-tree-bloom and choir-altar-psalter spawns (spawnIf bones.pear-bloomed / bones.psalter-given) but the facts are still written by Juniper's and Clatter's dialogue. Needs a graft/Nature-spell interaction on dead-pear-tree and a lay-psalter interaction on choir-altar (a src/game interact verb handler), plus the bloom VFX (E29).

  • mw-w4zIce slabs as floating physics objects and ice cue events (iceFormed, iceMelted)openP3feature

    Description

    Follow-up of mw-e03.7. Out of scope there: (1) broken or melted ice shed as floating slab physics objects that float (density < water), (2) iceFormed / iceMelted sim events for audio and VFX cue sheets, (3) the renderer drawing the ice surface by cell thickness (liquid.ice component).

    area:simepic:e03
  • mw-w7rCold air freezes liquid surfaces without a stimulus (frost zones, winter levels)openP3feature

    Description

    Follow-up of mw-e03.7. Surface ice cells (liquid.ice) only start from a heat or cold stimulus that reaches the volume. A cold air zone (element field temperature at or below the freeze point) should start ice on its own: scan awake chunks overlapping volumes. Today only the stimulus API starts ice.

    area:simepic:e03
  • mw-wifSurface art for the lane, valleys and slice: gravel/dirt/mud/leaves floors and their sound setsopenP3task

    Description

    mw-1jm tagged only the inn, store and riverbank, where the greybox can now show a surface patch. Remaining: briar-glen-lane (cobbles, riverbank alley dirt path), valley-01/02/03 (gravel, dirt, leaves, mud by the river) and the slice need real floor art (or at least agreed patches) before they are tagged, and an encounter retune check since surface dB changes what skeletons hear. Also sound sets for carpet, wood-hollow and mud (audio falls back to stone today).

  • mw-ye1Noise sources missing for ripples: noise-arrow payload does not emit noiseEmittedopenP3task

    Description

    From PR #349 (mw-e29.12): the noise ripple assist draws one ring per noiseEmitted, but noise arrows do not emit it (mw-e05 payload work), so no ripple. Player footsteps are covered by open mw-e09.5. The ripple was also hard to see in screenshots even at 0.8 opacity: tune by eye once footsteps emit.