Wound carry-over went through three integer truncations across the
legacy combat scale (123 max) and the dndChar scale (78 max). 101/123
persisted as int(64.04)=64, then restored as int(100.92)=100 — losing
0.92 HP every fight.
Switching both sides to math.Round means most HPs round-trip exactly;
the residual error is bounded by ±1 HP from the inherent scale mismatch
(1 dndChar HP ≈ 1.58 legacy HP, so some pairs collide on the smaller
scale). Acceptable; the prior always-truncate behavior was directionally
biased against the player.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two bugs reported back-to-back from a Rogue's run:
1. HP display reset between battles. End of fight 1: 101/123 → start of
fight 2: 100/100. applyDnDHPScaling was overwriting Stats.MaxHP with
the scaled wound value, so the display denominator dropped along with
the numerator. Wounded carry-over became invisible.
Fix: introduce CombatStats.StartHP. Combat engine reads it as the
entry-HP when set; MaxHP stays put. Display now reads "100/123" as
intended.
2. Auto-crit fired on a roll of 11 with no narrative tell. Rogue passive
AutoCritFirst was triggering correctly, but the renderer used the
generic crit pool, so the player saw "🎲 11 vs AC 10 → CRIT" with no
indication their *class* caused it.
Fix: tag the crit event with Desc="auto_crit" when the passive (not
the dice) caused it; new narrativePlayerAutoCrit pool calls out the
training/instinct/exploit theme.
Test bound for T5 dungeon death rate loosened from 0.02 to 0.01 — the
new Sudden Death phase from the previous commit shifted geared-T5
fights slightly toward player wins.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Audit confirmed saveAdvCharacter's fan-out (upsertAllPlayerMetaFromAdvChar)
covers all 13 migrated subsystems, so the per-call-site upsertPlayerMetaXxx
calls retained "as defense" through the L4-L5 migration are redundant
post-L5h. Removed 16 such call sites across arena (2), scheduler (4),
hospital (1), consumables (2), rival (1), housing (11), and reordered
masterwork to drop a now-pointless explicit upsert before the load+save.
Refreshed nine stale doc comments referencing the legacy
adventure_characters table or "soak window / fallback" language that no
longer applies after the L5 close-out (commit 596b2b7). No behavior
change; go vet + go test ./... pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rewires loadAdvCharacter / createAdvCharacter to source from player_meta,
drops every legacy-table fallback in the loadXxxState helpers, and adds a
GOGOBEE_LEGACY_PURGE=1 gate to drop the now-cold adventure_characters
table. Schema CREATE removed and column migrations tolerate the missing
table so the purge stays sticky across reboots.
§7.4 of the migration plan is reconciled to document that
player_meta.combat_level stays — combat_stats.go consumes it via the
overlay and is shared infrastructure, not legacy.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reconcile the migration plan with what actually shipped, and clear the
three remaining CombatLevel reader sites so the §7 grep gates hold.
Plan reconciliation (gogobee_legacy_migration.md §7.4):
The original deletion list was wrong on two counts. (1) AdventureCharacter
struct survives as the loaded-view shape post-L5h overlay; only the
backing table drops at purge. (2) combat_engine.go / combat_bridge.go /
combat_stats.go are not legacy — they're the live combat engine the D&D
system layers on top of (applyDnDPlayerLayer/EquipmentLayer/etc. mutate
CombatStats before SimulateCombat). Verified via grep: 21+ files reference
these symbols across arena/dungeon/zone/expedition. §7.4 rewritten to
reflect this; no L6 combat-engine migration needed.
Reader fixes:
- babysitDailyCost reframed for D&D-level scale. Formula 100 + level*100
preserves the curve at every old-CL boundary given the 5:1 compression
in dndLevelFromCombatLevel (Level 4 ≈ old CL 20 = €500/day, Level 10 ≈
old CL 50 = €1100/day). Caller switched to dndLevelForUser.
- dnd_sheet.go drops the vestigial "Combat (legacy) %d" stat-block line.
- D&D onboarding retired. Post-L5g the welcome DM never fires (every
legacy player already has a D&D row), so dnd_onboarding.go +
dnd_onboarding_test.go are deleted, the 3 production caller invocations
(dnd_zone_combat, combat_bridge, dnd_combat::ensureCharForDnDCmd) and
the dnd_setup.go stub-creation branch removed. OnboardingSent column
kept for a separate cleanup pass. dnd_audit_fixes_test.go ported.
go vet ./... && go test ./... clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
backfillDnDCharactersFromAdv walks adventure_characters rows that have no
dnd_character row and inserts an auto-migrated character (race/class
inferred from archetypes, Level seeded from dndLevelFromCombatLevel).
Idempotent via LEFT JOIN — pending-setup drafts and existing rows are
skipped. Wired into Init after the L5f backfill.
With every legacy player guaranteed a D&D row, the soak-window fallbacks
in dndLevelForUser, rivalLevelForUser, and hospitalCostsForUser are
retired (they now floor at level 1). dndLevelFromCombatLevel itself
stays — still used by autoBuildCharacter and the !setup seed paths.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GM→DM rename across docs and code (GMNarrationType→DMNarrationType,
GMState→DMState, narration constants, comments) so the system reads as
"Dungeon Master" everywhere. Player-visible "GM mood" wording stays
where it appears in flavor.
Streamed zone/expedition combat: zone advance now stages patrol →
patrol play-by-play → patrol resolution → room intro → room play-by-play
→ final outcome through sendZoneCombatMessages with 2–3s pacing
(arena keeps its 5–8s window). Combat narrative lines pick up a compact
d20-vs-AC roll annotation for hit/crit/miss/block events.
Combat outcome polish: dndHPSnapshot lets narration show sheet HP
rather than legacy combat-engine HP, and markAdventureDead clears the
zombie state where hp_current was 0 but the legacy alive flag stayed
true after a D&D-layer KO.
Adv 2.0 announcement (ADVENTURE_2.0_ANNOUNCEMENT.md), README rewrite
covering the new layer, and adv2_scenario_test.go — a full
zone-run + expedition + harvest playthrough against a copy of the prod
DB asserting persisted state end-to-end.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>