fix(ecleanse.lic): v2.3.1 bound search attempts, validate room between searches, stop duplicate events - #2402
fix(ecleanse.lic): v2.3.1 bound search attempts, validate room between searches, stop duplicate events#2402mrhoribu wants to merge 3 commits into
Conversation
Updated version to 2.3.1 and added improvements for hive traps, including search and disarm attempts.
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
scripts/ecleanse.lic (1)
1550-1566: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winApply the same duplicate-event fix to the remaining push sites.
Lines 1559 and 1562 now use the correct
unless ... include?guard. Lines 1550, 1552, 1564, and 1566 still useEcleanse.data.event_stack << :sym && !Ecleanse.data.event_stack.include?(:sym). In that expression<<binds first, so the symbol is always pushed and the&&result is discarded. These four events can queue duplicates.🐛 Proposed fix for the remaining sites
- Ecleanse.data.event_stack << :sanctum_recover && !Ecleanse.data.event_stack.include?(:sanctum_recover) + Ecleanse.data.event_stack << :sanctum_recover unless Ecleanse.data.event_stack.include?(:sanctum_recover) elsif server =~ /The flesh around the wound feels hot and cold at the same time, heavy with infection./ - Ecleanse.data.event_stack << :use_vat && !Ecleanse.data.event_stack.include?(:use_vat) + Ecleanse.data.event_stack << :use_vat unless Ecleanse.data.event_stack.include?(:use_vat)- Ecleanse.data.event_stack << :itchy_curse && !Ecleanse.data.event_stack.include?(:itchy_curse) + Ecleanse.data.event_stack << :itchy_curse unless Ecleanse.data.event_stack.include?(:itchy_curse) elsif server =~ /^An unseen force entangles you, restricting your movement!\r?\n?$/ - Ecleanse.data.event_stack << :remove_web_bound && !Ecleanse.data.event_stack.include?(:remove_web_bound) + Ecleanse.data.event_stack << :remove_web_bound unless Ecleanse.data.event_stack.include?(:remove_web_bound)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/ecleanse.lic` around lines 1550 - 1566, Update the remaining event pushes in the server-message handling branches for :sanctum_recover, :use_vat, :itchy_curse, and :remove_web_bound to guard insertion with an unless event_stack.include? check. Preserve the existing event symbols and ensure each is appended only when not already present, matching the corrected hive-trap and recovery-event patterns.
🧹 Nitpick comments (2)
scripts/ecleanse.lic (2)
925-928: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider comparing room identity explicitly.
hive_trap_room?relies onRoominstance equality. Lich cachesRoomobjects, so this works for mapped rooms. For robustness, compare the room ids when both ids are present, and fall back to object equality only when an id is nil. This is optional.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/ecleanse.lic` around lines 925 - 928, Update the hive_trap_room? method to compare room ids when both the stored hive trap room and Room.current have non-nil ids, falling back to object equality only when either id is nil. Preserve the existing false result when no hive trap room is configured.
939-958: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueExtract the bounded disarm loop into a helper.
The disarm loop repeats the deadline, attempt counter, room check, and muckled check from
hive_search. Extract a shared bounded-command helper that takes the command, the result pattern, the success pattern, and the attempt limit. Both searches and disarms can then return the same status symbols. This is optional.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@scripts/ecleanse.lic` around lines 939 - 958, Optionally extract the repeated bounded command logic from the hive search and disarm flows into a shared helper, reusing the existing deadline, attempt-limit, room, and muckled checks. Have the helper accept the command, result pattern, success pattern, and attempt limit, and update both callers to return the same status symbols while preserving their current behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@scripts/ecleanse.lic`:
- Around line 902-921: Update hive_search so the result assigned to lines is
always an array by converting Util.get_command("search", hive_search_result)
with to_a. Preserve the existing response matching and retry behavior, allowing
nil results to fall through without raising.
---
Outside diff comments:
In `@scripts/ecleanse.lic`:
- Around line 1550-1566: Update the remaining event pushes in the server-message
handling branches for :sanctum_recover, :use_vat, :itchy_curse, and
:remove_web_bound to guard insertion with an unless event_stack.include? check.
Preserve the existing event symbols and ensure each is appended only when not
already present, matching the corrected hive-trap and recovery-event patterns.
---
Nitpick comments:
In `@scripts/ecleanse.lic`:
- Around line 925-928: Update the hive_trap_room? method to compare room ids
when both the stored hive trap room and Room.current have non-nil ids, falling
back to object equality only when either id is nil. Preserve the existing false
result when no hive trap room is configured.
- Around line 939-958: Optionally extract the repeated bounded command logic
from the hive search and disarm flows into a shared helper, reusing the existing
deadline, attempt-limit, room, and muckled checks. Have the helper accept the
command, result pattern, success pattern, and attempt limit, and update both
callers to return the same status symbols while preserving their current
behavior.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 29a6bd74-1821-4579-b1ab-00e8a10d42c7
📒 Files selected for processing (1)
scripts/ecleanse.lic
Summary
Hive apparatus and ground trap handling could search 30+ times over ~2.5 minutes with combat and support scripts paused, long after the trap had already resolved. The attempt cap of 10 was a symptom, not the cause: the loop's early-exit conditions were unreachable, and duplicate events multiplied whatever the cap allowed.
Root cause
1. The search loop's break conditions were dead code.
/d100: /is passed toLich::Util.issue_commandasstart_pattern.issue_commanddiscards every line before that pattern and returns[]when it times out (until (line = get) =~ start_pattern; end— lich-5lib/util/util.rb). Search outcomes that produce no roll —You don't find anything of interest here.,You can't see well enough to search around!— therefore came back as an empty array after burning the full 5s timeout. Both theFailure!retry and theSuccess/nothing-found break were unreachable in exactly the cases they were written for, leavingsearch_count >= 10as the only exit.2. The duplicate-event guard never worked.
<<binds tighter than&&, so this parses as(stack << sym) && (!stack.include?(sym)). The push is unconditional and the boolean is discarded.Observed in the wild (Kresh Warrens, 2026-08-05):
11:14:55— three matching ground-trap lines arrived in the same second, queuing three runs. 32 searches spanning11:14:55–11:17:24, withbigshot,volnrestoreand506-trog2paused the entire time (scripts_resumeonly fires onceevent_stackdrains). The first search had already cleared the trap:As you begin sifting through the churning earth, the creature within retreats deeper into the ground and the shifting silt goes still.10:15:15— 11 searches; blinded mid-loop, then knocked unconscious, still searching.Changes
Action.hive_search— single helper shared by both trap types, returning:found/:clear/:blind/:moved/:muckled/:exhausted/:timeoutso each caller decides what to do next. Removes the duplicated loop body.:movedthe moment we're somewhere else.dead? || muckled?.Status.muckled?covers webbed / dead / stunned / bound / sleeping, and notably not prone, so a knockdown from the trap itself won't abort the disarm.get_command's internal...wait N secondsretry re-issues the command without touching the caller's counter, which is how a cap of 10 became 12+ searches in the log.hive_search_result/hive_disarm_result—start_patternunions covering every observed outcome, so a non-rolled result exits on attempt one instead of timing out silently.already initialized constantnor pins the previous value until Lich restarts.Action.hive_trap_room?— requires a non-nil marker on both sides, closing the unmapped-room case wherenil == Room.currentread as a match, and compares room ids.Roomoverrides neither==noreql?, so the old comparison was object identity, which fails across aMap.loadthat rebuilds everyRoominstance in@@list.unless ... include?for all six guarded pushes::hive_traps_apparatus,:hive_traps_ground,:sanctum_recover,:use_vat,:itchy_curse,:remove_web_bound. The four unguarded:recoverpushes are left alone — they dedupe per-noun viarecover_stuffand a symbol-level guard would drop a second disarmed weapon.hive_trap_roomcleared once the trap resolves or we give up, so any queued duplicate no-ops; preserved on:moved/:muckledso the trap's next announcement can retry.Behavior
Failure!Verification
ruby -cclean.get_commandoutcomes: success first try → 1 search; nothing-found → 1; all failures → 3 and:exhausted; empty/timeout → 3; blinded →:blindat 1; stale marker →:movedwith 0 searches; nil marker or nilRoom.current→:moved; muckled →:muckledwith 0 searches; moved after the first search →:moved; same room id via a freshRoominstance →:found.Follow-up (not in this PR)
The search and disarm loops still share their guard scaffolding (deadline, attempt cap, room, muckled). Collapsing them into one parameterized helper needs an ordered pattern-to-symbol table, since search distinguishes
:blind/:clear/:foundand retries onFailure!while disarm has a single terminal pattern. Roughly 12 lines saved for a layer of indirection — worth doing only if a third trap type shows up.