24 Commits

Author SHA1 Message Date
Alex
3ed47ed822 fix: raise maintenance budget for cross-act routes; document Trav findings (#40)
Some checks are pending
CI / Install & Test (Windows) (push) Waiting to run
* fix: raise maintenance budget for cross-act routes; document Trav findings

Travincal leaves the character in Act 3, but maintenance relocates it to
Act 4 (stash at a4_tyrael_stash, repair at a4_halbu) and the next run then
needs the A3 waypoint again -- two cross-act waypoint trips per game.

That travel is not attributed to any timed step, so a FAIL> trail can show
~38s of work inside a 250s maintenance window. The 240s budget (tuned when
Pindle kept all town business in one act) was tripped 5 times in one
session, each costing a whole game. Raised to 420s.

Also documents, in HANDOVER.md:

- The open_wp failures are NOT a stale template. Scored a5_wp.png against
  all three real failure frames: 0.96-0.98 full-frame, but that match is
  the belt/mana-orb HUD false positive the a5.py comment already documents.
  Inside the real cut_skill_bar ROI it scores 0.436-0.480 against a 0.55
  threshold at scattered positions -- noise. The waypoint is genuinely not
  on screen; the character never reaches it. Recapturing would fix nothing.
  Scoring a template without the ROI the code actually uses produces a
  confident wrong answer.

- PR #39's pather abort is merged, live, and finally firing (1 abort in 21
  games, after being 0-for-152 while it looked correct).

- Keeping Trav town business in Act 3 is the real fix for both the timeouts
  and the waypoint failures. a3.py already reports can_buy_pots/can_heal/
  can_stash as True, so the Act 4 trip is not a missing capability.

- FoH vs hammerdin on the council, and the [fohdin]/[paladin] section trap:
  concentration and redemption lived in [fohdin], which hammerdin does not
  read, so both would have gone silently unbound after a respec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: post-mortem for the hell Travincal / hammerdin session

Narrative write-up of 29 Aug 2026: run_trav on hell, FoHdin -> hammerdin.

Outcome: health chickens 3-in-8 -> 0-in-11, battle 64-68s -> 41-60s,
failure rate 12% -> 9%, zero deaths throughout.

The document covers the four times the obvious answer was wrong:

1. Battle time did not move after the respec, which looked like failure.
   hammerdin.kill_council casts for a FIXED duration with no kill detection,
   so the clock cannot report damage -- loot proved the respec worked.

2. a5_wp.png scored 0.96-0.98 full-frame on every failure frame, which reads
   as "template fine, search broken". That match is the belt/mana-orb HUD
   false positive the a5.py comment already documents. Inside the real
   cut_skill_bar ROI it scores 0.436-0.480 against a 0.55 threshold at
   wandering positions -- noise. The waypoint was never on screen.

3. Ormus: not masked (4-channel but fully opaque, so no mask is passed), and
   not a threshold problem (in-ROI best 0.342, background level -- lowering
   the bar would recreate the Bug 4 false-positive clicks). A3 town has
   frames with ZERO pather landmarks over threshold, so the character never
   arrives. One cause, three symptoms.

4. Reverses this session's own earlier recommendation to move Trav town
   business into Act 3. That was reasoned from a3.py reporting can_buy_pots/
   can_heal/can_stash as True -- a capability check, not evidence about
   pathing. A3 is the worst-supported town in the project.

Also documents three settings that were live but inert: binds under [fohdin]
which hammerdin never reads, casting_frames=8 (unreachable -- a paladin's
fastest cast is 10 frames, so every cast was cut short), and repair_npc=
a5_larzuk, which Bug 12 set to keep repair in-act for Pindle but which forces
a cross-act trip on Trav (35.8s vs 9.0s).

And a caution on the key auto-detector: it reported the wrong stand_still
bind both before and after a live remap, consistent with a stale .keyo read.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* docs: correct stale hammerdin migration notes in HANDOVER (Codex review)

Addresses Codex feedback on PR #40: the handover still described the character
as needing conversion to hammerdin with both skills blank, while the same commit
verified type=hammerdin and concentration='f6' loading live.

The conflict was worse than reported. The stale "Two things only you can do"
section instructed the operator to rebind F7 -> Concentration, but F7 is
Battle Orders (CTA). Following it would have overwritten the CTA bind and cost a
large share of the life pool -- the exact problem this session was fixing.

- Replaces the migration paragraph with the verified end state, and records that
  Blessed Hammer lives on LEFT-CLICK, not an F-key (_cast_hammers puts the aura
  on the right slot, so a hammer hotkey would replace it).
- Notes that concentration/redemption had to move into [paladin]; under [fohdin]
  a hammerdin never reads them and both would be silently unbound.
- Adds the full verified bind map so F7 cannot be reassigned by mistake.
- Rewrites the operator TODOs: fire resist is superseded (Zaka + Mara took
  chickens 3-in-8 -> 0-in-11); the live items are lightning/poison resist and
  the 75% FCR breakpoint, with the casting_frames mapping (75%=11, 60%=12,
  <48%=13) so cast timing tracks any gear change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* feat: baal_xp farm — game browser join, hide-and-wait state, config

- src/ui/game_browser.py: retry-wrapped join flow (Play -> Join Game tab ->
  OCR game list -> click row -> loading/InGame confirm), wait_for_in_game
- src/bot.py: 'baal_xp' state + run_baal_xp/end_run transitions;
  on_run_baal_xp: fast_save_and_exit -> hero select -> join public game ->
  corpse/nopickup/pre_buff -> walk to hide spot -> wait loop (XP every 30s,
  HP check, death recovery, InGame-miss re-anchor) -> leave -> recover to
  own game; on_end_run short-circuit straight to maintenance
- src/config.py: [baal_xp] section (enabled, game_name_filter, max_wait_s,
  xp_threshold, min_hp_pct, hide_x/y, join_timeout_s) with profile overrides
- config/params.ini: [baal_xp] section, order=run_baal_xp, run_trav
- profile paladalla: order=run_baal_xp, run_trav (profile routes override
  base config — without this the route never activates)
- stealth: daily budget cap (persisted, restart-proof), buy at A4 Jamella
  from A3 too (Ormus measured unreliable), session budget 20h

* fix: import mouse in bot.py (baal_xp hide-spot click)

* feat(stealth): hard per-day runtime cap that survives restarts, and quit D2R

session_budget_h is per PROCESS. Every restart re-rolls it, so a bot that gets
restarted -- by the user, or by the restart-on-crash path -- can run all day and
never trip it. That is exactly the signal a runtime cap is meant to remove. It
also silently failed in practice: params.ini still carried the temporary
levelling value session_budget_h = 20, which rolls 13-27h, so the live config
could not stop the bot within a day at all. Restored to 8.

Adds daily_budget_h, keyed on the CALENDAR DATE and persisted to
log/.daily_runtime.json, so restarts cannot hand out a fresh allowance.

Design points that matter:

- The rolled target is stored WITH the date. Re-rolling per process would make
  restarting a way to draw a bigger budget; once a day's target is chosen it is
  fixed until the date changes.
- Jitter subtracts ONLY. daily_budget_h is a ceiling, not an average: a
  two-sided roll on 8h could hand out 9h, which is not what "cap it at 8 hours"
  means. 8 with 0.12 jitter now runs 7.0-8.0h and never more. Verified over 300
  rolls: min 7.04h, max exactly 8.00h.
- Time before the first tick in a process is not counted, so a crash
  under-counts rather than over-counts -- the safe direction for a cap.

Also closes D2R when the cap trips (daily_budget_close_game, default on). The
check runs in on_end_game AFTER save-and-exit, so the character is at the menu
with nothing in progress and nothing is lost -- this is not the mid-game force
kill that leaves D2R unenterable. A bot parked at character select for 16h is
itself the pattern the cap exists to remove; a real player quits the game.

The stealth manifest reports daily_budget by checking the CALL SITE in bot.py,
not just the config value -- the lesson from chicken_variance and the AFK break
that was 0-for-225 while the manifest said "wired".

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: alexpolo1 <alex@alexpolo1.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 10:13:46 +02:00
alexpolo1
831e0d9319 docs: refresh post-mortem commit hashes after the pre-PR history rewrite
The webhook scrub rewrote the 18 stable-only commits, so the hashes quoted in the
post-mortem no longer resolved. Updated, and the rewrite itself is noted inline so the
change of hashes is not a mystery later.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 19:10:46 +02:00
alexpolo1
489f779849 merge: bring origin/main into stable ahead of the PR
main carried 19 commits of separate feature work (baal_xp, cold_plains, melee_hunt,
launch/tools) while stable carried the run_pindle repair. One real conflict, in
_run_wrapper, where both branches added a line at the same point:

    stable      self.tl("run", "approach", "start")   <- run timeline
    origin/main self._current_run = run_obj           <- baal_xp run tracking

Independent, so both are kept. config/params.ini and src/config.py auto-merged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 19:10:19 +02:00
alexpolo1
402c768fc8 docs: add the run_pindle post-mortem (26-27 Aug 2026)
Narrative record of the incident: failure rate 100% -> ~8%, character 32 -> 69, cycle time
185-250s -> ~52s across 17 commits. CLAUDE.md already carries the per-bug detail as Bugs
23-30; this is the part that does not fit a bug entry — the order things happened in, why
the silent failures cost far more than the loud ones, and the four times my own obvious
answer was wrong.

Two files:
  docs/postmortem_pindle_2026-08-27.md    canonical, diffable
  docs/postmortems/pindle-2026-08-27.html source of the published artifact, kept in-repo
                                          so it survives the scratchpad and stays editable

The corrections section is the reason this is worth committing rather than leaving as a
list of fixes. Each wrong turn looked correct in isolation:
  - the red-portal guard: the portal renders on BOTH sides, so "portal visible => still in
    town" blocked every genuine entry
  - XP as proof of a boss kill: it only proves something died (minions, merc kills)
  - "the template is degenerate": the Qual-Kehk asset scored 1.000 against a frame where
    the tag actually renders; the THRESHOLD was wrong
  - selling the charms: 673 blocked-sell lines were the guard working, not a clog, and
    disabling it vendored five resistance charms

Also records the durable lesson: every one of these cost hours because the log held events
rather than structure. That is what the TL>/FAIL>/digest instrumentation exists to fix.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 19:03:26 +02:00
alexpolo1
c26f249268 fix(input): snap cursor to exact target before click (SetCursorPos can land 1-2px off)
D2R UI hitboxes are tight; a 1px offset on the Join Game tab click was
enough to miss the button. Final SetCursorPos pass after the existing
verification check.
2026-08-25 00:26:44 +02:00
alexpolo1
c04c60ead7 release: v0.9.1 — production cleanup
- Restore FIRST-RUN.md onboarding guide
- Pin environment.yml to requirements.txt (was loose 24 packages)
- Remove debug screenshots from git (debug_*.png -> .gitignore)
- Remove .hermes/ dev plans from git (already in .gitignore)
- Archive botty_next/ test harness to alexpolo1/my-botty-tools
- Archive docs/legacy-go/ to alexpolo1/my-botty-tools
- Move 14 dev tools from repo root to tools/ directory
- Extend .gitignore to prevent dev artifacts re-entering root
- Promote stable branch with all bug fixes from main
- Bump version 0.8.4 -> 0.9.1
2026-08-08 09:59:31 +02:00
alexpolo1
6012934e66 Add chipped gem conversion runner 2026-06-21 16:06:58 +02:00
alex
594d633787 Fix D2R window sizing and input targeting 2026-06-07 19:00:15 +02:00
alex
7bd9d01023 docs: note Diablo template logging helper 2026-06-07 17:53:37 +02:00
alex
45fa775a2e fix: verify Diablo waypoint recovery 2026-06-07 17:52:55 +02:00
alex
f705091991 Send error message + screenshot to Discord on run failures
Adds Messenger.send_error across the Discord (red embed with screenshot attached)
and generic (text-only) APIs. Bot._save_error_screenshot now also pushes the
failure to the configured messenger after saving the screenshot to disk, so each
approach/battle/exception failure is reviewable in Discord with the visual.

Gated by new config discord_log_errors ([general], default 1) and the
[discord_events] error toggle. Both optional/backward-compatible. Verified wiring
and the suppression path via a stubbed messenger.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:55:41 +02:00
alex
8cf152cfb4 Stop bot cleanly when all routes are disabled
When every run has been auto-disabled there are no routes left to run, so save a
session report and shut down via safe_exit() instead of calling restart_or_exit
(which would needlessly restart D2R into empty games when restart_d2r_when_stuck
is enabled).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:52:22 +02:00
alex
af43051b22 Auto-disable runs after repeated failures + save error screenshots
Recovery: each run now has its own consecutive-failure counter. After
disable_run_after_failures (default 5) consecutive failures, that single run is
disabled for the rest of the session and the bot keeps doing the other runs
instead of stopping. A success resets the counter. If every run is disabled the
bot stops for investigation. Disable is in-memory only (restart re-enables).

Diagnostics: on every run failure (approach, battle, or exception) the bot saves
a timestamped screenshot to log/screenshots/error/ named with the run, reason,
and game/run counters so logs and visuals can be cross-referenced. Gated by the
new error_screenshots config (falls back to info_screenshots). The error/ dir is
routed through log rotation.

Adds config keys error_screenshots and disable_run_after_failures (both optional,
backward compatible) and docs/recovery_and_error_logging.md. Verified bot startup,
config parsing, Bot construction, the disable/reset logic, and screenshot writing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-07 15:49:44 +02:00
alex
6c8da72bf4 fix: weapon swap verification, health pot selling, town healing, pickup drought alert
- i_char.py: rewrite _pre_buff_cta() to verify each weapon switch via BC
  skill-bar template; detects wrong slot on game start (leftover from
  interrupted buff cycle), retries failed switches once, logs clearly
  when stuck on CTA slot to prevent dying with wrong weapon in combat

- personal.py: protect needed consumables from sell/drop in inspect_items;
  check get_needs() before marking a pot for discard — if the belt needs
  that pot type, skip it so fill_up_belt_from_inventory can restock later

- bot.py: add fill_up_belt_from_inventory + update_pot_needs after
  buy_consumables so inventory pots reach the belt even when out of gold;
  add town-heal loop at start of on_maintenance to drink health/rejuv pots
  until HP >= 95% before the next run (health manager is paused in town)

- game_stats.py: add rolling 10-game pickup health check; warns in log and
  sends Discord alert when zero item pickups occur across 10 games while
  chickens or merc deaths are present

- params.ini: fix show_belt=n -> show_belt=k (belt key was wrong, causing
  1.5s wasted recovery attempt every first game in a session)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-05 16:36:07 +02:00
alex
77f2092572 Refactor bot behavior on TP failure, enhance item processing logic, and improve game stats logging
- Updated bot behavior to end the game when no TP charges are left, instead of attempting to walk back to town.
- Refined item processing logic in `processing_helpers.py` to use identity checks for item comparisons and improved item removal methods.
- Enhanced game stats logging to include failure reasons and send Discord notifications for failed games.
- Improved health management logic to trigger chicken behavior based on health percentage after rapid rejuvination.
- Added error handling for item pickup failures in `pickit.py` to blacklist items that cannot be picked up.
- Introduced walking fallback nodes for Countess, Andariel, Mephisto, and Baal runs in `pather.py`.
- Implemented path data validation in run scripts for Countess, Andariel, Mephisto, and Baal to ensure paths are correctly defined.
- Enhanced item identification and stash processes in `diablo.py` with retry logic for failures.
- Updated town management to handle identification failures gracefully and log appropriate warnings.
- Improved character selection logic to provide clearer logging messages.
- Modified game restart logic to launch the game via PowerShell for better session handling.
- Added documentation for recording paths for the Countess run and created a PowerShell script for scheduled task management.
2026-06-05 14:58:50 +02:00
alex
4c88c7204f docs: add plan for broken runs - missing coords and templates 2026-06-03 23:28:38 +02:00
alex
19f4b8a553 Harden offline FG parser and add d2jsp collection tooling 2026-05-26 13:04:28 +02:00
alex
3888cc9666 Fix status XP/level math, env refs, and potion tier fallback 2026-05-26 11:36:58 +02:00
alex
055cd4fdf1 Expand cows route plan with screenshot and coordinate SOP 2026-05-26 09:53:13 +02:00
alex
64349a988d Add Hermes (Qwen) Botty takeover development/testing guide 2026-05-26 08:49:06 +02:00
alex
e54bb64d03 Add phased Linux port plan documentation 2026-05-26 08:19:07 +02:00
alex
dd45386579 Improve config docs and harden discord+difficulty parsing 2026-05-25 14:10:54 +02:00
Alex
15a90bfd47 feat: add route scaffolding tool and contributor guide 2026-05-17 15:22:24 +02:00
Alex
81ee6557f4 feat: add route scaffolder CLI, smoke tests, stealth docs 2026-05-17 13:26:31 +02:00