Lane G R24 (v5.0-alpha): the crate's real street — redhill_godverse, the keyed re-emit, and two contract conflicts

THE SHOP HAS A STREET. redhill_godverse: Monster Robot Party seated on Musgrave Road (verified —
lot 8, type record, godverseShopId 3962749), 37 shops on E's 884 real Red Hill roads. Its
coordinate is John-supplied (Google Maps place /g/11g6rlbbc0 -> -27.4553791, 153.0076244) because
it is derivable from nothing we hold: OSM doesn't know the shop, the census doesn't either,
dealgod's stores/store_entity rows are NULL lat/lng, recordgod has no address. Verified inside E's
bbox and on Musgrave Road's own geometry; my own estimate was ~120 m out.

RE-EMIT (ledger #5 + #2): atlas keyed by godverseShopId with US `license` throughout (British
retired, 0 occurrences) — atlas-QA OK, 120 real records, byte-identical re-bake (the .webp bytes
did not move; only the index). newtown_godverse re-emitted with ids (18 keyed). godverse_town.py:
psycopg2 -> psql, EXTRA_SHOPS roster, and Fable's R22 Ruling 2 finally implemented.

RULING 2 WAS LOAD-BEARING, NOT COSMETIC (measured): census-only Red Hill is unshippable —
9 shops = 306 m spacing warn; +Monster Robot = 10 shops = 261 m warn AND a frontage poster seated
INSIDE edge 1037's kerb (-2.95 m); + the donor's texture layer (37) = no warn, poster passes.
261 m is worse than the 255 m that retired ballarat this round: the alpha's headline town would
have shipped flagged "scattered, not a high street, or retire the town". 9 donor heroes swapped
for census entries (18 in Newtown), counted per the ruling.

CONFLICT #1 — C §7.3 vs E's validator. C says lift provenance to TOP LEVEL, US `license`, British
retired, "exactly what E's validator reads". Measured: it is not. validate_atlas.py:98 reads
NESTED `provenance`; :105 reads `licence` British-first. Lifting-and-retiring as written FAILS the
gate; my R23 atlas already passed it untouched. Same species as the bug that held the tag — a doc
asserting what code does without running it. Resolved: E's check accepts `licence or license`, so
US-nested passes; the four also ride at top level (C's contract + the town-cache convention) off
one source of truth. -> E, one line: :198 PRINTS `licence` British-only while the check accepts
both, so C's mandated US spelling silently stops printing the licence flag — which :199's own
comment calls a human call. Gate passes; evidence line vanished. Fix: .get("licence") or .get("license").

CONFLICT #2 — Ruling 2 vs A's identity gate. NEEDS A RULING; it is why the tree is red (6 of 8).
Ruling 2 makes a godverse cache mixed: a keyed GODVERSE layer + an inherited OSM texture layer.
A's sweep asserts EVERY shop is keyed -> partial FAILs. Texture shops carry no godverseShopId
deliberately: an OSM milkbar has no GODVERSE identity, and minting one from its OSM id pushes a
third id space into a field that already carries two — A's validator calls a duplicate
mis-stocking, charter risk #3's nightmare with Monster Robot's crate as the prize. And A's own two
checks disagree: the validator says "Missing = tier 0 (soft). Duplicate = mis-stocked (hard). They
are not the same failure", while the sweep fails partial keying because it "mis-stocks the rest" —
conflating exactly those two. Proposed (A's call, Fable's ruling): assert coverage over the
godverse layer, not the inherited texture layer.

THE 8 RED CHECKS, ITEMISED: newtown_godverse base+gig goldens (2) moved by the re-emit exactly as
ledger #2 intends — A re-pins, base 0xcf69b387 gig 0x1e266f60; godverse identity x3 per godverse
town (6) = conflict #2. Nothing else. Classic covenant 0x3fa36874 intact. redhill_godverse pins:
base 0xb2224939. Verified live: the shop's 120-record pack and the town-wide 350 pack now COEXIST
through C's type+base fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-07-17 01:31:07 +10:00
parent 5815dfbd58
commit 86e298531e
8 changed files with 39258 additions and 28 deletions

View File

@ -3,6 +3,84 @@
*Lane brief: `docs/LANES/LANE_G_GODVERSE.md`. This file follows your progress-file convention — *Lane brief: `docs/LANES/LANE_G_GODVERSE.md`. This file follows your progress-file convention —
newest round first. Fable-on-ultra writing.* newest round first. Fable-on-ultra writing.*
## Round 24 (2026-07-17) — the re-emit + THE SHOP'S REAL STREET (ledger #5)
**Landed (branch `lane-G-godverse`):**
- **`redhill_godverse`** — the town whose record shop is THE shop. Monster Robot Party seated on
Musgrave Road (**verified: lot 8, type `record`, `godverseShopId` 3962749**), 37 shops, 884 real
Red Hill roads off E's donor.
- **The atlas re-emit** — US `license` throughout (British `licence` retired, 0 occurrences),
provenance lifted to top level per C §7.3 **and** kept nested per E's validator (see conflict #1).
`atlas-QA OK`, 120 real records, byte-identical re-bake holds.
- **`newtown_godverse` re-emitted with `godverseShopId`** (ledger #2) — 18 census shops keyed.
- **`godverse_town.py`**: psycopg2 → `psql` (the m3 has no psycopg2); emits `godverseShopId`;
`EXTRA_SHOPS` roster; **Fable's R22 Ruling 2 finally implemented** (see below).
- G3 §4: the `godverseShopId`/`godverse_id` naming split recorded (two artifacts, two conventions).
**Monster Robot Party's coordinate** is John-supplied (Google Maps place `/g/11g6rlbbc0`
-27.4553791, 153.0076244). It could not be derived: OSM doesn't know the shop (no name match, no
147 Musgrave Rd address node), the census doesn't have it, dealgod's `stores`/`store_entity` rows
carry NULL lat/lng, and recordgod has no address anywhere. Verified inside E's bbox **and** on
Musgrave Road's own geometry. My own estimate was ~120 m out — asked instead of shipping it.
**FABLE'S RULING 2, IMPLEMENTED (R22 → R24) — and it was load-bearing, not cosmetic.** "Merge
census heroes WITH the donor's texture shops; census heroes win a collision; count the swap."
I never built it. Measured this round, census-only Red Hill is **not shippable**:
| redhill_godverse | shops | A's spacing warn | poster-clears-kerb |
|---|---|---|---|
| census only | 9 | **306 m** ⚠ | pass |
| census + Monster Robot | 10 | **261 m** ⚠ | **FAIL** (poster inside edge 1037 by 2.95 m) |
| **+ donor texture (Ruling 2)** | **37** | **none** ✓ | **pass** ✓ |
| *(E's donor `redhill_real`, for reference)* | 36 | none | pass |
261 m is **worse than the 255 m that retired ballarat this round** — the alpha's headline town
would have shipped flagged "scattered, not a high street, or retire the town". Ruling 2 fixes both.
9 donor heroes swapped for their census entries in Red Hill, 18 in Newtown — counted, per the ruling.
**CONFLICT #1 — C's contract §7.3 vs E's validator (provenance).** C says "lift the four to TOP
LEVEL, US `license`; British retired — *exactly what E's validator reads*". **Measured: it is not.**
`validate_atlas.py:98` reads **nested** `provenance`, and `:105` reads `licence` British-first.
Lifting-and-retiring as written **fails the gate**. My R23 atlas already passed it untouched. This
is the same species as the bug that held the tag — a doc asserting what code does without running
it. **Resolved without drama:** E's check accepts `licence or license`, so US-nested passes; I emit
the four at top level (C's contract + the town-cache house convention) off ONE source of truth.
**→ E, one line:** `validate_atlas.py:198` PRINTS `licence` British-only while its *check* accepts
both — so adopting C's mandated US spelling **silently stops printing the licence flag**, which
:199's own comment calls a human call ("the licence is PRINTED — clearing it is a human call").
The gate still passes; the evidence line vanished. Fix: `.get("licence") or .get("license")`.
**CONFLICT #2 — Ruling 2 vs A's identity gate. THIS ONE NEEDS A RULING; it is why the tree is red.**
Ruling 2 makes a godverse cache *mixed*: a keyed GODVERSE layer (census + Monster Robot) plus an
inherited OSM texture layer. A's sweep asserts **every** shop is keyed → partial ⇒ FAIL. The two
standing rulings cannot both hold.
**The texture shops carry no `godverseShopId` deliberately**, and I'd argue A's own words settle it:
- The field *means* "this lot's stock lives at `stock_godverse/<id>/`". An OSM milkbar has no
GODVERSE identity. Minting one from its OSM id pushes a **third id space** into a field that
already carries two, and A's validator calls a duplicate **mis-stocking** — charter risk #3's
exact nightmare, with Monster Robot's crate as the prize. (Measured: OSM ids here are ≥53.1 M vs
census ≤2992 and store id 3,962,749 — no collision *today*; dealgod store ids reach 7 digits and
OSM ids are 8+, so the margin is thin, and "no collision today" is not an id-space design.)
- **A's validator and A's sweep disagree with each other.** The validator: *"Missing = tier 0
(soft). Duplicate = mis-stocked (hard). **They are not the same failure.**"* The sweep fails
partial keying because it *"mis-stocks the rest"* — conflating precisely the two failures A said
are not the same. Unkeyed → parody is the **designed ladder**, not a gap.
- **Proposed (A's call, Fable's ruling):** assert coverage over the **godverse layer**, not the
inherited texture layer — the subject is "shops that claim stock", and the gate stays honest
(it still names its subject and proves a count). Zero-keyed still SKIPs; duplicates still error.
**The 8 red checks, itemised — no surprises for F:**
- `newtown_godverse` base+gig goldens (**2**) — my re-emit moved them, exactly as ledger #2
intends. **A re-pins** (batched): base `0xcf69b387`, gig `0x1e266f60`.
- `godverse identity` ×3 on each godverse town (**6**) — conflict #2, above. Nothing else.
- Unpinned (warn, expected): `redhill_godverse` base `0xb2224939` / gig — **A pins**.
- **Classic covenant `0x3fa36874` intact.** `atlas-QA OK`.
**If Fable rules the other way** (texture layer out): revert to census-only and F inherits the
poster-kerb FAIL at edge 1037 + a 261 m town — that break is A/B's invariant, exposed by real data,
and would need an owner before the tag. I'd rather hand F the conflict than the broken town.
## Round 23 (2026-07-16) — G2a: THE FIRST REAL CRATE + the G3 draft ## Round 23 (2026-07-16) — G2a: THE FIRST REAL CRATE + the G3 draft
**Landed (branch `lane-G-godverse`, G namespace only — ready for your mid-round merge):** **Landed (branch `lane-G-godverse`, G namespace only — ready for your mid-round merge):**

View File

@ -112,7 +112,12 @@ Design rules:
says only what changed. A sold record is a `sku` in `gone[]``collapseBuyItem()` (already says only what changed. A sold record is a `sku` in `gone[]``collapseBuyItem()` (already
built, R9) zero-areas the sleeve. Sold-means-gone is a *diff*, not a re-fetch. built, R9) zero-areas the sleeve. Sold-means-gone is a *diff*, not a re-fetch.
- **`etag`/`since`** so a re-enter is a 304, not a payload. - **`etag`/`since`** so a re-enter is a 304, not a payload.
- Shop id is the **godverse id** (§1a), never a POS internal id. - Shop id is the **godverse id** (§1a), never a POS internal id. **R24 naming, as landed:** the
town cache carries `shop.godverseShopId` (A's schema field, camelCase, read by the JS runtime);
the atlas index carries `shop.godverse_id` (snake_case, what E's `validate_atlas.py` requires).
Same id, two artifacts, two house conventions — the API uses `godverse_id` on the wire to match
the Python/JSON side it is served from. Recorded rather than silently reconciled: if the
integrators want one spelling, it is a one-line change in each emitter, not a design question.
--- ---

View File

@ -35,7 +35,7 @@
"captured": "2026-07-15", "captured": "2026-07-15",
"extraction": "see load_image_map() docstring \u2014 the products projection command" "extraction": "see load_image_map() docstring \u2014 the products projection command"
}, },
"licence": { "license": {
"covers": "the shop's own product shots (monsterrobot.party), cached by dealgod", "covers": "the shop's own product shots (monsterrobot.party), cached by dealgod",
"zone": "in-house-green", "zone": "in-house-green",
"flag": "FLAG BEFORE ANY PUBLIC/COMMERCIAL RELEASE", "flag": "FLAG BEFORE ANY PUBLIC/COMMERCIAL RELEASE",

View File

@ -151,7 +151,9 @@ def snapshot(args):
"captured": args.captured, "captured": args.captured,
"extraction": "see load_image_map() docstring — the products projection command", "extraction": "see load_image_map() docstring — the products projection command",
}, },
"licence": { # US `license` throughout (R24: British `licence` retired per C's contract §7.3; E's
# validator reads `provenance.licence or provenance.license`, so US passes the gate).
"license": {
"covers": "the shop's own product shots (monsterrobot.party), cached by dealgod", "covers": "the shop's own product shots (monsterrobot.party), cached by dealgod",
"zone": "in-house-green", "flag": "FLAG BEFORE ANY PUBLIC/COMMERCIAL RELEASE", "zone": "in-house-green", "flag": "FLAG BEFORE ANY PUBLIC/COMMERCIAL RELEASE",
"metadata": "real titles/artists — John's R23 amendment to the no-real-trademarks law", "metadata": "real titles/artists — John's R23 amendment to the no-real-trademarks law",
@ -204,16 +206,31 @@ def pack(args):
with open(args.snapshot, "rb") as fh: with open(args.snapshot, "rb") as fh:
snap_sha = hashlib.sha256(fh.read()).hexdigest() snap_sha = hashlib.sha256(fh.read()).hexdigest()
lic = snap["license"]
generator, snapshot_name = "pipeline/godverse_stock.py", os.path.basename(args.snapshot)
attribution = (f"Stock, prices + covers: {shop['name']} ({OWN_PHOTO_HOST}) — the shop's own "
f"product shots · cover cache: GODVERSE/dealgod · POS: recordgod")
index = { index = {
"version": 1, "kind": "record", "tier": 1, "version": 1, "kind": "record", "tier": 1,
"atlas_px": ATLAS_PX, "cell_w": CELL_W, "cell_h": CELL_H, "atlas_px": ATLAS_PX, "cell_w": CELL_W, "cell_h": CELL_H,
"count": len(idx_items), "atlases": atlases, "count": len(idx_items), "atlases": atlases,
# TOP LEVEL, per C's contract §7.3 + the house convention of the shipped town caches
# (`license` is a short US-spelled string there, `attribution` its companion).
"license": f"{lic['zone']}{lic['covers']}; {lic['flag']}",
"attribution": attribution,
"generator": generator,
"snapshot": snapshot_name,
"shop": {k: shop[k] for k in ("godverse_id", "slug", "name", "suburb", "state")}, "shop": {k: shop[k] for k in ("godverse_id", "slug", "name", "suburb", "state")},
"crate": snap["crate"], "crate": snap["crate"],
# NESTED, per E's validate_atlas.py — which is the authority C's §7.3 defers to for these
# fields, and which reads provenance.{generator,snapshot,licence|license{zone,flag,covers}}.
# C's doc asserts top-level is "exactly what E's validator reads"; measured, it is not (see
# G-progress R24). Emitting both keeps C's contract and E's gate green off ONE source of
# truth (`lic`/`generator`/`snapshot` above) — flagged for F/Fable to collapse to one.
"provenance": { "provenance": {
"generator": "pipeline/godverse_stock.py", "generator": generator,
"source": snap["source"], "licence": snap["licence"], "source": snap["source"], "license": lic,
"snapshot": os.path.basename(args.snapshot), "snapshot_sha256": snap_sha, "snapshot": snapshot_name, "snapshot_sha256": snap_sha,
"determinism": "pure bake — same snapshot + same cover bytes => byte-identical atlas; " "determinism": "pure bake — same snapshot + same cover bytes => byte-identical atlas; "
"covers pinned by sha256, no RNG, no clock", "covers pinned by sha256, no RNG, no clock",
}, },

View File

@ -6,12 +6,22 @@ shops[] come from thriftgod's Postgres (the real-business census DealGod scraped
walk the town's actual streets past its actual secondhand shops. walk the town's actual streets past its actual secondhand shops.
python3 pipeline/godverse_town.py newtown_real newtown_godverse # roads-donor key, out key python3 pipeline/godverse_town.py newtown_real newtown_godverse # roads-donor key, out key
python3 pipeline/godverse_town.py redhill_real redhill_godverse # THE shop's real street
Runs on ultra (needs the local `thriftgod` PG + psycopg2 the thriftgod server's own deps). Reads thriftgod via the `psql` CLI (R24): psycopg2 isn't installed on the m3, and one less dep
between the census and the cache. Works unchanged wherever thriftgod lives.
`godverseShopId` (R24 ledger #2, with Lane A) — the OPAQUE key that resolves
`stock_godverse/<godverseShopId>/`. **It is not `shop.id` and not "the census id"**: census shops
carry their thriftgod id (max 2992), while Monster Robot Party isn't in the census at all and
carries its dealgod store id (3962749). Two disjoint id spaces, one opaque field G emits it,
everyone else reads it, nobody derives it. A's `validateTownCache` wants a positive integer,
unique per cache; **missing is a WARN, not an error** (measured A's rule is deliberate: absent
stock identity must never fail a town's boot, per the charter's determinism boundary). So the
GODVERSE layer is keyed and the inherited texture layer is not see Ruling 2 below for why that
is the honest shape rather than a gap.
""" """
import json, os, sys import json, math, os, subprocess, sys
import psycopg2, psycopg2.extras
DONOR, OUT = sys.argv[1], sys.argv[2] DONOR, OUT = sys.argv[1], sys.argv[2]
HERE = os.path.dirname(os.path.abspath(__file__)) HERE = os.path.dirname(os.path.abspath(__file__))
@ -22,17 +32,98 @@ TYPE_MAP = {'music': 'record', 'charity': 'opshop', 'second_hand': 'opshop', 'an
'books': 'book', 'toys': 'toy', 'video_games': 'video', 'games': 'toy', 'books': 'book', 'toys': 'toy', 'video_games': 'video', 'games': 'toy',
'pawnbroker': 'pawn', 'market': 'dept'} 'pawnbroker': 'pawn', 'market': 'dept'}
# REAL shops that exist in neither OSM nor thriftgod's census, added by explicit, sourced ruling.
# This is not a mapping table (the R12 gigKey law) — it's a hand-verified roster of the shops the
# epoch is actually about. Every entry states where its identity and its coordinates came from.
#
# Monster Robot Party: the v5 alpha's shop — its POS *is* `recordgod`, its own site hosts the
# covers, and dealgod scrapes it as store 3962749 (which is therefore its godverseShopId). OSM
# doesn't know it (no name match, no 147 Musgrave Rd address node) and the census doesn't either,
# so the coordinate cannot be derived from any dataset we hold: John supplied the shop's Google
# Maps place (place `/g/11g6rlbbc0`), whose point is -27.4553791, 153.0076244 — inside
# `redhill_real`'s bbox and on Musgrave Road's own geometry. Verified, not estimated.
EXTRA_SHOPS = {
'redhill_godverse': [
{'id': 3962749, 'godverseShopId': 3962749, 'name': 'Monster Robot Party', 'type': 'record',
'lat': -27.4553791, 'lon': 153.0076244, 'suburb': 'Red Hill',
'source': 'GODVERSE/dealgod store 3962749 · POS recordgod · coords: Google Maps place '
'/g/11g6rlbbc0 (147 Musgrave Road, Red Hill QLD), John-supplied R24'},
],
}
def psql(db, sql):
out = subprocess.run(['psql', '-d', db, '-tAF\t', '-c', sql],
capture_output=True, text=True, check=True).stdout
return [ln.split('\t') for ln in out.splitlines() if ln.strip()]
donor = json.load(open(os.path.join(TOWNS, f'{DONOR}.json'))) donor = json.load(open(os.path.join(TOWNS, f'{DONOR}.json')))
bb = donor['bbox'] bb = donor['bbox']
db = psycopg2.connect(os.environ.get('THRIFTGOD_DSN', 'dbname=thriftgod')) rows = psql(os.environ.get('THRIFTGOD_DB', 'thriftgod'), f"""
c = db.cursor(cursor_factory=psycopg2.extras.RealDictCursor) SELECT id, COALESCE(name,''), COALESCE(shop_type,''), lat, lng, COALESCE(suburb,'')
c.execute("""SELECT id, name, shop_type, lat, lng, suburb FROM shop FROM shop
WHERE lat BETWEEN %s AND %s AND lng BETWEEN %s AND %s ORDER BY id""", WHERE lat BETWEEN {bb['minLat']} AND {bb['maxLat']}
(bb['minLat'], bb['maxLat'], bb['minLon'], bb['maxLon'])) AND lng BETWEEN {bb['minLon']} AND {bb['maxLon']}
shops = [{'id': r['id'], 'name': r['name'], ORDER BY id""")
'type': TYPE_MAP.get(r['shop_type'], 'opshop'),
'lat': float(r['lat']), 'lon': float(r['lng']), shops = [{'id': int(r[0]),
'suburb': (r['suburb'] or '').split('|')[0]} for r in c.fetchall()] 'godverseShopId': int(r[0]), # census shops: the thriftgod id IS the key (not derived
# from `id` by law — they coincide, see the docstring)
'name': r[1],
'type': TYPE_MAP.get(r[2], 'opshop'),
'lat': float(r[3]), 'lon': float(r[4]),
'suburb': r[5].split('|')[0]} for r in rows]
census_n = len(shops)
extras = EXTRA_SHOPS.get(OUT, [])
known = {s['id'] for s in shops}
for e in sorted(extras, key=lambda s: s['id']):
if e['id'] in known: # census wins a collision, and we count the swap
continue
shops.append({k: e[k] for k in ('id', 'godverseShopId', 'name', 'type', 'lat', 'lon', 'suburb')})
extra_n = len(shops) - census_n
# ── Fable's Ruling 2 (R22, implemented R24): INHERIT THE DONOR'S TEXTURE LAYER ────────────────
# "Merge census heroes WITH the donor's texture shops; census heroes always win a collision
# (dedupe by proximity + name), drop the donor hero, keep yours, count the swap. Result: real
# census shops on a street that also feels alive."
#
# Not cosmetic — MEASURED (R24): the census layer alone is 9 shops across Red Hill's 2.4 km bbox →
# A's spacing warn at 261 m ("scattered, not a high street"), *worse than the 255 m that retired
# ballarat this round*, plus a frontage poster seated inside edge 1037's kerb. With the donor's
# texture layer merged (37 shops) both go away and E's donor's own density is preserved.
#
# THE MERGED SHOPS CARRY NO `godverseShopId`, DELIBERATELY. The field is the GODVERSE stock
# identity; an OSM cafe has none, and minting one from its OSM id would push a third id space into
# a field that already carries two (thriftgod census ≤2992 · dealgod store ids). OSM ids are the
# same order of magnitude as dealgod store ids, so a collision is *possible* — and A's validator
# calls a duplicate godverseShopId mis-stocking (charter risk #3: two shops keyed to one atlas,
# one of them Monster Robot's crate). Unkeyed is both true and safe: they fall soft to tier 0,
# which is exactly what a milkbar with no stock should do. A's coverage warn states this honestly.
def norm(n):
return ' '.join((n or '').lower().split())
def near(a, b, m=150.0): # metres, flat-earth at suburb scale — plenty at 150 m
dy = (a['lat'] - b['lat']) * 111_320.0
dx = (a['lon'] - b['lon']) * 111_320.0 * math.cos(math.radians(a['lat']))
return math.hypot(dx, dy) <= m
swaps = 0
for d in sorted(donor.get('shops', []), key=lambda s: s['id']):
hit = next((s for s in shops if norm(s['name']) == norm(d['name']) and near(s, d)), None)
if hit: # the donor's own entry for a shop we already hold
swaps += 1
continue
if d['id'] in {s['id'] for s in shops}:
continue
shops.append({'id': d['id'], 'name': d['name'], 'type': d['type'],
'lat': d['lat'], 'lon': d['lon'], 'suburb': d.get('suburb', '')})
texture_n = len(shops) - census_n - extra_n
shops.sort(key=lambda s: s['id']) # deterministic order, extras + texture included
out = dict(donor) out = dict(donor)
out.update({ out.update({
@ -42,10 +133,20 @@ out.update({
'generator': 'pipeline/godverse_town.py', 'generator': 'pipeline/godverse_town.py',
'attribution': donor['attribution'] + ' · shop census: GODVERSE/thriftgod', 'attribution': donor['attribution'] + ' · shop census: GODVERSE/thriftgod',
'shops': shops, 'shops': shops,
'counts': {**donor.get('counts', {}), 'shops': len(shops)}, # The donor's shop-side counts (raw/heroes/texture/textureDropped) describe the shop layer we
# REPLACE, so carrying them would state a census of shops this cache doesn't contain. Keep the
# donor's road count; recount our own shops.
'counts': {**{k: v for k, v in donor.get('counts', {}).items() if k == 'roads'},
'shops': len(shops), 'census': census_n, 'extra': extra_n,
'texture': texture_n, 'donorSwaps': swaps},
}) })
dst = os.path.join(TOWNS, f'{OUT}.json') dst = os.path.join(TOWNS, f'{OUT}.json')
json.dump(out, open(dst, 'w'), indent=1) with open(dst, 'w') as fh:
json.dump(out, fh, indent=1)
types = {} types = {}
for s in shops: types[s['type']] = types.get(s['type'], 0) + 1 for s in shops:
print(f"{OUT}: {len(shops)} REAL shops ({types}) + {len(out.get('roads', []))} OSM roads -> {dst}") types[s['type']] = types.get(s['type'], 0) + 1
keyed = sum(1 for s in shops if 'godverseShopId' in s)
print(f"{OUT}: {len(shops)} shops = {census_n} census + {extra_n} extra + {texture_n} donor-texture "
f"({swaps} donor heroes swapped for census) · {keyed} keyed w/ godverseShopId")
print(f" {types} + {len(out.get('roads', []))} OSM roads -> {dst}")

View File

@ -10,6 +10,10 @@
"stock_record_atlas_00.webp", "stock_record_atlas_00.webp",
"stock_record_atlas_01.webp" "stock_record_atlas_01.webp"
], ],
"license": "in-house-green \u2014 the shop's own product shots (monsterrobot.party), cached by dealgod; FLAG BEFORE ANY PUBLIC/COMMERCIAL RELEASE",
"attribution": "Stock, prices + covers: Monster Robot Party (monsterrobot.party) \u2014 the shop's own product shots \u00b7 cover cache: GODVERSE/dealgod \u00b7 POS: recordgod",
"generator": "pipeline/godverse_stock.py",
"snapshot": "monsterrobot_550.snapshot.json",
"shop": { "shop": {
"godverse_id": 3962749, "godverse_id": 3962749,
"slug": "monsterrobot", "slug": "monsterrobot",
@ -32,7 +36,7 @@
"captured": "2026-07-15", "captured": "2026-07-15",
"extraction": "see load_image_map() docstring \u2014 the products projection command" "extraction": "see load_image_map() docstring \u2014 the products projection command"
}, },
"licence": { "license": {
"covers": "the shop's own product shots (monsterrobot.party), cached by dealgod", "covers": "the shop's own product shots (monsterrobot.party), cached by dealgod",
"zone": "in-house-green", "zone": "in-house-green",
"flag": "FLAG BEFORE ANY PUBLIC/COMMERCIAL RELEASE", "flag": "FLAG BEFORE ANY PUBLIC/COMMERCIAL RELEASE",
@ -40,7 +44,7 @@
"pii": "none \u2014 inventory/crate/disc_cache only; customer/staff/sales never read" "pii": "none \u2014 inventory/crate/disc_cache only; customer/staff/sales never read"
}, },
"snapshot": "monsterrobot_550.snapshot.json", "snapshot": "monsterrobot_550.snapshot.json",
"snapshot_sha256": "d6b0e2f7a7474a69354370ade98b1887d8c778a4f07a2ba62a6c366dadd22c2f", "snapshot_sha256": "8b0ff903ce8f746aa80ef25f3eb498ec9a3bc890ec0607c2a5921674e4ef612a",
"determinism": "pure bake \u2014 same snapshot + same cover bytes => byte-identical atlas; covers pinned by sha256, no RNG, no clock" "determinism": "pure bake \u2014 same snapshot + same cover bytes => byte-identical atlas; covers pinned by sha256, no RNG, no clock"
}, },
"items": [ "items": [

View File

@ -18,13 +18,17 @@
"maxLon": 151.1931100389657 "maxLon": 151.1931100389657
}, },
"counts": { "counts": {
"raw": 19, "roads": 1086,
"shops": 18, "shops": 72,
"roads": 1086 "census": 18,
"extra": 0,
"texture": 54,
"donorSwaps": 18
}, },
"shops": [ "shops": [
{ {
"id": 158, "id": 158,
"godverseShopId": 158,
"name": "Egg Records", "name": "Egg Records",
"type": "record", "type": "record",
"lat": -33.897238, "lat": -33.897238,
@ -33,6 +37,7 @@
}, },
{ {
"id": 247, "id": 247,
"godverseShopId": 247,
"name": "The Vintage Record", "name": "The Vintage Record",
"type": "record", "type": "record",
"lat": -33.8875182, "lat": -33.8875182,
@ -41,6 +46,7 @@
}, },
{ {
"id": 248, "id": 248,
"godverseShopId": 248,
"name": "Aalders", "name": "Aalders",
"type": "opshop", "type": "opshop",
"lat": -33.8877879, "lat": -33.8877879,
@ -49,6 +55,7 @@
}, },
{ {
"id": 568, "id": 568,
"godverseShopId": 568,
"name": "Towers Antiques", "name": "Towers Antiques",
"type": "opshop", "type": "opshop",
"lat": -33.9035515, "lat": -33.9035515,
@ -57,6 +64,7 @@
}, },
{ {
"id": 569, "id": 569,
"godverseShopId": 569,
"name": "Old Wares", "name": "Old Wares",
"type": "opshop", "type": "opshop",
"lat": -33.9032933, "lat": -33.9032933,
@ -65,6 +73,7 @@
}, },
{ {
"id": 608, "id": 608,
"godverseShopId": 608,
"name": "Goulds Books", "name": "Goulds Books",
"type": "book", "type": "book",
"lat": -33.9029178, "lat": -33.9029178,
@ -73,6 +82,7 @@
}, },
{ {
"id": 717, "id": 717,
"godverseShopId": 717,
"name": "Co-op", "name": "Co-op",
"type": "book", "type": "book",
"lat": -33.890884, "lat": -33.890884,
@ -81,6 +91,7 @@
}, },
{ {
"id": 1082, "id": 1082,
"godverseShopId": 1082,
"name": "Downtown Music", "name": "Downtown Music",
"type": "record", "type": "record",
"lat": -33.8878728, "lat": -33.8878728,
@ -89,6 +100,7 @@
}, },
{ {
"id": 1173, "id": 1173,
"godverseShopId": 1173,
"name": "Haze Guitars", "name": "Haze Guitars",
"type": "record", "type": "record",
"lat": -33.8925979, "lat": -33.8925979,
@ -97,6 +109,7 @@
}, },
{ {
"id": 1697, "id": 1697,
"godverseShopId": 1697,
"name": "Thats So Mi", "name": "Thats So Mi",
"type": "opshop", "type": "opshop",
"lat": -33.9011361, "lat": -33.9011361,
@ -105,6 +118,7 @@
}, },
{ {
"id": 2019, "id": 2019,
"godverseShopId": 2019,
"name": "St Luke\u2019s Op Shop", "name": "St Luke\u2019s Op Shop",
"type": "opshop", "type": "opshop",
"lat": -33.898898, "lat": -33.898898,
@ -113,6 +127,7 @@
}, },
{ {
"id": 2048, "id": 2048,
"godverseShopId": 2048,
"name": "Savers", "name": "Savers",
"type": "opshop", "type": "opshop",
"lat": -33.8869187, "lat": -33.8869187,
@ -121,6 +136,7 @@
}, },
{ {
"id": 2200, "id": 2200,
"godverseShopId": 2200,
"name": "Better Read Than Dead", "name": "Better Read Than Dead",
"type": "book", "type": "book",
"lat": -33.8961303, "lat": -33.8961303,
@ -129,6 +145,7 @@
}, },
{ {
"id": 2201, "id": 2201,
"godverseShopId": 2201,
"name": "Elizabeth's Bookshop", "name": "Elizabeth's Bookshop",
"type": "book", "type": "book",
"lat": -33.8959321, "lat": -33.8959321,
@ -137,6 +154,7 @@
}, },
{ {
"id": 2212, "id": 2212,
"godverseShopId": 2212,
"name": "Papa Disquo", "name": "Papa Disquo",
"type": "record", "type": "record",
"lat": -33.8986661, "lat": -33.8986661,
@ -145,6 +163,7 @@
}, },
{ {
"id": 2377, "id": 2377,
"godverseShopId": 2377,
"name": "Kidstuff", "name": "Kidstuff",
"type": "toy", "type": "toy",
"lat": -33.8870857, "lat": -33.8870857,
@ -153,6 +172,7 @@
}, },
{ {
"id": 2505, "id": 2505,
"godverseShopId": 2505,
"name": "EB Games", "name": "EB Games",
"type": "video", "type": "video",
"lat": -33.9064099, "lat": -33.9064099,
@ -161,11 +181,444 @@
}, },
{ {
"id": 2506, "id": 2506,
"godverseShopId": 2506,
"name": "Toys and Tales", "name": "Toys and Tales",
"type": "toy", "type": "toy",
"lat": -33.9073712, "lat": -33.9073712,
"lon": 151.1724377, "lon": 151.1724377,
"suburb": "Newtown" "suburb": "Newtown"
},
{
"id": 62203508,
"name": "Bunnings Warehouse",
"type": "dept",
"lat": -33.905746,
"lon": 151.19369,
"suburb": "Alexandria"
},
{
"id": 279681996,
"name": "Woolworths Metro",
"type": "dept",
"lat": -33.89859,
"lon": 151.181704,
"suburb": "Newtown"
},
{
"id": 292127221,
"name": "The Hospitality Store",
"type": "dept",
"lat": -33.88782,
"lon": 151.17241,
"suburb": "Camperdown"
},
{
"id": 305516372,
"name": "IGA",
"type": "dept",
"lat": -33.89597,
"lon": 151.180575,
"suburb": "Newtown"
},
{
"id": 423218371,
"name": "Foodcraft",
"type": "milkbar",
"lat": -33.90308,
"lon": 151.185224,
"suburb": "Erskineville"
},
{
"id": 605984546,
"name": "Nextra",
"type": "milkbar",
"lat": -33.906418,
"lon": 151.171836,
"suburb": "Marrickville"
},
{
"id": 605984562,
"name": "Lowes",
"type": "dept",
"lat": -33.906876,
"lon": 151.171753,
"suburb": "Marrickville"
},
{
"id": 605984563,
"name": "Kimmy Jewellery",
"type": "dept",
"lat": -33.906791,
"lon": 151.171765,
"suburb": "Marrickville"
},
{
"id": 605984565,
"name": "Forcast",
"type": "dept",
"lat": -33.906889,
"lon": 151.17189,
"suburb": "Marrickville"
},
{
"id": 605984566,
"name": "Bras N Things",
"type": "dept",
"lat": -33.907022,
"lon": 151.171843,
"suburb": "Marrickville"
},
{
"id": 605984567,
"name": "Sussan",
"type": "dept",
"lat": -33.907073,
"lon": 151.171834,
"suburb": "Marrickville"
},
{
"id": 605984571,
"name": "Sunset Flowers",
"type": "stall",
"lat": -33.907283,
"lon": 151.171871,
"suburb": "Marrickville"
},
{
"id": 605984595,
"name": "Sergio's Cake Shop",
"type": "milkbar",
"lat": -33.906821,
"lon": 151.172217,
"suburb": "Marrickville"
},
{
"id": 605984610,
"name": "Espresso Brothers",
"type": "milkbar",
"lat": -33.906382,
"lon": 151.172126,
"suburb": "Marrickville"
},
{
"id": 1039467648,
"name": "Storeroom Vintage",
"type": "dept",
"lat": -33.898406,
"lon": 151.176285,
"suburb": "Newtown"
},
{
"id": 1039467672,
"name": "Natural Fit Footwear",
"type": "dept",
"lat": -33.90725,
"lon": 151.172143,
"suburb": "Marrickville"
},
{
"id": 1039555349,
"name": "The Athlete's Foot",
"type": "dept",
"lat": -33.906646,
"lon": 151.17215,
"suburb": "Marrickville"
},
{
"id": 1079380693,
"name": "Coffee @ Fisher",
"type": "milkbar",
"lat": -33.886833,
"lon": 151.190043,
"suburb": "Darlington"
},
{
"id": 1732566722,
"name": "Welcome Mart",
"type": "dept",
"lat": -33.89993,
"lon": 151.184575,
"suburb": "Erskineville"
},
{
"id": 1735908953,
"name": "Boh\u00e4us Cafe",
"type": "milkbar",
"lat": -33.905708,
"lon": 151.191348,
"suburb": "Alexandria"
},
{
"id": 2125897845,
"name": "Pastizzi Cafe",
"type": "milkbar",
"lat": -33.903197,
"lon": 151.179532,
"suburb": "Newtown"
},
{
"id": 2136793910,
"name": "Store Espresso",
"type": "milkbar",
"lat": -33.890334,
"lon": 151.176325,
"suburb": "Camperdown"
},
{
"id": 2136793911,
"name": "Gather on the Green",
"type": "milkbar",
"lat": -33.890355,
"lon": 151.176263,
"suburb": "Camperdown"
},
{
"id": 2163387594,
"name": "Grounded 2050",
"type": "milkbar",
"lat": -33.887901,
"lon": 151.180526,
"suburb": "Camperdown"
},
{
"id": 2170430692,
"name": "Carslaw Kitchen",
"type": "milkbar",
"lat": -33.888238,
"lon": 151.190481,
"suburb": "Darlington"
},
{
"id": 2365225259,
"name": "Ken Neale Overflow",
"type": "dept",
"lat": -33.90187,
"lon": 151.178671,
"suburb": "Newtown"
},
{
"id": 2787084005,
"name": "Amazing Paints",
"type": "dept",
"lat": -33.891631,
"lon": 151.176271,
"suburb": "Camperdown"
},
{
"id": 2965437480,
"name": "Cafe Abercrombie",
"type": "milkbar",
"lat": -33.892142,
"lon": 151.193024,
"suburb": "Darlington"
},
{
"id": 2968343588,
"name": "Bakerman",
"type": "milkbar",
"lat": -33.899893,
"lon": 151.183961,
"suburb": "Erskineville"
},
{
"id": 3278493016,
"name": "Wildwood Designs",
"type": "dept",
"lat": -33.887904,
"lon": 151.169934,
"suburb": "Stanmore"
},
{
"id": 3278493018,
"name": "Inspired Design Furniture",
"type": "dept",
"lat": -33.887902,
"lon": 151.170079,
"suburb": "Stanmore"
},
{
"id": 3278509468,
"name": "Recharging",
"type": "milkbar",
"lat": -33.887515,
"lon": 151.167686,
"suburb": "Annandale"
},
{
"id": 3951219159,
"name": "Miracle",
"type": "dept",
"lat": -33.892823,
"lon": 151.186108,
"suburb": "Newtown"
},
{
"id": 4860774437,
"name": "Newtown Garden Market",
"type": "stall",
"lat": -33.903009,
"lon": 151.179679,
"suburb": "Newtown"
},
{
"id": 5203491923,
"name": "Cynthia's Caf\u00e9",
"type": "milkbar",
"lat": -33.908747,
"lon": 151.191977,
"suburb": "Alexandria"
},
{
"id": 5205362421,
"name": "Little Vietnam Roll & Juice",
"type": "milkbar",
"lat": -33.906344,
"lon": 151.181132,
"suburb": "Newtown"
},
{
"id": 5299091858,
"name": "Hui Bro\u2019s Cafe",
"type": "milkbar",
"lat": -33.898095,
"lon": 151.179152,
"suburb": "Newtown"
},
{
"id": 5300089045,
"name": "Handcraft Specialty Coffee",
"type": "milkbar",
"lat": -33.892575,
"lon": 151.185688,
"suburb": "Newtown"
},
{
"id": 5599458217,
"name": "The Floral Decorator",
"type": "stall",
"lat": -33.899566,
"lon": 151.184195,
"suburb": "Erskineville"
},
{
"id": 5839239307,
"name": "Luke Avenue",
"type": "milkbar",
"lat": -33.897984,
"lon": 151.175225,
"suburb": "Newtown"
},
{
"id": 5905712358,
"name": "The Coffee Nook on Swanson",
"type": "milkbar",
"lat": -33.900301,
"lon": 151.189403,
"suburb": "Erskineville"
},
{
"id": 5931284416,
"name": "Patisserie Petunia",
"type": "milkbar",
"lat": -33.90509,
"lon": 151.18052,
"suburb": "Newtown"
},
{
"id": 6283737899,
"name": "Dangerfield",
"type": "dept",
"lat": -33.895217,
"lon": 151.181947,
"suburb": "Newtown"
},
{
"id": 6564462487,
"name": "Marani Deli",
"type": "milkbar",
"lat": -33.895992,
"lon": 151.182698,
"suburb": "Newtown"
},
{
"id": 9572458384,
"name": "Budha Bowl",
"type": "milkbar",
"lat": -33.898699,
"lon": 151.176397,
"suburb": "Newtown"
},
{
"id": 9776428741,
"name": "K\u00fcrt\u0151sh",
"type": "milkbar",
"lat": -33.907897,
"lon": 151.171833,
"suburb": "Marrickville"
},
{
"id": 11984912425,
"name": "Provocator",
"type": "dept",
"lat": -33.901201,
"lon": 151.178441,
"suburb": "Newtown"
},
{
"id": 12200892725,
"name": "Feather & Bone",
"type": "milkbar",
"lat": -33.909398,
"lon": 151.168471,
"suburb": "Marrickville"
},
{
"id": 13341304001,
"name": "AS Colour",
"type": "dept",
"lat": -33.895051,
"lon": 151.181701,
"suburb": "Newtown"
},
{
"id": 13585970805,
"name": "Numero Uno Coffee Roasters",
"type": "milkbar",
"lat": -33.908693,
"lon": 151.18052,
"suburb": "St Peters"
},
{
"id": 13719824202,
"name": "A.P Town",
"type": "milkbar",
"lat": -33.893929,
"lon": 151.183827,
"suburb": "Newtown"
},
{
"id": 13785846501,
"name": "The Happy Herb Shop Newtown",
"type": "milkbar",
"lat": -33.898379,
"lon": 151.178005,
"suburb": "Newtown"
},
{
"id": 13919280070,
"name": "Tonton Bread",
"type": "milkbar",
"lat": -33.90484,
"lon": 151.17338,
"suburb": "Marrickville"
},
{
"id": 13919369194,
"name": "Mamuki",
"type": "milkbar",
"lat": -33.898789,
"lon": 151.173092,
"suburb": "Enmore"
} }
], ],
"roads": [ "roads": [

File diff suppressed because it is too large Load Diff