fix: catch_pending race condition — hook clears flag, not the roll script

Previously the catch roll script wrote catch_pending=False to disk before
the Bash process exited. The PostToolUse hook fired after exit, saw False,
and could auto-resolve the encounter on the same run as the catch attempt.

Fix: the hook now owns the flag lifecycle.
- Hook clears catch_pending after consuming it (protects exactly one run)
- Roll script never touches catch_pending (no premature clear)
- On failure, flag stays True through the roll, cleared by hook afterward
- Next /buddymon catch call re-sets it at the top as before

Net effect: a failed catch attempt always gets one full clean Bash run of
grace before auto-resolve can fire again.
This commit is contained in:
pyr0ball 2026-04-05 23:58:08 -07:00
parent 910da843fe
commit c12a234652
2 changed files with 12 additions and 5 deletions

View file

@ -457,8 +457,13 @@ def main():
# resolving encounters before the user can react.
if output and not encounter_still_present(existing, output, catalog):
if existing.get("catch_pending"):
# User invoked /buddymon catch — hold the monster for them
pass
# User invoked /buddymon catch — hold the monster for this run.
# Clear the flag now so the NEXT clean run resumes normal behavior.
# The skill sets it again at the start of each /buddymon catch call.
existing["catch_pending"] = False
enc_data = load_json(BUDDYMON_DIR / "encounters.json")
enc_data["active_encounter"] = existing
save_json(BUDDYMON_DIR / "encounters.json", enc_data)
elif existing.get("wounded"):
# Wounded: 35% chance to flee per clean run (avg ~3 runs to escape)
if random.random() < 0.35:

View file

@ -298,8 +298,9 @@ if not buddy_id:
enc = encounters.get("active_encounter")
# Clear catch_pending before rolling (win or lose)
enc["catch_pending"] = False
# catch_pending is cleared by the PostToolUse hook after it fires on this
# Bash run — do NOT clear it here or the hook will see it already gone and
# may auto-resolve the encounter on the same run as the catch attempt.
buddy_data = (catalog.get("buddymon", {}).get(buddy_id)
or catalog.get("evolutions", {}).get(buddy_id) or {})
@ -339,7 +340,8 @@ if success:
json.dump(encounters, open(enc_file, "w"), indent=2)
print(f"caught:{xp}")
else:
# Save cleared catch_pending back on failure
# Leave catch_pending as-is — the PostToolUse hook clears it after this
# Bash run completes, giving one full clean run before auto-resolve resumes.
encounters["active_encounter"] = enc
json.dump(encounters, open(enc_file, "w"), indent=2)
print(f"failed:{int(catch_rate * 100)}")