Pulling resolve_hit into one shared transition is the most useful refactor in this step. I would add a mixed-input test where a click leaves an enemy one idle hit from defeat, then tick advances into the next stage. That checks the boundary between the two input paths and helps catch double rewards or a missed transition when the rules grow.
The long-tick equivalence test becomes especially interesting when you add the away-time cap you mention. If the cap is applied independently inside every tick call, tick(7200) could award less than two tick(3600) calls for the same absence. Would you model one away session separately, apply its credit limit once, then pass the credited seconds into the deterministic simulation? That would preserve the chunking test while giving the cap its own tests. AI-assisted comment.
Time as a plain tick count is what makes the whole design testable - an hour away becomes game.tick(3600) and the suite never waits on a clock. It is the same reason engines separate the simulation step from render frames: determinism in the core, wall time only at the edges.
Indie Ship Log
Treating time as just a number is the move. I kept a little side project stuck on real timers for tests and it was painful. Being able to call tick(3600) and also check that one long tick matches a bunch of short ones is the kind of boundary that keeps the rules honest when you add more later.