Add opt-in phone gameplay recording and JSON export

This commit is contained in:
wuwi committed 2026-09-07 10:19:38 +02:00
1 parent ede1f48152
commit fe64242090
8 files changed
+394 -12

No files matched your search

+41
View File
@@ -4922,6 +4922,47 @@ This is stronger measured opposition, not a measured human win rate: league 5 st
Oliver's level-26 phone verdict. Oliver requested merging to main and pushing for his iPhone
test; this release carries the cache-busting entry version v350.
## Session log: THE PHONE PLAYTEST RECORDER (2026-09-07, v351)
Oliver: difficulty is better, but title defences still come easily — log real phone play so we
can explain his wins per game before tuning again. The old 50-entry `G.missLog` is tennis-only
and cannot do that. `src/recorder.js` adds opt-in, local-only diagnostics for solo cup, Climb and
training. No video, server endpoint, automatic upload, package or change to difficulty.
Use **STATS → RECORD PLAYTEST**, play, then **STATS → STOP RECORDING → EXPORT RECORDING**.
`?record=1` also arms/resumes it. A small REC below the quit chip marks active capture; normal
reloads restore the saved file paused. Export uses the phone's file-share sheet when supported,
otherwise a JSON download. Cancellation/export never deletes data. Replacement is a separate,
explicitly labelled button. The native iPhone share sheet still needs Oliver's phone verdict.
- Events identify run/segment, opponent encounter, roster position, cup round, point number and
the pre-verdict game/point score. Run starts capture build, viewport, court, league, player level
and actual TUNE values. No player name, account id, sync key or other credentials are exported.
- Both serves and returns capture quality, aim, resulting velocity, positions and habit/read
state; player swing attempts and actual probabilistic opponent whiffs get their own events.
- `resolveInterlude` accepts an optional diagnostic reason. Its existing decided/ending guards
gate the recorder too. Reasons distinguish out, double fault, double bounce, dead roller,
passed player, body destruction and the two early-unreachable adjudication paths. Record
BEFORE scoring mutates the state, including a point that kills the player.
- Every point includes up to 90 live update frames of player/opponent/ball movement (roughly
1.5 s at 60 Hz, deliberately not the inaccurate old 20 Hz closest-approach sampler). Timestamps
use update time; this is evidence for analysis, not a deterministic replay. An ace is derived
from the shot sequence and verdict, not guessed at the logging call site.
- Completed points and run boundaries checkpoint to `splatter-playtest-v1` in localStorage.
Visibility/pagehide also save; backgrounded/resumed play gets explicitly marked segments.
Event data caps at 1.5 million JSON characters, then stops with REC FULL instead of silently
discarding the beginning. Storage errors preserve in-memory export and report the limitation.
Validation: 138 tests pass, default seed plus 1, 42, 1234 and 20260907. A 180 s Level-26 cup
simulation has identical gameplay state AND RNG state with recording on/off (reset P.dustAcc in
the comparison fixture: resetState's Object.assign leaves that cosmetic accumulator behind).
Tests cover actual shots/scoring, guarded duplicate verdicts, fatal losses, early player wins,
quota failure, size limits, reload recovery, exclusions, file sharing/cancel/download fallback.
Browser checked: opt-in, REC, run exit, Stats export controls, reload paused with export retained,
download-request feedback and no console errors. The in-app browser did not expose a download
completion event; the exporter branches are tested with platform stubs, real Safari export is
the next phone check. New file is under src/, already covered by Docker's COPY.
# OPEN — leftovers, in rough priority order
Nothing here is broken; these are known gaps and unverified risks.