P0 — actual bugs:
- eldritch_blast: SRD-imported "Whatever" placeholder leaked to players;
overlay added in dnd_spells_data.go.
- Battle Master disarming_attack + parry: math.Max on multiplicative
DamageReduct was a no-op vs the 1.0 default. Switched to *= and added
regression tests covering the stacking case too.
- Extended TestSpellDescriptionsAreJargonFree to catch "Whatever",
trailing ellipses, mid-word truncation, and empty-size phrases. This
surfaced 4 more genuinely-broken SRD descriptions (find_familiar,
clairvoyance, glyph_of_warding, teleportation_circle); all now
overlayed in dnd_spells_data.go.
P1 — UX hygiene:
- Setup completion now nudges new casters toward !spells/!cast.
- Magic-item attunement vocab unified to "bond" everywhere user-facing;
renamed the Treasures sheet section to avoid clashing with the bond
vocab.
- Ambient DM footers stripped of "Threat +N" / "Supplies −N SU" hidden-
meter leakage; verb-form footers instead.
- !expedition status defaults to a days-left + threat-label summary;
raw SU / threat-out-of-100 / zone-stack / roll-modifier moved behind
`!expedition status --debug`.
- !zone taunt/compliment help text dropped the "(mood −10)" / "(mood +5)"
numerics that turned the hidden TwinBee-mood mechanic into a min/max
knob.
- TwinBee pronoun pass: switched she/her to singular they on the two
surfaces I touched plus achievements.bj_beat_twinbee.
P1 — correctness/scale:
- adventure_shop curio purchase now guards the euro.Debit bool return
before inventory grant + pot cut; the GetBalance preflight isn't
enough since a concurrent blackjack/lottery debit can slip the balance
across BLACKJACK_DEBT_LIMIT between read and write.
- equipMagicItem reordered: remove inventory item BEFORE equip, with a
best-effort rollback if equip fails. The prior order left a dup
window if the inventory delete tripped on a transient DB error.
- magicItemsByRarityCache promoted to sync.Once — concurrent cold-start
loot rolls otherwise raced on the lazy assignment.
Stale-audit verifications (no code change needed):
- light / druidcraft / water_walk overlays already exist and win the
SRD merge — the broken raw text never reaches players.
- bootstrapPhase5BHPRefresh is already wired at adventure.go:228.
Deferred:
- combatantsForSession per-turn 6-load DB chatter (perf P1-A): touches
the hot combat path; needs its own test pass before shipping. Tracked
in memory at project_combat_session_cache_deferred.
go vet clean; go test -race ./... green (229s).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The May audit's Phase A1 was overstated. Re-verification at HEAD
found:
- TestSpellDescriptionsAreJargonFree already exists with the
proposed regex set and passes.
- .Upcast is dead text (grep across internal/ shows no runtime
reader); audit's Upcast scope was moot.
- All four Description leaks cited by example (bless, command,
create_or_destroy_water, cure_wounds) were already overlaid in
the prior 2026-05 voice pass.
Real residual: 12 SRD-only utility/control entries whose Open5e
prose was bland (but not jargon-leaking). Overlay shims added in
the charm_person voice — second-person, verb-led, lightly wry.
Mechanics (Effect/CastTime/SaveStat/Concentration/AOE/
MaterialCost) preserved from the SRD originals.
Also closes out B1 (help jargon — already shipped) and B2
(TwinBee voice — shipped in Phase B2 voice pass) in the audit
doc; both were re-asserting completed work.
Remaining in the May audit: C1 backup wiring, C2+C3 maintenance
hardening, D1+D2 hygiene. No player-facing P0 left.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The A1 regex banned \b\d+d\d+\b (e.g. '1d20') but missed bare die
notation ('d20', 'd6') with no leading count. SRD's 'blink' Description
slipped through with 'Roll a d20 at the end of each of your turns...'.
- Add \bd(4|6|8|10|12|20|100)\b ban to the prose regex sweep.
- Add hand-authored overlay shim for blink in dnd_spells_data.go.
Classes union with SRD preserves Cleric/Sorcerer/Warlock availability.
Test now passes the wider sweep; no other reachable spells leak.
The audit plan flagged jargon leaks in the SRD spell prose surfaced by
!cast and !spellbook. Verifying against HEAD turned up two corrections
to the plan's framing:
- The overlay in dnd_spells_data.go wins on ID collision, so for the
~76 hand-authored spells the *overlay* Descriptions are what players
actually see — and those were crunchier than the SRD ("Heal 1d8 +
WIS mod HP. Touch.", "8d6 fire in 20 ft radius. DEX save half.",
etc.). Touching only the generated SRD file would have missed the
bigger leak.
- The Upcast field is never displayed at runtime (only the import
generator reads it), so testing it against the regex would test
dead data.
So this commit:
- rewrites every overlay Description into playful, jargon-free flavor
in the charm_person voice ("Sweet-talk a humanoid…") — no dice, no
saves, no AC math, no ability-mod references
- adds 31 overlay shims for SRD-only spells whose generated text was
broken (placeholder gaps from the Open5e classifier — "no larger
than a.", "up to to", "in a in range"), empty ("You touch a
creature."), typo-laden ("magicou", "undeadou", "diseasesou"), or
jargon-heavy (false_life's "1d4+4 temporary hit points")
- adds TestSpellDescriptionsAreJargonFree, a regex sweep over the
merged registry that bans "saving throw", "spell slot of",
"ability modifier", "hit points equal to", and \bNdN\b dice
notation. Currently passing; will fail-loud on regressions or new
SRD imports that need overlay shims.
The generated dnd_spells_srd_data.go is left untouched — overlay is
the regen-safe surface per its own header comment.
B2: Removed shield/counterspell from Mage/Sorcerer defaults and hellish_rebuke/counterspell
from Warlock — reactions are EffectReaction and combat has no reaction window yet, so
auto-granting them just litters the spellbook with dead entries. Substituted L1/L3
staples (sleep, fly, burning_hands, chromatic_orb where class-tagged appropriately).
B3: Replaced the stale "Mage, Cleric, Ranger, and Arcane Trickster (L5+)" enumeration in
!cast/!spells learn/!prepare error paths with class-aware route hints via a new
spellRouteHintFor() helper.
R15: Removed the duplicate hand-authored healing_word_spell entry; Cleric default now
references the canonical SRD healing_word (cleric/druid/bard tagged). parseSpell
and lookupSpell now resolve "healing word" deterministically.
R16: !cast --drop now appends "(slot refunded)" when applicable.
R17: Prep-cap message rewritten to "Your prepared list is full (N/N)."
R19: Removed shillelagh from Druid default — the overlay flags it cleric/ranger only and
it has no real attack profile yet (BuffSelf, no DamageDice).
Bonus correctness: dndSpellRegistry now unions Classes on overlay collision instead of
replacing wholesale. The hand-authored buildSpellList() entries were tagged Mage-only,
so every Sorcerer/Warlock/Bard/Druid spell that collided with the SRD silently lost its
class list — meaning auto-granted defaults were rejected at the classOK gate. Union
merge restores SRD coverage without forcing a hand-edit of every overlay entry.
Tests:
- TestDefaultKnownSpellsHaveNoReactions covers B2.
- TestDefaultKnownSpellsAreCastableByClass guards the overlay-narrow regression.
- TestHealingWordResolvesDeterministically covers R15.
- TestCastNonCasterErrorHasNoClassEnumeration covers B3.
- Existing dnd_prepare_test.go updated to reference healing_word.