Lane E round 8: REAL stock packs (record 350 / book 311 / toy 273) live on depot
John unblocked GODVERSE DB access (m1ultra native-Postgres clones, read-only SELECT, peer auth). All 3 packs rebuilt from real data: - record 350: discogs_full.inventory (real store stock) join release/release_image, real Discogs cover art. - book 311 + toy 273: dealgod.products by category_path, real product photos + prices. Metadata parody-transformed (deterministic, no source-token leak -> no real trademarks in pack text); cover images are real release/product art (read-only, non-economy, decision #2); book prices seeded (source is info-only, John's call). 15 atlases published to the depot; indexes committed (the C contract) + staged for ?localdepot; all pass the pack-QA gate. build_stock_pack.py gained --from-tsv (extract-on-DB-box -> build-here), portrait 176x256 book cell, seeded-price fallback. qa --strict GREEN 5/5. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
900b274a9a
commit
a667283cf3
3
.gitignore
vendored
3
.gitignore
vendored
@ -13,3 +13,6 @@ pipeline/.peds_orig/
|
|||||||
pipeline/.props_orig/
|
pipeline/.props_orig/
|
||||||
pipeline/.peds_r6/
|
pipeline/.peds_r6/
|
||||||
pipeline/_stockpack/
|
pipeline/_stockpack/
|
||||||
|
pipeline/_records.tsv
|
||||||
|
pipeline/_books.tsv
|
||||||
|
pipeline/_toys.tsv
|
||||||
|
|||||||
@ -16,9 +16,15 @@ other lanes' files was touched.*
|
|||||||
qa** — proven (inverted-UV+empty-title → exit 1). qa `--strict` GREEN 5/5.
|
qa** — proven (inverted-UV+empty-title → exit 1). qa `--strict` GREEN 5/5.
|
||||||
- **Tags pushed** (John-delegated): origin/main = HEAD (1a20501) + v1.0/v1.1/v2.0-alpha/v2.0-beta all
|
- **Tags pushed** (John-delegated): origin/main = HEAD (1a20501) + v1.0/v1.1/v2.0-alpha/v2.0-beta all
|
||||||
live on origin — verified.
|
live on origin — verified.
|
||||||
- **Blocker (flagged to Fable):** real ~150–250-item book/toy (+ record) packs need `GODVERSE_DSN`
|
- **REAL packs LIVE (John unblocked DB access).** All 3 packs rebuilt from GODVERSE (m1ultra
|
||||||
(dealgod Postgres, up on :5432, read from env). One `--kind X --from-db` command each once set.
|
Postgres clones, read-only SELECT, peer auth): **record 350** (`discogs_full.inventory` — John's
|
||||||
Current packs are synthetic placeholders (real index format). No fal spend.
|
real store stock + real Discogs covers), **book 311** + **toy 273** (`dealgod.products` by
|
||||||
|
category, real product photos + prices). Metadata parody-transformed (no real trademarks); covers
|
||||||
|
are real art (decision #2); book prices seeded (info-only source). 15 atlases published to the
|
||||||
|
depot, indexes committed to `pipeline/packs/` + staged, all pass the pack-QA gate. `build_stock_pack.py`
|
||||||
|
gained `--from-tsv` (extract on the DB box → build here) + portrait book cell + seeded-price
|
||||||
|
fallback. Access path: deployment DB was Docker-internal/SSH-denied → used the m1ultra clones per
|
||||||
|
John. No fal spend.
|
||||||
- **On-call** (B rain-streak/puddle, D door-swing tell): none requested.
|
- **On-call** (B rain-streak/puddle, D door-swing tell): none requested.
|
||||||
|
|
||||||
## Round 7 (Fable) — the two feeders (ped merge + stock pack)
|
## Round 7 (Fable) — the two feeders (ped merge + stock pack)
|
||||||
|
|||||||
@ -1,6 +1,19 @@
|
|||||||
# LANE E — cross-lane notes
|
# LANE E — cross-lane notes
|
||||||
|
|
||||||
## Round 8
|
## Round 8 — REAL packs live (update)
|
||||||
|
|
||||||
|
**→ Lane C: all 3 stock packs are now REAL** (GODVERSE data, John unblocked DB access). Same schema
|
||||||
|
you wired — just richer data, no code change needed:
|
||||||
|
- **record** — 350 real vinyl (John's store stock, real Discogs covers), 6 atlases, cell 256×256.
|
||||||
|
- **book** — 311 real book covers (`dealgod.products` books), 4 atlases, cell **176×256 (portrait
|
||||||
|
face-out cover**, not thin spine — I only have cover art; render books face-out).
|
||||||
|
- **toy** — 273 real toy/collectible photos, 5 atlases, cell 256×256.
|
||||||
|
Metadata is parody-transformed (no real titles/artists/brands); covers are real art; book prices are
|
||||||
|
seeded (source is info-only). Indexes committed to `pipeline/packs/` + staged (`assets/models/`, your
|
||||||
|
`?localdepot` path); atlases published to the depot. All pass the pack-QA gate. If your book shelf
|
||||||
|
wants thin spines, tell me — I'd need spine art (don't have it; covers only).
|
||||||
|
|
||||||
|
## Round 8 (synthetic samples — superseded by REAL above)
|
||||||
|
|
||||||
**→ Lane C (E1 — book + toy packs staged for you):** `build_stock_pack.py` is generalized over kinds;
|
**→ Lane C (E1 — book + toy packs staged for you):** `build_stock_pack.py` is generalized over kinds;
|
||||||
book/toy **sample packs are staged** (`web/assets/models/stock_{book,toy}_{index.json,atlas_00.webp}`,
|
book/toy **sample packs are staged** (`web/assets/models/stock_{book,toy}_{index.json,atlas_00.webp}`,
|
||||||
|
|||||||
@ -328,3 +328,26 @@ hunt). One command each once set: `build_stock_pack.py --kind book --from-db --c
|
|||||||
current staged packs are synthetic placeholders (real index format); provenance of the real packs =
|
current staged packs are synthetic placeholders (real index format); provenance of the real packs =
|
||||||
GODVERSE metadata (OpenLibrary/toygod) **parody-transformed** (no real titles/authors/brands ship) +
|
GODVERSE metadata (OpenLibrary/toygod) **parody-transformed** (no real titles/authors/brands ship) +
|
||||||
real cover art (read-only, non-economy). No fal spend this round.
|
real cover art (read-only, non-economy). No fal spend this round.
|
||||||
|
|
||||||
|
## Round 8 (cont.) — REAL stock packs live (GODVERSE, John-authorized DB access)
|
||||||
|
|
||||||
|
The synthetic samples are replaced by **real** packs, built from GODVERSE via peer-auth on m1ultra
|
||||||
|
(`johnking@100.91.239.7`, native Postgres, `psql` at `/opt/homebrew/Cellar/libpq/18.4/bin`). Access
|
||||||
|
resolved after the deployment DB proved Docker-internal (port closed, SSH denied) — John pointed to
|
||||||
|
the m1ultra clones. All extraction was **read-only SELECT**; no creds guessed, no writes.
|
||||||
|
|
||||||
|
| pack | items | source (m1ultra) | covers | prices |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| **record** | 350 | `discogs_full`: `inventory` (John's real store stock) ⋈ `release` ⋈ `release_image` | real Discogs cover art (`monsterrobot.party` CDN, from `local_url`) | real store prices |
|
||||||
|
| **book** | 311 | `dealgod.products` WHERE `category_path LIKE 'books%'` | real product photos (`image_url`, portrait 176×256) | real `current_price` |
|
||||||
|
| **toy** | 273 | `dealgod.products` WHERE `category_path LIKE 'collectables-hobbies-toys%'` | real product photos (`image_url`) | real `current_price` |
|
||||||
|
|
||||||
|
Build: `build_stock_pack.py --kind <k> --from-tsv` (rows extracted to a gitignored TSV, covers fetched
|
||||||
|
at build time, resized into atlas cells). **Metadata is parody-transformed** (titles/artists/authors/
|
||||||
|
brands → house word banks, deterministic, shares no source token — "Dark Side of the Moon"/"Pink Floyd"
|
||||||
|
→ "Quiet Milk Bar"/"The Galahs") so **no real trademark ships in the pack text**; the **cover images are
|
||||||
|
real release/product art** (read-only, non-economy, per decision #2 — John's own store inventory + AU
|
||||||
|
marketplace listings). Books are info-only in the source → **prices seeded deterministically** (John's
|
||||||
|
call). 15 atlases + 3 indexes: atlases published to the depot (`/api/upload`), indexes committed to
|
||||||
|
`pipeline/packs/` (the C contract) + staged for `?localdepot`. All 3 pass the pack-QA gate. Toy filter
|
||||||
|
is broad (some comics/coins among the collectibles) — acceptable for a collectibles shop; tighten later.
|
||||||
|
|||||||
@ -54,8 +54,16 @@ BANKS = {
|
|||||||
"Wattle", "Billabong", "Outback", "Reef City"],
|
"Wattle", "Billabong", "Outback", "Reef City"],
|
||||||
band_b=["Toys", "Playsystems", "Games", "Fun Co.", "Novelties", "Workshop", "Mfg.", "Play Lab"]),
|
band_b=["Toys", "Playsystems", "Games", "Fun Co.", "Novelties", "Workshop", "Mfg.", "Play Lab"]),
|
||||||
}
|
}
|
||||||
CELL = {"record": (256, 256), "book": (96, 256), "toy": (256, 256)} # book = tall-thin spine
|
CELL = {"record": (256, 256), "book": (176, 256), "toy": (256, 256)} # book = portrait cover (2:3-ish)
|
||||||
GRID = {"record": 8, "book": 16, "toy": 8} # columns per atlas row
|
GRID = {"record": 8, "book": 10, "toy": 8} # columns per atlas row
|
||||||
|
|
||||||
|
|
||||||
|
def seeded_price(kind, title, artist):
|
||||||
|
"""Some sources carry no price (books are info-only) — mint a deterministic, kind-plausible
|
||||||
|
price so the buy loop + price bands work. Same item → same price every build."""
|
||||||
|
s = _seed("price", kind, title or "", artist or "")
|
||||||
|
lo, hi = {"book": (3, 40), "toy": (4, 35), "record": (8, 60)}.get(kind, (5, 40))
|
||||||
|
return lo + s % (hi - lo + 1)
|
||||||
|
|
||||||
|
|
||||||
def _seed(*p):
|
def _seed(*p):
|
||||||
@ -115,6 +123,29 @@ def rows_from_db(kind, count):
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def rows_from_tsv(path):
|
||||||
|
"""Rows from a `artist\\ttitle\\tprice\\tcover_url` TSV extracted from GODVERSE (discogs_full
|
||||||
|
inventory JOIN release JOIN release_image — John's real store stock + saved Discogs covers).
|
||||||
|
Covers are fetched from the URL at build time; metadata is parody-transformed downstream."""
|
||||||
|
out = []
|
||||||
|
for line in open(path, encoding="utf-8"):
|
||||||
|
parts = line.rstrip("\n").split("\t")
|
||||||
|
if len(parts) < 4 or not parts[3]: # need a cover URL
|
||||||
|
continue
|
||||||
|
col0, col1, price, cover = parts[0], parts[1], parts[2], parts[3]
|
||||||
|
# record source is (artist, title); single-field sources (books/toys from products) put the
|
||||||
|
# title in col0 and leave col1 empty — carry the real title through so parody seeds off it.
|
||||||
|
if col1:
|
||||||
|
artist, title = col0, col1
|
||||||
|
elif col0:
|
||||||
|
artist, title = "", col0
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
out.append({"artist": artist, "title": title,
|
||||||
|
"price": int(price) if str(price).lstrip("-").isdigit() else None, "img": cover})
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def rows_sample(kind, n):
|
def rows_sample(kind, n):
|
||||||
"""Synthetic rows (solid-colour cells at the kind's aspect) — proves the pipeline with no DB."""
|
"""Synthetic rows (solid-colour cells at the kind's aspect) — proves the pipeline with no DB."""
|
||||||
from PIL import Image, ImageDraw
|
from PIL import Image, ImageDraw
|
||||||
@ -154,8 +185,9 @@ def build_pack(kind, rows):
|
|||||||
sheet.paste(cov, (gx * cw, gy * ch))
|
sheet.paste(cov, (gx * cw, gy * ch))
|
||||||
ptitle, partist = parody(kind, r["title"], r["artist"])
|
ptitle, partist = parody(kind, r["title"], r["artist"])
|
||||||
u0, v0 = gx * cw / W, gy * ch / H
|
u0, v0 = gx * cw / W, gy * ch / H
|
||||||
|
price = r["price"] if r.get("price") else seeded_price(kind, r["title"], r["artist"])
|
||||||
item = {"id": f"{kind[:3]}_{len(items):04d}", "title": ptitle, "artist": partist,
|
item = {"id": f"{kind[:3]}_{len(items):04d}", "title": ptitle, "artist": partist,
|
||||||
"price": int(r["price"] or 4), "price_band": price_band(kind, r["price"]),
|
"price": int(price), "price_band": price_band(kind, price),
|
||||||
"atlas": aname, "uv": [round(u0, 4), round(v0, 4),
|
"atlas": aname, "uv": [round(u0, 4), round(v0, 4),
|
||||||
round(u0 + cw / W, 4), round(v0 + ch / H, 4)]}
|
round(u0 + cw / W, 4), round(v0 + ch / H, 4)]}
|
||||||
items.append({k: item[k] for k in INDEX_FIELDS})
|
items.append({k: item[k] for k in INDEX_FIELDS})
|
||||||
@ -189,7 +221,9 @@ def main():
|
|||||||
f".webp atlases + *_index.json via /api/upload.")
|
f".webp atlases + *_index.json via /api/upload.")
|
||||||
return
|
return
|
||||||
kind = a[a.index("--kind") + 1] if "--kind" in a else "record"
|
kind = a[a.index("--kind") + 1] if "--kind" in a else "record"
|
||||||
if "--sample" in a:
|
if "--from-tsv" in a:
|
||||||
|
rows = rows_from_tsv(a[a.index("--from-tsv") + 1])
|
||||||
|
elif "--sample" in a:
|
||||||
rows = rows_sample(kind, int(a[a.index("--sample") + 1]))
|
rows = rows_sample(kind, int(a[a.index("--sample") + 1]))
|
||||||
elif "--from-db" in a:
|
elif "--from-db" in a:
|
||||||
rows = rows_from_db(kind, int(a[a.index("--count") + 1]) if "--count" in a else 250)
|
rows = rows_from_db(kind, int(a[a.index("--count") + 1]) if "--count" in a else 250)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user