Skip to content

Build1 publisher3 min readPublished

A same-machine replay comparison catches the four desync causes one computer can reproduce

The dev.to post behind Tickwise argues that the cheap determinism test is one computer, one recording and one compare command, and it lists the four single-machine faults that test exists to surface.

The Engineer · Build desk

What happened

  • A dev.to post proposes a three-step determinism check that needs one computer: record a session, feed the same recorded inputs back through the simulation, then compare the two recordings with tickwise compare.
  • Tickwise writes the inputs and a hash of every tick into a .rec file. Those stored per-tick hashes are what make the two runs comparable after the fact.
  • The four causes the post lists are unordered container iteration, wall-clock or frame-delta reads, stale or uninitialized state, and global mutable state, and all four fail without a network.

Compiled by The EngineerSomething wrong?How this is made

Why it matters

  • constraint A simulation that fails the same-machine compare will never pass the multi-machine version, so hours of triage across two builds and two network stacks are spent on a fault that one machine would have shown.
  • cost Adopting the check costs a recording format, per-tick state hashing and an input path that can be fed from a file, all of it build work inside the simulation.
  • capability The whole class of fault becomes reachable offline by one engineer before a match is ever played, with no second client and no other player to schedule.
  • decision Teams pick between diffing two finished recordings and verifying each tick as the replay runs; the second puts the failure inside a live process where a debugger is already attached.

Start with iteration order. It sets a constraint on how the second pass runs. Rust randomizes hash seeds per process, so the second run walks the same entities in a different order, and in an order-sensitive physics step the two runs diverge [9]. Two runs inside one process share a seed, so a HashMap walk can agree by luck; the replay has to be a separate process for that class to surface at all [19]. Tickwise ships iteration order as one of four chaos modes for this reason [9].

The post calls time leaking the case that hides well [10]. A subsystem reads the wall clock or a frame delta instead of the fixed tick, and in the post's example the recorded frame took 16.2 milliseconds against the replay's 15.9, which was enough for the simulation to take a different branch [10]. On a fast machine the two numbers look close enough to be invisible [10].

Two of the four classes are about state nobody cleared. A scratch buffer left dirty between ticks, or a lazily built cache that exists on the second pass and not the first, starts the replay from a slightly different world than the recording [11]. A static counter or a shared random generator leaves the same kind of fingerprint across sessions [12].

Take the published verdict as a claim about the tool's own plumbing. The --chaos flag injects a known class of non-determinism at a tick you choose, and it exists so the tool can prove it works [14]. Injecting stale-value at 4021 produces a compare verdict of first divergence at tick 4021, caught by the light hash, confirmed by the full hash at tick 4200, last agreement at tick 4020 [15]. Confirmation trails detection by 179 ticks [16]. There are two hash tiers in that verdict, a cheap one per tick and an expensive one at intervals [21], so for the same shape to repeat on your code the cheap hash has to cover whatever field went stale.

The same check can happen during the replay instead of after it. Replayer::open takes a ReplayConfig, and with verify_hashes: true every tick of the replay is checked against the hash stored in the file [18].

The argument rests on the cost of the test. The post asserts that a large share of desync bugs were never about the second machine and that nobody had checked the single-machine case [2], and it does not offer a measurement [20]. It does give a procedure you can run alone, offline, in a few seconds, before any player is involved [8]. Lockstep netcode depends on the multi-machine version of the same promise [3]. The author wrote that the self-check is "the first thing I would run on any simulation that claims to be deterministic" [5].

What to watch

  • Whether Tickwise documents the interval on the full hash, which sets how far confirmation can trail detection.
  • Whether anyone reports the share of their own desync tickets that a single-machine self-check resolved.
  • Whether the four shipped chaos modes grow to cover further classes of non-determinism.
Loading claim ledger
Loading source directory links
Loading share composer
Loading topic controls
Loading related stories