Extends the town timeline to the whole cycle and times every step:
grep "TL>" log/log.txt
TL> g2 r1 | game | spawn | ok | at a5_town_start
TL> g2 r1 | town | inspect_inventory | ok | took=3.0s | in pack=2 keep=0 sell=2
TL> g2 r1 | town | repair | ok | took=19.3s | at a5_larzuk
TL> g2 r1 | town | item_sell | ok | SOUL IMPALER @ (928, 465)
TL> g2 r1 | town | resurrect_merc | fail | took=113.6s | NPC not reachable
TL> g2 r1 | town | maintenance | ok | took=137.6s | at a5_larzuk
TL> g2 r1 | run | run_pindle | start | from a5_larzuk
TL> g2 r1 | run | approach | fail | took=71.9s | step=click_red_portal
TL> g2 r2 | game | end | fail | Approach failed [step: click_red_portal]
- phases: game (start / spawn / end), town (all maintenance steps), run (approach /
battle / loot), stlth.
- every terminating line carries took=Ns; "start" stamps the clock in Bot._tl_starts
keyed by (phase, step). The sample above pays for itself immediately: a failed game
spent 113.6s of its 137.6s town visit on a merc resurrect that failed.
- stealth decisions are tracked: afk_break (timed across the sleep), skip_run and
wrong_waypoint.
Bot.timeline() is a static entry point so utils/stealth.py and inventory/personal.py can
emit without importing Bot at module level (that would be circular). Both use a lazy
guarded import and it no-ops when no Bot is live. Item sells/stashes/drops now route
through it too, so they share the game/run counters and column widths instead of being a
separately formatted line.
Prefix moved TOWN> -> TL> now that it spans more than town.
Co-Authored-By: Claude Opus 5 <[email protected]>