feat(hint): idle-gated wallet-free vs_ai hint on a monotonic clock (B4) #207
Reference in New Issue
Block a user
Delete Branch "feature/offline-hint-gate"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fast-follow (e): the local vs_ai hint presents its 30-min idle gate instead of erroring.
Behaviour: vs_ai hints are unlimited + wallet-free, idle-gated (unlock ~30 min into a stuck turn; the human first move is exempt). Gated -> an enabled button with a 🔒 badge; a tap shows «Будет доступно через N мин.» / «Available in N min.»; the lock lifts live.
Clock handling (revised per owner to Option A): the wait now persists across relaunches — the unlock is a wall-clock instant (
hintUnlockAtMs, stamped off the robot reply, stored on the record, carried on the move delta). Read through a sanitiser (cap atnow + window) so a device clock set back cannot freeze the gate; a clock set forward just opens the hint early (harmless in a solo game). We accept that rare clock-change case for a wait that survives leaving/reopening the app. (An earlier revision used a session-scoped monotonic clock that reset on reload; the owner chose persistence.)Online vs_ai will gate the same way from the server clock — a separate follow-up.
Verified: check 0 / unit 488 / e2e 198 (both engines, incl. lock-survives-reload) / app entry 114.1/115 KB.
A vs_ai hint is now unlimited and wallet-free, but idle-gated as an anti-frustration aid: it unlocks only after the player has been stuck ~30 min on a turn (timed from the robot's last move; the human's first move, before the robot has played, is exempt). While gated the hint button carries a small lock badge and a tap shows the remaining minutes ('Available in N min.'); the lock lifts live at the mark. The gate is enforced CLIENT-SIDE against a MONOTONIC clock (performance.now()), never a wall-clock timestamp: a device clock the player controls (or an auto-sync) must not be able to open or freeze it. The wait is therefore session-scoped -- a reload restarts it (there is no tamper-proof way to carry idle time across a relaunch without a wall clock). An online vs_ai game will gate the same way but from the server's clock (a follow-up). - lib/hints.ts: HINT_GATE_MS + pure hintGateRemainingMs (monotonic) + hintLockMinutes; removed the wall-clock hintRemainingMs. Unit-tested red->green. - Game.svelte: the monotonic gate (hintGateStart/monoNow, armed on the turn change), a vs_ai hint button (plain: no confirm, no count; lock badge + gated tap -> toast), a live 10s tick. - localgame: removed the wall-clock hint gate and the now-dead robotLastMoveAtUnix field from source.ts/serialize.ts (the client is authoritative); hint() just serves the top move. - i18n game.hintLockedIn. - offline.spec.ts: assert the first move is un-gated and the lock arms after the robot moves. - Docs FUNCTIONAL(+_ru) + ARCHITECTURE; bundle budget 114->115 (game-screen feature).New commits pushed, approval review dismissed automatically according to repository settings