Variant Slug + Influence “X” Handling
| Date | 2026-06-03 |
| Status | Accepted |
| Decision Makers | @GaultierRomon |
Context and Problem Statement
The Echoes of Astra Products sheet has two columns that don’t fit the generic SheetImporter cleanly:
variant— every row has a value (Normal,Serialized,Framebreak, orSignature). The base importer appends any non-"standard"variant to the printing slug, soNormalrows would all get a redundant-normalsuffix.influence— most cards have a numeric value (0–3), but some have the literalX(variable influence). The base importer coerces range attributes withNumber(), turningXintoNaN.
Decision Drivers
- Slugs must stay stable and clean. Games without a variant column produce
…-imp001/…-imp001-foil; Echoes of Astra should match that for its base printings. - Special variants are genuinely distinct printings and must keep a differentiating slug.
NaNmust never be persisted to the database.- We must not modify the shared
SheetImporterfor one game’s quirks.
Considered Options
- Override
transformSheetProductinEoaImporter— handle both quirks locally. - Modify the base
SheetImporter— rejected; leaks game-specific behaviour into shared code. - Pre-process the sheet — rejected; the sheet is publisher-owned.
Decision Outcome
Chosen option: Override transformSheetProduct in EoaImporter.
Variant
const rawVariant = product.variant != null ? String(product.variant) : undefined
const isNormalVariant = !rawVariant || rawVariant.toLowerCase() === "normal"
// Neutralize "Normal" so the base slug builder skips the suffix.
if (isNormalVariant) product.variant = undefined
const card = super.transformSheetProduct(product, expansion)
// Restore + persist the real variant so it stays filterable.
product.variant = rawVariant
if (rawVariant) card.printings[0].variant = rawVariant as EoaVariantNormal→ no slug suffix, but the printing still storesvariant: "Normal"for filtering.Serialized/Framebreak/Signature→ kept onproduct.variant, so the base builder appends the suffix and auto-maps the attribute. They form distinct printings (e.g.…imp045-serialized-foil).
Influence
const cardRecord = card as unknown as Record<string, unknown>
for (const stat of ["supplyCost", "influence", "attack", "health"]) {
if (typeof cardRecord[stat] === "number" && Number.isNaN(cardRecord[stat] as number)) {
delete cardRecord[stat]
}
}Any stat that coerced to NaN (in practice only influence: "X") is stripped, so cards with variable influence simply have no numeric influence rather than a poisoned value. Range filters and the SEO builder skip the missing field cleanly.
Consequences
- âś… Clean, stable slugs; special variants remain distinguishable.
- âś… No
NaNreaches the database; range filters behave. - ⚠️ Cards with
Xinfluence are not matched by any influence range filter (acceptable —Xis not a fixed value).
Last updated on