fix(stealth): roll the AFK break on the path a single-route rotation actually takes

afk_break fired 0 times in 9 games at a 50% test rate — odds of roughly 1 in
500, so not variance.

The four call sites added earlier all sit in on_end_run's town-return branches,
and with one route configured the bot never reaches them. After the run it goes
straight to end_game:

    Loot from run_pindle: ...
    TL> g8 r8 | game | end | ok
    Clicking SAVE_AND_EXIT ... End game. Elapsed time: 69.80s
    Starting game #9

No return_to_town or tp_town line appears anywhere in the log. Maintenance runs
at game START, not after the run, so those branches are dead code for this
configuration.

The roll now sits in on_end_game beside the scheduled-break check — the same
path that demonstrably works, since scheduled_break has fired and resumed.
Between games is also the right moment semantically: the game is closed, so
idling there is safe.

Worth recording why the guard missed it. The STEALTH> manifest reported
"afk_break 5% wired - 4 call sites" throughout, which was true and useless: a
call site EXISTING is not the same as a call site being REACHED. Static
reachability is not something the manifest can decide. The digest's "NEVER
FIRED" line is the check that actually catches this class, and it is why that
line exists.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
alexpolo1
2026-08-28 12:46:41 +02:00
parent 963b19dbe5
commit c8e63bc9fa
2 changed files with 35 additions and 0 deletions

View File

@@ -1201,6 +1201,20 @@ class Bot:
# time: a break at exactly 120 minutes every time is still a pattern,
# just a slower one than taking no break at all.
from utils.stealth import break_schedule, idle_drift
# Unscheduled AFK break, rolled BETWEEN GAMES.
#
# It used to live only in on_end_run's town-return branches. Those are
# never reached on a single-route rotation: after the run the bot goes
# straight to end_game (loot -> game|end -> save+exit -> next game), so
# all four call sites sat on dead code and afk_break fired 0 times in 9
# games at a 50% test rate — odds of about 1 in 500.
#
# The manifest reported "wired - 4 call sites" throughout, which was
# true and useless: a call site existing is not the same as a call site
# being REACHED. The digest's "NEVER FIRED" line is the check that
# actually catches this.
maybe_afk_break()
if self._next_break_after is None:
self._next_break_after, self._next_break_len = break_schedule()
if self._next_break_after:

View File

@@ -349,3 +349,24 @@ def test_pickup_skip_is_decided_once_per_item():
src = inspect.getsource(PickIt._should_walk_past)
assert "_stealth_skipped" in src, "skip decision is not memoised per item"
def test_afk_break_is_rolled_on_the_end_of_game_path():
"""The roll must sit where a single-route rotation actually goes.
It originally lived only in on_end_run's town-return branches. With one
route configured the bot never reaches them — after the run it goes straight
to end_game (loot -> game|end -> save+exit -> next game) — so afk_break
fired 0 times in 9 games at a 50% test rate, odds of roughly 1 in 500.
The manifest said "wired - 4 call sites" the whole time. That was true and
useless: a call site existing is not a call site being reached.
"""
import inspect
from bot import Bot
src = inspect.getsource(Bot.on_end_game)
assert "maybe_afk_break()" in src, (
"afk_break is not rolled on the end-of-game path, which is the only path "
"a single-route rotation takes"
)