CardDb: make loadCard idempotent (fix latent duplicate-PaperCard bug) - #11586
CardDb: make loadCard idempotent (fix latent duplicate-PaperCard bug)#11586shoeless wants to merge 1 commit into
Conversation
|
artIndex is on my list to be removed anyway I just need to find a better way to rename the image files #7771 |
42e35cb to
a4bb8e1
Compare
|
Good to know — this guard doesn't lean on artIndex, only on loadCard adding all of a (name, set)'s printings in one call, so it should carry over cleanly (or simplify) when artIndex goes away with #7771. Pushed a small hardening while re-checking it: the existing-printing check now also matches the card's rules name, since a lookup name can be shared across different cards (CopyFaceFrom alt faces, flavor names) — no stock data hits that today, but custom content could. To be clear, the duplication itself isn't artIndex's doing — |
a4bb8e1 to
36502d6
Compare
loadCard is not idempotent: addSetCard unconditionally increments the art index and appends a fresh PaperCard, so a redundant call for a (name, set) printing already loaded duplicates it in allCardsByName (and, since initialize() resets artIds per edition, the duplicates repeat artIndex 1..n — inflating the art counts CardPool's random-art selection uses). Skip when that exact card's (name, set) printing already exists. The guard matches the card's rules name, not just the lookup name: names can be shared across cards (CopyFaceFrom alt faces, flavor names), and it only applies to resolvable set codes — the null/UNKNOWN-set path is unchanged. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
36502d6 to
0afbbe1
Compare
Problem
CardDb.loadCardis not idempotent:addSetCardunconditionally increments the art index and appends a freshPaperCard. A redundant call for a(name, set)printing that's already loaded therefore duplicates thatPaperCardinallCardsByName.Fix
Skip when that exact
(name, set)printing already exists, via a new side-effect-freehasPrintingInSetcheck. Guarding on card-name presence alone would break the "add a printing from a not-yet-loaded set" path (StaticData.getOrLoadCommonCard), where the card can already exist under other sets while the requested set's printing is still missing — so the guard is keyed on the specific edition.Why "any printing present" is a safe guard despite multi-printing sets
A set can contain multiple printings of the same name (
CardEdition.getCardInSetreturns aList<EditionEntry>— basic-land arts, showcase variants; that's whatartIndexis for). The guard is still sound becauseloadCardis all-or-nothing per(name, set):addFromSetByNameloops over everyEditionEntryof that name in the set andaddSetCards each one.addSetCardhas exactly two callers — that loop, and the eager full-set path ininitialize— so no code path ever adds a subset of a name's printings for a set. Any-printing-present therefore implies the(name, set)load already ran, art variants included. (Entries excluded by the functional-variant filter are excluded on every call equally, so the invariant holds.)Single file,
forge-coreonly.🤖 Generated with Claude Code