Observify

User Tests · milkshake
← all user tests
USER TEST PLAN

milkshake

Derived from: commit 5ff530b (detached HEAD, the play/ worktree of game's dev branch), 2026-08-07, against the native macOS Godot 4.7 build launched via play.sh — the surface the 2026-07-30 workspace inventory names as "the only sanctioned headed surface." ⚠ ~/Projects/milkshake/game/ currently has 32 uncommitted files and is a different, unreviewed tree; game/_build/run.sh boots that tree windowed instead. Do not substitute one launcher for the other while running this plan — F1 makes the distinction explicit.

0/56 checked · 0 pass · 0 fail

Flows

check each step and final check
F1

Launch the sanctioned build, not the dirty one

Proves play.sh boots the correct, committed tree — not the 32-files-dirty game/ tree that a different script also launches.

Persona / precondition: a terminal open at ~/Projects/milkshake; no Godot process currently running; Godot 4.7 installed.

0/3

Run ./play.sh. Expect: a fullscreen window opens with no crash dialog and no immediate return to the shell prompt.

Note that play.sh execs Godot with --path ".../milkshake/play" — the clean worktree pinned at commit 5ff530b — and passes MILKSHAKE_FORCE_COLD_OPEN=1, which is documented in the script's own header comment as consumed "only by the local play route" and never touching your saved progress. Expect: this is the tree you are testing for the rest of this document; if you instead wanted to test the in-progress, uncommitted game/ tree, the separate game/_build/run.sh launches that one windowed and without the forced cold open — do not mix the two mid-session.

Final check: the terminal that launched play.sh shows a normal Godot engine startup banner with no repeated SCRIPT ERROR: lines scrolling past.

F2

The forced cold open: the open Founder visual gate

Proves whether the still-unresolved 2026-07-25 visual rejection — "choppy transitions, desynchronized audio, off-campaign manhua look" — is actually fixed in this v3 preview. This is the literal blocking item on the workspace's Thread 2 (game/_pipeline/CONTROL.yaml directive d81); nobody has rendered a verdict on it since it was rejected.

Persona / precondition: freshly launched via F1; sound on; this judgment has not been rendered before on this exact commit, so treat every "Expect" below as a real question rather than a known-good baseline.

0/5

Let the cutscene run without touching Attack. Expect: a HOLD ATTACK TO SKIP label with a fill meter is visible throughout (this control exists in code) but you do not use it yet.

Judge the picture and sound together, start to finish. Expect (to confirm — this is the open question, not a settled fact): no visibly choppy or stuttering cuts between shots, dialogue and score audio stay in sync with the picture rather than drifting, and the visual register reads as the intended cinematic ink look rather than an "off-campaign manhua" look. If any of the three 2026-07-25 symptoms is still present, name which one in your notes — that is the actionable output of this flow.

Confirm the story lands in the binding beat order: adult disciples defend the dojo, exactly three pages are removed mid-fight, the thief escapes without his identity ever being shown on screen, Ten Dan slams the doors open, the disciples kneel, Ten Dan examines the book and says the line Now the book looks raggedy, fucking up the feng shui., then a beat of silence, a fade, and the title. Expect: every beat present, in this order, thief's face never shown, no slideshow or still-photo montage standing in for any of it.

Hold Attack partway through. Expect: the skip meter fills over a short hold and the cutscene cuts directly to the title screen.

Final check: quit and relaunch play.sh. Expect: the cutscene forces itself again on this exact launcher every single time, regardless of having just seen it — that is deliberate (the force flag exists specifically so Wolf can re-review it on demand) and is not a bug; a normal player launch without the env var would instead play it once and never again.

F3

Title screen: exact copy plus two undocumented controls

Verifies the title's exact production text and surfaces F11/M — two controls that exist in code but appear in no shipped controls list.

Persona / precondition: at the title screen, having played or skipped F2.

0/5

Read the left-aligned title block. Expect exactly: eyebrow THE FIRST POUR, the title itself I DRINK YOUR MILKSHAKE across two lines, genre line A CINEMATIC KUNG FU PARODY, and a music credit reading MUSIC — ARAM / ARVM BEATS.

Find the primary button. Expect: a single button reading exactly OPEN THE MENU.

Press M. Expect: game audio mutes, and pressing M again unmutes it — this key is hardwired on every screen in the game, not just gameplay.

Press F11. Expect: the window toggles between windowed and fullscreen. This exists in code but is not listed in the shipped PLAY.md controls block — worth adding there if confirmed.

Final check: press Attack (J/Space), Interact (E/Enter), or a gamepad A button — any one of the three. Expect: the campaign menu (THE MENU) opens, same as clicking OPEN THE MENU with the mouse.

F4

Campaign menu on a fresh save

The menu's honest empty state: exactly one real, playable course, and one hidden slot that is provably unreachable rather than merely unlisted.

Persona / precondition: a fresh campaign — check ~/Library/Application Support/Godot/app_userdata/I Drink Your Milkshake/save.json for "has_run": false; if it instead shows real progress from earlier testing, either treat the exact numbers below as illustrative or fully quit the app and delete that file before relaunching to reproduce this exact state.

0/6

Read the heading and subheading. Expect exactly: THE MENU, then EIGHT COURSES. ONE IS BEING SERVED. — a direct admission that only one of eight planned courses is built yet; that is a scope fact from the code, not something to file as a bug.

Read the main course card. Expect exactly three lines: THE MAIN COURSE, GRANDMASTER TEN DAN, SERVING NOW.

Read the Continue button. Expect exactly two lines: CONTINUE, NO COURSE ON FILE — and it must be disabled; clicking it does nothing beyond a soft "deny" sound.

Look for a ninth or hidden campaign slot anywhere on this screen — try tabbing/arrowing focus through every visible control. Expect: none is visible or reachable. In code it exists as a button named HiddenCheckSlot reading THE CHECK, unconditionally set invisible, disabled, and focus-excluded; its unlock condition ("all eight courses complete") cannot fire in a build that only contains one course, so this is provably permanent right now, not a race you could win by trying harder.

Read the status line at the bottom of the menu. Expect exactly: COURSE 1 OF 8 · THE KITCHEN IS OPEN.

Final check: press Escape (or gamepad B). Expect: you return to the title screen with OPEN THE MENU visible again — the menu's own way back out works.

F5

[sensitive content omitted]

The settings screen deliberately exposes only a subset of the audio it actually stores. Confirm that boundary is honest by design, not silently broken.

Persona / precondition: from the campaign menu.

0/4

Activate SETTINGS. Expect exactly six rows, in this order: MASTER VOLUME, MUSIC, SCREEN SHAKE, FLASH INTENSITY, CLOCK SPEED, DISPLAY MODE.

Look for separate Effects or Ambience volume sliders, or any Gore toggle. Expect: none exist on this screen by design — a code comment states gore is the game's identity rather than a settings switch, and sound effects/ambience are hard-muted under the current music-only policy while the effects pass is still unbuilt. Only mark this a defect if you can produce an actual sound effect during real gameplay (F7) that this policy claims does not exist yet.

Change DISPLAY MODE and CLOCK SPEED away from their current values. Expect: both change immediately, with an audible confirm cue and (for display mode) a visible window-mode change.

Final check: back out to the campaign menu, then reopen SETTINGS. Expect: your step-3 changes persisted — they are written into user://save.json's settings block, not reset per session.

F6

The Character Forge

Proves the art-comparison harness Wolf uses to judge character-render tracks cycles cleanly without stranding the player.

Persona / precondition: from the campaign menu.

0/4

Activate CHARACTER FORGE. Expect: a comparison view mounts, showing a track label, an animation-state label, and a palette label.

Cycle the animation state control through its full list. Expect: it steps through a fixed named set including idle, walk, stance_ladle, stance_debt, stance_funeral, attack, hit, and taunt — note whether the on-screen label shows these raw internal names verbatim (stance_debt, stance_funeral) or cleaner display text; the code only confirms the former.

Cycle the palette control. Expect: the backdrop's grade/light/accent colors change together with the palette name, cycling through named sets such as MANTIS COURTYARD, IRON AUNTIE FORT, and PORRIDGE KITCHEN.

Final check: exit the Forge back to the campaign menu. Expect: you land on THE MENU with the main course card intact — no crash, no stuck overlay.

F7

Start THE MAIN COURSE: movement, combat, pause, mute

The actual playable slice: the first-person 3D Ten Dan campaign, not the older 2D top-down look described in some of the project's earlier planning docs.

Persona / precondition: a fresh save (Continue disabled, per F4).

0/8

Activate THE MAIN COURSE from the campaign menu. Expect: the menu closes, gameplay music switches on, and you are placed inside a first-person 3D world.

Move with W/A/S/D or the arrow keys. Expect: camera-relative movement, with no immediate wall-clipping or falling through the floor at spawn.

Press J or Space. Expect: an attack action fires.

Press K or Shift. Expect: a dodge fires, visibly distinct from the attack.

Approach an NPC and press E or Enter. Expect: an interact or dialogue prompt engages.

Press Escape mid-run, then press Escape or Attack again. Expect: the game pauses on the first press (a pause panel appears, time stops) and resumes exactly where it paused on the second — no position or HP reset.

Press M once while paused and once while unpaused. Expect: audio mutes/unmutes both times — the mute key is special-cased to work through the pause panel rather than being swallowed by it.

Final check: press F11 mid-run. Expect: fullscreen and windowed toggle without pausing or otherwise interrupting gameplay.

F8

A duel and its stance keys

The "Shadow-Play Board" duel system — the mechanical form of the Twelve Ingredients lore, where stances are read against the opponent rather than freely spammed.

Persona / precondition: the run from F7, having reached its first duel encounter (the M1 tutorial fight or the first school duel).

0/5

Enter a duel. Expect: the camera and controls shift into a dedicated duel framing, visibly distinct from open-world first-person movement.

Press 1, then 2, then 3 in turn. Expect: your character visibly changes stance on each key — these three physical number keys are hard-bound to three stance slots. Note in your record whatever on-screen label (if any) actually names each stance; this was not independently confirmed by reading the code.

Attack (J/Space) while holding a stance you believe reads the opponent correctly. Expect: a visible hit response on the opponent — not a silent whiff either way.

Deliberately hold the wrong stance or stand still. Expect: an honest failure signal — a visible HP or state change, or a retry offer — not a silent stall with no feedback.

Final check: resolve the duel to its end (win, or whatever its designed failure path is). Expect: control returns cleanly to open-world first-person movement — no stuck duel camera, no input left frozen.

F9

Save, quit, Continue

The persistence loop the entire campaign menu is built around.

Persona / precondition: mid-campaign progress from F7/F8, past at least the M1 checkpoint.

0/5

From gameplay, pause (Escape) then press Interact (E/Enter). Expect: this quits out to the title screen.

From the title, open the menu. Expect: the main course card's third line now reads ON FILE · <beat> with your actual current beat (for example M1) in place of SERVING NOW.

Read the Continue button. Expect exactly two lines: CONTINUE, then <beat> · DUELS n/6 — six is the total duel count in this build (mantis, tiger, leopard, monkey, crane, snake) and n is however many you have actually completed — and the button is now enabled.

Click Continue. Expect: gameplay resumes at the saved beat and position, not a restart from M1.

Final check: quit the app completely (⌘Q or close the window) and relaunch with play.sh. Expect: after the forced cold open (F2), Continue at the campaign menu still reflects the same saved beat — the save survived a full process exit, not just in-session state.

F10

Replay Cold Open from the menu must not touch your save

The menu exposes a manual re-watch of the opener, separate from the boot-forced one in F2 — prove it is non-destructive.

Persona / precondition: a save with real progress, from F9.

0/3

From the campaign menu, activate REPLAY COLD OPEN. Expect: the same filmed sequence from F2 plays again.

Let it finish, or skip it by holding Attack. Expect: you land back on the campaign menu (THE MENU) — not the title screen; replaying from the menu returns to the menu, unlike the boot path in F2 which returns to the title.

Final check: read the main course card and Continue button again. Expect: both still show your F9 progress unchanged — the script's own header comment claims this replay path "is not consumed" against a real save, and this step is the direct check of that claim.

F11

Dim Sum's Ledger

The campaign journal's states — no run, run not indexed, real ledger — must not blur into each other.

Persona / precondition: vary the save state per step as noted.

0/4

On a fresh save (no run started), open the campaign menu. Expect: the ledger button reads DIM SUM'S LEDGER, NO COURSE ON FILE, and is disabled.

With a save present but no campaign started (to confirm — not independently walked in this pass): expect the same button to instead read DIM SUM'S LEDGER, RUN NOT YET INDEXED, still disabled; once a campaign has actually started, expect it to read plain DIM SUM'S LEDGER and be enabled.

With a started campaign, open the ledger. Expect: a full-page journal listing your current objective and progress, matching the same state the main course card and Continue button show elsewhere in the menu — no contradiction between the three.

Final check: close the ledger (Escape or ui_cancel). Expect: you return to the campaign menu, not the title screen or a blank screen.

F12

Full completion: COURSE SERVED (the capstone, and the workspace's #1 blocker)

Per the 2026-07-30 workspace inventory, this is the single highest-leverage unresolved item in the entire project: twelve build units are sealed "AWAITING-WOLF" specifically because nobody has played the campaign through to its end. This flow exists to finally close that gap.

Persona / precondition: a full playthrough, M1 through M14, across as many Continue-linked sessions as it takes.

0/4

Reach and clear M14, the campaign's final beat. Expect (to confirm — not re-verified against this exact commit): a protected, uninterrupted closing sequence — hard silence, a first-light beat, an unchanged-HP moment, then the protected close and credits, per the prior D3 story-walk's recorded shape.

Return to the campaign menu. Expect exactly: the main course card's third line reads COURSE SERVED, and the Continue button reads exactly two lines, CONTINUE then COURSE SERVED.

Open Dim Sum's Ledger. Expect: it reflects the completed state with no beat still shown as active.

Final check: this is the actual Founder headed verdict the workspace has been waiting on since at least 2026-07-24, when PLAY.md recorded its own F20 line as DEFERRED-⚠ Wolf must run the build and play the full course headed. A real pass/fail recorded here — with notes on anything that broke the illusion along the way — is the deliverable this whole document exists to produce.

Not covered and why

  • Duel feel beyond stance-switching (parry timing, camera framing quality, combo depth against a real opponent) — needs a played duel to judge, not a code read; F8 only proves the mechanism exists and responds.
  • The remaining seven of "eight courses" and the hidden ninth (THE CHECK) — do not exist in this build yet; the menu's own subheading says so.
  • The headless regression gate (game/_build/gate.sh, MILKSHAKE_SMOKE=1) — that is the agent-facing automated suite, not a human user flow, and is not exercised here.
  • The game/ tree's 32 uncommitted files — a different, unreviewed state from what play.sh boots; testing it honestly needs its own provenance line and its own pass of this document.
  • Gamepad input — the code wires JOY_BUTTON_A/B/D-pad directions, but no controller was available to confirm any of it end-to-end.
  • Sound effects and ambience — explicitly unbuilt per the project's own roadmap ticket for a future sound-effects pass; F5 documents the current placeholder policy rather than testing content that does not exist yet.
  • Signing, notarization, and distribution to any machine but this dev Mac — the company readiness file lists that chain as blocked on a purchase; out of scope for a local play test.
  • Multi-session save durability beyond one relaunch (F9's final check) — a save surviving weeks, OS updates, or a Godot version bump was not tested.

Results

FlowVerdictFailures → tickets
F1 launch (right tree)
F2 cold open (visual gate)
F3 title screen
F4 campaign menu (fresh)
F5 settings
F6 character forge
F7 main course controls
F8 duel stances
F9 save / continue
F10 replay cold open
F11 Dim Sum's ledger
F12 course served (capstone)
updated just nownext 3m 00s