# Event timestamps, frame elapsed time and pause gates Static pass, 2026-10-11. Reproduce with `python3 scripts/analyze_frame_timing.py`; validate with `python3 scripts/test_frame_timing.py`. [Generated evidence](frame-timing.json) records ten instruction graphs, file-backed constants, two seven-entry event tables, direct pause cvar assignments, frame/pause instruction windows and 64 bounded synthetic native instruction traces. Inputs are verified against the original and disassembly SHA-256 identities before analysis. No original process or complete VM is launched. ## TIME-001: elapsed-time modification Both Linux ELF64 images contain `Com_ModifyMsec` (dedicated `0x42d4de`, client `0x43df8a`) and equivalent inlined calculations in `Com_Frame`. The memory float compared with timescale is **0.0**, verified from the actual file-backed bytes `00000000`; a nearby symbol name does not identify that constant. For finite, in-range values, the observed helper selects milliseconds in this order: 1. A nonzero `com_fixedtime` integer replaces incoming elapsed time, bypassing multiplication. 2. Otherwise a nonzero timescale multiplies elapsed time using single-precision conversion/multiplication and truncation toward zero. 3. Otherwise a nonzero camera-mode integer keeps the zero candidate; with camera mode zero, incoming elapsed time is used. 4. A nonpositive candidate is replaced with one if timescale is nonzero. With zero timescale that correction is skipped. The zero-timescale/camera path also bypasses the nonpositive test with its zero candidate. 5. Apply the upper bound according to the table below. | Dedicated cvar | Local server running | Upper bound | Diagnostic | | --- | --- | --- | --- | | Nonzero | Either | 5000 ms | With a running server, a candidate strictly greater than 500 ms is passed to `Com_Printf` before clamping. | | Zero | Nonzero | 200 ms | No dedicated-hitch diagnostic in this path. | | Zero | Zero | 5000 ms | No dedicated-hitch diagnostic in this path. | The table depends on cvars, rather than simply the executable filename. Representative traces in **both images** produce: elapsed 201 → 200 for a local nondedicated server; elapsed 5001 → 5000 when no local server runs; dedicated/running 500 → 500 with no print, 501 → 501 with one print. Timescale 0 with elapsed 16 and camera mode 0 produces 16; setting camera mode 1 produces 0. Fixed time -5 with zero timescale produces -5, whereas with timescale 1 it becomes 1. Fixed time 17 with timescale 2 remains 17. These branches make “timescale zero always pauses” an incorrect replacement contract for this helper. `Com_Frame` stores the raw measured interval in `com_frameMsec` before the inlined modification. It sends the resulting interval to `SV_Frame`; on its nondedicated branch, it pumps events and executes buffered commands again before `CL_Frame`. The earlier [simulation-tick calculation](ENGINE_CONTROL.md) separately multiplies the FPS-derived tick by timescale. Do not merge the raw host interval, modified frame interval and authoritative simulation clock into one Rust clock. The evaluator executes only decoded instructions from `Com_ModifyMsec`, with symbolic cvar pointers and synthetic values. It rounds scalar operations to float32, follows the actual conditional targets and records diagnostic calls without entering callees. It rejects unknown opcodes/operands, nonfinite timescale and out-of-range float-to-int conversion. It does not model SSE exceptions, arbitrary memory, ABI execution, the full inlined frame body or reachable cvar constraints. Negative fixed time is a synthetic boundary example, not a claim about normal gameplay settings. ## TIME-002: event timestamp source and dispatch | Function | Dedicated address | Client address | | --- | --- | --- | | `Sys_GetEvent` | `0x4a7308` | `0x555d88` | | `Com_GetRealEvent` | `0x42ee3e` | `0x43fba4` | | `Com_EventLoop` | `0x42f1de` | `0x43ff42` | `Sys_GetEvent` first consumes an already queued event if available. Otherwise it polls key events, console input, input-frame processing and network packets. If no event becomes available, it zeroes a 32-byte event record and places `Sys_Milliseconds()` at offset zero. `Com_GetRealEvent` normally delegates to that provider; journal mode 2 instead reads a 32-byte event record and optional payload, while mode 1 writes the record and payload. Short record/payload I/O routes to `Com_Error`. Journal paths therefore prevent an assumption that every frame timestamp comes directly from a fresh host-clock sample. `Com_EventLoop` consumes its pushed-event ring before calling `Com_GetRealEvent`. For type zero it drains client and server loopback packet queues, then returns the event timestamp. Nonzero types dispatch through the file-backed tables at dedicated `0x4b3ea8` and client `0x56ba10`: | Type | Observed service/path | | --- | --- | | 0 | Table entry points to payload cleanup, but the earlier type-zero branch bypasses this switch and handles loopback/return. | | 1 | `CL_KeyEvent`, with event time forwarded. | | 2 | `CL_CharEvent`. | | 3 | `CL_MouseEvent`, with event time forwarded. | | 4 | `CL_JoystickEvent`, with event time forwarded. | | 5 | `Cbuf_AddText` calls for console input and a second string. | | 6 | Packet handling with `com_dropsim`, payload length checks and server/client routing. | The collector reads all 56 table bytes from their mapped file offsets and verifies every target is an instruction in the function. Linear entry windows can span other cases and are not standalone case executions. Out-of-range event types route to `Com_Error`; payload cleanup calls `Z_Free` on the ordinary handled-event paths. Detailed packet/drop simulation and queue overflow/ownership behavior remain follow-up work. At the first frame event pump, `Com_Frame` compares the returned timestamp with retained `lastTime` using a signed comparison. A smaller timestamp resets `lastTime` to that value before subtraction. It pumps again until the elapsed value meets the selected minimum interval. The ordinary minimum is one millisecond; the nondedicated, positive-maxfps, non-timedemo path uses integer `1000 / com_maxfps`. Raw elapsed is recorded before the modification described above. This is bounded static ordering evidence, not a complete wraparound or scheduling specification. ## TIME-003: pause state and inline gate `SV_CheckPaused` appears at dedicated `0x41035a` and client `0x4782da`. With `cl_paused` zero, it returns zero directly. Otherwise it scans native client records with stride **0x2df40**, admitting a record into its count when the state word is unsigned greater than one and the word at **0x24ee4** is unsigned at least one. The second predicate follows from `cmp 1` and `sbb -1`; its semantic field name remains unresolved here. Do not call this a human-client or bot filter without recovering that layout. With count at most one, the helper sets `sv_paused` to string `"1"` if needed and returns one. With count greater than one, it sets `sv_paused` to `"0"` if needed and returns zero. Both direct `Cvar_Set` argument pairs are decoded from the original bytes and included in the report. If `cl_paused` is zero, this helper does not clear a previously set `sv_paused` value. `SV_Frame` contains an equivalent inlined gate before its tick calculation and game callback loop: the pause path returns without running those simulation steps. This is server-engine pause evidence, not the game-mode timeout implementation. Full paused networking, accumulated-time behavior, client presentation, game timeout rules and all-platform parity remain unverified. ## Completion and follow-up RE-232–234 cover these bounded static deliverables. RE-231 and PROV-001 remain open because complete catch-up, restart, callback ordering, runtime constraints and Windows/macOS/ELF32 behavior have not been recovered. Next recover the counted native field, validate actual configurations and journal fixtures, and compare the complete host-frame/server-frame paths across platforms. The Rust scheduling contract must preserve observed clock distinctions and explicitly address unsupported numeric domains after further evidence. Follow-up: [EVT-001](EVENT_QUEUES.md) resolves field 0x24ee4 to the native netchannel address type and identifies zero-type bots. The raw predicate and runtime limitations above remain applicable.