/** * Reading the engine's mobile-parity verdict out of the console verify already captures. * * `GameTemplate` calls `playerController.verifyMobileParity()` on every game start — desktop runs * included — and when it finds gaps the engine logs one `console.error` listing every one of * them (`game/src/engine/PlayerController.ts`, documented in * `game/agent-docs/control-system.md`). Nothing consumed it, so a game with actions no phone can * reach passed verify silently. * * Parsing that line rather than listening for the `aitopia:mobile-parity-gap` postMessage the * same check also fires is deliberate on two counts: the console is already captured, so this * needs no new browser plumbing; and only the console line carries the `(source)` annotation * naming which system registered an orphan key, which is the difference between "KeyF is * unreachable" and "the attack system left KeyF unreachable". * * The line's format is a documented contract, but this parser still degrades rather than * insisting on it: anything it cannot read comes back null, which classifies as "not observed" * and never as a failure. Two legitimate ways to get null: a clean game (the engine logs nothing * when parity holds) and a genre whose controller has no parity check at all — the 2D genres' * `Physics2DPlayerController` deliberately has no `verifyMobileParity`, so `GameTemplate`'s * duck-typed guard skips it. */ /** The engine's marker. Also what a reader greps the console log for. */ export declare const MOBILE_PARITY_MARKER = "[mobile-parity]"; export interface MobileParityGap { /** * Unpaired desktop keys exactly as the engine names them, source annotation included — * `KeyF(CombatSystem)`, or `KeyF((anonymous))` when the registration passed no `source`. The * annotation is the actionable half: it points at the call site to fix. */ unpairedDesktopKeys: string[]; /** Mobile buttons with no desktop key, as bare action names. */ unpairedMobileActions: string[]; } /** * The gap the engine reported during this run, or null when it reported none. * * The last matching line wins: a run that starts gameplay more than once (a restart during the * settle) logs the check once per start, and the newest verdict is the one about the game as it * ended up. */ export declare function parseMobileParityGap(consoleLines: string[]): MobileParityGap | null;