Adv 2.0 L5 close-out fix: bootstrap player_meta from legacy on Init

The L5 close-out (596b2b7) rewired loadAdvCharacter to read from
player_meta and simultaneously deleted the 13 backfill one-shots from
Init. That's only safe if every account already has a player_meta row
from prior dual-writes — fresh restores from old backups, dev
environments cloned from older snapshots, or a prod upgrade that
skipped the soak window all silently strand every character (loader
returns empty).

Adds bootstrapPlayerMetaFromLegacy: a single consolidated migrator that
walks adventure_characters, finds rows missing from player_meta, and
fans them out via the audited upsertAllPlayerMetaFromAdvChar helper.
Idempotent (re-runs touch zero rows once migrated; no-ops post-purge).
Wired into AdventurePlugin.Init before loadAllAdvCharacters.

proddb_simulation_test.go exercises the full bootstrap + fan-out +
overlay round-trip against a copy of data/gogobee.db with 11 subtests
covering every migrated subsystem (skills, arena, babysit, streak,
death/revive, NPC counters, pet incl. JSON-packed flags, house, save
idempotency, last_active advance, fresh createAdvCharacter).

dnd_proddb_integration_test.go also calls the bootstrap explicitly to
mirror prod startup ordering.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
prosolis
2026-05-09 13:16:27 -07:00
parent 9d6e8f6bf2
commit c8849fd819
4 changed files with 538 additions and 0 deletions

View File

@@ -171,6 +171,11 @@ func (p *AdventurePlugin) Commands() []CommandDef {
}
func (p *AdventurePlugin) Init() error {
// Bootstrap: migrate any legacy adventure_characters rows that don't yet
// have a player_meta row. Idempotent. Required for DBs that didn't go
// through the L4-L5h dual-write soak (fresh deploys, restored backups).
bootstrapPlayerMetaFromLegacy()
// Rehydrate DM room mappings for existing characters
chars, err := loadAllAdvCharacters()
if err != nil {