From 85af20b6f17cb125e7bbd63fbc0c09425f8020b0 Mon Sep 17 00:00:00 2001 From: pyr0ball Date: Thu, 2 Apr 2026 22:40:38 -0700 Subject: [PATCH] feat: 6 control-flow bug monsters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit InfiniteWisp — while/until loops that never exit (KeyboardInterrupt, hung process) BoundsHound — off-by-one, IndexError, ArrayIndexOutOfBounds BranchGhost — wrong branch taken, unreachable/dead code, fallthrough SwitchTrap — unhandled case/switch arms, non-exhaustive match, missing default RecurseWraith — missing base case, RecursionError, StackOverflow CatchAll — broad exception handlers; rare, defeat=false (catch only) Total bug_monsters: 18 --- lib/catalog.json | 164 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/lib/catalog.json b/lib/catalog.json index 1f155ab..e061376 100644 --- a/lib/catalog.json +++ b/lib/catalog.json @@ -320,6 +320,170 @@ {"action": "add_documenting_comment", "strength_reduction": 10} ], "flavor": "Your model fit in VRAM yesterday. You added one layer." + }, + "InfiniteWisp": { + "id": "InfiniteWisp", + "display": "🌀 InfiniteWisp", + "type": "bug_monster", + "rarity": "common", + "base_strength": 30, + "xp_reward": 55, + "catchable": true, + "defeatable": true, + "description": "Spawned from a while loop with no exit. Runs forever. Eats your CPU. Doesn't know it's lost.", + "error_patterns": [ + "KeyboardInterrupt", + "Traceback.*KeyboardInterrupt", + "infinite loop", + "loop.*infinite", + "maximum iteration", + "process.*hung", + "timed out after" + ], + "weaken_actions": [ + {"action": "write_failing_test", "strength_reduction": 20}, + {"action": "isolate_reproduction", "strength_reduction": 30}, + {"action": "add_documenting_comment", "strength_reduction": 10} + ], + "flavor": "Your fan was always loud. You just never checked why." + }, + "BoundsHound": { + "id": "BoundsHound", + "display": "🐕 BoundsHound", + "type": "bug_monster", + "rarity": "common", + "base_strength": 25, + "xp_reward": 45, + "catchable": true, + "defeatable": true, + "description": "Lurks at the edge of every array. Patient. Knows you'll be off by one eventually.", + "error_patterns": [ + "IndexError", + "index out of range", + "list index out of range", + "ArrayIndexOutOfBoundsException", + "array index.*out of bounds", + "index.*out of bounds", + "subscript out of range", + "out of bounds access", + "RangeError.*index" + ], + "weaken_actions": [ + {"action": "write_failing_test", "strength_reduction": 25}, + {"action": "isolate_reproduction", "strength_reduction": 25}, + {"action": "add_documenting_comment", "strength_reduction": 10} + ], + "flavor": "It was always length minus one. You just forgot." + }, + "BranchGhost": { + "id": "BranchGhost", + "display": "🔀 BranchGhost", + "type": "bug_monster", + "rarity": "uncommon", + "base_strength": 40, + "xp_reward": 75, + "catchable": true, + "defeatable": true, + "description": "Lives in the else branch you swore would never execute. It executed.", + "error_patterns": [ + "unreachable code", + "dead code", + "branch.*never.*taken", + "always.*true", + "always.*false", + "condition.*always", + "else.*never", + "fallthrough" + ], + "weaken_actions": [ + {"action": "write_failing_test", "strength_reduction": 30}, + {"action": "isolate_reproduction", "strength_reduction": 20}, + {"action": "add_documenting_comment", "strength_reduction": 10} + ], + "flavor": "You were so sure that case was impossible." + }, + "SwitchTrap": { + "id": "SwitchTrap", + "display": "🪤 SwitchTrap", + "type": "bug_monster", + "rarity": "uncommon", + "base_strength": 35, + "xp_reward": 65, + "catchable": true, + "defeatable": true, + "description": "Hides in unhandled cases. Switch statements with no default. Match arms that never close. It found the gap.", + "error_patterns": [ + "fall.?through", + "missing.*case", + "unhandled.*case", + "no.*default", + "non-exhaustive.*pattern", + "MatchError", + "match.*non-exhaustive", + "switch.*not.*handled", + "Missing case for", + "Unhandled variant" + ], + "weaken_actions": [ + {"action": "write_failing_test", "strength_reduction": 25}, + {"action": "isolate_reproduction", "strength_reduction": 25}, + {"action": "add_documenting_comment", "strength_reduction": 10} + ], + "flavor": "You added that new enum value last week. The switch didn't notice." + }, + "RecurseWraith": { + "id": "RecurseWraith", + "display": "🌪️ RecurseWraith", + "type": "bug_monster", + "rarity": "uncommon", + "base_strength": 45, + "xp_reward": 85, + "catchable": true, + "defeatable": true, + "description": "The function that forgot to stop. Calls itself into oblivion. The base case was almost right.", + "error_patterns": [ + "RecursionError", + "maximum recursion depth", + "stack overflow", + "StackOverflowError", + "too much recursion", + "Maximum call stack size exceeded", + "infinite recursion", + "stack.*exhausted" + ], + "weaken_actions": [ + {"action": "write_failing_test", "strength_reduction": 25}, + {"action": "isolate_reproduction", "strength_reduction": 25}, + {"action": "add_documenting_comment", "strength_reduction": 10} + ], + "flavor": "The base case was there. It just couldn't be reached." + }, + "CatchAll": { + "id": "CatchAll", + "display": "🕳️ CatchAll", + "type": "bug_monster", + "rarity": "rare", + "base_strength": 60, + "xp_reward": 120, + "catchable": true, + "defeatable": false, + "description": "Born from broad exception handlers. Swallows errors whole. Cannot be defeated — only caught, by narrowing the catch.", + "error_patterns": [ + "except Exception", + "except:$", + "catch.*\\(Exception e\\)", + "catch.*\\(e\\).*\\{\\}", + "swallowed.*exception", + "error.*ignored", + "bare except", + "catch-all.*handler" + ], + "weaken_actions": [ + {"action": "write_failing_test", "strength_reduction": 30}, + {"action": "isolate_reproduction", "strength_reduction": 30}, + {"action": "add_documenting_comment", "strength_reduction": 15} + ], + "flavor": "If you catch everything, you learn nothing." } },