Fable (integrator): merge Lane G R1 at the v4.0-beta boundary — godverse adapter + newtown_godverse (per FABLE_TO_LANE_G ruling)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
m3ultra 2026-07-16 21:42:04 +10:00
commit dd4489c70e
4 changed files with 33380 additions and 0 deletions

49
G-progress.md Normal file
View File

@ -0,0 +1,49 @@
# G-progress — GODVERSE lane (runs on ultra)
*Lane brief: `docs/LANES/LANE_G_GODVERSE.md`. This file follows your progress-file convention —
newest round first. Fable-on-ultra writing.*
## Round 1 (2026-07-16, ultra) — the marriage's first artifact
**Landed:**
- `pipeline/godverse_town.py` — thriftgod PG census + donor OSM cache → `<key>_godverse.json`
(schema v2, `source: "godverse+osm"`). Deterministic, stdlib+psycopg2, runs where the DB lives
(ultra). Type map thriftgod→registry: music→record, charity/second_hand/antiques→opshop,
books→book, toys/games→toy, video_games→video, pawnbroker→pawn, market→dept.
- `web/assets/towns/newtown_godverse.json`**18 REAL Newtown shops** (Sydney; DealGod census)
on your real 1,086-road graph (roads donated from `newtown_real`, attribution extended).
- Verified on ultra: boots via `?plansrc=osm&town=newtown_godverse&seed=20261990` — splash and
HUD show Newtown, selector shows "Newtown Godverse · OSM fixture", streets render, 25 chunks /
~78 draws. Real shop names should render on facades exactly as your fictional ones do
(data-driven) — **not yet eyeball-confirmed on a specific facade** (see bookmark ask below).
**Found while verifying (asks, no files touched):**
1. **Per-town bookmarks:** `DBG.teleport('shopfront_detail')` on an OSM town lands inside
geometry (synthetic-town coords). Suggest bookmarks resolve against the active plan.
2. **`DBG.enterShop(selector)`** — took neither a type nor a shop name from the cache; a
name/type/id selector would make cross-repo QA one-liners. (Your harness is excellent —
`info/teleport/shot` made this round's verification trivial.)
3. **Sync:** gitea `origin/main` is at `06fe648` (R20 kickoff); the m3 clone holds R20 lane
commits beyond that (up to `94e56ed`). Push when the round closes so ultra tracks you.
**Context from the ultra side (useful to AF):**
- **MODELBEAST grew:** `trellis_mac` (local TRELLIS.2 image→3D, ~$0, proven 15/15 on thriftgod's
Tier-1 props), `sf3d`, `bg_remove_local`, `mflux_image_edit`, `seedvr2_upscale` all live on the
m3's own queue (:8777). Lane E's "HF-gated, setup needed" note is stale — weights are unlocked.
- ⚠️ **Do NOT run trellis_mac output through the MESHGOD finish farm** — its fill_holes+decimate
shreds 200k-tri marching-cubes meshes (proven on ultra, post-mortem in dealgod memory). The
working pipeline: raw GLB → `npx @gltf-transform/cli optimize --compress draco --texture-compress
webp --texture-size 1024 --simplify-error 0.01` → 0.41.8 MB at raw-quality look.
- **Which collides with your no-Draco law** → the ruling ask in the lane brief. If no-Draco wins,
same command minus `--compress draco` (files ~2-3× bigger, still fine); if Draco wins, three.js
needs the DRACOLoader wire your vendored addons already include. Either is one re-emit; the
depot should hold ONE law.
- **15 thriftgod hero props** sit in `OPSHOPGAME/tools/props_out/game/` on ultra (record-crate,
rummage-tub, teapot, crt-tv, suitcase, mannequin-bust…) — op-shop interior dressing your Lane C
might want; John is picking keepers for the 3GOD depot now.
**Next round (G2, proposed):** real-stock atlases — dealgod inventory → `build_stock_pack.py`
per-shop record/book atlases keyed by the godverse shop id, behind `?stock=real`. Contract I'd
like C/E's eyes on: atlas file per shop vs per town; budget per interior; cache invalidation
when stock sells (thriftgod items are one-of-a-kind — sold means GONE, which is the whole
GODVERSE magic: the crate you riffle is a real crate in a real shop).

View File

@ -0,0 +1,43 @@
# Lane G — GODVERSE (the marriage lane)
**Who:** runs on **ultra** (John's M1 Ultra — the machine with the thriftgod/dealgod Postgres),
branch `lane-G-godverse`. Fable-on-ultra integrates this side; your integrator rules on anything
that touches AF's files. **This lane owns:** `pipeline/godverse_*.py`,
`web/assets/towns/*_godverse.json`, this brief, `G-progress.md`. It touches nothing else without
a ruling.
## Mission
PROCITY built the town; GODVERSE has the *census*. thriftgod's Postgres holds **2,928 real
Australian secondhand shops** (names, types, lat/lng, suburbs, opening hours — DealGod-scraped,
OSM-anchored) and dealgod holds **1.77M real items with photos**. Lane G plugs that real world
into your engine, in slices, without disturbing the v4 lanes:
1. **Real shops on real streets** (LANDED, first cut) — `pipeline/godverse_town.py` marries an
existing OSM cache's `roads[]` with thriftgod's real shop census for the same bbox →
`<town>_godverse.json` (`source: "godverse+osm"`, schema v2 unchanged). First artifact:
`newtown_godverse` — 18 real Newtown shops (5 record, 6 opshop, 4 book…) on the real 1,086-road
graph. Boots clean: `?plansrc=osm&town=newtown_godverse`.
2. **Real stock in the bins** (NEXT) — your `?stock=real` hook + `build_stock_pack.py` atlases,
fed from dealgod's live per-shop inventory instead of a static TSV. Contract sketch in
G-progress.md; needs your ruling on atlas budgets per interior.
3. **The economy backend** (LATER, the big one) — thriftgod's server (items, basket, buy/sell,
GodBay, THE BIBLE) as the transactional brain behind your interiors. Design doc first; nothing
moves without both integrators agreeing.
## House-law compliance
Seeded everything ✓ (adapter is deterministic; no RNG). Zero-asset law untouched ✓ (a godverse
cache is just another town JSON). Licensing: shop names/locations are OSM-derived (ODbL,
attribution kept) + DealGod's own scrape; item photos are the stores' own product shots —
🟢 for the in-house games, flag before any public/commercial release.
## Open asks for the m3 crew (see G-progress.md for detail)
- **The Draco ruling** — your GLB law says no Draco; ultra's new thriftgod hero props are
Draco-compressed. Pick one law for the shared depot; either side can re-emit.
- **Per-town bookmark coords**`DBG.bookmarks` teleports assume the synthetic town; on OSM
towns they land inside geometry.
- **Density fence** for godverse caches — 18 real shops across a full suburb bbox is sparse by
your round-20 standards; consider bbox-cropping godverse towns to the retail spine (King St)
or letting the R20 density widening backfill non-census buildings.

51
pipeline/godverse_town.py Normal file
View File

@ -0,0 +1,51 @@
#!/usr/bin/env python3
"""Lane G — GODVERSE town adapter: thriftgod's REAL shop census -> a procity-town-cache/2.
Marries the two halves: roads[] come from an existing OSM cache (Lane E's build_towns.py),
shops[] come from thriftgod's Postgres (the real-business census DealGod scraped). Result:
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
Runs on ultra (needs the local `thriftgod` PG + psycopg2 the thriftgod server's own deps).
"""
import json, os, sys
import psycopg2, psycopg2.extras
DONOR, OUT = sys.argv[1], sys.argv[2]
HERE = os.path.dirname(os.path.abspath(__file__))
TOWNS = os.path.join(HERE, '..', 'web', 'assets', 'towns')
# thriftgod shop_type -> procity SHOP_TYPES (registry.js is the vocabulary of record)
TYPE_MAP = {'music': 'record', 'charity': 'opshop', 'second_hand': 'opshop', 'antiques': 'opshop',
'books': 'book', 'toys': 'toy', 'video_games': 'video', 'games': 'toy',
'pawnbroker': 'pawn', 'market': 'dept'}
donor = json.load(open(os.path.join(TOWNS, f'{DONOR}.json')))
bb = donor['bbox']
db = psycopg2.connect(os.environ.get('THRIFTGOD_DSN', 'dbname=thriftgod'))
c = db.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
c.execute("""SELECT id, name, shop_type, lat, lng, suburb FROM shop
WHERE lat BETWEEN %s AND %s AND lng BETWEEN %s AND %s ORDER BY id""",
(bb['minLat'], bb['maxLat'], bb['minLon'], bb['maxLon']))
shops = [{'id': r['id'], 'name': r['name'],
'type': TYPE_MAP.get(r['shop_type'], 'opshop'),
'lat': float(r['lat']), 'lon': float(r['lng']),
'suburb': (r['suburb'] or '').split('|')[0]} for r in c.fetchall()]
out = dict(donor)
out.update({
'key': OUT,
'town': donor['town'],
'source': 'godverse+osm', # shops = thriftgod census, roads = OSM (donor)
'generator': 'pipeline/godverse_town.py',
'attribution': donor['attribution'] + ' · shop census: GODVERSE/thriftgod',
'shops': shops,
'counts': {**donor.get('counts', {}), 'shops': len(shops)},
})
dst = os.path.join(TOWNS, f'{OUT}.json')
json.dump(out, open(dst, 'w'), indent=1)
types = {}
for s in shops: types[s['type']] = types.get(s['type'], 0) + 1
print(f"{OUT}: {len(shops)} REAL shops ({types}) + {len(out.get('roads', []))} OSM roads -> {dst}")

File diff suppressed because it is too large Load Diff