Card Identity and Alternate-Art Architecture
Card Identity and Alternate-Art Architecture
Status
This document describes the current extension contract. It supersedes the
implementation plans in the EXTENSION-*-HANDOFF.md files when those plans differ
from the checked-in implementation.
The extension is already published. Changes to this contract require explicit approval, compatibility review, and testing of the exact release package.
Sources of truth
Use these in order when verifying behavior:
- The checked-in implementation:
card-art.js,deck-card-art.js, anddeck-custom.js. - The generated packaged allowlist:
remote-card-art.js. - The generator:
scripts/build-remote-card-art.py. - The reviewed catalog inputs and runtime manifest used by the generator.
- Historical handoff documents, which provide rationale and regression cases but may describe an earlier plan.
remote-card-art.js is generated data and must not be edited by hand.
Canonical card identity
A deck row is anchored by UVS Ultra’s numeric canonical card ID. Ordinary rendered image identity is read from the actual same-origin image URL:
/images/extensions/{setId}/{cardNumber}.jpg
/images/extensions/{setId}/{cardNumber}-preview.jpg
/images/extensions/{setId}/{cardNumber}-mini.jpg
/images/extensions/{setId}/{cardNumber}-ci-micro.jpg
setId and cardNumber are validated path segments. cardNumber remains a string
because leading zeroes are significant. Size suffixes are removed before Forum
Code is generated.
Card names are display and validation data, not unique identity. Duplicate names are matched in deck order rather than collapsed into one record.
Forum Code contract
The extension emits qualified card lines as:
{quantity} -{setId}/{cardNumber} {complete card name}
For an ordinary image, the qualifier is its validated UVS Ultra image directory
and filename stem. For a selected alternate, forumQualifier from the packaged
allowlist takes precedence.
The qualifier grammar is:
^[A-Za-z0-9_-]+/[A-Za-z0-9_-]+$
Ordinary and Ultra-hosted printings retain their validated Ultra set ID. Alternate
art stored in the project repository uses the source-neutral repo namespace,
including artwork first discovered through a third-party catalog. Build-time
provenance is not part of public Forum Code identity. Consumers must resolve the
complete qualifier through importer-owned allowlisted data. They must not
interpolate untrusted Forum Code into a network URL.
TTS/importer behavior and compatibility parsing are described in
TTS-IMPORTER-EXTENSION-HANDOFF.md.
Reviewed alternate relationships
The extension offers alternate art only when variants are nested under the exact canonical card ID in the packaged reviewed catalog. It does not infer an alternate relationship from names, collector numbers, sets, image similarity, or live-page scraping.
The detailed review criteria and negative cases are in
EXTENSION-ALT-ART-MATCHING-RULES.md.
Every card entry begins with an explicit original variant. Alternate records use
a stable artworkId and may contain:
forumQualifierfor exported identity;legacyQualifiersfor safe storage migration;- commit-pinned preview and micro image URLs; and
- a paired
transformBackrecord.
Selection storage and migration
Artwork selections are stored in local storage under uvsu-card-art-v1. The
selection scope is:
{deckId}:{canonicalCardId}
The stored value is the selected variant’s exact artworkId.
Legacy values are accepted only when they resolve to exactly one allowlisted
variant by exact set/card identity, known public legacy qualifier, legacy set ID,
or a validated qualifier token that has one source-neutral repo match. This
last path migrates previously stored source-specific selections without packaging
or emitting the old namespace. An ambiguous or unknown legacy value is not
guessed; selection returns to the first variant, which is the explicit Original
record.
Page-provided values and local storage cannot provide arbitrary image URLs. A selection must match an existing packaged variant before it is persisted or used.
Remote artwork security boundary
Remote artwork is limited to non-executable images under a commit-pinned path in
the project-owned uvs-tts-assets repository on
https://raw.githubusercontent.com.
At assignment time, card-art.js requires:
- the expected HTTPS origin;
- a full 40-character pinned Git revision;
- the exact repository and
alternate-art/path prefix; - no username or password;
- no query string; and
- no fragment.
deck-card-art.js sets referrerPolicy to no-referrer before assigning an image
source. The extension uses generated preview and micro derivatives rather than
full-resolution remote artwork in deck UI slots.
The extension does not fetch a remote manifest or executable code at runtime.
Transform and shift cards
A selected front variant may include one nested transformBack. Preview behavior
updates both front and back panes while keeping the front image as the deck-row
thumbnail.
One front Forum Code qualifier represents the selected pair. The transformed back is not emitted as a second deck line. Importers must retrieve the paired back from their own allowlisted record for that front qualifier.
Catalog update procedure
Catalog updates are build-time operations, not runtime discovery:
- Regenerate or obtain the reviewed extension catalog.
- Prepare missing preview and micro assets in the separate assets repository.
- Commit those assets.
- Run
scripts/build-remote-card-art.pyagainst the reviewed full asset commit. - Review generated counts, qualifier uniqueness, source paths, and transform pairs.
- Test ordinary, alternate, multiple-alternate, mismatch, unknown, and transform cases.
- Build and smoke-test the exact release ZIP.
The generator rejects malformed qualifiers, duplicate identities, missing source files, paths outside the assets checkout, unexpected catalog counts, and asset files absent from the pinned revision.
Compatibility requirements
Do not intentionally change these without explicit approval:
- Existing stored
artworkIdvalues continue to resolve. - Unique legacy selections continue to migrate.
- Ambiguous legacy selections fail closed to Original.
- Existing Ultra-hosted and
repoForum Code qualifiers remain importer-resolvable. - Superseded source-specific alternate qualifiers migrate locally when unique but are not emitted as public identities.
- Ordinary card identities preserve exact filename stems and leading zeroes.
- Unknown or mismatched qualified identities never fall back silently to another printing.
- Transform alternates retain their paired back image.
- No new permission, remote-code path, or undisclosed data flow is introduced.
Historical documents
These files remain at their existing paths to preserve references:
EXTENSION-CARD-NUMBER-HANDOFF.mdEXTENSION-VALIDATED-ALT-ART-HANDOFF.mdTTS-IMPORTER-EXTENSION-HANDOFF.md
They are useful for rationale, examples, and regression cases. Treat this document and the checked-in implementation as authoritative for current extension behavior.