Skip to content

refactor(tick): split RunTick into phase functions (move-only) - #483

Merged
Maxaubert merged 31 commits into
mainfrom
refactor/split-runtick
Oct 14, 2026
Merged

Maxaubert merged 31 commits into
mainfrom
refactor/split-runtick

Conversation

@Maxaubert

@Maxaubert Maxaubert commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Closes #478

Splits RunTick (src/main.cpp, about 1,725 lines) into static phase functions in the same file, called in the same order. RunTick is now 38 lines; the zoomed/Inspect branch is RunActiveTick (42 lines).

Move-only

No behaviour change: same order of side effects, the same early-return-free flow, the same log lines and SpanScope timing spans, and TickWorkTimer still wraps the whole tick in RunTick. Every block moved verbatim (re-indented where it left a nested scope) together with its comments. Locals that a later phase reads come back in small structs (TickClock, TickInput, TickModes, PanDelta, TickForeground, PointerMap) and are unpacked into locals with the original names, so the call sites read like the old code.

The only edits that are not pure moves:

  • The keyDown / modsHeld / comboHeld lambdas became BindKeyDown / BindModsHeld / BindComboHeld, which take the tick's single kbHook read, so StepTracking can share them. ResolveInputAndZoom and StepTracking each keep a one-line comboHeld lambda that forwards to it, so their call sites are unchanged.
  • if (loaded) { ... } around the reload apply is now if (loaded) ApplyReloadedConfig(...).
  • LogHeldState dropped the bare { } scope the block had inside RunTick.
  • RunTick's rawDx/rawDy are const. The Inspect-entry zeroing now acts on RunActiveTick's copy, and nothing after the branch read them.

Extracted functions (lines in the new src/main.cpp)

Function Lines Size
BeginTick 1020-1045 26
ApplyReloadedConfig (from the reload) 1049-1117 69
PollConfigReload 1120-1183 64
WatchForegroundAndKbHook 1187-1267 81
BindKeyDown / BindModsHeld / BindComboHeld 1274-1288 5 / 7 / 1
ResolveInputAndZoom 1293-1427 135
ResolveTickModes 1432-1464 33
RetargetSessionMonitor 1467-1508 42
PickEngineAtZoomIn 1511-1540 30
EnterSession 1544-1615 72
EnterInspect 1619-1663 45
ExitInspect 1667-1696 30
ResolvePanDelta 1701-1848 148
ReadForegroundAndArmWall 1853-1910 58
MapPointer 1915-2005 91
StepTracking 2009-2163 155
ProbeClicks 2166-2218 53
CommitInspectClicks 2221-2261 41
InstantHybridSwitch 2264-2357 94
BuildPresentExtras 2361-2476 116
PaceAndPresent 2480-2556 77
RevealAndHandover 2560-2629 70
AssertGameInspectSteal 2632-2649 18
UpdateCursorBaseline 2653-2713 61
TeardownSession 2716-2748 33
IdleTick 2751-2760 10
RunActiveTick 2765-2806 42
LogHeldState 2809-2854 46
LogFramePacing 2857-2882 26
WriteTestTelemetry 2885-2908 24
RunTick 2910-2947 38

The phases stay static in main.cpp. Moving them to a tick_*.cpp would expose g_input, g_track, g_tint, g_color, g_trayBlock, g_focusStealer, g_mpoDisabled, g_testlog and the fg-cache helpers, which is more surface than this split needs.

How it was checked

  • One extraction per commit (30 code commits plus 1 docs commit), each made by a script that cuts a line range out of RunTick, removes a fixed indent and pastes it unchanged into the new function. Each commit passed build.bat check before it was committed. Review with git diff --color-moved=zebra --color-moved-ws=allow-indentation-change, commit by commit.
  • Moved-lines diff: every non-blank line of origin/main:src/main.cpp, with whitespace stripped, was compared as a multiset with the branch. The only lines that exist on main but not on the branch are the three lambda heads, two lambda }; closers, if (loaded) { with its closing guard comment, and the LogHeldState scope {, all listed above. Every other line on the branch that is not on main is a new function signature, a struct, a return {...}, a call, or a one-line function comment.
  • Gates: build.bat check (exit 0, no new warnings), build.bat test (643/643 test cases pass), build.bat (Wind.exe and WindTray.exe link). src/config_ui and ui/ are untouched, so build.bat config and Playwright were not needed.
  • Not deployed or run. Because the tick code is field-tuned, deploy-verify it before merging (zoom in/out, Inspect, a hybrid switch, a game session).

Docs: docs/architecture/02-tick-loop.md gets a phase-to-function table; 04 and 05 name the functions that now hold reveal and wall arming.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH

Maxaubert and others added 30 commits October 14, 2026 02:27
Move-only: the idle colour filter, dt, zoom timeline step, stale press
stamp and tray frame sample move verbatim into BeginTick (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the config hot-reload block moves verbatim into PollConfigReload (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the launch-quiesce cover watch, the noSwallowApps hook suspension and the keyboard-hook watchdog move verbatim into WatchForegroundAndKbHook (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
…unTick

Move-only: the keyDown/modsHeld/comboHeld lambdas become static functions taking the tick's kbHook read, so later phases can share them; comboHeld stays as a one-line forwarding lambda in RunTick (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: held-bind resolution, the zoom controller step, the smooth-zoom release stop, recenter and Inspect toggle edges, quick zoom and the tray level publish move verbatim into ResolveInputAndZoom (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the raw-motion drain, the zoomed/inspect/active flags, the stale-lock reset, the zoom timeline arm and the keyboard-pan arm move verbatim into ResolveTickModes (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the zoom-in monitor retarget (both engines, refresh rate, mapper, detector) moves verbatim into RetargetSessionMonitor (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the per-session hybrid engine pick at zoom-in moves verbatim into PickEngineAtZoomIn (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the body of the enterActive branch (per-session resets, retarget and engine pick calls, refresh-rate re-read, mapper/baseline/detector seeds, warp-lock seed, cursor hide, onActivate) moves verbatim into EnterSession (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the body of the inspectEnter branch (freeze clip, look-point seed, game-inspect decision and log) moves verbatim into EnterInspect (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the body of the inspectExit branch (game-inspect end, click drain, unfreeze, look-point warp) moves verbatim into ExitInspect (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the pan-delta resolve (free / locked / Inspect regimes, lock detector, lockApps, LockApplies, gain learner, drag-follow, per-tick bound) moves verbatim into ResolvePanDelta (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the per-tick foreground facts, the MPO pan wall / write clamp arming, the device-lost backstop stamp and the per-tick launch-cover tracking move verbatim into ReadForegroundAndArmWall (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the free-cursor decision, pan glide, game-drawn cursor lag, pointer history pin and the mapper step move verbatim into MapPointer (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: caret/focus tracking, keyboard panning and the view-owner step move verbatim into StepTracking; it builds its own comboHeld from the tick's kbHook read, so RunTick no longer needs one (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the dead-zone probe (probeClicks) moves verbatim into ProbeClicks (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the Inspect click-to-look-point injection moves verbatim into CommitInspectClicks (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the mid-session hybrid engine switch moves verbatim into InstantHybridSwitch (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the PresentExtras build (outline dwell and idle fade, cursor mode, weld suppression, colour filter, write pauses, DWM centring, tray-menu guard, Inspect freeze re-assert) moves verbatim into BuildPresentExtras (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the game pacing levers and the engine present (with its zoom timeline stamp and pointer-hidden read-back) move verbatim into PaceAndPresent (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the post-present reveal gating and the handover overlap countdown move verbatim into RevealAndHandover (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the deferred game-inspect foreground steal moves verbatim into AssertGameInspectSteal (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the next-tick cursor baseline and the divergence diagnostics move verbatim into UpdateCursorBaseline (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the active -> idle teardown branch body moves verbatim into TeardownSession (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the idle branch body (engine idleTick, cursor tint) moves verbatim into IdleTick (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the zoomed/Inspect branch body (now a sequence of phase calls) moves verbatim into RunActiveTick; RunTick's rawDx/rawDy become const (the Inspect-entry zeroing now acts on RunActiveTick's copy, and nothing after the branch read them) (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the held-state timeline diagnostics (issue #113) move verbatim into LogHeldState; the bare scope braces go, so the body is dedented one level (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the frame-pacing diagnostics move verbatim into LogFramePacing (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the test telemetry sample moves verbatim into WriteTestTelemetry (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
Move-only: the core-relevant reload apply (re-binds, hotkeys, live engine
prefs, zoom and mapper rebuild) moves verbatim out of PollConfigReload
into ApplyReloadedConfig (#478).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
02-tick-loop gains a phase-to-function table; 04 and 05 name the phase
functions that now hold reveal and wall arming.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TdjopXZfsUiesYxYLYHEdH
@Maxaubert
Maxaubert force-pushed the refactor/split-runtick branch from a952ef1 to d9f5e07 Compare October 14, 2026 00:27
@Maxaubert
Maxaubert merged commit 6f615a5 into main Oct 14, 2026
1 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor: split RunTick into phase functions (move-only)

1 participant