Commit Graph

25 Commits

Author SHA1 Message Date
m3ultra
10db373e67 Lane E R18 (v4.0-alpha): the other 4 towns' road geometry (data-only) + Overpass retry
Newtown/Fremantle/Bendigo/Castlemaine now schema v2 with roads[] (1086/622/1552/397 real streets),
same fidelity cut (street tier only). Data-only: only katoomba gates the round; A hardens against these.
build_towns.py: added Overpass retry/backoff (public API 504s under load — hit one mid-run).

The poster-clearance finding is SYSTEMATIC: it reproduces on all 5 real-road towns, every seed (23
checks, -0.9 to -4.7m), confirming it's plan-level poster placement (A's pickVenues/POSTER_CLEAR), not
town data. Scoping holds: only the real/* v2 path fails; synthetic + fixtures + classic + default boots
stay green. A's one fix generalizes to all five. ODbL: raw roads committed, SOURCES.md current.

-> Lane A: all 5 towns' roads live; the systematic poster finding is yours to resolve + re-pin goldens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 16:32:10 +10:00
m3ultra
dbb52c2390 Lane E R18 (v4.0-alpha): katoomba_real real road geometry (schema v2, ledger #3)
Extend build_towns.py: bounded way[highway](bbox) out geom per town -> raw cached in-repo -> roads[]
in A's v2 contract ({id,kind,pts:[[lat,lon]]}, kind=raw OSM highway class). katoomba_real is now
schema v2 with 484 real streets (Bathurst Rd, Cliff Drive, ...). Fidelity cut (charter risk #4, flagged
to A): fetch every ROAD_KIND tier -> raw; EMIT the town street tier only, excluding service/track/
footway/path/steps/cycleway (1461 of 2506 Katoomba ways = bushwalking tracks/sidewalks/stairs/driveways).

A's lift builds a real town from it (verified): 484 streets -> 872 nodes/799 edges (main 232 side 531
arcade 36) -> 12 blocks, 20 lots, 3 venues (pub/band_room/rsl), 12 gigs. pickVenues lands venues on the
real graph (ledger #2 met).

FINDING for A (alpha failure-list, charter risk #3): on the real graph, spine posters overhang crossing
carriageways -- selfcheck kerb-clearance fails on 4 seeds (-1.6 to -2.5m; e.g. seed 20261990 poster 50 vs
edge 58 = -2.42m). Same class as A's R15/R16 corner-poster fix, now on real cross-street geometry. Owner:
A (pickVenues/POSTER_CLEAR on the real graph, the 'A again' harden step) -- my roads data is VALID (cache
validates; failures are plan-level poster placement). Golden settles after A's fix (pre-fix 0x6014a8e6).
ODbL: raw roads committed, SOURCES.md updated.

-> Lane A: katoomba roads live; harden the lift + resolve the poster finding + re-pin the golden.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 16:27:55 +10:00
m3ultra
483a4b75c6 Lane E R17 (v3.2): the real-map scout — 5 AU town caches + publish --verify fix
Ledger #4 (warm-up): publish.py --verify no longer false-flags non-procity_ published assets
(sit.glb, vintage-cash-register). It compares the _published.json name record against the depot's
full file list (fetch_depot_files) instead of a procity_ prefix filter; only OUR namespace flags as
unrecorded. --verify now: all 39 recorded assets live.

Ledger #6 (the scout): new pipeline/build_towns.py ports thriftgod build_city()'s Overpass route to
per-town caches in A's procity-town-cache/1 contract. 5 real compact AU towns under web/assets/towns/
(katoomba/newtown/fremantle/bendigo/castlemaine, 6-21 shops, spans <2.4km): bounded Overpass query ->
raw cached in-repo (re-runs never re-fetch) -> dedupe/suburb-fill/parody (trademarked chains only;
indie shops keep real OSM names)/type-map. Deterministic (byte-identical re-run, no RNG). ODbL:
SOURCES.md licence table + license/attribution on every cache. All 5 boot through the full
structural+gig suites (selfcheck 16596/16596 green; synthetic golden 0x3fa36874 unmoved). Overpass
fetch John-authorized (Standing #2).

-> Lane A: caches live under web/assets/towns/; pin the per-town goldens selfcheck printed (katoomba
   0x61760542 newtown 0x95978b45 fremantle 0xee9fd09a bendigo 0x5e3e76a6 castlemaine 0xf1a628a1) +
   feed through plan_osm. E->A handshake.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 14:49:40 +10:00
m3ultra
b322c998db Lane E R16 (v3.1): the drummer's sit clip — sit.glb produced + published
Ledger #2 asset half (E produces, D wires). Fetched Adobe Mixamo Sitting_Idle.fbx (533KB) by scp
from the tailnet source box, converted on-device via Blender (new pipeline/fbx_to_clip.py: import ->
skinned GLB export -> pure-python mesh-strip) to web/models/peds/sit.glb (109KB, mesh-free,
structurally identical to walk/idle: 66 nodes, 65 mixamorig bones, dangling skin, 195 channels).
Verified: three.js loads + 195/195 tracks bind to peds + 0 NaN; Blender confirms seated (hips
0.955->0.299m, stature 1.276->0.758m) + eyes-on bone-dot render (docs/shots/laneE/sit_clip.png).
Published to depot via tailnet under John's R13 auth (_published.json 38->39; benign non-procity_
drift note). Provenance: Adobe Mixamo royalty-free, same zone as the shipped walk/idle; LANE_E_NOTES
v3.1 amendment marker.

-> Lane D: sit.glb ready at web/models/peds/sit.glb (+ on depot); canon binds 195/195; seated confirmed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 12:37:27 +10:00
m3ultra
55f6698fb2 Lane E R14 (v3.0 release): provenance freeze + doc-consistency fixes
Provenance close-out for the v3.0 tag. Verified via a 6-agent inventory+audit workflow
(both adversarial audits PASS, 0 blockers) cross-checked against glb_stat/ffprobe/manifest.

- LANE_E_NOTES: v3.0-FROZEN provenance table + full audio(28)/GLB(38)/skins(96)/packs(3)
  inventories; by-design notes + v3.1 deferrals (street_bin decimation).
- AUDIT.md: add R13 gig-layer finalization section (14k decimation, _hi published, gigKey
  rename + 2 beds, depot publish done) — ledger was stale at R12.
- manifest glb_law string: state the documented <=8k-hero / <=14k-instrument tiers so the
  frozen contract is self-consistent (regenerated; 1-line diff, Gate 3 still 0/0).
- gen_audio: roomtone-video gain 0.3 -> 0.35 to match the shipped manifest.

Gate 3 GREEN; publish.py --verify clean; 0 quarantine assets in manifest; goldens unmoved
(synthetic 0x3fa36874, gig 0x1f636349). No new synthesis (genres final); no poster templates
(no ask from B).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-16 01:18:40 +10:00
m3ultra
5dac2cac5a Lane E R13: publish decimated instruments + _hi originals to depot
John OK'd direct publish. Pushed the 5 base instruments (14k) + 5 _hi hi-poly originals
via the passwordless tailnet ingress (this box is allowlisted). Public digalot.fyi now
serves the 14k bytes (amp 5.9MB->1.3MB) + the _hi originals; -70% decimation win is live
in production. _published.json 33->38; validate_manifest --depot GREEN. Gate-3 flag cleared.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 23:12:48 +10:00
m3ultra
bf98b41b16 Lane E R13 (v3.0-beta): gigKey rename + grunge/covers beds + instrument decimation
- debt #1: the manifest music key IS the gigKey, always gig-<genreKey>. Renamed
  pubrock-live -> gig-pubrock (files + gen_audio + build_manifest); old files deleted.
  B/F switch readers, F deletes the GIG_BED bridge (both fail soft to silence til then).
- two new gig beds: gig-grunge (band_room, quiet-loud dynamic) + gig-covers (RSL, mellow
  organ-led); procedural/seeded/loopable/$0. New organ() + grungechord() synth helpers.
- decimate the 5 instrument GLBs to 14k tris each (was 43-96k; fleet 236k->70k, -70%) via
  collapse (thin features survive); _hi hi-poly originals kept for depot; thumbs re-rendered.
- manifest regen (validates 0/0 incl --depot); app boots clean flags-off / ?gigs=1 (3-venue
  district, all 3 beds resolve) / ?noassets=1&gigs=1 (0 audio+GLB fetches).
- depot re-publish (14k bytes + _hi originals) gated on John's OK.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 23:03:14 +10:00
m3ultra
7795780336 Lane E R12 (v3.0-alpha gig layer): 5 instruments + 4 posters + 3 gig audio
Instruments (MODELBEAST flux_local concept -> trellis_mac -> normalize):
electric_guitar, bass_guitar, drum_kit, guitar_amp, mic_stand -> manifest
fittings + thumbs, published to the tailnet depot. All 5 reconstructed
cleanly (thin mic-boom + cymbals survived); heavy tris (30-96k, amp the
outlier) accepted like the R3 props. gen_props.py gains --batch;
gig_instruments.json + gig_norm_batch.json + _gig_results.json.

Posters (flux_local, gen_skins.py --posters): poster-xerox/screenprint/
grunge/retro -> skins.poster with nameZone for band-name overprint, blank
name-band (no baked text) like blank-signboard facades.

Gig audio (procedural, gen_audio.py): music-pubrock-live (original 90s
pub-rock riff), ambience-crowd-walla, sfx-applause -> manifest audio,
flagged gig:true for F. Pack now 26 assets, 9.1 MB of 25.

build_manifest reads _gig_results.json + emits skins.poster + gig audio;
validate_manifest green (--depot 0 err, all live). Provenance in AUDIT.md
(section Round 12); README + E-progress updated. Touched no other lane's
files. F owns the v3.0-alpha tag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 19:44:48 +10:00
m3ultra
be9f967d19 Lane E R11 (audio): procedural audio pack — 23 assets, free/on-device
gen_audio.py: a numpy synthesis engine (osc / ADSR / filters / reverb /
seamless-loop crossfade + note sequencer + drum synth). Renders 6 ambience
beds (street day/night, rain, 3 interior roomtones) + 13 sfx (doorbell,
door, till, record-riffle, toast, tram bell/rumble, 6 footsteps) + 4
instrumental 90s music loops (record-shop, milkbar, video-synth, arcade)
-> web/assets/audio/ as OGG/Opus + M4A/AAC. 8.1 MB of the 25 MB budget.

Tool = 100% procedural synthesis (not a neural model): $0, deterministic/
seeded, perfectly loopable, parody-safe by construction. Documented in
README (§ audio) + AUDIT.md provenance.

manifest audio:{ambience,sfx,music} — file + m4a fallback + loop + gain;
interior roomtone/music carry types[] (seed-pick per shop, like facades);
footstep is {surface:[variants]}. build_manifest.py builds it,
validate_manifest.py checks it. qa.sh --strict green (audio 23, 0 err).

Verified technically (peaks <= -0.4 dBFS, all loops seamless, durations)
via spectrogram sheet + numeric — subjective ear-check is John's/F's.

E leads the audio round; F owns the v2.1 tag + push. Not pushed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 14:50:15 +10:00
m3ultra
23c0667dca Lane E round 9 (E1+E2): VRAM/texture audit + half-res book/toy atlases
E1 memory audit: measured all texture sources (decoded RGBA+mips). Resident VRAM
~240MB default boot / ~420MB worst case (all flags + all shop types); stock packs
the swing. Cheap win: half-res'd book+toy atlases (quick pull-cards, not the deep
record dig — covers verified legible) → stock VRAM 323->181MB, no index/UV change,
re-published to depot. Verdict: fine to ship v2.0; flagged stockpack cache-cap (C)
+ KTX2/Basis (4-8x) for v3. E2 hygiene: validate --depot 0 err, pack-QA 3/3,
provenance-drift clean (27 live), 0 orphan atlases. Numbers + verdict in AUDIT.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 10:59:22 +10:00
m3ultra
a667283cf3 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>
2026-07-15 04:09:14 +10:00
m3ultra
081755bb71 Lane E round 8 (E1+E2): book/toy stock packs + pack-QA gate
E1: build_stock_pack.py generalized over kinds — record (256x256 sleeves), book
(96x256 tall-thin spines), toy (256x256 boxes), per-kind parody word banks, same
build-time/parody/atlas/index laws. Book+toy sample packs built + staged (?localdepot)
+ indexes committed to pipeline/packs/ so Lane C wires book/toy shelves now. Parody
deterministic + no distinctive-token leak across all 3 kinds.
E2: validate_pack.py QA gate (wired into validate_manifest -> qa gate 3) — bad UV /
empty title / bad price_band / dangling atlas / dup id fails qa (proven). qa strict
GREEN 5/5.
Real 150-250-item packs blocked on GODVERSE_DSN (flagged to Fable); samples are
placeholders in the real index format. No fal spend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 02:27:50 +10:00
m3ultra
0c12dacb6d Lane E round 7 (E2): GODVERSE stock-pack pipeline (parody + atlas + index), proven
pipeline/build_stock_pack.py builds C's ?stock=real pack offline (nothing queries the
dataset at runtime): recordgod (dealgod discogs_release) → curate → parody-transform
title/artist (deterministic, shares no source token — no real trademarks) → atlas WebPs
+ JSON index {id,title,artist,price,price_band,atlas,uv}. Proven end-to-end with
--sample 24 (synthetic sleeves); sample pack staged to web/assets/models/ so Lane C
wires ?stock=real against the real index format now. Real 200-400 pack blocked on
GODVERSE_DSN (dealgod Postgres creds — flagged to Fable) + C's schema confirmation;
one command (--from-db --count 300) once they land.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 00:43:08 +10:00
m3ultra
447188a516 Lane E round 7 (E1): merge ped rigs to ONE draw each (gates roster flip)
Each of the 19 ped rigs carried 1-9 primitives / 1-3 materials (fleet 92 draws,
~116 at the 24-rig near cap). merge_ped.py (Blender) merges each to 1 primitive +
1 atlased material: join meshes -> pack material UVs into a non-overlapping atlas UV
-> EMIT-bake base-colours into one 1024 atlas -> single material. Skinning + skeleton
preserved (65 joints, walk/idle untouched, clips retarget unchanged). Fleet 92->19
draws (1/ped); near-cap 116->24 (79% cut). Verified in vendored GLTFLoader: all 19
load as SkinnedMesh + bind walk; man_suit poses byte-identical to original. Hands to
Lane D (D1) for full validation + full-density numbers, then F flips the roster.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 00:33:03 +10:00
m3ultra
2511610373 Lane E round 6 (E1): publish.py merges (not clobbers) + provenance-drift QA gate
- publish.py: _published.json now MERGE (read existing → union → sorted write), never
  replace — fixes the R5 --only clobber (27→1). Proven: a real no-op re-publish kept it
  at 27. Added --verify + post-publish drift-check vs the live depot (/api/list procity_*).
- validate_manifest.py: new provenance-drift gate — every manifest procity_* GLB must be
  in _published.json or QA fails. Proven: simulated clobber (→1) exits 1 w/ per-file errors.
- Record verified: 27-entry _published.json is byte-exact vs the live depot.
- qa.sh --strict GREEN (5 gates incl. F1 harness).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 22:37:55 +10:00
m3ultra
d71420f482 Fable R5 review: regenerate _published.json from live depot (27 GLBs — publish.py rewrite had clobbered it to 1 entry) + true-up v2 flags table
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 22:17:32 +10:00
m3ultra
019304d647 Lane E round 5 (E2): depot growth — street bin + record-crate stack (consumer-driven)
v2 features are procedural (no forced GLB needs), so E2 is light per Fable's "no
unconsumed entries": two synthetic depot props with clear homes — council-bin ->
procity_street_bin_01 (Lane B street dressing) + milk-crate-stack ->
procity_fit_crate_stack_01 (Lane C floor piles / dig). Both 3k tris, base-origin,
re-normalized to procity names + thumbs, published, verified loading, validate --depot
0 err. Manifest 18 fittings + 10 furniture (28 GLBs). Also noted B3 resolved
(novelty_record 26.5k->8k via E1 bake).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 21:27:13 +10:00
m3ultra
8644d3f7ac Lane E round 5 (E3): fal Hunyuan glass_case + bus_shelter + magazine_rack (~$0.64)
The 2 R3 TRELLIS glass rejects + optional magazine-rack, generated on fal.ai
Hunyuan3D v2 (John-authorized, $22 balance). pipeline/gen_props_fal.py drives the
fal operator using the FAL_KEY from MODELBEAST settings (never hardcoded). Frosted/
opaque flux_local concepts gave the reconstructor a surface (clear glass defeated
TRELLIS). glass-case 1 att, bus-shelter 2 att (opaque back wall), magazine-rack 1 att
= ~$0.64 total, guardrail held. All baked to <=8k via bake_lowpoly.py (switched to
EMIT albedo bake — Hunyuan materials bake near-black under DIFFUSE). Verified loading
in vendored GLTFLoader, published, validate --depot 0 err. Manifest 17 fittings + 9
furniture; aliases wire glass_case/glass_cabinets/magazine_rack/fridge/listening_corner.
Costs logged in AUDIT R5. Last 2 primitive-only fittings retired.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 21:20:44 +10:00
m3ultra
c52246444d Lane E round 5 (E1): bake 6 hero props to <=8k tris (288k->48k), live on depot
pipeline/bake_lowpoly.py — Blender headless: voxel-remesh -> decimate -> Cycles
base-colour bake onto fresh UVs (R3 lesson: simplify-only floors on TRELLIS
shell-soup; the re-bake is the point). drinks_fridge/milkshake_mixer/arcade_cabinet/
listening_booth/novelty_record/counter_till all 25-77k -> <=8k, ~0.9M each. Every
prop eyeballed (docs/shots/laneE/props_baked.png) + verified loading in vendored
GLTFLoader; footprints unchanged (no C re-map needed). Re-published; validate --depot
0 err. Originals gitignored in pipeline/.props_orig/. Unblocks C's interior re-measure
+ F's v1.1 tag.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 20:56:07 +10:00
m3ultra
fd8b0bfcfc Fable: correct stale fal.ai budget — Hunyuan v2 ~14-17¢/gen, remainder is 2-3 props (~$0.30-0.50, ~$1 ceiling), not $2.70
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 20:36:12 +10:00
m3ultra
dafb079ff4 Lane E round 4 (E2): fix record_crate + ship counter-with-till, both live on depot
- record_crate: R3 normalize left a sourceless texture (packed AO/roughness map
  didn't survive WebP export; metallicRoughness+occlusion pointed at it) → three.js
  'undefined uri' crash. New pipeline/fix_glb_textures.py strips material slots that
  reference a sourceless texture. Verified loads in vendored GLTFLoader; re-published.
- counter_till (new fitting): ~2m timber counter + period till, flux_local→trellis_mac
  on-device, 1.61x0.64m / 1.15m tall, 32k tris. Verified loads; published. Lane C maps
  kind counter -> counter_till (balcao 4m 'counter' kept for long-bar use).
- publish.py: --only <name> filter + passwordless tailnet detection (GOD3_DEPOT override).
- manifest rebuilt (15 fittings, alias counter->counter_till); validate --depot 0 errors.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 19:07:15 +10:00
m3ultra
518678d4e4 Lane E round 4 (E1): decimate 19 ped rigs 924k→46k tris (≤3k each) for gate 3
weld + meshopt simplify (--ratio 0.05 --error 0.12); skinning + skeleton preserved
(65 joints intact), walk/idle clips untouched, silhouettes clean at street distance.
Originals backed up to gitignored pipeline/.peds_orig/. Hands to Lane D (D2) for rig
validation; Lane F re-measures gate 3 (~24-rig cap × ≤3k ≈ ≤67k fleet).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 18:29:50 +10:00
m3ultra
bd40ec7e7a Lane E round 3 (landed by Fable after review): 5 hero props gen'd local + published, local-depot mode, manifest 14 fittings + 8 furniture
- gen_props.py: flux_local -> trellis_mac -> normalize pipeline; 5/8 props kept
  (arcade-cabinet, listening-booth, drinks-fridge, milkshake-mixer, novelty-record)
- magazine-rack -> primitive (thin-wire gotcha); glass-case + bus-shelter -> fal.ai fallback
- cash-register reused from depot; all 22 GLBs live, validate --depot 0/0
- loaders.js ?localdepot=1 + stage_local_depot.py for network-free GLB validation
- qa.sh --strict GREEN 4/4 at commit time

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 18:03:03 +10:00
m3ultra
862bbcd8de Lane E publish landed: 16 GLBs + thumbs live on 3GOD depot; pipeline fixes
Depot publish executed over the new passwordless tailnet path (allowlist auth,
GOD3_DEPOT=http://100.94.195.115:8788). Two contract bugs fixed en route:
- publish.py: /api/thumb wants JPEG keyed by the GLB name (was posting PNG keyed
  by a .png name -> 404 that mislabelled successful GLB uploads as ERR); thumb
  push now isolated per the MESHGOD house contract (cosmetic, never fails publish).
- validate_manifest.py: send a custom User-Agent (Cloudflare 403s Python-urllib
  on the public path) + honor GOD3_DEPOT override like publish.py.

validate_manifest.py --depot -> 0 errors, 0 warnings. qa.sh --strict all green.
_published.json records the 16 published assets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 15:35:28 +10:00
m3ultra
063a959e29 Lane E (assets): pipeline, manifest + 23 on-device facade skins
Audit -> normalize (16 GLBs + thumbs) -> web/assets/manifest.json (the
contract Lanes B/C/D read) -> facade gap-fill.

Step 4 facades generated locally on the M3 Ultra via MODELBEAST
flux_local (FLUX.2-klein-4B / MLX on MPS): 23 skins, free, ~5.7s each,
blank signboard, eyeballed, harvested, mapped to shop types. Every
registry type now has >=3 facades (stall 2->4, closing the Lane A gap).
Corner-lot -side walls tagged face:"side" with empty types so no shop
front ever selects a windowless wall. manifest validates green.

Still gated on John (both optional -- the game runs asset-free):
publish the 16 GLBs to 3GOD (needs GOD3_PW), MeshGod hero props (~$2.70).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 13:48:25 +10:00