--- name: Offline simulator architecture description: Background OfflineSimulator in game/offline.go runs real server-side combat ticks for offline heroes; replaced fake retroactive simulateOffline type: project --- Real offline simulation system added 2026-03-27. Key decisions: - `game.OfflineSimulator` ticks every 30s, queries heroes with `state='walking'` and `updated_at < now - 1min` - `game.SimulateOneFight` is the canonical single-fight function used by both simulator and catch-up - `game.PickEnemyForLevel`, `game.ScaleEnemyTemplate`, `game.AutoEquipWeapon`, `game.AutoEquipArmor` were extracted from handler to game package (exported) - handler's `pickEnemyForLevel`/`autoEquipWeapon`/`autoEquipArmor` now delegate to game package - `catchUpOfflineGap` in handler covers server-down gap (hero.UpdatedAt to serverStartedAt) - `buildOfflineReport` reads real adventure_log entries instead of generating fake ones - `serverStartedAt` passed from main.go -> router.Deps -> GameHandler **Why:** Old simulateOffline generated fake events retroactively at login. New system writes real events to adventure_log as they happen. **How to apply:** When touching offline/idle combat, work in game/offline.go. The handler no longer owns combat simulation logic for offline heroes.