diff --git a/C-progress.md b/C-progress.md index 2482f4f..90136d1 100644 --- a/C-progress.md +++ b/C-progress.md @@ -3,7 +3,40 @@ *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.* -Last updated: 2026-07-16 (round 19) · owner: PROCITY-C · reviewer: Fable +Last updated: 2026-07-16 (round 20) · owner: PROCITY-C · reviewer: Fable + +--- + +## Update 2026-07-16 (round 20, v4.0-beta FIVE TOWNS) — the class→archetype mapping (ledger #2, C's half) + +R20 §Lane C (I lead — E builds to it, half-day rule): **published the OSM shop-class → interior archetype +mapping** in [LANE_C_PUB.md](docs/LANES/LANE_C_PUB.md) **§6** (new v4.0-beta amendment; the frozen venue +contract §0–§5 untouched). This is the density widening — real towns fetch **general retail**, not just the +thriftgod secondhand classes, so the main street holds its real bakery/cafe/chemist/clothes shops. + +**Design (John's directive: SUBTLE — texture, not takeover):** +- **No new archetypes.** General retail wears **existing** recipes: food/grocer/newsagent/chemist → `milkbar` + (the canonical AU counter shop); clothes/hardware/big-retail → `dept`; produce/florist → `stall`. +- **Secondhand stays the hero** — charity/antiques→opshop, books→book, music→record, video/games→video, + pawn→pawn, toys→toy; never subsampled. +- **Unknown/unlisted → `opshop`** (R18-proven safe). Included a copy-paste JSON map for E's `build_towns.py` + + a tasteful fetch list (skip vehicle/funeral/industrial/pure-services like hairdresser/bank). +- **Guardrail for E:** if a town's general retail would visually drown the secondhand strip, seed-subsample + the texture classes toward ~2–3× the secondhand count and count the drops in `norm.dropped`. + +**Mechanic note:** `plan_osm` keeps only registry types (unknowns flatten to opshop), so E bakes a **registry +type** per the map into each cache's `shop.type` — no C code change, all targets are existing recipes/registry +entries, budgets unchanged. **C→E handshake: §6 is live.** + +**Pre-validated the mapping (measurement over folklore, before E builds to it):** milkbar/dept/stall/opshop all +build valid at the katoomba lot (8.5×14) — 0 carves, ≤143 draws, pathOK. Rendered `dept` (my one flagged case +— the escalator centrepiece): reads as a clean **dressed-retail floor** (cube shelves of goods + clothes rack + +counter + "GROUND FLOOR/HABERDASHERY" signage) in the 7.9×11.7 hall, escalator does *not* dominate — so +`clothes`/`hardware` → `dept` is confirmed, not a concern. + +**Pending (ledger #6, after E re-emits the 5 widened caches):** the five-town sampled door-soak — every town, +sampled doors at the new density, all types resolve, no carve, budgets; one table, five rows. I'll watch that +`dept` reads right on small real lots (the escalator centrepiece). Docs-only this commit; door-soak follows E. --- diff --git a/docs/LANES/LANE_C_PUB.md b/docs/LANES/LANE_C_PUB.md index 7af1596..d8bb868 100644 --- a/docs/LANES/LANE_C_PUB.md +++ b/docs/LANES/LANE_C_PUB.md @@ -1,9 +1,10 @@ -# LANE C — venue interface contract (v3.0-FROZEN: the district) → Lane D + Lane F +# LANE C — interiors contract (venues + real-town class mapping) → Lanes A/D/E/F -> **v3.0-FROZEN** · 2026-07-16 · durable contract for Lane D + Lane F. Describes the *shipped* state; -> changes require a version bump (CITY_SPEC amendment law). Verified R13 (build) + R14 (release audit). -> **v3.1 amendment (2026-07-16):** §3 becomes the `stage.backline[]` contract (ledger #5 — the amp -> unification); C dropped its primitive ampStacks. Everything else in this doc is unchanged and stands. +> **v3.0-FROZEN** · 2026-07-16 · durable contract for Lane D + Lane F. §0–§5 describe the *shipped* +> venue state; changes require a version bump (CITY_SPEC amendment law). Verified R13 (build) + R14 (audit). +> **v3.1 amendment:** §3 became the `stage.backline[]` contract (ledger #5 — the amp unification). +> **v4.0-beta amendment (2026-07-16):** **§6 added — the real-town shop-class → archetype mapping** +> (ledger #2, the density widening; C→E handshake). The frozen venue contract (§0–§5) is unchanged. *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 @@ -136,4 +137,84 @@ bar in the corner — the PA louder than the room. `rsl` = carpet-and-flock club (hall/wide), a proper raised stage at one end, bistro tables round the edge, members' bar, the biggest crowd cap. Both reuse the `pub` venue machinery (`theme.js venueSpec` + `layout.js` placeStage/placeWatchPoints); only the dressing + `venueSpec` differ. Stage/PA keep GLB slots for Lane E (primitive fallback holds); the -primitive ampStacks are the backline fallback (see §3). +backline amp is D's, planted at `stage.backline[0]` (see §3). + +--- + +## 6. Real-town shop-class → interior archetype mapping (v4.0-beta, ledger #2) → Lane E + +**Directive (John, kickoff — SUBTLE: texture, not takeover).** The secondhand shops stay the **heroes** of +the town (they *are* the game). The widening adds general retail as *texture* — the everyday main-street +staples a real Australian town has — mapped onto **existing** archetypes (**no new archetypes this round**). +The player should feel the town's more alive, not that the game changed. + +**How it's applied (E owns the emission).** `plan_osm` keeps only **registry types** (`SHOP_TYPES` — unknowns +flatten to `opshop`). So E maps each fetched OSM `shop=*` / `amenity=*` value to a **registry type** below and +bakes it into the cache's `shop.type`. Every target is an existing type, so C's recipes, A's registry, and the +budgets are all unchanged. Unknown/unlisted classes degrade safely to `opshop` (R18-proven: 18 real OSM types +all built valid). + +**Heroes — secondhand (unchanged; NEVER subsampled):** +| OSM class | → type | +|---|---| +| `charity`, `second_hand`, `antiques`, `vintage` | `opshop` | +| `books`, `bookshop` | `book` | +| `music` | `record` | +| `video`, `games` | `video` | +| `pawnbroker` | `pawn` | +| `toys` | `toy` | + +**Widened — everyday main-street texture (general retail):** +| OSM class(es) | → type | wears it as | +|---|---|---| +| `bakery`, `cafe`†, `confectionery`, `pastry`, `chocolate`, `deli`/`delicatessen`, `butcher`, `cheese`, `coffee`, `tea` | `milkbar` | the food counter | +| `convenience`, `kiosk`, `general`, `dairy` | `milkbar` | the corner store | +| `newsagent`, `stationery` | `milkbar` | papers + magazines | +| `chemist`, `pharmacy`, `cosmetics`, `perfumery` | `milkbar` | dispensary counter | +| `clothes`, `fashion`, `boutique`, `shoes`, `bag`, `jewelry`/`jewellery` | `dept` | the dressed retail floor | +| `department_store`, `variety_store`, `supermarket` | `dept` | big general retail | +| `hardware`, `doityourself`, `trade`, `electronics`, `mobile_phone`, `furniture`, `houseware`/`homeware` | `dept` | shelved goods | +| `greengrocer`, `florist`, `farm`, `garden_centre` | `stall` | produce/plants on trestles | + +† `cafe`/`fast_food` are `amenity=*`, not `shop=*` — fetch them from the amenity tag; everything else is `shop=*`. +**Fallback:** any fetched class not listed → `opshop`. + +**Copy-paste map for E (`build_towns.py`):** +```json +{ + "charity":"opshop","second_hand":"opshop","antiques":"opshop","vintage":"opshop", + "books":"book","bookshop":"book","music":"record","video":"video","games":"video", + "pawnbroker":"pawn","toys":"toy", + "bakery":"milkbar","cafe":"milkbar","confectionery":"milkbar","pastry":"milkbar","chocolate":"milkbar", + "deli":"milkbar","delicatessen":"milkbar","butcher":"milkbar","cheese":"milkbar","coffee":"milkbar","tea":"milkbar", + "convenience":"milkbar","kiosk":"milkbar","general":"milkbar","dairy":"milkbar", + "newsagent":"milkbar","stationery":"milkbar", + "chemist":"milkbar","pharmacy":"milkbar","cosmetics":"milkbar","perfumery":"milkbar", + "clothes":"dept","fashion":"dept","boutique":"dept","shoes":"dept","bag":"dept","jewelry":"dept","jewellery":"dept", + "department_store":"dept","variety_store":"dept","supermarket":"dept", + "hardware":"dept","doityourself":"dept","trade":"dept","electronics":"dept","mobile_phone":"dept", + "furniture":"dept","houseware":"dept","homeware":"dept", + "greengrocer":"stall","florist":"stall","farm":"stall","garden_centre":"stall" +} +``` +Default (not in the map) → `opshop`. + +**Subtlety guardrails (E):** +- Fetch only these tasteful staples — **not** every OSM `shop=*`. Skip vehicle/tyres/fuel, funeral, storage, + industrial, and pure services the player never browses (`hairdresser`, `beauty`, `travel_agency`, `bank`, + `laundry`, `estate_agent`). +- **Never** subsample the secondhand heroes. +- If a town's general-retail count would visually **drown** the secondhand strip, seed-subsample the *texture* + classes (the milkbar/dept/stall targets) toward **~2–3× the secondhand count**, and count the drops in + `norm.dropped` like every other drop. + +**Why these targets:** `milkbar` (counter + fridge + magazine rack + glass case) is the canonical Australian +counter shop — it wears cafe/bakery/deli/newsagent/chemist naturally; `dept` (cube shelves + clothes racks + +glass cases) wears clothes + hardware + big retail; `stall` (trestles + crates) wears produce + florist. Three +general-retail looks + the six secondhand heroes + the three venues = variety with no new archetypes. +**Pre-verified (seed 20261990, real-town lot 8.5×14):** milkbar/dept/stall/opshop all build valid (0 carves, +≤143 draws); `dept` reads as a clean **dressed-retail floor** (cube shelves + clothes racks + counter, the +escalator does *not* dominate the ~7.9×11.7 room), so `clothes`/`hardware` → `dept` is confirmed. C re-checks +the full result in the five-town door-soak (ledger #6) once E's caches land. (FYI: C's `theme.js canonicalType`/ALIAS already recognizes several +of these — `deli`/`corner_store`→milkbar etc. — for any direct `buildInterior(rawClass)`; the authoritative +mapping for the caches is this table.)