Compare commits
4 Commits
2c1ae37160
...
533fa32b59
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
533fa32b59 | ||
|
|
4314622c1b | ||
|
|
a493c0a13c | ||
|
|
0d8d59a22a |
@ -3,7 +3,39 @@
|
||||
*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-17 (round 24) · owner: PROCITY-C · reviewer: Fable
|
||||
Last updated: 2026-07-17 (round 25) · owner: PROCITY-C · reviewer: Fable
|
||||
|
||||
---
|
||||
|
||||
## Update 2026-07-17 (round 25, the tag earned) — sku-derived slot ids (ledger #3, C's one line)
|
||||
|
||||
R25 §Lane C: one contract line, published first so G re-emits against it. **§7.2a added** — F's id-collision
|
||||
finding made structural, while there are two atlases to migrate instead of fifty.
|
||||
|
||||
**The collision, measured:** both packs number items positionally from zero, so **all 120 godverse ids are
|
||||
also generic-pack ids — 120/120 overlap.** An id-equality gate cannot discriminate which pack a rendered
|
||||
item came from; that's exactly why the brief's own #7a spec was vacuous. (The vacuous-gate law's first
|
||||
application broke the law — and my own R23 metric had the same disease. It's a persistent species.)
|
||||
|
||||
**The rule (§7.2a):** `items[].id` MUST derive from the source's stable key, never from position, and MUST
|
||||
be unique across ALL packs. Real-stock packs: **`id = "sku_" + <POS sku>`** — G's snapshot already carries
|
||||
`sku` per item (e.g. `20260314070442`), it's just dropped at emit, so this is index-only. Generic packs keep
|
||||
`rec_NNNN` as their namespace; real-stock must not emit into it.
|
||||
|
||||
**I gave it two reasons, and the second is the one that outlives the gate.** The collision is the presenting
|
||||
symptom. The deeper defect is that **position is not identity**: a positional id renumbers on every re-bake,
|
||||
so selling one record out of crate 550 silently makes `rec_0050` a *different* record. Anything holding an
|
||||
id across snapshots — a wallet purchase, a saved dig, a gate assertion, and above all **tier-2's
|
||||
sold-means-gone** — would point at the wrong item. The POS sku is stable because it's the shop's own
|
||||
identity for that copy (`release_id` identifies the pressing, not the copy). So this line isn't only a gate
|
||||
fix; it's the identity tier-2 will need, bought now for free.
|
||||
|
||||
**Scope kept honest:** index-only, no atlas bytes, no town cache, no goldens. `id` isn't read by the loader
|
||||
(§7.3) — the dig/buy consumers and the gates read it, so no C code changes. **→ G:** re-emit with `sku_`
|
||||
ids. **→ E:** assert the form (present, unique within the pack, `sku_`-prefixed for real-stock).
|
||||
|
||||
*Process note:* F's six files were staged in the shared tree mid-flight; committed by explicit pathspec, so
|
||||
F's session is untouched.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@ -3,6 +3,45 @@
|
||||
*Lane brief: `docs/LANES/LANE_G_GODVERSE.md`. This file follows your progress-file convention —
|
||||
newest round first. Fable-on-ultra writing.*
|
||||
|
||||
## Round 25 (2026-07-17) — the sku re-emit (ledger #3), index-only
|
||||
|
||||
**Landed (main — G is a full lane now, pathspec-atomic; F's six staged files and E's in-flight
|
||||
`validate_atlas.py` untouched):**
|
||||
- `godverse_stock.py` emits **`id = "sku_<POS sku>"`** per C §7.2a. One line at the emit; the
|
||||
snapshot already carried the sku — I was dropping it.
|
||||
- `stock_godverse/3962749/stock_record_index.json` re-emitted. **Index-only, as briefed:**
|
||||
|
||||
| check | result |
|
||||
|---|---|
|
||||
| **id overlap with the generic pack** | **0/120** — was **120/120** (F's finding) |
|
||||
| ids unique in-pack / all `sku_`-prefixed / none in `rec_` namespace | 120/120 · yes · yes |
|
||||
| **atlas .webp bytes moved** | **none** — sha-identical both files |
|
||||
| town caches / goldens touched | none |
|
||||
| ids stable when a record sells (drop item 50, re-derive) | **0 drift** |
|
||||
| E's validator (their R25 build, live in-tree) | `atlas-QA OK · 1 licence line(s) shown · 0 warnings` |
|
||||
| live loader: shop pack vs town pack | 120 / 350, coexist; uv + one-material-per-atlas hold |
|
||||
|
||||
**Id equality is discriminating again** — verified through the live loader, not just the file.
|
||||
|
||||
**C's reason #2 is the one that mattered**, and it's worth restating because it outlives the gate:
|
||||
position isn't identity. Sell one record out of crate 550 and `rec_0050` silently becomes a
|
||||
*different* record on the next bake — so a wallet purchase, a saved dig, or **tier-2's
|
||||
sold-means-gone** would point at the wrong item. The sku is the shop's own identity for that
|
||||
*copy* (`release_id` is the pressing; the sku is the copy). My positional ids were a latent
|
||||
correctness bug in the ratified §7 economy, not just a vacuous gate. Caught while there were two
|
||||
atlases to migrate instead of fifty.
|
||||
|
||||
**Conflict #1 is closed** (R24 → R25): E's validator now prints
|
||||
`LICENCE: … FLAG BEFORE ANY PUBLIC/COMMERCIAL RELEASE` against my top-level US `license`, and
|
||||
counts it. The flag a human must read on real product photos is unmissable. Nothing owed.
|
||||
|
||||
**→ F (one line, your file, your call — not touching it mid-flight):** `interior_mode.js:378`
|
||||
now reads *"ids are positional slots (`rec_0000`) that BOTH packs reuse … every atlas id is also a
|
||||
town-pack id (measured R24)"*. As of this commit that's false — 0/120. **Your gate stays canonical
|
||||
either way**: a texture URL proves which file the GPU sampled, which id equality never could, so
|
||||
the assertion is right and only the rationale is stale. Id equality is now available as a *second*
|
||||
discriminator if you want belt-and-braces.
|
||||
|
||||
## Round 24 (2026-07-17) — the re-emit + THE SHOP'S REAL STREET (ledger #5)
|
||||
|
||||
**THE WRITE-BACK RULING — John, 2026-07-17: A THEN B.** G3 §7 is **ratified** with the ruling
|
||||
|
||||
@ -1,11 +1,38 @@
|
||||
# LANE A — CITYGEN · progress (PROCITY-A)
|
||||
|
||||
*Status: **all deliverables landed; self-check all-green (152,030/152,030); rounds 2–24 closed** (see below).
|
||||
R24 (v5.0-alpha): the **`godverseShopId`** identity field — schema v2 (optional), carried through the lift
|
||||
onto `plan.shops[]`, **no golden moved**. R23: the spacing warn (150 m). classic `0x3fa36874` /
|
||||
gig `0xb1d48ea1` frozen. (Pack is 21 real + 1 godverse — E retired toowoomba in R23.)*
|
||||
*Status: **all deliverables landed; self-check ALL GREEN (156,211/156,211); rounds 2–25 closed** (see below).
|
||||
R25 (v5.0-alpha): the sweep reconciled with **Ruling 2** (keyed asserts are per-layer), the uniqueness check
|
||||
rebuilt so it can actually fail, the **orphaned-atlas gate** added, and **six goldens pinned** — F's tag is
|
||||
unblocked from my side. classic `0x3fa36874` / gig `0xb1d48ea1` frozen.*
|
||||
*Date: 2026-07-17 · owner: PROCITY-A (Opus 4.8)*
|
||||
|
||||
## Round 25 (2026-07-17) — v5.0-alpha: the sweep vs Ruling 2 + the six pins (ledger #1)
|
||||
|
||||
All 8 tree reds cleared — **6 were my own gate asserting Ruling 2 away**, 2 were goldens awaiting my pin.
|
||||
selfcheck **ALL GREEN 156,211/156,211**, scaffold + consistency green, classic frozen.
|
||||
|
||||
- **My R24 gate encoded an assumption that Ruling 2 falsified.** I built the identity arm believing a
|
||||
godverse cache is *all* census shops. It's **mixed** by design — a keyed GODVERSE layer + an inherited OSM
|
||||
texture layer that G measured to be load-bearing (census-only Red Hill: 306 m spacing warn + a poster
|
||||
inside a kerb). So `newtown_godverse` (18 keyed + 54 texture) and `redhill_godverse` (10 + 27) were
|
||||
**healthy towns my gate called broken**. Keyed asserts now run **per-layer over the keyed subset only**;
|
||||
the "N/M missing" warn is gone. The one honest requirement left: a `godverse+osm` cache must have a
|
||||
**non-empty** godverse layer (else it's an osm cache with the wrong `source`) — still a warn.
|
||||
- **The uniqueness check was broken in both directions.** `new Set(all ids).size === shops.length` collapses
|
||||
every `undefined` into one entry, so it failed structurally on mixed caches *and* could hide a real
|
||||
duplicate behind the same collapse. Now over **defined ids only** — and, per the vacuous-gate law, proven
|
||||
able to fail: the validator rejects dups at the front door, so the test feeds one **straight to the lift**
|
||||
(`generatePlanOSM` doesn't validate) and asserts the predicate catches it.
|
||||
- **New: the orphaned-atlas gate** — my own R24 finding, enforced rather than filed. A committed
|
||||
`stock_godverse/<id>/` whose shop the lift dropped = real stock keyed to a shop that isn't in the town.
|
||||
Node-side, subject-aware (SKIPs by name when a town has no atlas), so it catches in seconds what F's #7b
|
||||
could only catch in a browser at the end of a round. **It already found one, benign today:** redhill drops
|
||||
keyed shop 2286 "Empire Revival" (unstocked ⇒ no orphan ⇒ gate passes). Filed for G: stocking it at the
|
||||
beta would orphan. Monster Robot Party is seated (lot 8).
|
||||
- **The six pins**, cross-checked two ways before landing — byte-identical across two fresh processes, and
|
||||
matching the values G stated independently in `86e2985`: `newtown_godverse` `0xcf69b387`/`0x1e266f60`,
|
||||
`redhill_real` `0x6046700f`/`0x673785ee`, `redhill_godverse` `0xb2224939`/`0xc6f80e18`.
|
||||
|
||||
## Round 24 (2026-07-17) — v5.0-alpha: the identity field (ledger #2)
|
||||
|
||||
`shop.godverseShopId` — the optional key resolving `stock_godverse/<id>/`. Schema **stays v2**; absent
|
||||
|
||||
@ -437,16 +437,28 @@ census shops use thriftgod `shop.id` (max **2992**), while **Monster Robot Party
|
||||
census at all** and uses its **dealgod store id 3962749**. So: never derive it from `id`, never assert
|
||||
equality, never build a mapping table (the R12 gigKey law — one key, zero mapping). **G emits, all read.**
|
||||
|
||||
**A godverse cache is MIXED, by design — RULING 2 (confirmed as law, ROUND25).** It carries a **keyed
|
||||
GODVERSE layer** (census shops + injected shops like Monster Robot) **plus an inherited OSM texture layer
|
||||
that is legitimately unkeyed**. G measured that the texture layer is load-bearing, not cosmetic:
|
||||
census-only Red Hill shipped a 306 m spacing warn and a poster inside a kerb; with the texture layer it
|
||||
passes. **So "shops without an id" is the design, and no gate may assert it away** — mine did, in R24, and
|
||||
failed 54/72 on a healthy town.
|
||||
|
||||
**`validateTownCache` arms** (split by hazard, not tidiness): a **malformed** id (not a positive integer)
|
||||
is an **error** — it names a path segment, and `"3962749"` vs `3962749` is exactly the coercion drift that
|
||||
broke the atlas contract; a **duplicate** id is an **error** — two shops sharing one atlas *is* mis-stocking
|
||||
(charter risk #3: "never mis-stocked"); a **missing** id on a `source: "godverse+osm"` cache is a **warn**,
|
||||
and those shops fall soft to **tier 0**. Missing is deliberately *not* an error: the charter's determinism
|
||||
boundary says *world = seeded and gated, stock = data tiers*, so a town must never fail to load because its
|
||||
**stock** identity is absent — tier 0 is the designed ladder, not a defect. The teeth live in `selfcheck`:
|
||||
**partial keying FAILS** (a half-keyed town silently mis-stocks the rest) and zero keying prints an explicit
|
||||
**SKIP** naming the town and count, per the round's vacuous-gate law. *(Recorded departure from the ledger's
|
||||
"requires" — reasons above; Fable's to overrule.)*
|
||||
(charter risk #3: "never mis-stocked"); a godverse cache with an **entirely empty GODVERSE layer** (no id on
|
||||
any shop) is a **warn** — it's an osm cache wearing the wrong `source`, and it stays a warn because the
|
||||
charter's determinism boundary says *world = seeded and gated, stock = data tiers*: a town must never fail
|
||||
to load because its **stock** identity is absent. Tier 0 is the designed ladder, not a defect.
|
||||
|
||||
**The `selfcheck` arm runs per-layer** — every assert is over the **keyed subset only**: the layer reaches
|
||||
the plan, its ids are **unique over defined ids only** (the R24 version compared a Set of *all* ids, which
|
||||
collapses every `undefined` into one entry — it failed structurally on a mixed cache *and* could hide a real
|
||||
duplicate behind that collapse), and the lift invents no identity. Plus the **orphaned-atlas gate**: a
|
||||
committed atlas under `stock_godverse/<id>/` whose shop the lift dropped means real stock keyed to a shop
|
||||
that isn't in the town — it fails, and SKIPs by name when a town has no atlas. Dropped keyed shops are
|
||||
printed, never silent (the R19/R20 drop-and-count ruling).
|
||||
|
||||
**It survives the lift:** `plan_osm` copies it onto `plan.shops[]` (the runtime reads the plan, never the
|
||||
cache — otherwise the field is decoration and F's per-shop `base` can never resolve). Absent ⇒ the key is
|
||||
|
||||
@ -2,6 +2,52 @@
|
||||
|
||||
Durable answers to questions other lanes raised against Lane A. Full status in `A-progress.md`.
|
||||
|
||||
## Round 25 (2026-07-17) — v5.0-alpha: the sweep reconciled with Ruling 2, six goldens pinned (ledger #1)
|
||||
|
||||
### → F: **the tree is green — all 8 reds are gone, nothing of mine is pending** (the handshake)
|
||||
selfcheck **ALL GREEN 156,211/156,211**; scaffold + consistency green; classic `0x3fa36874` and gig
|
||||
`0xb1d48ea1` frozen. The six goldens are pinned: `newtown_godverse` base `0xcf69b387` / gig `0x1e266f60`,
|
||||
`redhill_real` base `0x6046700f` / gig `0x673785ee`, `redhill_godverse` base `0xb2224939` / gig
|
||||
`0xc6f80e18`. Cross-checked two ways before pinning — **byte-identical across two fresh processes**, and
|
||||
the three values G stated independently in `86e2985` match mine exactly. **Your third attempt is unblocked
|
||||
from my side.**
|
||||
|
||||
Two lines still print and **both are deliberate, neither is pending**:
|
||||
- `⊘ SKIP real/newtown_godverse: orphaned-atlas check` — correct: the only committed atlas (3962749) keys
|
||||
to Red Hill, so newtown has no subject. The vacuous-gate law says say so rather than pass quietly.
|
||||
- `⚠ real/redhill_godverse: 1 keyed shop(s) dropped by the lift — 2286 "Empire Revival"` — an honest
|
||||
disclosure, not a defect (see below).
|
||||
|
||||
### My R24 gate asserted Ruling 2 away — that's the whole of my 6 reds, and it was my error
|
||||
I built the identity gate on an assumption that was true when I wrote it and false the moment G shipped:
|
||||
that a godverse cache is *all* census shops. Ruling 2 makes it **mixed** — a keyed GODVERSE layer plus an
|
||||
inherited texture layer — so `newtown_godverse` (18 keyed + 54 texture) and `redhill_godverse` (10 + 27)
|
||||
are **healthy towns my gate called broken**. Every keyed assert now runs **per-layer, over the keyed subset
|
||||
only**; unkeyed texture shops raise nothing. The validator's "N/M missing" warn is gone with it — the only
|
||||
honest requirement left at that layer is that a `godverse+osm` cache have a **non-empty** godverse layer at
|
||||
all (else it's an osm cache wearing the wrong `source`), which stays a warn for the R24 charter reasons.
|
||||
|
||||
### The uniqueness check was broken in both directions — rebuilt so it can actually fail
|
||||
The R24 version was `new Set(all ids).size === shops.length`. Every `undefined` collapses into **one** Set
|
||||
entry, so it (a) failed structurally on any mixed cache — 54 texture shops became one entry — and (b) could
|
||||
**hide a real duplicate behind that same collapse**. It now runs over **defined ids only**. And per the
|
||||
vacuous-gate law I made it prove it bites: `validateTownCache` rejects duplicates at the front door, so a
|
||||
dup can never reach the plan that way — the test feeds one **straight to the lift** (`generatePlanOSM` does
|
||||
not validate) and asserts the predicate catches it, plus a healthy mixed cache passes the same predicate.
|
||||
A check nobody can watch fail is not a check.
|
||||
|
||||
### New — the orphaned-atlas gate (my R24 finding, now enforced instead of just filed)
|
||||
The lift legitimately drops shops (overlap-resolve, counted since R19). Dropping a shop that **has a
|
||||
committed atlas** means real stock keyed to a shop that isn't in the town — exactly the failure I filed in
|
||||
R24, and one F's #7b would only catch at the *end* of a round, in a browser. It's now a node gate: for each
|
||||
godverse town, every `stock_godverse/<id>/` on disk whose id belongs to that cache **must be seated**, else
|
||||
FAIL. Subject-aware — SKIPs by name when a town has no atlas.
|
||||
|
||||
**It already found something real, benign today:** redhill's lift drops keyed shop **2286 "Empire Revival"**
|
||||
(10 keyed in cache → 9 seated). It has no atlas, so nothing is orphaned and the gate passes. **→ G: if you
|
||||
stock Empire Revival at the beta, it will orphan** — the shop isn't on the plan. Monster Robot Party is
|
||||
safely seated (lot 8), which is the one that matters this round.
|
||||
|
||||
## Round 24 (2026-07-17) — v5.0-alpha: the identity field (ledger #2)
|
||||
|
||||
### → G: **`godverseShopId` is live — emit it, and mind the id-space trap** (the handshake for your #5)
|
||||
|
||||
@ -12,6 +12,9 @@
|
||||
> held F's tag. §7 now states what `stockpack.js` actually implements, extended per-shop, and the
|
||||
> `type+base` cache keying is landed. **G's R23 atlas layout is ratified** (G re-emits provenance field
|
||||
> names only, §7.3). §0–§6 unchanged.
|
||||
> **v5.0-alpha amendment (2026-07-17, R25 ledger #3):** **§7.2a added — slot ids must be sku-derived,**
|
||||
> unique across packs and stable across re-emits (F's id-collision finding, made structural). Index-only;
|
||||
> no atlas bytes, no goldens. §0–§6 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
|
||||
@ -257,6 +260,32 @@ The loader is `preloadStockPack(type, { base })` → it fetches **`<base>stock_<
|
||||
- **`uv: [u0,v0,u1,v1]`, origin TOP-LEFT** — the loader flips V itself (`uvRect`). Do not pre-flip.
|
||||
- Read by the dig/buy consumers (not by the loader): **`id`, `title`, `artist`, `price`, `price_band`**.
|
||||
|
||||
### 7.2a Slot ids — unique across packs, stable across re-emits (v5.0-alpha, R25 ledger #3)
|
||||
**Rule: `items[].id` MUST derive from the source's own stable key — never from position — and MUST be
|
||||
unique across ALL packs.** For a real-stock (godverse) pack that key is the shop's POS sku:
|
||||
**`id = "sku_" + <POS sku>`** (e.g. `sku_20260314070442`; G's snapshot already carries `sku` per item, it's
|
||||
just dropped at emit). The shipped generic packs keep `rec_NNNN` as their namespace — **a real-stock pack
|
||||
must not emit into it.**
|
||||
|
||||
**Why — two reasons, both measured:**
|
||||
1. **Positional ids collide by construction.** Both packs number from zero, so **all 120 godverse ids are
|
||||
also generic-pack ids — 120/120 overlap (measured R25)**. An id-equality gate therefore cannot
|
||||
discriminate which pack a rendered item came from: that is what made the brief's own #7a spec vacuous.
|
||||
F caught it and replaced it with title-sets + texture-URL provenance (now the canonical honest-gate
|
||||
pattern for stock). Sku ids make id-equality discriminating again — permanently, and while there are
|
||||
two atlases to migrate instead of fifty.
|
||||
2. **Position is not identity — and this one outlives the gate.** A positional id renumbers on every
|
||||
re-bake: sell one record out of crate 550 and `rec_0050` silently becomes a *different* record. Anything
|
||||
holding an id across snapshots — a wallet purchase, a saved dig, a gate assertion, and above all
|
||||
**tier-2's sold-means-gone** — would then point at the wrong item. The POS sku is stable precisely
|
||||
because it is the shop's own identity for that record: the same principle that makes `godverseShopId`
|
||||
the POS shop id. *(`release_id` identifies the pressing, not the copy — the sku is the copy.)*
|
||||
|
||||
**Scope: index-only.** `id` is not read by the loader (§7.3) — the dig/buy consumers and the gates read it.
|
||||
**No atlas bytes, no town cache, no golden moves.**
|
||||
**→ Lane E:** assert the form — `id` present, **unique within the pack**, and `sku_`-prefixed for
|
||||
real-stock packs.
|
||||
|
||||
### 7.3 Fields the runtime IGNORES — and the provenance ruling (the drift dies here)
|
||||
`version`, `atlas_px`, `cell`/`cell_w`/`cell_h`, `count`, `kind`, `tier`, `shop`, `crate`,
|
||||
`provenance` — **`stockpack.js` reads none of them.** So the authority for their shape is not C's
|
||||
|
||||
99
docs/LANES/ROUND26_INSTRUCTIONS.md
Normal file
99
docs/LANES/ROUND26_INSTRUCTIONS.md
Normal file
@ -0,0 +1,99 @@
|
||||
# PROCITY — Round 26 lane instructions (from Fable, integrator)
|
||||
|
||||
Date: 2026-07-17 · **R25 verdict: one commit and one harness verdict from done.** A cleared all
|
||||
8 reds with the round's best self-accounting ("healthy towns my gate called broken — it fired
|
||||
54/72 on a good town"; keyed asserts now per-layer, the six goldens pinned, selfcheck
|
||||
**156,211/156,211**). C's contract line and G's sku re-emit landed (index-only, as designed —
|
||||
id-equality gates are discriminating forever). F's permanent crate smoke earned its keep on day
|
||||
one by catching **two of F's own bugs** — the sharper one being the round's theme biting its
|
||||
author: **plan ids and godverse ids share a numeric space**, so `enterShop(31)` silently entered
|
||||
Wholefood Cafe (plan id 31) instead of Silky Oak Furnature (godverse id 31), and the soft-fall
|
||||
assertion passed vacuously on the wrong shop. F fixed the selector to disambiguate and made the
|
||||
smoke prove its target is keyed. *Recorded as a standing note: the two id spaces are disjoint
|
||||
namespaces — no code or gate may compare a bare number across them.*
|
||||
|
||||
**Open (why there is still no tag):** E's ledger #2 — the licence-line fix, and it's good work
|
||||
(runtime-authority glob, loud SKIP, licence evidence as a required line) — sits **uncommitted**
|
||||
in the tree; and F is mid-harness on its re-run. Round 26 opens by closing both, then the beta.
|
||||
|
||||
## WAVE 0 — close the alpha (before anything else starts)
|
||||
|
||||
1. **E: commit your own work.** `pipeline/validate_atlas.py` carries your R25 rebuild, unstaged.
|
||||
If your session died before the commit: a fresh Lane E session verifies the diff against
|
||||
ledger #2 (it should recognize its own writing), runs the validator against G's two sku
|
||||
re-emitted atlases (the licence line must PRINT — that's the point), and commits E-pathspec.
|
||||
Nobody else touches this file — it's yours.
|
||||
2. **F: land the verdict.** Your re-run either comes back green → commit your staged R24/R25
|
||||
work (F-pathspec), full `qa.sh --strict --matrix`, README teaser with the tag, tag
|
||||
**`v5.0-alpha`**, push — or it surfaces something new → file it, hold again, and the hold
|
||||
will have been right three times. Nothing downstream starts until the tag verdict is known.
|
||||
|
||||
## Then: v5.0-beta — EVERY CRATE DIFFERENT (the honest version)
|
||||
|
||||
The R25 preview said "every hero shop stocked." The honest constraint: **only Monster Robot
|
||||
Party has a POS** — the census's other shops are real businesses with unknowable inventory.
|
||||
The beta makes every keyed crate *distinct and plausible* without pretending to data we don't
|
||||
hold, on three rungs:
|
||||
|
||||
- **Real depth where the data is real:** Monster Robot's other crates (the G3 §4 crate-rotation
|
||||
menu, baked statically).
|
||||
- **Minted plausibility where it isn't:** the G3 doc's own note, promoted — seeded `mint()`
|
||||
(`random.Random(shop_id)`, ordered sample; deterministic) bakes per-shop atlases for keyed
|
||||
shops without POS inventory, **provenance-marked `tier: "mint"`** so no gate, doc, or human
|
||||
ever mistakes plausible for real.
|
||||
- **Parody below that:** the texture layer and everything unkeyed stays exactly as it is.
|
||||
|
||||
## The ledger
|
||||
|
||||
1. **The mint contract line (C, first — half-day rule).** §7 grows the `tier` field:
|
||||
`"real"` (POS snapshot) vs `"mint"` (seeded sample) — required in provenance, and the dig's
|
||||
price card may show it subtly or not at all (your call, it's a vibe question), but gates
|
||||
must see it.
|
||||
2. **The mint baker + Monster Robot depth (G).** Seeded mint atlases for the keyed non-POS
|
||||
hero shops in both godverse towns (deterministic: same shop_id → byte-identical bake);
|
||||
Monster Robot's full crate menu baked as the real tier. Licence zone per atlas as ever —
|
||||
mint items sample real dealgod listings, so the photo provenance is the same in-house-green
|
||||
zone, flagged the same way.
|
||||
3. **The validator grows the tier arm (E).** `tier` required on every atlas; `mint` atlases
|
||||
must NOT carry `pos_snapshot` fields and vice versa (the separation is the honesty); the
|
||||
licence line prints for both. Vacuous-gate law applies: an atlas with no tier FAILS.
|
||||
4. **The dig UX for real items (C).** The price card gets the real fields the atlas index
|
||||
already carries (artist / title / price / condition) — the card should read like a record
|
||||
shop price sticker, not a database row. Budget ceilings unchanged.
|
||||
5. **B returns — dig-adjacent street polish (your pick, at last).** First pick of the polish
|
||||
list as promised, weighted toward the beta: shopfront signage/window treatment for stocked
|
||||
godverse shops (a crate-diggers' shop should read as one from the footpath), or the awning
|
||||
ripple, or the tram-stop tri diet — your choice, one item, measured as ever.
|
||||
6. **The beta gate (F).** Per-shop distinctness (no two keyed crates identical — assert on
|
||||
title sets, the R24 pattern), tier provenance visible in gate output (a mint crate never
|
||||
reports as real), the ladder re-proof, `qa.sh --strict --matrix`, tag **`v5.0-beta`**, push.
|
||||
7. **A / D — on-call.** A: nothing pending (your R25 close was clean). D: nothing — unless F's
|
||||
distinctness gate wants a crowd check at a stocked shop (patronage at Monster Robot on a
|
||||
Saturday feels like a D flourish, not a requirement).
|
||||
|
||||
## Laws
|
||||
|
||||
Charter v5 + vacuous-gate + the id-namespace note above. Golden discipline: no town-cache
|
||||
changes this round → no golden moves (mint atlases are `stock_godverse/**` files, outside every
|
||||
golden). No server code — tier 2 stays design until the beta ships and the v5.0 round charters
|
||||
it against the ratified G3.
|
||||
|
||||
## THE EXACT RUN ORDER
|
||||
|
||||
0. **WAVE 0: E commits; F lands the verdict and (on green) tags `v5.0-alpha`.** Hard stop until
|
||||
the tag verdict is known.
|
||||
1. **Start together: C (#1 contract line + #4 dig card) + B (#5 pick).**
|
||||
2. **When C's line lands: G (#2 mint baker + depth) and E (#3 tier arm) in parallel.**
|
||||
3. **When G + E are in: F (#6)** — distinctness gate, ladder, tag **`v5.0-beta`**, push.
|
||||
|
||||
Waves: **[E-commit, F-verdict] → [C, B] → [G, E] → [F]**. A/D on-call.
|
||||
|
||||
## Standing
|
||||
|
||||
- **John — nothing needs you.** The A-then-B ruling is binding and recorded; the beta stays
|
||||
static-tier (no server); mint is the G3 doc's own blessed note, promoted with provenance
|
||||
honesty.
|
||||
- **v5.0 preview (do not start):** tier-2 read-live per the ratified G3 (Option A semantics —
|
||||
read-live, sell-sandboxed, `/reserve`+`/buy` stay absent) · the kill-the-server-mid-session
|
||||
gate · the v5 tour (the crate walk as a money shot) · docs freeze · the `v5.0` tag · the
|
||||
epoch retro.
|
||||
@ -196,7 +196,14 @@ def pack(args):
|
||||
sheet.paste(cov, (gx * CELL_W, gy * CELL_H))
|
||||
u0, v0 = gx * CELL_W / W, gy * CELL_H / H
|
||||
idx_items.append({
|
||||
"id": f"rec_{len(idx_items):04d}", "title": it["title"], "artist": it["artist"],
|
||||
# C §7.2a (R25): sku-derived, never positional. `rec_NNNN` is the generic packs'
|
||||
# namespace and a real-stock pack must not emit into it — positionally, all 120 of
|
||||
# our ids WERE generic-pack ids, which is what made an id-equality gate vacuous.
|
||||
# And position isn't identity: sell one record out of the crate and `rec_0050`
|
||||
# silently becomes a different record on the next bake, which is exactly what
|
||||
# tier-2's sold-means-gone must never do. The POS sku is the shop's own identity
|
||||
# for that copy (release_id identifies the pressing; the sku identifies the copy).
|
||||
"id": f"sku_{it['sku']}", "title": it["title"], "artist": it["artist"],
|
||||
"price": int(round(it["price"])), "price_band": price_band(it["price"]),
|
||||
"atlas": aname, "uv": [round(u0, 4), round(v0, 4),
|
||||
round(u0 + CELL_W / W, 4), round(v0 + CELL_H / H, 4)],
|
||||
|
||||
@ -49,7 +49,7 @@
|
||||
},
|
||||
"items": [
|
||||
{
|
||||
"id": "rec_0000",
|
||||
"id": "sku_20260314070442",
|
||||
"title": "Abstract Latin Lounge II (Part II)",
|
||||
"artist": "Various",
|
||||
"price": 15,
|
||||
@ -63,7 +63,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0001",
|
||||
"id": "sku_20250507152003",
|
||||
"title": "The Lowdown Sampler Vol 1",
|
||||
"artist": "Various",
|
||||
"price": 20,
|
||||
@ -77,7 +77,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0002",
|
||||
"id": "sku_20260208003559",
|
||||
"title": "Yoshitoshi Artists - In House We Trust / Deep Dish - Penetrate Deeper",
|
||||
"artist": "Various",
|
||||
"price": 50,
|
||||
@ -91,7 +91,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0003",
|
||||
"id": "sku_20260313083125",
|
||||
"title": "Voyage Direct: First Mission Sampler 1",
|
||||
"artist": "Various",
|
||||
"price": 20,
|
||||
@ -105,7 +105,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0004",
|
||||
"id": "sku_20250726020618",
|
||||
"title": "Local Talk 5 1/2 Years Later (Part Two)",
|
||||
"artist": "Various",
|
||||
"price": 25,
|
||||
@ -119,7 +119,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0005",
|
||||
"id": "sku_20260307032128",
|
||||
"title": "Bar 1 | Autumn.04 | The Vinyl Edition (Part 2)",
|
||||
"artist": "Various",
|
||||
"price": 25,
|
||||
@ -133,7 +133,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0006",
|
||||
"id": "sku_20250821021324",
|
||||
"title": "Distille Cup",
|
||||
"artist": "Various",
|
||||
"price": 25,
|
||||
@ -147,7 +147,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0007",
|
||||
"id": "sku_20260314234401",
|
||||
"title": "The Esensual EP",
|
||||
"artist": "Various",
|
||||
"price": 20,
|
||||
@ -161,7 +161,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0008",
|
||||
"id": "sku_20260313073221",
|
||||
"title": "First Filtration Of The Duplex Brains",
|
||||
"artist": "Various",
|
||||
"price": 15,
|
||||
@ -175,7 +175,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0009",
|
||||
"id": "sku_20250410004205",
|
||||
"title": "Get Down",
|
||||
"artist": "Various",
|
||||
"price": 60,
|
||||
@ -189,7 +189,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0010",
|
||||
"id": "sku_20260312011415",
|
||||
"title": "It's A DJ Thing 3",
|
||||
"artist": "Various",
|
||||
"price": 50,
|
||||
@ -203,7 +203,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0011",
|
||||
"id": "sku_20250529095405",
|
||||
"title": "Lost On Arrival (Part 1 of 2)",
|
||||
"artist": "Various",
|
||||
"price": 40,
|
||||
@ -217,7 +217,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0012",
|
||||
"id": "sku_20250410003605",
|
||||
"title": "Moovemints Vol. 1",
|
||||
"artist": "Various",
|
||||
"price": 40,
|
||||
@ -231,7 +231,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0013",
|
||||
"id": "sku_20250601121101",
|
||||
"title": "The Innercity Experience Part 1",
|
||||
"artist": "Various",
|
||||
"price": 15,
|
||||
@ -245,7 +245,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0014",
|
||||
"id": "sku_20260320031744",
|
||||
"title": "Moving House",
|
||||
"artist": "Various",
|
||||
"price": 25,
|
||||
@ -259,7 +259,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0015",
|
||||
"id": "sku_20250521143700",
|
||||
"title": "Star Chasers",
|
||||
"artist": "4 Hero",
|
||||
"price": 20,
|
||||
@ -273,7 +273,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0016",
|
||||
"id": "sku_20250223130605",
|
||||
"title": "Feel So High",
|
||||
"artist": "51 Days",
|
||||
"price": 30,
|
||||
@ -287,7 +287,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0017",
|
||||
"id": "sku_20250322223205",
|
||||
"title": "Forbidden Love",
|
||||
"artist": "52 Pik - Up",
|
||||
"price": 25,
|
||||
@ -301,7 +301,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0018",
|
||||
"id": "sku_20260212004619",
|
||||
"title": "Music Of Life",
|
||||
"artist": "ACME",
|
||||
"price": 15,
|
||||
@ -315,7 +315,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0019",
|
||||
"id": "sku_20251005025944",
|
||||
"title": "Thus Far EP",
|
||||
"artist": "AlphaMotive",
|
||||
"price": 15,
|
||||
@ -329,7 +329,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0020",
|
||||
"id": "sku_20251005030122",
|
||||
"title": "Blue Blackness",
|
||||
"artist": "Alan Smithee",
|
||||
"price": 20,
|
||||
@ -343,7 +343,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0021",
|
||||
"id": "sku_20250223165003",
|
||||
"title": "Blue Blackness",
|
||||
"artist": "Alan Smithee",
|
||||
"price": 20,
|
||||
@ -357,7 +357,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0022",
|
||||
"id": "sku_20250731022038",
|
||||
"title": "Quarter Of A Century (Part 3 Of 3)",
|
||||
"artist": "ADNY & The Persuader",
|
||||
"price": 25,
|
||||
@ -371,7 +371,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0023",
|
||||
"id": "sku_20250320144603",
|
||||
"title": "Community / Everything Is Alright (Part Two)",
|
||||
"artist": "Audio Soul Project",
|
||||
"price": 20,
|
||||
@ -385,7 +385,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0024",
|
||||
"id": "sku_20250731021731",
|
||||
"title": "Quarter Of A Century - Part 2 Of 3",
|
||||
"artist": "ADNY & The Persuader",
|
||||
"price": 30,
|
||||
@ -399,7 +399,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0025",
|
||||
"id": "sku_20250529161104",
|
||||
"title": "The John Gore EP",
|
||||
"artist": "Alex Agore / James Johnston (5)",
|
||||
"price": 20,
|
||||
@ -413,7 +413,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0026",
|
||||
"id": "sku_20250904081809",
|
||||
"title": "LabSamples",
|
||||
"artist": "Atjazz",
|
||||
"price": 30,
|
||||
@ -427,7 +427,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0027",
|
||||
"id": "sku_20250509114903",
|
||||
"title": "Simple",
|
||||
"artist": "Alumna",
|
||||
"price": 20,
|
||||
@ -441,7 +441,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0028",
|
||||
"id": "sku_20260325010301",
|
||||
"title": "Cascades Of Colour",
|
||||
"artist": "Ananda Project, The Feat. Gaelle Adisson",
|
||||
"price": 40,
|
||||
@ -455,7 +455,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0029",
|
||||
"id": "sku_20260228030040",
|
||||
"title": "Time And Space EP",
|
||||
"artist": "Andrew Macari",
|
||||
"price": 25,
|
||||
@ -469,7 +469,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0030",
|
||||
"id": "sku_20260208023822",
|
||||
"title": "Hot 'N' Spycy (The Album)",
|
||||
"artist": "Angel Moraes",
|
||||
"price": 40,
|
||||
@ -483,7 +483,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0031",
|
||||
"id": "sku_20251017085011",
|
||||
"title": "I Like It (I Like How You're Lov'in Me)",
|
||||
"artist": "Angel Moraes",
|
||||
"price": 15,
|
||||
@ -497,7 +497,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0032",
|
||||
"id": "sku_20250303003804",
|
||||
"title": "Release Yourself / Deep Inside Your Love",
|
||||
"artist": "Angel Moraes",
|
||||
"price": 30,
|
||||
@ -511,7 +511,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0033",
|
||||
"id": "sku_20251005041410",
|
||||
"title": "Heaven Knows (I Can't Understand)",
|
||||
"artist": "Angel Moraes Featuring Basil Rodericks",
|
||||
"price": 20,
|
||||
@ -525,7 +525,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0034",
|
||||
"id": "sku_20250815063017",
|
||||
"title": "Tout Est Bleu (Fran\u00e7ois K. Rmx)",
|
||||
"artist": "\u00c2me Strong",
|
||||
"price": 50,
|
||||
@ -539,7 +539,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0035",
|
||||
"id": "sku_20250927001753",
|
||||
"title": "Are You Ready",
|
||||
"artist": "Affair (3), The",
|
||||
"price": 20,
|
||||
@ -553,7 +553,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0036",
|
||||
"id": "sku_20250509104701",
|
||||
"title": "It's Been Too Long",
|
||||
"artist": "Alyoa",
|
||||
"price": 15,
|
||||
@ -567,7 +567,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0037",
|
||||
"id": "sku_20250216121604",
|
||||
"title": "Change",
|
||||
"artist": "Bugge Wesseltoft",
|
||||
"price": 30,
|
||||
@ -581,7 +581,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0038",
|
||||
"id": "sku_20250513235504",
|
||||
"title": "Die Hard + 2",
|
||||
"artist": "Baba Stiltz",
|
||||
"price": 25,
|
||||
@ -595,7 +595,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0039",
|
||||
"id": "sku_20260203022809",
|
||||
"title": "Living Room Chronicles Vol. III: Forward Movement",
|
||||
"artist": "DJ Buck",
|
||||
"price": 50,
|
||||
@ -609,7 +609,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0040",
|
||||
"id": "sku_20250301154200",
|
||||
"title": "Lone Cat (Holding On)",
|
||||
"artist": "Ben Watt",
|
||||
"price": 30,
|
||||
@ -623,7 +623,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0041",
|
||||
"id": "sku_20260320051206",
|
||||
"title": "Music Is Our Life",
|
||||
"artist": "Back To Earth",
|
||||
"price": 20,
|
||||
@ -637,7 +637,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0042",
|
||||
"id": "sku_20250817064358",
|
||||
"title": "All True (African)",
|
||||
"artist": "Basil",
|
||||
"price": 15,
|
||||
@ -651,7 +651,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0043",
|
||||
"id": "sku_20250207224901",
|
||||
"title": "Rated X (Re-Make)",
|
||||
"artist": "Benny Bobby Boogie",
|
||||
"price": 15,
|
||||
@ -665,7 +665,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0044",
|
||||
"id": "sku_20260326061120",
|
||||
"title": "Rock To The Rhythm Of Love",
|
||||
"artist": "Beloved, The",
|
||||
"price": 12,
|
||||
@ -679,7 +679,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0045",
|
||||
"id": "sku_20260320032136",
|
||||
"title": "7 Days",
|
||||
"artist": "Big Strick",
|
||||
"price": 25,
|
||||
@ -693,7 +693,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0046",
|
||||
"id": "sku_20250410104801",
|
||||
"title": "Volume II",
|
||||
"artist": "Black Traxx",
|
||||
"price": 35,
|
||||
@ -707,7 +707,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0047",
|
||||
"id": "sku_20250318010204",
|
||||
"title": "Tried So Hard",
|
||||
"artist": "Bobby Pruit",
|
||||
"price": 40,
|
||||
@ -721,7 +721,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0048",
|
||||
"id": "sku_20250731015554",
|
||||
"title": "Best Intentions For Failed Inventions",
|
||||
"artist": "Brett Johnson",
|
||||
"price": 30,
|
||||
@ -735,7 +735,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0049",
|
||||
"id": "sku_20250824052221",
|
||||
"title": "Highlights / 405",
|
||||
"artist": "DJ Buck",
|
||||
"price": 90,
|
||||
@ -749,7 +749,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0050",
|
||||
"id": "sku_20250406234001",
|
||||
"title": "The Purist",
|
||||
"artist": "Byron Stingily",
|
||||
"price": 30,
|
||||
@ -763,7 +763,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0051",
|
||||
"id": "sku_20250816021721",
|
||||
"title": "Boogie Drive 678 (Remix & Dub)",
|
||||
"artist": "Boo",
|
||||
"price": 35,
|
||||
@ -777,7 +777,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0052",
|
||||
"id": "sku_20260313082548",
|
||||
"title": "Costa Del Sol",
|
||||
"artist": "Bad Boy Bill Feat. Nadine Ren\u00e9e",
|
||||
"price": 15,
|
||||
@ -791,7 +791,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0053",
|
||||
"id": "sku_20260222035021",
|
||||
"title": "When I Fall In Love (Remixes)",
|
||||
"artist": "Blaze Featuring Sybil",
|
||||
"price": 30,
|
||||
@ -805,7 +805,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0054",
|
||||
"id": "sku_20250321121804",
|
||||
"title": "Fly Life Extra (Unreleased Mixes)",
|
||||
"artist": "Basement Jaxx",
|
||||
"price": 30,
|
||||
@ -819,7 +819,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0055",
|
||||
"id": "sku_20250406095702",
|
||||
"title": "Beach Flea EP",
|
||||
"artist": "Beach Flea",
|
||||
"price": 25,
|
||||
@ -833,7 +833,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0056",
|
||||
"id": "sku_20251017005854",
|
||||
"title": "Be Yourself",
|
||||
"artist": "Blaze Presents Underground Dance Artists United For Life Feat. Joi Cardwell",
|
||||
"price": 15,
|
||||
@ -847,7 +847,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0057",
|
||||
"id": "sku_20250419165802",
|
||||
"title": "Why Can't We See",
|
||||
"artist": "Blind Truth featuring Tata Vega and Toney Lee",
|
||||
"price": 25,
|
||||
@ -861,7 +861,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0058",
|
||||
"id": "sku_20250201132301",
|
||||
"title": "I Think Of You",
|
||||
"artist": "Blaze Featuring Amira",
|
||||
"price": 15,
|
||||
@ -875,7 +875,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0059",
|
||||
"id": "sku_20250926055332",
|
||||
"title": "Intro To (R)Evolution / Asphalt Yards",
|
||||
"artist": "Carl Hancock Rux",
|
||||
"price": 12,
|
||||
@ -889,7 +889,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0060",
|
||||
"id": "sku_20250413163600",
|
||||
"title": "Ngbaka Chant / Come Fly With Me",
|
||||
"artist": "Calm Presents Kiyotaka Fukagawa",
|
||||
"price": 30,
|
||||
@ -903,7 +903,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0061",
|
||||
"id": "sku_20250711035800",
|
||||
"title": "The Shiva Chant",
|
||||
"artist": "Coco Da Silva",
|
||||
"price": 20,
|
||||
@ -917,7 +917,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0062",
|
||||
"id": "sku_20260325035717",
|
||||
"title": "Eternally / Fruitcake",
|
||||
"artist": "Can 7 Feat. Angela Caran",
|
||||
"price": 15,
|
||||
@ -931,7 +931,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0063",
|
||||
"id": "sku_20250206134701",
|
||||
"title": "Chara Claridade",
|
||||
"artist": "Clara Moreno",
|
||||
"price": 15,
|
||||
@ -945,7 +945,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0064",
|
||||
"id": "sku_20250409122501",
|
||||
"title": "Take Me Higher",
|
||||
"artist": "CZR Featuring Alexander East",
|
||||
"price": 15,
|
||||
@ -959,7 +959,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0065",
|
||||
"id": "sku_20250409220600",
|
||||
"title": "Cinemascope EP",
|
||||
"artist": "Cinnamone",
|
||||
"price": 35,
|
||||
@ -973,7 +973,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0066",
|
||||
"id": "sku_20260329044244",
|
||||
"title": "Club Hit EP",
|
||||
"artist": "Contriva",
|
||||
"price": 20,
|
||||
@ -987,7 +987,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0067",
|
||||
"id": "sku_20250926093442",
|
||||
"title": "Eternally / Fruitcake",
|
||||
"artist": "Can 7 Feat. Angela Caran",
|
||||
"price": 15,
|
||||
@ -1001,7 +1001,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0068",
|
||||
"id": "sku_20250215122904",
|
||||
"title": "The Sun Will Shine",
|
||||
"artist": "Cast Of Thousands Featuring Mimi Johnson",
|
||||
"price": 25,
|
||||
@ -1015,7 +1015,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0069",
|
||||
"id": "sku_20251011030603",
|
||||
"title": "Northern Lights / The Crystal Wave",
|
||||
"artist": "Caucasian Boy / Century Falls",
|
||||
"price": 50,
|
||||
@ -1029,7 +1029,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0070",
|
||||
"id": "sku_20250923041304",
|
||||
"title": "The Only One (Remixed By Groove Armada)",
|
||||
"artist": "Cerrone",
|
||||
"price": 15,
|
||||
@ -1043,7 +1043,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0071",
|
||||
"id": "sku_20260314065922",
|
||||
"title": "Dance To The Music (Body Action) / Jazz It Up",
|
||||
"artist": "C.F.M. Band",
|
||||
"price": 20,
|
||||
@ -1057,7 +1057,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0072",
|
||||
"id": "sku_20250507155205",
|
||||
"title": "Return Of The Big Tool",
|
||||
"artist": "Chris Lum",
|
||||
"price": 25,
|
||||
@ -1071,7 +1071,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0073",
|
||||
"id": "sku_20250831024809",
|
||||
"title": "Tick Tock",
|
||||
"artist": "Chiapet",
|
||||
"price": 40,
|
||||
@ -1085,7 +1085,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0074",
|
||||
"id": "sku_20250731022109",
|
||||
"title": "Wish (Remixes)",
|
||||
"artist": "Chymera",
|
||||
"price": 20,
|
||||
@ -1099,7 +1099,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0075",
|
||||
"id": "sku_20250528174602",
|
||||
"title": "The Return",
|
||||
"artist": "Circulation (2)",
|
||||
"price": 40,
|
||||
@ -1113,7 +1113,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0076",
|
||||
"id": "sku_20260313010844",
|
||||
"title": "All I Do",
|
||||
"artist": "Cleptomaniacs",
|
||||
"price": 40,
|
||||
@ -1127,7 +1127,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0077",
|
||||
"id": "sku_20250323151903",
|
||||
"title": "Right Here And Now",
|
||||
"artist": "Clinton Daniel",
|
||||
"price": 15,
|
||||
@ -1141,7 +1141,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0078",
|
||||
"id": "sku_20250703002101",
|
||||
"title": "Burning Sunshine",
|
||||
"artist": "Coco Bongo",
|
||||
"price": 12,
|
||||
@ -1155,7 +1155,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0079",
|
||||
"id": "sku_20250927021639",
|
||||
"title": "I'm Attracted To You",
|
||||
"artist": "Cookie Watkins",
|
||||
"price": 25,
|
||||
@ -1169,7 +1169,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0080",
|
||||
"id": "sku_20260325040240",
|
||||
"title": "Wishing On A Star",
|
||||
"artist": "Cover Girls, The",
|
||||
"price": 25,
|
||||
@ -1183,7 +1183,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0081",
|
||||
"id": "sku_20260208011045",
|
||||
"title": "Pirates Life EP",
|
||||
"artist": "Cpen",
|
||||
"price": 90,
|
||||
@ -1197,7 +1197,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0082",
|
||||
"id": "sku_20260307022426",
|
||||
"title": "Go Around",
|
||||
"artist": "Criminal Element Orchestra",
|
||||
"price": 12,
|
||||
@ -1211,7 +1211,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0083",
|
||||
"id": "sku_20250322111402",
|
||||
"title": "Fried",
|
||||
"artist": "Crispin J. Glover",
|
||||
"price": 20,
|
||||
@ -1225,7 +1225,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0084",
|
||||
"id": "sku_20250319130303",
|
||||
"title": "Waiting Hopefully",
|
||||
"artist": "D*Note",
|
||||
"price": 15,
|
||||
@ -1239,7 +1239,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0085",
|
||||
"id": "sku_20260318005638",
|
||||
"title": "The Dizko Knights Remixes Vol. 1",
|
||||
"artist": "Dizko Knights, The",
|
||||
"price": 15,
|
||||
@ -1253,7 +1253,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0086",
|
||||
"id": "sku_20250802054759",
|
||||
"title": "Dreamin'",
|
||||
"artist": "D3",
|
||||
"price": 12,
|
||||
@ -1267,7 +1267,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0087",
|
||||
"id": "sku_20250406095005",
|
||||
"title": "Key Of Soul",
|
||||
"artist": "Dan Curtin And Warren Harris Present Key Of Soul",
|
||||
"price": 20,
|
||||
@ -1281,7 +1281,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0088",
|
||||
"id": "sku_20250426152700",
|
||||
"title": "Twentygreenfoursday EP",
|
||||
"artist": "Daniel Madlung & Johannes Retschke",
|
||||
"price": 25,
|
||||
@ -1295,7 +1295,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0089",
|
||||
"id": "sku_20250816031139",
|
||||
"title": "Wow!",
|
||||
"artist": "Danny Tenaglia Presents Hambone",
|
||||
"price": 25,
|
||||
@ -1309,7 +1309,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0090",
|
||||
"id": "sku_20250322215200",
|
||||
"title": "More Than Anything",
|
||||
"artist": "Darryl D'Bonneau",
|
||||
"price": 25,
|
||||
@ -1323,7 +1323,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0091",
|
||||
"id": "sku_20260228031623",
|
||||
"title": "The Future Of The Future (Stay Gold)",
|
||||
"artist": "Deep Dish With Everything But The Girl",
|
||||
"price": 35,
|
||||
@ -1337,7 +1337,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0092",
|
||||
"id": "sku_20250731011503",
|
||||
"title": "The Way I Feel ",
|
||||
"artist": "DFLN",
|
||||
"price": 30,
|
||||
@ -1351,7 +1351,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0093",
|
||||
"id": "sku_20250510130705",
|
||||
"title": "When The World Is Running Down (You Can't Go Wrong)",
|
||||
"artist": "Different Gear Vs. Police, The",
|
||||
"price": 15,
|
||||
@ -1365,7 +1365,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0094",
|
||||
"id": "sku_20250815043151",
|
||||
"title": "10 Steps To Heaven",
|
||||
"artist": "DJ Disciple",
|
||||
"price": 30,
|
||||
@ -1379,7 +1379,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0095",
|
||||
"id": "sku_20250802024708",
|
||||
"title": "Take Me Higher / Sueno De Bahia",
|
||||
"artist": "Don Carlos",
|
||||
"price": 30,
|
||||
@ -1393,7 +1393,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0096",
|
||||
"id": "sku_20260301015349",
|
||||
"title": "Bug Eyed EP",
|
||||
"artist": "Dubble D",
|
||||
"price": 15,
|
||||
@ -1407,7 +1407,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0097",
|
||||
"id": "sku_20250226165204",
|
||||
"title": "Dom Dom 05",
|
||||
"artist": "Deep, The And Fred Melosax",
|
||||
"price": 25,
|
||||
@ -1421,7 +1421,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0098",
|
||||
"id": "sku_20250815070301",
|
||||
"title": "Misturada One (Mixing)",
|
||||
"artist": "Friends From Rio",
|
||||
"price": 30,
|
||||
@ -1435,7 +1435,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0099",
|
||||
"id": "sku_20251010035246",
|
||||
"title": "Beijo",
|
||||
"artist": "Earth, Wind & Fire",
|
||||
"price": 70,
|
||||
@ -1449,7 +1449,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0100",
|
||||
"id": "sku_20251017042537",
|
||||
"title": "Starlite (Remixes)",
|
||||
"artist": "Eddy & Dus",
|
||||
"price": 12,
|
||||
@ -1463,7 +1463,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0101",
|
||||
"id": "sku_20250312135004",
|
||||
"title": "Work This Pussy",
|
||||
"artist": "Ellis-D presents Boom Boom (2)",
|
||||
"price": 25,
|
||||
@ -1477,7 +1477,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0102",
|
||||
"id": "sku_20250315005602",
|
||||
"title": "The Nia Deep Project Vol. 1",
|
||||
"artist": "En' Sense Ltd.",
|
||||
"price": 20,
|
||||
@ -1491,7 +1491,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0103",
|
||||
"id": "sku_20250316154104",
|
||||
"title": "Havana",
|
||||
"artist": "Eric Kupper Presents Organika",
|
||||
"price": 20,
|
||||
@ -1505,7 +1505,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0104",
|
||||
"id": "sku_20250801001005",
|
||||
"title": "We Are One (Les Remixes)",
|
||||
"artist": "Ernest Saint Laurent Feat. Chezer\u00e9",
|
||||
"price": 15,
|
||||
@ -1519,7 +1519,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0105",
|
||||
"id": "sku_20250328124404",
|
||||
"title": "Berlingo",
|
||||
"artist": "D'Julz",
|
||||
"price": 15,
|
||||
@ -1533,7 +1533,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0106",
|
||||
"id": "sku_20260221235504",
|
||||
"title": "Blackness Of The Sea",
|
||||
"artist": "Deepchild",
|
||||
"price": 12,
|
||||
@ -1547,7 +1547,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0107",
|
||||
"id": "sku_20251009025229",
|
||||
"title": "You Don't Notice Me",
|
||||
"artist": "Etienne Br\u00e9nche",
|
||||
"price": 12,
|
||||
@ -1561,7 +1561,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0108",
|
||||
"id": "sku_20250406094801",
|
||||
"title": "K-Scope 4",
|
||||
"artist": "Eric Kupper Presents K-Scope (2)",
|
||||
"price": 15,
|
||||
@ -1575,7 +1575,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0109",
|
||||
"id": "sku_20250606124303",
|
||||
"title": "Notes From The Underground Part 3",
|
||||
"artist": "Freaks",
|
||||
"price": 15,
|
||||
@ -1589,7 +1589,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0110",
|
||||
"id": "sku_20250223163203",
|
||||
"title": "Sound Effects For Clubs & DJs Vol. 2",
|
||||
"artist": "Flower S.E. Productions",
|
||||
"price": 30,
|
||||
@ -1603,7 +1603,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0111",
|
||||
"id": "sku_20250816015945",
|
||||
"title": "House Of LZ",
|
||||
"artist": "Faze II",
|
||||
"price": 30,
|
||||
@ -1617,7 +1617,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0112",
|
||||
"id": "sku_20260304060646",
|
||||
"title": "In The Trees (Carl Craig Unreleased Mixes)",
|
||||
"artist": "Faze Action",
|
||||
"price": 90,
|
||||
@ -1631,7 +1631,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0113",
|
||||
"id": "sku_20250424111303",
|
||||
"title": "Unbreakable / First Fruit",
|
||||
"artist": "Felix Dickinson & Nick The Record",
|
||||
"price": 20,
|
||||
@ -1645,7 +1645,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0114",
|
||||
"id": "sku_20250824043324",
|
||||
"title": "Voyage EP",
|
||||
"artist": "Flow",
|
||||
"price": 80,
|
||||
@ -1659,7 +1659,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0115",
|
||||
"id": "sku_20250409112205",
|
||||
"title": "Midnite Sun",
|
||||
"artist": "Frankie Valentine",
|
||||
"price": 20,
|
||||
@ -1673,7 +1673,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0116",
|
||||
"id": "sku_20250420114001",
|
||||
"title": "Untitled",
|
||||
"artist": "Freestyle Man",
|
||||
"price": 40,
|
||||
@ -1687,7 +1687,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0117",
|
||||
"id": "sku_20250815061653",
|
||||
"title": "Open Up",
|
||||
"artist": "Free Radikalz, The",
|
||||
"price": 35,
|
||||
@ -1701,7 +1701,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0118",
|
||||
"id": "sku_20250927044701",
|
||||
"title": "Do I",
|
||||
"artist": "French Connection, The",
|
||||
"price": 12,
|
||||
@ -1715,7 +1715,7 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "rec_0119",
|
||||
"id": "sku_20260405023654",
|
||||
"title": "Entertainment",
|
||||
"artist": "Floppy Sounds Feat. Sarah Jones",
|
||||
"price": 20,
|
||||
|
||||
@ -68,17 +68,29 @@ is about. Two id spaces ride this field, and G verified they're disjoint:
|
||||
So treat it as an **opaque key**: never derive it from `id`, never assume equality, never build a mapping
|
||||
table (the R12 gigKey lesson — one key, zero mapping; **G emits it, everyone else reads it**).
|
||||
|
||||
**A godverse cache is MIXED — that's the design (Ruling 2, law as of R25).** It carries a **keyed GODVERSE
|
||||
layer** (census shops + injected shops like Monster Robot) **plus an inherited OSM texture layer that is
|
||||
legitimately unkeyed**. The texture layer is load-bearing, not cosmetic — G measured that census-only Red
|
||||
Hill was unshippable (306 m spacing warn, a poster inside a kerb) and the texture layer fixed it. Real
|
||||
shape today: `newtown_godverse` = 18 keyed + 54 texture; `redhill_godverse` = 10 keyed + 27 texture.
|
||||
**Unkeyed shops are not a gap and no gate may assert them away.**
|
||||
|
||||
**Rules** — split by what is actually a hazard, not by tidiness:
|
||||
- **Malformed → ERROR.** Must be a **positive integer**. It names a path segment, so `"3962749"` and
|
||||
`3962749` are the same folder but different JSON; that coercion drift is the species that produced the
|
||||
`licence`/`license` atlas break. One truth.
|
||||
- **Duplicate within a cache → ERROR.** Two shops keyed to one atlas *is* mis-stocking (charter risk #3:
|
||||
"fail-soft to tier 0, **never mis-stocked**").
|
||||
- **Missing on a `source: "godverse+osm"` cache → WARN, and those shops fall soft to tier 0 (parody).**
|
||||
Not an error: the charter's determinism boundary is *world = seeded and gated, stock = data tiers*, so a
|
||||
town must never fail to load because its **stock** identity is absent. The teeth are in `selfcheck`,
|
||||
where **partial keying FAILS** (a half-keyed town silently mis-stocks the rest) and zero keying prints an
|
||||
explicit **SKIP** with the count, per the vacuous-gate law.
|
||||
- **An entirely empty GODVERSE layer → WARN.** A `godverse+osm` cache with no id on *any* shop is an osm
|
||||
cache wearing the wrong `source`. Still a warn, not an error: the charter's determinism boundary is
|
||||
*world = seeded and gated, stock = data tiers*, so a town must never fail to load because its **stock**
|
||||
identity is absent — tier 0 is the designed ladder.
|
||||
- **Mixed → silent.** Some keyed, some not, is normal and raises nothing.
|
||||
|
||||
`selfcheck` gates the keyed subset per-layer: the layer reaches the plan, ids are unique **over defined ids
|
||||
only**, the lift invents no identity — plus an **orphaned-atlas gate** (a committed atlas whose shop the
|
||||
lift dropped = real stock keyed to a shop that isn't in the town → FAIL). Dropped keyed shops are printed,
|
||||
never silent.
|
||||
|
||||
**It survives the lift.** `plan_osm` copies it onto `plan.shops[]`, because the runtime reads the *plan*,
|
||||
never the cache — without that the field would be decoration and F's per-shop `base` could never resolve.
|
||||
|
||||
@ -178,20 +178,20 @@ export function validateTownCache(cache) {
|
||||
}
|
||||
if (badGid) errors.push(`${badGid} shop(s) with a malformed godverseShopId (want a positive integer — it is a path segment, not a label)`);
|
||||
if (dupGid) errors.push(`${dupGid} duplicate godverseShopId(s) — two shops cannot share one stock atlas (mis-stock)`);
|
||||
// WHY MISSING IS A WARN AND NOT AN ERROR (ROUND24 ledger #2 says "requires"; recorded as a
|
||||
// departure, with reasons, per measurement-over-brief):
|
||||
// 1. The charter's determinism boundary: "world = seeded, frozen, gated. Stock = data tiers."
|
||||
// An error here inverts it — the TOWN would fail to load because its STOCK identity is absent.
|
||||
// Tier 0 must always boot; a shop with no id is a parody shop, which is the designed ladder.
|
||||
// 2. Charter risk #3 names the remedy for identity gaps: "fail-soft to tier 0, never mis-stocked."
|
||||
// Missing = tier 0 (soft). Duplicate = mis-stocked (hard). They are not the same failure.
|
||||
// 3. Sequencing: `newtown_godverse` carries 0 ids today and is G's to re-emit in wave 2 (their
|
||||
// namespace, and the census DB isn't on this machine). An error would red the tree for C and E
|
||||
// through all of wave 1 to convey what this warn already says.
|
||||
// The teeth live in selfcheck: PARTIAL coverage fails, and zero coverage prints an explicit SKIP
|
||||
// naming the town and the count (the vacuous-gate law) — so this cannot pass unnoticed.
|
||||
if (isGodverseCache(cache) && withGid < cache.shops.length) {
|
||||
warnings.push(`${cache.shops.length - withGid}/${cache.shops.length} shop(s) missing godverseShopId on a '${GODVERSE_SOURCE}' cache → those shops fall soft to tier 0 (parody); G re-emits`);
|
||||
// RULING 2 (ROUND25, confirmed as law): a godverse cache is deliberately MIXED — a keyed GODVERSE
|
||||
// layer (census shops + injected shops like Monster Robot) PLUS an inherited OSM texture layer that
|
||||
// is legitimately unkeyed. G measured that the texture layer is load-bearing, not cosmetic:
|
||||
// census-only Red Hill shipped a 306 m spacing warn and a poster inside a kerb; with the texture
|
||||
// layer it passes. So "shops without an id" is the DESIGN, and my R24 warn (which counted every
|
||||
// unkeyed shop as a gap) was asserting the design away — it fired 54/72 on a healthy town.
|
||||
//
|
||||
// What is still worth saying: a cache that CLAIMS godverse provenance but carries NO identity at all
|
||||
// has no godverse layer — it is an osm cache wearing the wrong `source`. That is the only honest
|
||||
// requirement left at this layer, and it's a warn for the R24 reasons that still hold (the charter's
|
||||
// determinism boundary: a town must never fail to load because its STOCK identity is absent; tier 0
|
||||
// is the designed ladder). Missing = tier 0 (soft), duplicate = mis-stocked (hard) — different arms.
|
||||
if (isGodverseCache(cache) && withGid === 0) {
|
||||
warnings.push(`'${GODVERSE_SOURCE}' cache carries no godverseShopId on any of ${cache.shops.length} shops — the GODVERSE layer is empty (every shop falls to tier 0; is this really a godverse cache?)`);
|
||||
}
|
||||
// wide-spread warning: an over-broad Overpass bbox marches into an unusable multi-km strip (the R17
|
||||
// real-data risk). Metadata only — plan_osm still boots a valid plan; it just isn't a coherent town.
|
||||
|
||||
@ -16,6 +16,7 @@ import { xmur3 } from '../core/prng.js';
|
||||
|
||||
const HERE = dirname(fileURLToPath(import.meta.url));
|
||||
const ASSETS = join(HERE, '..', '..', 'assets', 'gen');
|
||||
const STOCK_GODVERSE_DIR = join(HERE, '..', '..', 'assets', 'stock_godverse'); // G's tier-1 atlases (orphan check)
|
||||
|
||||
let failures = 0, checks = 0;
|
||||
const ok = (cond, msg) => { checks++; if (!cond) { failures++; console.error(' ✗ ' + msg); } };
|
||||
@ -462,29 +463,58 @@ for (const [label, cache, needle] of [
|
||||
const v = validateTownCache(gv(withIds.map((s, i) => i === 1 ? { ...s, godverseShopId: withIds[0].godverseShopId } : s)));
|
||||
ok(!v.ok && v.errors.some(e => /duplicate godverseShopId/.test(e)), `godverse cache: duplicate id REJECTED (mis-stock)`);
|
||||
}
|
||||
// MISSING → warn + fail-soft, NOT an error (the charter's determinism boundary: the world must not
|
||||
// fail to load because stock identity is absent). Partial coverage still warns and still boots.
|
||||
// RULING 2 (ROUND25): a MIXED cache — keyed GODVERSE layer + unkeyed texture layer — is the DESIGN,
|
||||
// not a gap. My R24 arm counted every unkeyed shop as missing and fired 54/72 on a healthy town; it
|
||||
// was asserting the design away. A mixed cache is now simply normal: valid, and silent.
|
||||
{
|
||||
const v = validateTownCache(gv(withIds.map((s, i) => i < 2 ? { ...s, godverseShopId: undefined } : s)));
|
||||
ok(v.ok, `godverse cache: missing ids stay VALID (fail-soft to tier 0, never a boot failure)`);
|
||||
ok(v.warnings.some(w => /2\/8 shop\(s\) missing godverseShopId/.test(w)), `godverse cache: missing ids WARN with a count (${v.warnings.find(w => /godverseShopId/.test(w)) || 'NO WARN'})`);
|
||||
const mixed = gv(withIds.map((s, i) => i < 2 ? { ...s, godverseShopId: undefined } : s));
|
||||
const v = validateTownCache(mixed);
|
||||
ok(v.ok, `godverse cache: MIXED (keyed + texture) is VALID — Ruling 2 is the design`);
|
||||
ok(!v.warnings.some(w => /godverseShopId/.test(w)), `godverse cache: MIXED raises NO identity warn (texture shops are legitimately unkeyed)`);
|
||||
}
|
||||
// ...but a godverse cache with NO identity at all has no godverse layer — an osm cache wearing the
|
||||
// wrong `source`. That's the one honest requirement left at this layer, and it stays a warn.
|
||||
{
|
||||
const v = validateTownCache(gv(cluster(8)));
|
||||
ok(v.ok, `godverse cache: empty GODVERSE layer stays VALID (tier 0 must always boot)`);
|
||||
ok(v.warnings.some(w => /GODVERSE layer is empty/.test(w)), `godverse cache: empty layer WARNS (${v.warnings.find(w => /GODVERSE/.test(w)) || 'NO WARN'})`);
|
||||
}
|
||||
// a plain osm cache must never be asked for ids
|
||||
ok(!validateTownCache(mkCache(cluster(8))).warnings.some(w => /godverseShopId/.test(w)), `osm cache: no identity warn (godverse-only requirement)`);
|
||||
ok(!validateTownCache(mkCache(cluster(8))).warnings.some(w => /godverseShopId|GODVERSE/.test(w)), `osm cache: no identity warn (godverse-only requirement)`);
|
||||
|
||||
// THE SEAM THAT MATTERS: the id survives the lift onto plan.shops. Without this the field is a
|
||||
// cache-only decoration and F's per-shop base can never resolve — the runtime reads the PLAN.
|
||||
{
|
||||
const cache = gv(withIds);
|
||||
const cache = gv(withIds.map((s, i) => i < 2 ? { ...s, godverseShopId: undefined } : s)); // mixed, like the real ones
|
||||
const p = generatePlanOSM(20261990, 'gvtest', { cache });
|
||||
const keyed = p.shops.filter(s => s.godverseShopId !== undefined);
|
||||
ok(keyed.length === p.shops.length, `godverse lift: every seated shop carries godverseShopId (${keyed.length}/${p.shops.length})`);
|
||||
ok(keyed.length > 0 && keyed.length <= p.shops.length, `godverse lift: the keyed layer survives onto plan.shops (${keyed.length} of ${p.shops.length} seated)`);
|
||||
ok(keyed.every(s => Number.isSafeInteger(s.godverseShopId) && s.godverseShopId > 0), `godverse lift: ids survive as positive integers`);
|
||||
ok(new Set(keyed.map(s => s.godverseShopId)).size === keyed.length, `godverse lift: ids stay unique through the lift (no atlas collision)`);
|
||||
// and an unkeyed cache writes NO key — that absence is what keeps all 22 pinned goldens frozen today
|
||||
ok(p.shops.filter(s => !('godverseShopId' in s)).length === p.shops.length - keyed.length, `godverse lift: texture shops carry NO key (absent, not undefined)`);
|
||||
// and an unkeyed cache writes NO key — that absence is what keeps every pinned osm golden frozen
|
||||
const plain = generatePlanOSM(20261990, 'plaintest', { cache: mkCache(cluster(8)) });
|
||||
ok(plain.shops.every(s => !('godverseShopId' in s)), `plain lift: the key is ABSENT, not undefined (byte-identical JSON ⇒ goldens frozen)`);
|
||||
}
|
||||
|
||||
// THE UNIQUENESS CHECK, REBUILT SO IT CAN ACTUALLY FAIL (ROUND25 ledger #1). The R24 version compared
|
||||
// `new Set(all ids).size === shops.length`, which collapses every `undefined` into ONE entry — so on a
|
||||
// mixed cache it fails structurally (54 texture shops → 1 entry) while a REAL duplicate among two
|
||||
// defined ids could hide behind that same collapse. Uniqueness now runs over DEFINED ids only.
|
||||
//
|
||||
// And per the vacuous-gate law: a check nobody can see fail is not a check. `validateTownCache`
|
||||
// rejects duplicates, so a dup can never reach the plan through the front door — `generatePlanOSM`
|
||||
// does NOT validate, so this feeds one straight to the lift and proves the assert bites.
|
||||
{
|
||||
const dupCache = gv(withIds.map((s, i) => i === 3 ? { ...s, godverseShopId: withIds[0].godverseShopId } : s));
|
||||
ok(!validateTownCache(dupCache).ok, `uniqueness: the validator still rejects a duplicate at the front door`);
|
||||
const p = generatePlanOSM(20261990, 'duptest', { cache: dupCache }); // bypasses validation, as the lift does
|
||||
const ids = p.shops.map(s => s.godverseShopId).filter(id => id !== undefined);
|
||||
ok(new Set(ids).size < ids.length, `uniqueness: a duplicate that BYPASSES the validator is visible on the plan (${ids.length} ids → ${new Set(ids).size} unique) — the check can fail`);
|
||||
// the same predicate on a healthy mixed cache must pass — no false positive from the undefineds
|
||||
const okIds = generatePlanOSM(20261990, 'gvtest2', { cache: gv(withIds.map((s, i) => i < 2 ? { ...s, godverseShopId: undefined } : s)) })
|
||||
.shops.map(s => s.godverseShopId).filter(id => id !== undefined);
|
||||
ok(new Set(okIds).size === okIds.length, `uniqueness: a healthy MIXED cache passes the same predicate (no undefined-collapse false positive)`);
|
||||
}
|
||||
}
|
||||
// (d) the registry seam: register → osmTownKeys() sees it → generatePlanOSM resolves it
|
||||
{
|
||||
@ -559,13 +589,15 @@ const REAL_TOWN_GOLDENS = {
|
||||
launceston_real: 0x32b1ab7b,
|
||||
marrickville_real: 0x60148e37,
|
||||
newcastle_real: 0xbb2c3050,
|
||||
newtown_godverse: 0x24e63feb,
|
||||
newtown_godverse: 0xcf69b387,
|
||||
newtown_real: 0x741c18ec,
|
||||
northbridge_real: 0x1a645848,
|
||||
// toowoomba_real RETIRED by E in R23 (cache deleted) — pin removed with it. A golden for a town that
|
||||
// cannot load is dead config: it can never fire, so it can never fail. Same species as the round's
|
||||
// vacuous-gate law, one layer down. (E tried the re-bbox first and it GAMED my spacing metric — median
|
||||
// NN 395.7 → 89.4 m "passes" while hub density fell 3/12 → 2/12, the pack's worst. Right call.)
|
||||
redhill_godverse: 0xb2224939,
|
||||
redhill_real: 0x6046700f,
|
||||
westend_real: 0x5b1e5ffe,
|
||||
};
|
||||
// ROUND20: the GIG-layer golden per real town (district + capped posters) — the base golden above is
|
||||
@ -592,10 +624,12 @@ const REAL_TOWN_GIG_GOLDENS = {
|
||||
launceston_real: 0xeaf7ff4d,
|
||||
marrickville_real: 0xea21be51,
|
||||
newcastle_real: 0x66fc2bf9,
|
||||
newtown_godverse: 0xc5ed0b92,
|
||||
newtown_godverse: 0x1e266f60,
|
||||
newtown_real: 0xacdb3eee,
|
||||
northbridge_real: 0x83a1d5be,
|
||||
// toowoomba_real RETIRED by E in R23 — see the note on the base map above.
|
||||
redhill_godverse: 0xc6f80e18,
|
||||
redhill_real: 0x673785ee,
|
||||
westend_real: 0xb2c7ddb6,
|
||||
};
|
||||
// `index.json` is E's towns INDEX (key/town/state/shops/roads for B's selector), not a town cache — skip it.
|
||||
@ -618,22 +652,47 @@ for (const f of townFiles) {
|
||||
const gwant = REAL_TOWN_GIG_GOLDENS[key];
|
||||
if (gwant === undefined) console.log(` ⚠ real/${key}: gig UNPINNED — add REAL_TOWN_GIG_GOLDENS['${key}'] = 0x${ghash.toString(16).padStart(8, '0')}`);
|
||||
else ok(ghash === (gwant >>> 0), `real/${key}: gig golden 0x${ghash.toString(16)} matches pinned 0x${(gwant >>> 0).toString(16)}`);
|
||||
// ROUND24 ledger #2 — the identity gate on the REAL godverse caches, written to the round's own
|
||||
// vacuous-gate law: it names its subject, it proves it touched it (a count), and it CANNOT pass while
|
||||
// its subject is absent. Zero ids ⇒ explicit SKIP with the reason and the count. Partial ⇒ FAIL (a
|
||||
// half-keyed town silently mis-stocks half its shops). Full ⇒ assert the ids reach plan.shops.
|
||||
// ROUND25 ledger #1 — the identity gate, RECONCILED WITH RULING 2. A godverse cache is deliberately
|
||||
// MIXED: a keyed GODVERSE layer + an inherited OSM texture layer that G measured to be load-bearing.
|
||||
// So every assert runs over the GODVERSE LAYER ONLY (shops carrying an id); an unkeyed texture shop is
|
||||
// the design, not a defect. My R24 arm asserted every-shop-keyed and failed 54/72 on a healthy town —
|
||||
// it was asserting Ruling 2 away. Still written to the vacuous-gate law: names its subject, proves it
|
||||
// touched it with a count, SKIPs loudly rather than passing when the subject is absent.
|
||||
if (cache.source === 'godverse+osm') {
|
||||
const keyed = cache.shops.filter(s => Number.isSafeInteger(s && s.godverseShopId) && s.godverseShopId > 0).length;
|
||||
if (keyed === 0) {
|
||||
const cacheKeyed = cache.shops.filter(s => Number.isSafeInteger(s && s.godverseShopId) && s.godverseShopId > 0);
|
||||
if (!cacheKeyed.length) {
|
||||
console.log(` ⊘ SKIP real/${key}: godverse identity — 0/${cache.shops.length} shops carry godverseShopId. ` +
|
||||
`Subject absent: G re-emits with ids (R24 ledger #2). This gate binds the moment one id lands.`);
|
||||
`Subject absent (the GODVERSE layer is empty). This gate binds the moment one id lands.`);
|
||||
} else {
|
||||
ok(keyed === cache.shops.length,
|
||||
`real/${key}: godverse identity — ${keyed}/${cache.shops.length} shops keyed (partial keying mis-stocks the rest)`);
|
||||
const seated = generatePlanOSM(20261990, key, { cache }).shops;
|
||||
const lifted = seated.filter(s => s.godverseShopId !== undefined).length;
|
||||
ok(lifted === seated.length, `real/${key}: godverse identity survives the lift (${lifted}/${seated.length} seated shops keyed)`);
|
||||
ok(new Set(seated.map(s => s.godverseShopId)).size === seated.length, `real/${key}: godverse ids unique on the plan (no shared atlas)`);
|
||||
const seatedIds = seated.filter(s => s.godverseShopId !== undefined).map(s => s.godverseShopId);
|
||||
const cacheIds = new Set(cacheKeyed.map(s => s.godverseShopId));
|
||||
ok(seatedIds.length > 0,
|
||||
`real/${key}: GODVERSE layer reaches the plan — ${seatedIds.length}/${seated.length} seated shops keyed (${cache.shops.length - cacheKeyed.length} texture shops legitimately unkeyed)`);
|
||||
// uniqueness over DEFINED ids only: the R24 Set-collapse version folded every `undefined` into one
|
||||
// entry, so it failed structurally on a mixed cache AND could hide a real duplicate behind them.
|
||||
ok(new Set(seatedIds).size === seatedIds.length,
|
||||
`real/${key}: godverse ids unique on the plan (${new Set(seatedIds).size}/${seatedIds.length} distinct — no shared atlas)`);
|
||||
ok(seatedIds.every(id => cacheIds.has(id)),
|
||||
`real/${key}: every seated godverse id came from the cache (the lift invents no identity)`);
|
||||
// ORPHANED-ATLAS GATE. The lift legitimately drops shops (overlap-resolve, counted since R19) — but
|
||||
// dropping a shop that HAS a committed atlas means real stock keyed to a shop that isn't in the
|
||||
// town: exactly the failure R24 predicted and F's #7b would only catch at the end of a round.
|
||||
// Subject = the atlas dirs on disk, so it SKIPs by name when this town has none.
|
||||
const atlasIds = (existsSync(STOCK_GODVERSE_DIR) ? readdirSync(STOCK_GODVERSE_DIR) : [])
|
||||
.filter(d => /^\d+$/.test(d)).map(Number).filter(id => cacheIds.has(id));
|
||||
if (!atlasIds.length) {
|
||||
console.log(` ⊘ SKIP real/${key}: orphaned-atlas check — no committed atlas under stock_godverse/ keys to this town.`);
|
||||
} else {
|
||||
const seatedSet = new Set(seatedIds);
|
||||
const orphans = atlasIds.filter(id => !seatedSet.has(id));
|
||||
ok(orphans.length === 0,
|
||||
`real/${key}: no orphaned atlas — ${atlasIds.length} stocked shop(s) on disk, all seated` +
|
||||
(orphans.length ? ` (ORPHANED: ${orphans.join(', ')} — real stock keyed to a shop the lift dropped)` : ''));
|
||||
}
|
||||
// a dropped keyed shop is legitimate but must never be silent (the R19/R20 drop-and-count ruling)
|
||||
const dropped = cacheKeyed.filter(s => !new Set(seatedIds).has(s.godverseShopId));
|
||||
if (dropped.length) console.log(` ⚠ real/${key}: ${dropped.length} keyed shop(s) dropped by the lift — ${dropped.map(s => `${s.godverseShopId} "${s.name}"`).join(', ')} (unstocked today; would orphan an atlas if stocked)`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user