activeOmen() is a pure function of the UTC ISO (year, week): omenTable
indexed by (year*53+week)%len, so it advances weekly with no schema, no
ticker state, no persistence. Five non-combat seams read it — harvest yield,
supply freebie, expedition start mood, arena payout (scales gross earnings
before the pot tax), and ingredient drop chance. TwinBee reveals the active
omen in the existing morning DM (no net-new scheduled message).
Launch set is buffs-with-texture on non-combat levers only: Bountiful
Harvest, Quartermaster's Blessing, Golden Purse, Overflowing Satchels, Still
Waters. Nothing touches SimulateCombat or the turn engine — the omen is keyed
on the real clock, so a combat mutator would make the golden and the balance
corpus week-dependent. The plan's "elites +2 ATK" is deliberately dropped for
that reason.
The balance sim drives the real expedition loop and would otherwise traverse
all five seams, making corpus sweeps depend on the wall-clock week. NewSimRunner
sets simOmenDisabled (mirrors simAutoArmEnabled), so activeOmen returns a
no-effect omen under the sim. Still Waters subtracts from the daily threat
*rise* only, floored at hold-steady — it never forces active decay.
Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
Overflow XP that grantDnDXP used to drop at L20 now accumulates as Renown
on player_meta.renown_xp (cumulative, atomic +=; renown_level derived as
renown_xp/25000). The reward is prestige-only: a derived rank ladder
(Renowned→…→Eternal), a cosmetic ✦N marker on the sheet and leaderboard,
a games-room shout on rank promotion, and !level progress once capped.
Renown perks are the two combat-neutral economy levers only — +loot / +XP,
capped at a streak-30 grant's economic half (+15% / +20%). combat_stats.go
reads DeathModifier/SuccessBonus/ExceptionalBonus (which map to Defense/
Attack/CritRate) but never LootQuality/XPMultiplier, so renown pays out even
through loadCombatBonuses without moving the golden or the balance corpus.
The plan's "-death penalty" perk is deliberately dropped (it would inflate
Defense).
The overflow→renown conversion and the character save commit in one
transaction (saveDnDCharacterExec now takes an executor), so a crash can
neither drop the overflow nor double-credit it on the next grant.
Schema: renown_xp column, DEFAULT 0 correct for every existing row, no
bootstrap (journal_pages/epilogue_cleared pattern).
Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
Turn the dead top housing tiers into something worth buying. All three
land without a schema bump, and TestCombatCharacterization stays
byte-identical (the balance corpus never sets the new fields).
T3 trophy room: treasure cap 3->4 at HouseTier>=3 (maxTreasuresForTier).
Enforced at the save gate only -- HouseTier is never written downward,
so a held 4th treasure below tier 3 is unreachable and a load-time cap in
computeAdvBonuses would just add a query for an impossible state. The
all-irreplaceable manual discard prompt now lists the 4th slot too.
T3 workshop: +5% craft success at HouseTier>=3, lifting the cap 0.95->0.98
so a maxed forager still gains. craftingSuccessRate takes a workshopBonus,
threaded through autoCraftConsumables and renderRecipesKnown.
Well-rested buff (replaces the plan's T4 "inn-quality rest", a verified
no-op -- home rest already equals inn rest). Home-only (the inn and a
tier-1 shack grant nothing), starts at T2 and grows through T4, expires at
the next long rest:
- Temp HP cushion (8/12/16% of MaxHP). TempHP was a dormant field; wired
into applyDnDHPScaling as MaxHP headroom -- additive and golden-safe.
- Bonus spell slots (+1/+2/+3 at the caster's highest slot level), the
real reward, lifting casters who trail on spell-pool richness.
applyLongRestSpellSlots resets the pool to base then folds in the
bonus; expiry is stateless (next rest's reset drops it).
Magnitudes are tunable defaults; revisit against the post-parties
re-baseline.
Claude-Session: https://claude.ai/code/session_017mEwUmmS7aQTP2NQXj6rUa
Mechanical `gofmt -w ./internal ./cmd`. Mostly struct-field realignment that
had drifted, plus a few trailing-newline fixes. No behaviour change — gofmt is
semantics-preserving, and build/vet/test are green either side.
Split out from the code-review fixes that follow so those stay reviewable
instead of hiding inside a wall of realignment.
Removes !forage / !mine / !scavenge / !fish / !essence / !commune from
the command surface. Typing one now returns a one-line deprecation DM
pointing at the auto-harvest flow ("Harvest is automatic now — just
walk."). The internal handleHarvestCmd / handleStandaloneHarvest paths
are left in place; operator deletes after soak per plan §H3.
Help text and the supplies-low autopilot pause line no longer mention
the manual verbs.
Tedium-removal pass driven by live play feedback. Three big threads:
Expedition autopilot Phase 4 — background auto-run + harvest-until-dry:
- New expeditionAutoRunTicker walks active expeditions every 15min
(5min tick, per-expedition CAS on new last_autorun_at column). Skips
combat sessions, briefing/recap quiet windows, expeditions <30min old.
- Walks up to 3 rooms/tick with compact narration; suppresses DMs when
0 rooms walked or just hitting the per-tick cap (no "stretch complete"
filler). Player only hears from the bot when a real decision is needed.
- Compact mode: one-line combat narration for trash/elite, auto-resolves
elite doorways via the forward-sim engine (boss still pauses). Threaded
via new advanceOnceWithOpts → resolveRoom → resolveCombatRoom.
- Auto-harvest now grinds each Common/Uncommon node until dry (cap at 8
attempts/visit), mirroring manual !scavenge retries. Rare+ still pauses.
- Ambient ticker: anti-repeat by Kind via new last_ambient_kind column
(avoids two pack_rat DMs in a row when the pool only has 6 lines).
- !expedition go <n> now routes to the fork-choice handler when active +
numeric; fork footer rewritten to suggest !expedition go instead of
!zone go. Boss/Elite doorway: formatNextRoomMessage routes the action
hint by next room type and autopilot loop breaks via new nextRoomType
field so "Room X/Y — Boss" doesn't double-print with contradictory
hints (!zone advance vs !fight).
- runAutopilotWalk extracted from expeditionCmdRun so foreground and
background share the loop body.
Rogue Sneak Attack actually exists now:
- Audit found the rogue's "Sneak Attack" passive was AutoCritFirst +
5% damage rider. No Nd6, ever. Phase 2 Monte Carlo masked this
with a small flat buff; the class's defining mechanic never matched
its tooltip or 5e identity.
- Added SneakAttackDie int to CombatModifiers, per-hit Nd6 in
combat_primitives.go (same lane as DivineStrikePerHit). Scales with
level: 1d6 at L1-2 ... 4d6 at L7-8 ... capped at 10d6 at L19-20.
- AutoCritFirst + 5% rider retained as bonuses on top of working sneak
attack — preserves the opener-burst feel.
- L7 rogue expected per-hit ~8 → ~22 damage. Valdris fight math goes
from "16 rounds to kill, die in 8" to winnable.
TwinBee voice sweep (Phase B3):
- ~530 line changes across 24 files replacing third-person "TwinBee
notes/files/tracks/respects/..." constructions with first-person
inside flavor string literals. Code identifiers (TwinBeeLine,
twinBeeLine, etc.), chat-prefix labels (🎭 **TwinBee:**), item names
(TwinBee's Bell), achievements, and game-title references in
fun.go (Konami TwinBee ship) left intact.
- Catches a real bug: Valdris fight rendered "TwinBee marks the
Legendary Resistance" mid-combat in third person, contradicting
the Phase B2 convention.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bundle of uncommitted working-tree edits across combat engine, expedition
cycle, flavor pools, and TwinBee/zone narration. Includes new files:
combat_debug.go, dnd_boss_consumables.go, dnd_dex_floor.go, plus
CHANGES_24H.md and REBALANCE_NOTES.md scratch notes.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two longstanding warts surfaced when the user inspected today's TwinBee
daily report:
1. Active players were rendering "Acted today — no log recorded." The
adventure_activity_log path only captures !rest now; harvest/zone/
expedition action logging was lost during Phase R/L migration. The
stale HasActedToday() check fired on fossil harvest_actions_used
counters that nothing modern increments.
2. Per-player headline still rendered legacy four-skill line ("Combat
Lv.X | Mining Lv.Y | Forage Lv.Z | Fishing Lv.W"). No D&D level,
race, class, or HP — discoverability gap for the layer that's now
canonical.
Fix both:
- adventure_activity_unified.go: new loadAdvDailyActivity(date) unions
dnd_zone_run (zone runs touched today) + dnd_expedition_log
(expedition activity rolled up per expedition) + legacy
adventure_activity_log (mostly !rest). One source of truth.
- adventure_render.go: AdvPlayerDaySummary gains HasDnDChar/DnDLevel/
DnDRace/DnDClass/HPCurrent/HPMax. New advPlayerHeadline helper
renders "Lv.N Race Class — HP cur/max" when a dnd_character row
exists, falls back to the legacy four-skill line plus an inline
"(no D&D sheet — run !setup)" nudge for accounts that haven't
completed setup yet. titleizeDnDToken("half_elf") → "Half-Elf".
- adventure_scheduler.go: postDailySummary swaps loadAdvLogsForDate
for loadAdvDailyActivity. IsResting now derives from "len(acts)==0"
rather than the fossil HasActedToday() counter check, so dead
harvest_actions_used bytes can't trip the active-player branch.
- proddb_daily_report_test.go: renders the report against a copy of
data/gogobee.db and prints it for visual confirmation. Verified
output for 2026-05-09 shows real zone-run outcomes (Withdrew from
Sunken Temple at room 1/6, etc.) instead of the previous "no log
recorded" placeholder.
go vet + go test ./... clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Swap all char.DisplayName / c.DisplayName reader sites in
internal/plugin/ to loadDisplayName(userID). Touches 12 files
across combat (combat_bridge, dnd_zone_combat, dnd_zone_cmd,
dnd_expedition_combat), arena, hospital, events, render,
masterwork, robbie, scheduler, and adventure.go.
Only intentional char.DisplayName references remaining are in
adventure_character.go (scan + save + dual-write) and the
player_meta.go doc comment. go vet + go test ./internal/plugin/...
clean.
Unblocks deferred L2 step 9 (arena AdvCharacter import drop)
once L4 hospital/pets/render also lands.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drop the coop_dungeon system per migration plan §5. 11 coop_*.go files
removed; cleanup_l3.go added with an idempotent per-run status-guarded
UPDATE that cancels any open/active runs and refunds member contributions
plus unsettled bets via EuroPlugin.Credit. Tables retained for now;
schema purge deferred to a future GOGOBEE_COOP_PURGE pass.
adventure.go drops !coop dispatch, coopTicker, the startup combat-lock
hook, and the !coop help line. adventure_scheduler.go loses the
activeCoopMemberSet skip branch and the post-reset combat-lock call.
adventure_render.go drops the teaser plus the in-coop status block;
replaced with a one-week morning-DM closure announcement
(TODO: remove after 2026-05-16). TestPickCoopTeaserCandidate_SkipsLeader
removed.
go vet ./... and go test ./... clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Babysit pivots from harvest service to pet-care + safe-rest perk:
- runBabysitDaily/runAutoBabysitDay/runBabysitAction deleted; replaced
by runBabysitDailyTrickle (3 pet XP/day while subscribed).
- BabysitSafeRest predicate promotes Standard camps to Fortified-tier
rest (HP+1d6, threat -5, resources refresh) and reduces wandering
monster check campMod from 0 to -4. Hooks live in
dnd_expedition_camp.go and dnd_expedition_night.go.
- !adventure babysit auto/focus subcommands removed; status/purchase
DMs reflect the new perks.
Scheduler drops the auto-babysit fallback block (no more silent
debits + harvest-day for missed logins). Babysit subscribers still
skip the morning DM; trickle runs in the background.
TwinBee daily simulator self-contained: simulateTwinBeeOutcome +
simulateTwinBeeLoot replace the resolveAdvAction call against a
fake CombatLevel=35 character. Outcome distribution and reward
shape preserved; gold-share to active players unchanged.
Legacy activity resolver retired: resolveAdvAction,
advEligibleLocations, AdvEligibleLocation, resolveAdvEmptyOutcome
deleted from adventure_activities.go (zero production callers
post-babysit/twinbee). AdvActionResult kept — combat_bridge still
produces it for arena/dungeon flows; dies in L2/L3.
Migration plan doc gogobee_legacy_migration.md added: five-phase
L1-L5 plan covering arena (Adv 2.0 boss flow rebuild), co-op
deletion, perk-gate sweep, and final teardown of AdventureCharacter
+ CombatLevel + combat_engine.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Retires the standalone !adventure dungeon/mine/forage/fish daily loop in
favor of !expedition. Gate intercepts legacy 1/2/3/4 + word-form input
and DMs a deprecation notice; town services (shop/blacksmith/rest/thom)
stay on !adventure.
- Delete dead resolveActivity (269 lines) + parseActivityLocation; add
isLegacyActivityInput + renderLegacyActivityDeprecation.
- Morning-DM menu rewritten to point at !expedition and the !forage etc.
harvest commands; writeAdvLocationLines removed (sole caller).
- New dnd_r1_migration.go runs archiveOrphanZoneRuns at Init: archives
any active dnd_zone_run not linked to an active expedition (via
exp.run_id or region_state.region_runs). Idempotent.
- Pre-existing flake in TestPickEveningRecap_BossOverridesAll fixed
(E6c pool added entries without literal "boss"; widen substring set).
- Internal helpers (resolveAdvAction, advEligibleLocations, AdvLocation
tier data, consumable drops) preserved — babysit/scheduler still use
them passively.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Adventure characters now record DeathSource ("adventure"|"arena") and
DeathLocation when killed. Threaded through Kill() and transitionDeath.
Daily report uses the recorded death location instead of misattributing
arena deaths to the day's adventure log: when DeathSource != "adventure",
the adventure block shows the alive icon and a separate "Later fell in
{location}." line. Standout-loss flavor uses DeathLocation. Empty
DeathSource (legacy rows) falls back to current behavior.
- calcDamage applies a ±15% per-hit jitter, so successive hits in a phase
no longer produce identical numbers. Previously every hit in a phase was
flat (e.g. 17, 17, 17, 17) and mirror-symmetric between player/enemy,
reading as scripted.
- assessThreat rewritten to use the engine's actual penetration formula:
damage-per-round each direction, then rounds-to-kill ratio. The old
additive HP+Attack*3 model ignored Defense, so even fights could be
rated trivial — players died after consumables were skipped with the
"threat assessed as manageable" message.
- SelectConsumables never skips on trivial when arenaRound > 0. Arena
losses cost real money and equipment, so the cost of a wrong assessment
is too high to gamble on; adventure-side fights still skip trivial
threats to avoid wasting items on chump enemies.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Status sheet now shows lifetime craft count + a hint pointing at
!adventure recipes (only displayed once the player has crafted at
least once — keeps the line absent for non-foragers).
- README gains a Crafting subsection documenting the auto-craft flow,
XP rewards, level gates, the recipes command, and the consumable
protection (Robbie + sell-all both skip them).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Players in a co-op were getting their combat action back every midnight
reset and offered the dungeon option in the morning DM. Per spec they
should be "off in the Co-op" and unable to also solo-grind dungeons.
Fix at the DB layer (so all CanDoCombat() paths agree):
- New helper lockCoopCombatActions() sets combat_actions_used=99 for any
user in an active coop run. Called immediately after every
resetAllAdvDailyActions() — at startup and at midnight.
- Render layer: morning DM now shows "combat locked (in Co-op #N, day
X/Y)" and replaces the dungeon section with an explanatory line
pointing them at !coop status.
Combat returns to normal automatically once the run completes/wipes —
the next midnight reset finds status != 'active' and skips the lock.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replaces the single-roll probability system for dungeon and arena combat with
a multi-phase simulation engine where gear, buffs, pets, and NPCs are meaningful
mechanical inputs. Adds consumable items (auto-crafted from forage/mine/fish drops),
monster abilities for T2+ enemies, and Dragon Quest-style combat narrative with
phased message delivery.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Part 3 (Housing, Thom Krooke & Pets):
- Housing system with tiered upgrades, mortgage loans, FRED API rates
- Thom Krooke realtor NPC with !thom commands and !thom pay extra principal
- Pet system with arrival, naming, leveling, combat, morning defense
- Pet ditch recovery scales with level, name validation
Wordle overhaul:
- Remove daily expiration — puzzles persist until solved/failed
- Auto-start new puzzle after solve, fail, or skip
- Sequential puzzle IDs instead of date-based
- Auto-create puzzle on first guess if none active
Adventure fixes:
- Double XP/money boost toggle (!adv boost, admin only)
- Fix ensureCharacter wiping existing data on query errors
- Fix rival RPS format string bug
- Fix daily summary empty data (load today+yesterday logs)
- Fix holdem DM-to-room reply routing
- Fix Robbie payout to 25% of item value
- Add fishing to leaderboard and TwinBee calculations
- Add Thom to morning menu
- Persist mortgage rate across restarts via db.CacheGet/Set
Infrastructure:
- Daily database backup via VACUUM INTO with 7-day retention
- Admin DM notification on backup failure (async)
- Daily NPC house balance reset for holdem
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Character sheet now checks isHolidayToday() for correct remaining
action counts on holidays
- Remove renderAdvHolidaySecondPrompt (dead code after economy split)
and its test
- Babysit harvest counter clamped to max to prevent exceeding budget
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Action economy: replace single daily action with 1 combat + 3 harvest
actions per day. Holidays grant +1 to each bucket. Rest consumes all
remaining actions. Arena remains outside both buckets.
- Add CombatActionsUsed/HarvestActionsUsed counters to AdventureCharacter
- Add CanDoCombat/CanDoHarvest/AllActionsUsed/HasActedToday helpers
- Update all 14 ActionTakenToday check sites across adventure, scheduler,
babysit, twinbee, events, and render
- Morning DM shows action budget and grays out exhausted categories
- Activity resolution checks per-bucket availability before proceeding
- Midnight reset zeros both counters
- Post-action nudge shows remaining actions instead of holiday prompt
Cross-plugin lookup: export XPPlugin.GetLevel(), wire into AdventurePlugin
via p.chatLevel(userID) for upcoming chat level perks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- St. Guildmore's Memorial Hospital: !hospital command with Nurse Joy,
procedural itemized billing, same-day revival, 6-hour dead timer,
hospital ad after death, 2-hour nudge follow-up
- Robbie the Friendly Bandit: automated inventory cleaner, random daily
visits (8-21 UTC, 40% chance), collects sub-tier gear at €50/item,
donates to community pot, drops Get Out of Medical Debt Free card
- Fix MW auto-equip: T1 MW no longer replaces better equipped gear
- Fix shop MW block: allow purchasing upgrades over lower-tier MW
- Float64 equipment scoring: advEffectiveTier and advEquipmentScore
return float64, no mid-calculation truncation (MW 1.25x, Arena 1.5x)
- Fix markdown rendering: convert *asterisk* to _underscore_ italics
across all flavor text files (shop, blacksmith, rival, hospital)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Blacksmith: equipment repair with tier-based pricing, DM confirmation flow,
masterwork/arena surcharges, full flavor text pools. Added to main adventure
menu as option 6 (rest bumped to 7).
Lottery: weekly draw (Friday 23:59 UTC), ticket purchases with 100/week cap,
Fisher-Yates number generation, fixed+jackpot prize tiers, community pot
funding, Thursday reminders, draw history.
Audit fixes: TOCTOU in blacksmith repair costs (recompute from fresh equipment),
user lock in DM slot selection, partial repair refund tracking, error logging
on save failures, Fisher-Yates bias correction, communityPotDebit return value
checks in draw execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rival System:
- RPS-based duels between combat level 5+ players (best of 3, ties re-prompt)
- Stakes scale with level, split 50/50 between winner and community pot
- 3-4 day randomized challenge interval, 7-day same-pair cooldown
- 24h response window with auto-forfeit
- Full flavor text pools, character sheet integration, !adventure rivals
Babysitting Service:
- Weekly/monthly auto-play service targeting weakest skill
- Babysitter rerolls death, claims items, credits gold and XP
- Rivals automatically declined during service
- End-of-service summary with diaper report
Revive fixes:
- On-demand revive in handleMenu, parseAndResolveChoice, handleStatus
- Morning DM respawn check now runs before babysit interception
- Players no longer stuck dead after DeadUntil expires mid-day
Other changes:
- Multilingual !define searches all DreamDict languages by default
- TwinBee empty haul now shows "jackshit" instead of blank
- Wordle solve payouts increased (e.g. 1-guess: €100 -> €500)
- Per-message euro payouts doubled across all tiers
- Audit fixes: user locks on RPS/babysit handlers, TOCTOU on gold
transfers, dead code removal, deprecated strings.Title replaced,
error logging on silent failures
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Adventure — Masterwork Rework:
- Expand from 3 generic items to 15 tiered masterwork items across
mining (weapon), fishing (armor), and foraging (boots) with per-tier
drop rates (5%/4%/3%/2%/1.5%) and location gating
- Skill-specific cross-skill bonuses replace flat masterwork check
- Auto-equip if better, silent discard for duplicates, inventory for rest
- Add !adventure equip command for manual masterwork equipping
- Tiered room announcements: T1-2 DM only, T3 quiet, T4-5 full
- First-drop detection with special message
- Character sheet shows ⭐/⚔️ markers for masterwork/arena gear
- Sell protection for special gear in shop
Adventure — Arena Combat Log:
- Turn-based Dragon Quest style narrative for arena fights
- Outcome-first design: roll determines win/loss, log assembled backward
- No-repeat flavor text via actionPicker with per-pool tracking
- 60 participation XP on arena loss
Adventure — Death's Reprieve Fix:
- All equipment set to 1 condition instead of death-level degradation
Wordle:
- Refactored word sourcing and expanded fallback word list
- Simplified Wordnik integration
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Market plugin (#49): daily index snapshots (Yahoo Finance + Finnhub fallback),
Ollama-generated summaries, !howsthemarket, !marketstatus, !marketreport commands,
exchange hours with DST support, 30-min room cooldown
- Adventure arena: 5-tier combat gauntlet with 20 monsters, risk-reward cashout,
death lockout changed from 24h to midnight UTC across all code and flavor text
- Adventure holidays: double daily actions on holidays
- Adventure DM fix: 15-minute response window prevents bare numbers from triggering
adventure during UNO games
- Adventure scheduler: jitter between morning DMs to avoid Matrix rate limits
- Adventure revive: wire up adv_revived achievement on admin revive
- Column migration system for existing databases (holiday_action_taken)
- Fix italic markdown rendering after newlines
- Fix holdem DMs broken by space groups including DM rooms
- UNO No Mercy: remove stacking escalation rule (any draw card stacks on any other)
- UNO multiplayer: add turn announcements after stack absorption and turn passes,
jitter between rapid-fire messages with safe mutex handling
- Birthday: add €1,000 gift and 10 XP + €100 community celebration bonus
- Market: guard against division by zero, nil pointer, and timezone errors
- README updates: plugin count 48→49, all new commands, feature flags, architecture
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add forex plugin (Frankfurter v2 API) with rate lookups, analysis,
DM-based alerts, and daily cron poll. Backfills 1 year of history
on startup for moving averages and buy signal scoring.
- Fix bot hang caused by SQLite lock contention in reminder polling:
rows cursor was held open while writing to the same DB. Collect
results first, close cursor, then process. Same fix in milkcarton.
- Add sync retry loop so the bot reconnects after network drops
instead of silently exiting. StopSync() for clean Ctrl+C shutdown.
- Add panic recovery to all dispatch, syncer, and cron paths.
- Make all HTTP-calling plugin commands async (goroutines) so a slow
or dead external API cannot block the message dispatch pipeline.
Affects: lookup, stocks, forex, anime, movies, concerts, gaming,
retro, wotd, urls, howami.
- Extract DisplayName to Base, add db.Exec helper, convert silent
error discards across the codebase.
- Fix UNO mercy-kill bug (eliminated bot continues playing), adventure
DM nag spam, stats column mismatch, per-call regex/replacer allocs.
- Update README: forex commands, Finance section, 47 plugins.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>