Wave 1 — contract lines published first; G and E build to them. #1 THE BRIEF SAID `tier`. IT CAN'T BE (§7.2b). G's atlases already emit tier: 1 = the CHARTER'S LADDER RUNG (0 parody / 1 static-real / 2 live), and `kind` is already the stock type. A mint atlas is ALSO rung 1 — same mechanism (a statically baked per-shop atlas); only the data's origin differs. Real-vs-mint is an orthogonal axis, not a rung — overloading `tier` puts two meanings in one name, the same species as the plan-id/godverse-id collision just standing-noted, and as R25's positional ids. RULING: top-level `sourcing: "real"|"mint"`, REQUIRED; `tier` stays the numeric rung. A mint index MUST NOT carry POS-snapshot fields (the separation is the honesty). Gates read `sourcing`; absent => FAIL. #4 `condition` ISN'T IN THE INDEX (§7.2c) — the ledger assumed it was. The index carries artist/title/price/price_band; G's SNAPSHOT has condition + sleeve_cond and drops them at emit, so pickRealOffers mapped cond:'' and the card rendered dangling separators around a hole. That WAS the "database row". Ruled optional index fields, emitted when the source has them; no invented grades on mint items (a plausible-but-fictional grade is what `sourcing` exists to prevent). #6 THE ATLAS MANIFEST (§7.2d): stock_godverse/index.json is the authority for which shops carry atlases — no entry => no fetch => zero 404s, so the zero-console-errors law holds with no attribution exception. Shape + both-ways consistency specified. No manifest + no atlases = a legitimate silent zero-shop state, not an error. THE PRICE STICKER (code): the pull panel is now the shop's price sticker — manila card, rotation + shadow, typewriter caps, italic title, a stamped condition grade, and the round yellow $ sticker the sleeve art already uses (the panel echoes dig.js's own canvas language instead of fighting it). Fields compose only when present: a missing field never leaves a stray separator. VERIFIED (fresh context, 5 card shapes, both star branches): real grail VG+/VG + ★GRAIL; real standard VG+ + STANDARD; real ungraded COLLECTOR (grade omitted cleanly); parody NM + 1973 PUNK; parody rare (seed 4) VG + 1973 POP + ★RARE. No dangling separators anywhere. The verification caught a defect in MY OWN card: a real grail read "GRAIL ★ GRAIL" — `s` carried the price_band AND `rare` derived from that same band (parody is immune: its `s` is a genre). Fixed at the mapping. And I didn't leave the parody-rare branch on assumption — scanned seeds until a rare pull appeared and asserted it says RARE, not GRAIL. An unexercised branch is an unproven one. Budgets: the card is DOM — zero draws, zero tris, no 3D change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
e7d58eaad5
commit
4f0adf12d8
@ -3,7 +3,62 @@
|
|||||||
*Status: **v1 complete & verified**. Standalone interiors library + test page. Every shop door opens
|
*Status: **v1 complete & verified**. Standalone interiors library + test page. Every shop door opens
|
||||||
into a unique, seeded, themed interior, generated on demand in ~4ms, byte-identical every revisit.*
|
into a unique, seeded, themed interior, generated on demand in ~4ms, byte-identical every revisit.*
|
||||||
|
|
||||||
Last updated: 2026-07-17 (round 25) · owner: PROCITY-C · reviewer: Fable
|
Last updated: 2026-07-17 (round 26) · owner: PROCITY-C · reviewer: Fable
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Update 2026-07-17 (round 26, v5.0-beta EVERY CRATE DIFFERENT) — three contract lines + the price sticker
|
||||||
|
|
||||||
|
R26 §Lane C, wave 1 (ledgers #1, #4, #6). Contract lines published FIRST — G and E build to them.
|
||||||
|
|
||||||
|
### The brief said `tier`. It can't be `tier` — that name is taken twice (§7.2b)
|
||||||
|
G's atlases already emit **`tier: 1`** = the **charter's ladder rung** (0 parody · 1 static-real · 2 live),
|
||||||
|
and `kind` is already the stock type. **A mint atlas is also rung 1** — same mechanism (a statically baked
|
||||||
|
per-shop atlas); only the data's *origin* differs. Real-vs-mint is an **orthogonal axis, not a rung**.
|
||||||
|
Overloading `tier` would put two meanings in one name — the same species as the plan-id/godverse-id
|
||||||
|
collision that just became a standing note, and as R25's positional ids. **Ruling: top-level
|
||||||
|
`sourcing: "real" | "mint"`, REQUIRED; `tier` stays the numeric rung.** A mint index MUST NOT carry
|
||||||
|
POS-snapshot fields (the separation IS the honesty); gates read `sourcing`, and an index without it FAILS.
|
||||||
|
|
||||||
|
### `condition` isn't in the index — the ledger assumed it was (§7.2c)
|
||||||
|
Ledger #4 said the card gets "the fields the atlas index already carries (artist/title/price/**condition**)".
|
||||||
|
It carries artist/title/price/price_band — **not condition**. G's *snapshot* has `condition` + `sleeve_cond`
|
||||||
|
and drops them at emit, so `pickRealOffers` mapped `cond: ''` and the card rendered dangling separators
|
||||||
|
around a hole. That *was* the "database row". Ruled: `condition`/`sleeve_cond` are **optional** index fields,
|
||||||
|
emitted when the source has them; **no invented grades** on mint items — a plausible-but-fictional grade is
|
||||||
|
exactly what `sourcing` exists to prevent.
|
||||||
|
|
||||||
|
### The atlas manifest (§7.2d) — existence declared, never probed
|
||||||
|
`web/assets/stock_godverse/index.json` is the authority for which shops carry atlases; **no entry ⇒ no
|
||||||
|
fetch ⇒ zero 404s**, so the zero-console-errors law holds with no attribution exception. Shape + both-ways
|
||||||
|
consistency (atlas without manifest entry FAILS, and vice versa) in §7.2d. A tree with no godverse atlases
|
||||||
|
and no manifest is a legitimate silent zero-shop state, not an error.
|
||||||
|
|
||||||
|
### The price sticker (ledger #4, code)
|
||||||
|
The pull panel is now the shop's **price sticker**, not a data readout: manila card, slight rotation +
|
||||||
|
shadow, typewriter caps, italic title, a rubber-stamped condition grade, and **the round yellow $ sticker
|
||||||
|
the sleeve art already uses** (dig.js's own canvas language — the panel now echoes it instead of fighting
|
||||||
|
it). Fields compose only when present: **a missing field never leaves a stray separator.**
|
||||||
|
|
||||||
|
**Verified — five card shapes, both star branches, fresh context:**
|
||||||
|
| case | card |
|
||||||
|
|---|---|
|
||||||
|
| real grail | `$28` · Deep Dish · *Penetrate Deeper* · `VG+/VG` · **★ GRAIL** |
|
||||||
|
| real standard, graded | `$15` · `VG+` · `STANDARD` |
|
||||||
|
| real ungraded (today's index / mint) | `$15` · `COLLECTOR` — grade omitted cleanly |
|
||||||
|
| parody | `$15` · THE VERANDAHS · *Tinny* · `NM` · `1973 PUNK` |
|
||||||
|
| parody rare (seed 4) | `$16` · HILLS HOIST · *Servo at Midnight* · `VG` · `1973 POP` · **★ RARE** |
|
||||||
|
|
||||||
|
**The verification caught a defect in my own card:** a real *grail* rendered **"GRAIL ★ GRAIL"** — `s` carried
|
||||||
|
the price_band *and* `rare` derived from that same band. (Parody is immune: its `s` is a genre.) Fixed at the
|
||||||
|
mapping — grail becomes the ★ stamp and leaves `s` empty. And I did not leave the parody-rare branch on
|
||||||
|
assumption: scanned seeds until a rare pull appeared (seed 4) and asserted it says RARE, not GRAIL. An
|
||||||
|
unexercised branch is an unproven one.
|
||||||
|
|
||||||
|
**Budgets:** the card is DOM — zero draws, zero tris, no 3D change. Ceilings untouched.
|
||||||
|
**→ G:** `sourcing` + `condition`/`sleeve_cond` + the manifest. **→ E:** assert `sourcing` (absent ⇒ FAIL),
|
||||||
|
the mint/POS-field separation both ways, and manifest↔files both ways. **→ F:** consult the manifest before
|
||||||
|
fetching — that's what retires the 404 attribution exception.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@ -15,6 +15,10 @@
|
|||||||
> **v5.0-alpha amendment (2026-07-17, R25 ledger #3):** **§7.2a added — slot ids must be sku-derived,**
|
> **v5.0-alpha amendment (2026-07-17, R25 ledger #3):** **§7.2a added — slot ids must be sku-derived,**
|
||||||
> unique across packs and stable across re-emits (F's id-collision finding, made structural). Index-only;
|
> unique across packs and stable across re-emits (F's id-collision finding, made structural). Index-only;
|
||||||
> no atlas bytes, no goldens. §0–§6 unchanged.
|
> no atlas bytes, no goldens. §0–§6 unchanged.
|
||||||
|
> **v5.0-beta amendment (2026-07-17, R26 ledger #1/#4/#6):** **§7.2b `sourcing` (real|mint — NOT `tier`,
|
||||||
|
> which is already the ladder rung), §7.2c `condition` for the price card, §7.2d the atlas manifest**
|
||||||
|
> (existence declared, never probed — kills the 404 attribution exception). All index/manifest-only:
|
||||||
|
> no atlas bytes, no town caches, no goldens. §0–§6 unchanged.
|
||||||
|
|
||||||
*The district ships **three** venue archetypes behind `?gigs=1` — `pub`, `band_room`, `rsl`. Lane A
|
*The district ships **three** venue archetypes behind `?gigs=1` — `pub`, `band_room`, `rsl`. Lane A
|
||||||
converts a chosen shop to a venue kind in place (`shop.type = kind`); C keys the interior recipe off
|
converts a chosen shop to a venue kind in place (`shop.type = kind`); C keys the interior recipe off
|
||||||
@ -286,6 +290,57 @@ must not emit into it.**
|
|||||||
**→ Lane E:** assert the form — `id` present, **unique within the pack**, and `sku_`-prefixed for
|
**→ Lane E:** assert the form — `id` present, **unique within the pack**, and `sku_`-prefixed for
|
||||||
real-stock packs.
|
real-stock packs.
|
||||||
|
|
||||||
|
### 7.2b `sourcing` — real vs mint, and why it is NOT `tier` (v5.0-beta, R26 ledger #1)
|
||||||
|
The beta needs every keyed crate marked as **actual POS inventory** or **seeded plausibility**, so no gate,
|
||||||
|
doc or human mistakes one for the other. The brief called that field `tier`. **It can't be `tier`: that name
|
||||||
|
is already taken, twice over.**
|
||||||
|
- G's atlases already emit **`tier: 1`** = the **charter's ladder rung** (0 parody · 1 static-real · 2 live
|
||||||
|
GODVERSE). A mint atlas **is also rung 1** — same mechanism (a statically baked per-shop atlas); only the
|
||||||
|
*data's origin* differs. And `kind` is already the stock type (`record`).
|
||||||
|
- So real-vs-mint is an **orthogonal axis**, not a rung. Overloading `tier` would put two meanings in one
|
||||||
|
name — the same species as the plan-id/godverse-id collision now standing-noted, and as the positional
|
||||||
|
ids in §7.2a. One name, one meaning.
|
||||||
|
|
||||||
|
**Rule: top-level `sourcing: "real" | "mint"`, REQUIRED on every real-stock atlas index.** `tier` stays the
|
||||||
|
numeric ladder rung, unchanged.
|
||||||
|
- **`"real"`** — baked from that shop's own POS snapshot (Monster Robot Party). The index carries its
|
||||||
|
`snapshot` provenance (§7.3).
|
||||||
|
- **`"mint"`** — a deterministic seeded sample (`random.Random(shop_id)`) standing in for a keyed shop with
|
||||||
|
no POS. Plausible, never claimed as that shop's stock. **A mint index MUST NOT carry POS-snapshot fields**
|
||||||
|
(the separation IS the honesty — E asserts both directions).
|
||||||
|
- **Gates read `sourcing`** (vacuous-gate law: an index with no `sourcing` FAILS). A mint crate can never
|
||||||
|
report as real. The dig card's treatment is C's call — see §7.2c.
|
||||||
|
|
||||||
|
### 7.2c Price-card fields — `condition` (v5.0-beta, R26 ledger #4)
|
||||||
|
The dig card is a **record-shop price sticker**, and a sticker's fields are artist / title / **condition** /
|
||||||
|
price. `condition` is **not in the index today** — G's snapshot carries `condition` + `sleeve_cond` per item
|
||||||
|
and drops them at emit, so `pickRealOffers` currently maps `cond: ''` and the card renders dangling
|
||||||
|
separators around a hole. That's the "database row" the ledger wants gone.
|
||||||
|
**Rule: `condition` (and optionally `sleeve_cond`) are OPTIONAL index item fields; emit them when the source
|
||||||
|
has them.** Index-only; the loader never reads them (§7.3). C's card renders whatever is present and omits
|
||||||
|
what isn't — a missing field must never leave a stray separator. **Mint items:** emit `condition` only if the
|
||||||
|
sampled listing genuinely carries one; a plausible-but-invented grade is exactly the kind of fiction
|
||||||
|
`sourcing` exists to prevent.
|
||||||
|
|
||||||
|
### 7.2d The atlas manifest — existence is declared, never probed (v5.0-beta, R26 ledger #6)
|
||||||
|
Fail-soft-by-404 collides with the zero-console-errors law: the runtime probes per-shop atlases blind and
|
||||||
|
eats the 404 noise (8 in F's R24 gate run), tolerated by attribution — a workaround, not a design.
|
||||||
|
**Rule: `web/assets/stock_godverse/index.json` is the authority for which shops carry atlases. No entry ⇒ no
|
||||||
|
fetch.** Shape:
|
||||||
|
```json
|
||||||
|
{ "version": 1,
|
||||||
|
"shops": [ { "godverseShopId": 3962749, "types": ["record"], "sourcing": "real" },
|
||||||
|
{ "godverseShopId": 31, "types": ["record"], "sourcing": "mint" } ] }
|
||||||
|
```
|
||||||
|
- **`godverseShopId` is a number in the GODVERSE namespace** — never compare it to a plan id (standing note).
|
||||||
|
- **→ F:** consult the manifest before fetching; no entry ⇒ no probe ⇒ **zero 404s, no attribution
|
||||||
|
exception**. A shop in the manifest whose fetch still fails keeps the existing fail-soft → parody.
|
||||||
|
- **→ G:** emit it alongside the atlases (mint entries included).
|
||||||
|
- **→ E:** manifest↔files consistency **both ways** — an atlas on disk absent from the manifest FAILS, and a
|
||||||
|
manifest entry with no atlas FAILS.
|
||||||
|
- **Manifest absent entirely** (a tree with no godverse atlases): that is a legitimate zero-shop state — the
|
||||||
|
wire probes nothing and stays silent. Not an error.
|
||||||
|
|
||||||
### 7.3 Fields the runtime IGNORES — and the provenance ruling (the drift dies here)
|
### 7.3 Fields the runtime IGNORES — and the provenance ruling (the drift dies here)
|
||||||
`version`, `atlas_px`, `cell`/`cell_w`/`cell_h`, `count`, `kind`, `tier`, `shop`, `crate`,
|
`version`, `atlas_px`, `cell`/`cell_w`/`cell_h`, `count`, `kind`, `tier`, `shop`, `crate`,
|
||||||
`provenance` — **`stockpack.js` reads none of them.** So the authority for their shape is not C's
|
`provenance` — **`stockpack.js` reads none of them.** So the authority for their shape is not C's
|
||||||
|
|||||||
@ -113,13 +113,21 @@ export function createDig(THREE, renderer) {
|
|||||||
const css = el('style'); css.textContent = `
|
const css = el('style'); css.textContent = `
|
||||||
.pcdg-hint{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);background:rgba(0,0,0,.7);color:#d8d8e0;padding:6px 14px;font:13px "Courier New",monospace;pointer-events:none;display:none;z-index:60}
|
.pcdg-hint{position:fixed;left:50%;bottom:16px;transform:translateX(-50%);background:rgba(0,0,0,.7);color:#d8d8e0;padding:6px 14px;font:13px "Courier New",monospace;pointer-events:none;display:none;z-index:60}
|
||||||
.pcdg-cur{position:fixed;left:50%;top:64px;transform:translateX(-50%);color:#ffd23d;font:700 15px "Courier New",monospace;text-shadow:0 1px 4px #000;pointer-events:none;text-align:center;max-width:80%;display:none;z-index:60}
|
.pcdg-cur{position:fixed;left:50%;top:64px;transform:translateX(-50%);color:#ffd23d;font:700 15px "Courier New",monospace;text-shadow:0 1px 4px #000;pointer-events:none;text-align:center;max-width:80%;display:none;z-index:60}
|
||||||
.pcdg-panel{position:fixed;right:6%;top:50%;transform:translateY(-50%);width:250px;background:#0e0e16;border:1px solid #ffd23d;padding:16px;color:#d8d8e0;font:14px "Courier New",monospace;display:none;z-index:61}
|
/* The pull panel is the shop's PRICE STICKER, not a data readout: manila card, typewriter ink, the
|
||||||
.pcdg-panel h3{margin:.1em 0;color:#ffd23d;font-size:15px}
|
round yellow $ sticker that already sits on the sleeve art (see the sleeve canvas above), a rubber-
|
||||||
.pcdg-panel .meta{color:#8a8a9a;font-size:12px;margin:4px 0 8px}
|
stamped condition grade. Fields render only when present — a missing one leaves no stray separator. */
|
||||||
.pcdg-panel .price{font-size:24px;color:#3dff8b}
|
.pcdg-panel{position:fixed;right:6%;top:50%;transform:translateY(-50%) rotate(-1.1deg);width:262px;background:#f4ecd8;border:1px solid #cbbf9e;box-shadow:0 10px 26px rgba(0,0,0,.55);padding:15px 16px 14px;color:#241f18;font:14px "Courier New",monospace;display:none;z-index:61}
|
||||||
.pcdg-panel button{margin-top:12px;width:100%;padding:9px;border:1px solid #666;background:#1d1d2b;color:#d8d8e0;font:inherit;cursor:pointer}
|
.pcdg-panel .sticker{float:right;width:54px;height:54px;border-radius:50%;background:#f4e11a;border:1px solid #d3bf00;color:#c1121f;font:700 18px Arial;line-height:54px;text-align:center;transform:rotate(5deg);margin:-2px -4px 4px 10px;box-shadow:0 1px 3px rgba(0,0,0,.25)}
|
||||||
.pcdg-panel button:hover{border-color:#3dff8b;color:#3dff8b}
|
.pcdg-panel h3{margin:.1em 0 3px;color:#241f18;font-size:15px;font-weight:700;text-transform:uppercase;letter-spacing:.02em}
|
||||||
.pcdg-panel .x{position:absolute;top:6px;right:11px;cursor:pointer;color:#888}
|
.pcdg-panel .ttl{color:#4c4436;font-size:13px;font-style:italic;margin:0 0 9px;line-height:1.25}
|
||||||
|
.pcdg-panel .stamps{clear:both;display:flex;gap:6px;align-items:center;flex-wrap:wrap;min-height:1px}
|
||||||
|
.pcdg-panel .grade{border:1.5px solid #b3121f;color:#b3121f;padding:1px 6px;font:700 11px "Courier New",monospace;letter-spacing:.08em;transform:rotate(-2.5deg)}
|
||||||
|
.pcdg-panel .tag{color:#6f6553;font-size:11px;letter-spacing:.05em}
|
||||||
|
.pcdg-panel .star{color:#b3121f;font-size:13px}
|
||||||
|
.pcdg-panel button{margin-top:13px;width:100%;padding:9px;border:1px solid #8a7f66;background:#e7dcc2;color:#241f18;font:700 13px "Courier New",monospace;letter-spacing:.06em;cursor:pointer}
|
||||||
|
.pcdg-panel button:hover:not(:disabled){background:#241f18;color:#f4e11a;border-color:#241f18}
|
||||||
|
.pcdg-panel button:disabled{color:#9a917c;border-color:#c3b99f;cursor:default}
|
||||||
|
.pcdg-panel .x{position:absolute;top:4px;left:8px;cursor:pointer;color:#a89e86;font-size:13px}
|
||||||
.pcdg-out{position:fixed;left:16px;top:16px;background:#1d1d2b;border:1px solid #666;color:#d8d8e0;padding:8px 14px;font:13px "Courier New",monospace;cursor:pointer;display:none;z-index:60}
|
.pcdg-out{position:fixed;left:16px;top:16px;background:#1d1d2b;border:1px solid #666;color:#d8d8e0;padding:8px 14px;font:13px "Courier New",monospace;cursor:pointer;display:none;z-index:60}
|
||||||
.pcdg-out:hover{border-color:#3dff8b;color:#3dff8b}
|
.pcdg-out:hover{border-color:#3dff8b;color:#3dff8b}
|
||||||
.pcdg-toast{position:fixed;left:50%;top:40%;transform:translate(-50%,-50%);background:#0e0e16;border:1px solid #3dff8b;color:#3dff8b;padding:14px 22px;font:700 15px "Courier New",monospace;z-index:62;display:none}`;
|
.pcdg-toast{position:fixed;left:50%;top:40%;transform:translate(-50%,-50%);background:#0e0e16;border:1px solid #3dff8b;color:#3dff8b;padding:14px 22px;font:700 15px "Courier New",monospace;z-index:62;display:none}`;
|
||||||
@ -211,10 +219,21 @@ export function createDig(THREE, renderer) {
|
|||||||
function showPanel(entry) {
|
function showPanel(entry) {
|
||||||
const o = entry.offer;
|
const o = entry.offer;
|
||||||
const cash = getCashCb ? getCashCb() : 999;
|
const cash = getCashCb ? getCashCb() : 999;
|
||||||
panel.innerHTML = `<div class="x">✕</div><h3>${o.a}</h3>`
|
// A price sticker, composed from what this item ACTUALLY has. Real pack items carry no year (and
|
||||||
+ `<div class="meta">“${o.t}” · ${o.y} ${o.s} · ${o.cond}${o.rare ? ' · ★ RARE' : ''}</div>`
|
// may carry no grade); procedural ones carry both. Build the stamp row from present parts only —
|
||||||
+ `<div class="price">$${o.price}</div>`
|
// never emit a separator around a hole (that's what read as a database row). §7.2c.
|
||||||
+ `<button ${o.price > cash ? 'disabled' : ''}>${o.price > cash ? 'not enough cash' : 'BUY IT'}</button>`;
|
const esc = (s) => String(s).replace(/[&<>"]/g, m => ({ '&':'&','<':'<','>':'>','"':'"' }[m]));
|
||||||
|
const stamps = [];
|
||||||
|
if (o.cond) stamps.push(`<span class="grade">${esc(o.cond)}${o.sleeveCond ? '/' + esc(o.sleeveCond) : ''}</span>`);
|
||||||
|
const line = [o.y, o.s].filter(Boolean).join(' '); // "1974 SOUL" | "SOUL" | "" — never " · "
|
||||||
|
if (line) stamps.push(`<span class="tag">${esc(line)}</span>`);
|
||||||
|
if (o.rare) stamps.push(`<span class="star">★ ${o.real ? 'GRAIL' : 'RARE'}</span>`);
|
||||||
|
panel.innerHTML = `<div class="x">✕</div>`
|
||||||
|
+ `<div class="sticker">$${esc(o.price)}</div>`
|
||||||
|
+ `<h3>${esc(o.a)}</h3>`
|
||||||
|
+ (o.t ? `<div class="ttl">“${esc(o.t)}”</div>` : '')
|
||||||
|
+ (stamps.length ? `<div class="stamps">${stamps.join('')}</div>` : '')
|
||||||
|
+ `<button ${o.price > cash ? 'disabled' : ''}>${o.price > cash ? 'NOT ENOUGH CASH' : 'BUY IT'}</button>`;
|
||||||
panel.style.display = 'block';
|
panel.style.display = 'block';
|
||||||
panel.querySelector('.x').onclick = unpull;
|
panel.querySelector('.x').onclick = unpull;
|
||||||
const b = panel.querySelector('button');
|
const b = panel.querySelector('button');
|
||||||
@ -271,8 +290,16 @@ export function createDig(THREE, renderer) {
|
|||||||
const rr = mulberry32(seed >>> 0), out = [];
|
const rr = mulberry32(seed >>> 0), out = [];
|
||||||
for (let i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
const it = pack.items[(rr() * pack.items.length) | 0];
|
const it = pack.items[(rr() * pack.items.length) | 0];
|
||||||
|
// Real fields straight off the atlas index (§7.2c): condition/sleeve_cond are OPTIONAL — present on
|
||||||
|
// POS-sourced items, absent on mint ones that had no genuine grade. `y` (year) is never in the index,
|
||||||
|
// so it stays empty and the card simply omits it. No invented values: an unstated grade stays unstated.
|
||||||
|
// `grail` becomes the ★ stamp, so it must NOT also ride in `s` — otherwise the card reads
|
||||||
|
// "GRAIL ★ GRAIL". (Procedural sleeves are unaffected: their `s` is a genre, not the band.)
|
||||||
|
const band = (it.price_band || '').toUpperCase();
|
||||||
out.push({ real: true, pack, item: it, a: it.artist, t: it.title, price: it.price,
|
out.push({ real: true, pack, item: it, a: it.artist, t: it.title, price: it.price,
|
||||||
s: (it.price_band || '').toUpperCase(), y: '', cond: '', rare: it.price_band === 'grail' });
|
s: band === 'GRAIL' ? '' : band, y: '',
|
||||||
|
cond: it.condition || '', sleeveCond: it.sleeve_cond || '',
|
||||||
|
rare: it.price_band === 'grail' });
|
||||||
}
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user