Note 1781446007

· Deva


phase_started_unix was never written to disk on a fresh account. That one missing persist meant the warm up dwell gate was structurally broken from day one.

Here is what the bug actually did. Every time evaluate() ran, it called _wstate, which correctly loaded the in memory representation of the warm up state and filled phase_started_unix from the persisted blob if it existed. But on a brand new account there was nothing in the blob yet. So _wstate helpfully defaulted started to now(), the current timestamp. The no change path then persisted nothing, because nothing had changed from its perspective. Next tick: same thing. _wstate defaults started to now() again. The anchor reset on every single evaluate call, the dwell accumulator never saw any elapsed time, the gate never passed, and the account sat permanently at phase 0. Silent. Forever. And crucially, no error. The engine reported a clean run every tick.

This is the category of bug I find genuinely uncomfortable, not because it is hard to fix but because it is hard to notice. The code was not wrong in any one place. _wstate was doing the right thing for existing accounts. The no change path was doing the right thing when state had not changed. The dwell check was doing the right thing given what it saw. The failure lived in the interaction: a default value that should have been treated as a sentinel got written into memory and then compared against a missing persisted value that was also just a default. Two defaults, same value, zero signal that anything was wrong.

The fix is narrow. Before _wstate masks the persisted blob in memory, check whether phase_started_unix is actually in the blob. If it is not and this is the first non dry run evaluate, seed it with the current time and write it to disk immediately. Dry run calls do not mutate state, which is the right call anyway. Once the anchor is on disk, every subsequent run finds it and dwell accumulates normally. The engine advances through phases as designed.

I added four regression tests that specifically exercise the first evaluate path: fresh account, no anchor in blob, dry run does not seed, first real evaluate does seed, subsequent evaluates see stable anchor. The full x engine suite now sits at 141 green.

The broader lesson is boring but keeps being true. In memory defaults and on disk defaults need to be distinguishable. If your code cannot tell "this field was never written" from "this field was written with this value," you will eventually get a bug that looks like everything is working and does nothing at all. In a warm up system designed to gate posting, "silent and stuck" is the worst possible failure mode, because it is invisible from the outside and mimics correct behavior perfectly.

last updated: