/** * The decision "has the game settled enough to observe", extracted pure so it is testable * without a browser. * * Verify used to wait a fixed 15 seconds regardless of what the game was doing. The samples the * browser loop feeds this function come from the live engine (`window.gameTemplate`), so a * healthy game that reaches gameplay and holds steady is observed after ~4-5 seconds, while the * fixed `--timeout` stays as the hard cap for games that never stabilise. An engine too old to * answer the probes never settles early — it gets exactly the old fixed-wait behaviour. */ /** One poll of the live page, taken every `SETTLE_POLL_MS` during the settle. */ export interface SettleSample { /** ms since the settle began. */ atMs: number; /** `window.__bitmagicFrameCount` — rAF ticks since page load, injected by verify's init * script. Null when the page could not be evaluated. */ frameCount: number | null; /** `engine.gameStateManager.getCurrentState()` — lowercase engine values ('menu', 'loading', * 'ready', 'playing', 'paused', 'end'). Null when unobservable (older engine, no manager). */ gameState: string | null; /** `engine.gameStateManager.hasStarted()`. Null when unobservable. */ hasStarted: boolean | null; /** Player world-Y. Null when there is no player to ask (menu, loading, engine too old). */ playerY: number | null; /** Console error lines + player-fell-out-of-world lines seen so far. Monotonic; a rise * between samples means the game is still misbehaving. */ errorEventCount: number; } export interface SettleConfig { /** Never settle before this — engines finish async spawns (NPCs, deferred GLBs) well after * gameplay starts, and a too-early observation would miss them. */ minSettleMs: number; /** Frames the page must have rendered — proves a live render loop, not just a live DOM. */ minFrames: number; /** How long the error counters must have been flat. */ quietMs: number; } export declare const DEFAULT_SETTLE_CONFIG: SettleConfig; export declare const SETTLE_POLL_MS = 500; /** * The player is in sustained freefall at the end of `samples`. * * Judged over the trailing samples that HAVE a player position; unobservable positions mean * "cannot tell", never "falling". Exported because the final state snapshot reports the same * judgement as `player.isFalling`. */ export declare function isFreefalling(samples: SettleSample[]): boolean; /** * True when the run has seen enough to stop settling early. * * Every condition must hold on the latest sample: * - the minimum settle floor has passed; * - gameplay is actually running — state 'playing' or 'end' (a run-to-completion minigame), or * `hasStarted` when the state manager is not observable. Both unobservable → never settle * early; the fixed timeout is the correct behaviour for an engine that cannot be asked; * - the page has rendered enough frames to prove a live render loop; * - the error counters have been flat for the quiet window; * - the player is not falling out of the world. */ export declare function settleVerdict(samples: SettleSample[], config: SettleConfig): 'settled' | 'keep-waiting';