diff --git a/docs/A-progress.md b/docs/A-progress.md index f6ed2ed..5406d5e 100644 --- a/docs/A-progress.md +++ b/docs/A-progress.md @@ -1,11 +1,42 @@ # LANE A — CITYGEN · progress (PROCITY-A) -*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.* +*Status: **all deliverables landed; self-check ALL GREEN (156,212/156,212); rounds 2–27 closed** (see below). +R27 (v5.0 close): **CITY_SPEC v5 section** (tier ladder · `sourcing` vs `tier` · the three id-space fences · +the manifest · Ruling 2) + the **charter risk list judged line by line** — risk #1 deliberately CARRIED, not +pre-retired, because F's kill-the-server gate is what retires it. classic `0x3fa36874` / gig `0xb1d48ea1` +frozen; **no golden moved this epoch**.* *Date: 2026-07-17 · owner: PROCITY-A (Opus 4.8)* +## Round 27 (2026-07-17) — v5.0 THE LIVE CRATE: the docs freeze (ledger #6) + +Lane A's half of the epoch close. Docs only; **no code, no golden moved** — correct, since tier 2 touches no +plan, no cache, no atlas bytes. selfcheck **ALL GREEN 156,212/156,212**. + +- **CITY_SPEC v5 section**, written from the artifacts rather than the briefs (the epoch's own lesson): + the **tier ladder** (0 parody / 1 static real / 2 live, each degrading softly); **`sourcing` is not + `tier`** — both ship in every index, `tier: 1` is the rung and a mint atlas is *still* rung 1, while + `sourcing: "real"|"mint"` is provenance (15 keyed atlases = **1 real + 14 mint**); the **three id-space + fences**; the **manifest** (existence declared, never probed — the root fix for fail-soft-404 vs the + zero-console-errors law; 15 entries, 15 dirs); **Ruling 2**; and A's single seam, `godverseShopId`. +- **The id fences, verified not restated.** The plan-id/godverse-id trap is still live in the data and I + reproduced it: in `redhill_godverse`, bare **`31`** is "Wholefood Cafe" as a plan id and "Silky Oak + Furnature" as a godverse id — the exact ambiguity that made F's `enterShop(31)` assert vacuously on the + wrong shop. It's a standing rule, not a fixed bug, and the spec says so. +- **The risk list judged, without pre-retiring anyone's gate.** #1 (tier-2 latency) **CARRIED** — written in + wave 2, F's reader doesn't exist yet, and *nothing retires that line except the gate going green*; + retiring it from a doc while the code is unwritten is the precise species this epoch spent four holds + catching. #2 **retired** (measured: max 2 atlases/shop vs C's cap of 2; mint at 16 items/1024², only the + real POS shop at 2048²; the mecca case served by crate rotation — the remedy the risk itself named). + #3 **retired — designed out, not solved**: it assumed fuzzy name-matching, and there is no matcher; + Monster Robot is in *neither* census nor OSM, so no matcher could ever have found it. #4 **split**: + write-back retired by John's ruling-as-mechanism (`/reserve`+`/buy` absent, not stubbed — you can't race a + verb that doesn't exist), the `gone` read carried to F's #4. Two new carried: **#6 orphaned atlas**, + **#7 "real" is one shop wide** (14/15 are mint — honest and marked, but the headline rests on one shop). +- **The gate that armed itself.** My R25 orphan gate SKIPped on `newtown_godverse` while no atlas keyed + there; G's mint atlases landed and it **began binding unattended** — 156,211 → **156,212**, and that +1 is + the gate arming itself. Near-miss carried: redhill's lift drops keyed shop **2286 "Empire Revival"**; + G stocked neighbour **2287**. Stocking 2286 today would orphan it. + ## 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. diff --git a/docs/CITY_SPEC.md b/docs/CITY_SPEC.md index 6c250d6..10793d8 100644 --- a/docs/CITY_SPEC.md +++ b/docs/CITY_SPEC.md @@ -516,6 +516,79 @@ nothing outside the cache-schema path). > count beats teleport.** The frozen set is unmoved by the entire epoch: synthetic `0x3fa36874`, gig > `0xb1d48ea1`, marched fixtures, classic. +## The stock ladder (v5 — THE REAL SHOP; frozen at `v5.0`, ROUND27 ledger #6) + +> **v4 made the towns real; v5 makes the shops real.** The map-level contract above is unchanged by this +> epoch: **stock is DATA, not world.** The charter's determinism boundary is the load-bearing line — +> *world = seeded, frozen, golden-gated; stock = data tiers riding the asset law.* Nothing in this section +> may move a plan golden, and nothing in it did: the whole epoch left synthetic `0x3fa36874`, gig +> `0xb1d48ea1`, the marched fixtures and classic untouched. + +**The tier ladder.** Each rung is fully playable and degrades **softly** to the one below — the fail-soft +pattern proven since `?noassets` on day one, made structural: + +| tier | what | flag | deterministic? | +|---|---|---|---| +| **0 · parody** | seeded canvas sleeves (v1) | any boot | yes — the QA baseline | +| **1 · static real** | per-shop atlases baked from dealgod/POS | `?stock=real`, **no server** | yes — atlases are files | +| **2 · live GODVERSE** | thriftgod read-only endpoints; sold-means-gone | server reachable | **no — by design** | + +**The offline law (charter law #1) is the epoch's gate, not a footnote:** the server *enriches, never +gates*. No boot path, gate, or tag may depend on a reachable server. Tier 2 is therefore **never inside a +golden or a byte-identical assert**; it gets its own smoke class whose server lifecycle the gate itself +controls, so the *assertion* is deterministic even though the *stock* isn't. + +**`sourcing` is not `tier`** (C's ruling, R26 — and it's the distinction that keeps the ladder honest). The +rung and the provenance are different axes, and both ship in every atlas index: +- **`tier: 1`** — the ladder rung. A minted atlas is *still* a static file, so it is *still* rung 1. +- **`sourcing: "real" | "mint"`** — where the contents came from. **`real`** = a POS snapshot (Monster Robot + Party's actual crates). **`mint`** = a seeded `random.Random(shop_id)` sample of real dealgod listings — + *plausible, not that shop's stock*. Only one shop in the world has a POS; minting is how the other keyed + shops get distinct crates **without pretending to data we don't hold**. Current pack: **15 keyed atlases = + 1 real + 14 mint**. No gate, doc, or human may read a mint crate as real — that is the whole point of the + field, and gates assert on it. + +**The id-space fences.** Three namespaces meet at the crate, and **every collision this epoch came from +comparing across them**. They are fences, not decoration: + +| space | form | scope | fenced from | +|---|---|---|---| +| **plan `shop.id`** | small int, `0..N` per town | one CityPlan, local | `godverseShopId` — **numerically overlapping** | +| **`godverseShopId`** | census id (**≤2992**) ∪ dealgod store id (e.g. **3962749**) | the stock namespace | its two halves are numerically **disjoint by construction** (G) | +| **atlas slot id** | **`sku_`** / **`mint_`** | one atlas index | each other, by **prefix** | + +- **plan id vs `godverseShopId` — never compare a bare number across them.** They are *semantically* + disjoint namespaces that *numerically overlap*, which is the trap: in `redhill_godverse` today, bare + **`31`** is **"Wholefood Cafe"** as a plan id and **"Silky Oak Furnature"** as a godverse id. That exact + ambiguity made F's `enterShop(31)` enter the wrong shop and a soft-fall assertion pass **vacuously on the + wrong subject**. Verified still live in the data — so this is a standing rule, not a fixed bug. +- **`sku_` vs `mint_` is a sourcing-scoped namespace fence** (C §7.2a as amended, R26 wave 4). A crate + wearing the other sourcing's prefix **fails**. The fence is *stronger* than the rule it replaced: the easy + green was deleting the prefix check; instead the prefix now proves its sourcing. +- **Positional ids are banned** (R25): `rec_0000…` numbering collides across packs by construction, which + is what made the integrator's own id-equality gate vacuous. Slot ids are sku-derived and unique across + packs, stable across re-emits. + +**The manifest — `web/assets/stock_godverse/index.json`** (G emits, F consumes, E validates, C's §7.2d). +It declares **which `godverseShopId`s carry atlases** (`types[]` + `sourcing` per entry; mint included). +**Existence is declared, never probed.** This is the root fix for a real collision between two laws: +fail-soft-by-404 vs the zero-console-errors law — the runtime used to probe blind and eat 404 noise, +tolerated by attribution, which is a workaround, not a design. No manifest entry ⇒ no fetch ⇒ **zero 404s, +no exceptions**. Consistency is gated both ways (an atlas on disk absent from the manifest **fails**, and +vice versa — vacuous-gate law shape). Today: **15 entries, 15 dirs on disk.** + +**Lane A's seam to all of it** is exactly one field — **`godverseShopId`** (documented above): it rides the +town cache, survives the lift onto `plan.shops[]`, and is what the runtime resolves `stock_godverse//` +from. **`'godverseShopId' in shop` is the tier test**: present ⇒ tier-1+ candidate, absent ⇒ tier 0. The +key is *absent, not undefined*, on every unkeyed shop — which is why the entire stock epoch moved **no plan +golden**. `selfcheck` gates the seam per-layer (Ruling 2), including the **orphaned-atlas** check: a +committed atlas whose shop the lift dropped is real stock keyed to a shop that isn't in the town. + +**Ruling 2 (law):** a godverse cache is **deliberately mixed** — a keyed GODVERSE layer + an inherited OSM +texture layer that is legitimately unkeyed. G measured it load-bearing: census-only Red Hill was +unshippable (306 m spacing warn, a poster inside a kerb). **No gate may assert it away** — mine did, and +called two healthy towns broken. + ## Shop types v1 (registry lives in `web/js/core/registry.js`, Lane A writes it, all lanes read) > **`web/js/core/registry.js` is the machine-readable source of truth** — import `SHOP_TYPES` for diff --git a/docs/LANES/LANE_A_NOTES.md b/docs/LANES/LANE_A_NOTES.md index 334d8a7..3441963 100644 --- a/docs/LANES/LANE_A_NOTES.md +++ b/docs/LANES/LANE_A_NOTES.md @@ -2,6 +2,40 @@ Durable answers to questions other lanes raised against Lane A. Full status in `A-progress.md`. +## Round 27 (2026-07-17) — v5.0: the docs freeze — CITY_SPEC v5 + the risk list judged (ledger #6) + +### → F + Fable: **A's docs half is done and the tree is green; nothing of mine gates your tag** +selfcheck **ALL GREEN 156,212/156,212**, classic `0x3fa36874` / gig `0xb1d48ea1` frozen, **no golden moved** +(none should — tier 2 touches no plan, no cache, no atlas bytes). CITY_SPEC has its **v5 section** (the tier +ladder · `sourcing` vs `tier` · the three id-space fences · the manifest · Ruling 2 · A's one seam), and the +charter risk list is judged line by line in `V5_REAL_SHOP.md`. + +### The risk list: I did NOT pre-retire your gate +Written in wave 2, so **risk #1 (latency/stutter at tier 2) is CARRIED, not retired** — your reader and +kill-the-server gate don't exist yet, and **nothing retires that line except the gate going green**. Retiring +it from a doc while the code is unwritten would be the exact species this epoch spent four holds catching: a +rule meeting a case that doesn't exist yet. #2 retired (measured), #3 retired (designed out), #4 **split** — +write-back retired by John's ruling-as-mechanism, the `gone` read carried to your #4. Two new carried lines +(#6 orphaned atlas, #7 "real" is one shop wide). + +### The gate that armed itself — worth seeing, since it's the law working unattended +My R25 orphaned-atlas gate **SKIPped** on `newtown_godverse` all through R25 ("no committed atlas keys to +this town" — subject absent, so it said so instead of passing). The moment G's 14 mint atlases landed, it +**started binding on its own** and passed: selfcheck went 156,211 → **156,212**, and that +1 is the gate +arming itself. Nobody edited it. That's what the vacuous-gate law buys — a gate that waits, in the open, for +its subject. + +**Live near-miss on the books → G:** `redhill_godverse`'s lift drops keyed shop **2286 "Empire Revival"**; +you stocked its numeric neighbour **2287**. Nothing is orphaned and the gate is green — but **stocking 2286 +would orphan it today**, and the hazard grows with every shop stocked. Carried as risk #6. + +### One correction to the round doc's framing, for the record +The brief lists "the manifest" and "sourcing" as if `tier` were superseded. The artifacts say otherwise, and +**C's ruling is the precise one**: every atlas index carries **both** — `tier: 1` (the ladder rung; a mint +atlas is *still* a static file, so still rung 1) **and** `sourcing: "real"|"mint"` (where the contents came +from). They are different axes. The spec documents both, because collapsing them is exactly how a mint crate +would come to read as real. + ## 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) diff --git a/docs/V5_REAL_SHOP.md b/docs/V5_REAL_SHOP.md index 4de51f9..1167d7f 100644 --- a/docs/V5_REAL_SHOP.md +++ b/docs/V5_REAL_SHOP.md @@ -81,3 +81,52 @@ plus this epoch's own: 5. **Settled non-risks:** the dig/wallet/stockAdapter machinery (shipped v2, soaked 16 rounds); static-atlas determinism (E's byte-identical pipeline discipline); the fail-soft ladder (proven pattern from `?noassets` day one). + +### Retired-or-carried at the v5.0 close (ROUND27 ledger #6 — Lane A, line by line) + +Verdicts against what shipped, not against the plan. Written in **wave 2**, so tier-2 items that F's reader +and kill-the-server gate will decide are **carried, not pre-retired** — the gate retires them, not this doc. + +1. **CARRIED — and it is this round's defining gate, not a footnote.** The only risk here the epoch has not + yet measured. The reader (#2) and the kill-the-server gate (#3) don't exist as I write this; **nothing + retires this line except that gate going green** — boot server-up (live fields consumed), kill mid-session + (degrade to tier 1, zero console errors, frame-time measured across the failure), boot server-down (pure + tier 1). Until then the charter's offline law is a promise, and the whole point of #3 is that a promise + isn't a gate. *(If tier 2 proves bigger than one round, F holds and this line simply carries — four holds + have proven nobody forces an epoch close.)* +2. **RETIRED — the remedy the risk named is the remedy that shipped.** It predicted "pagination/crate + rotation rather than bigger atlases", and that is exactly what happened: the mecca case is served by the + **crate-rotation menu**, not by growing the sheet. Measured across all **15 keyed atlases**: max **2 + atlases/shop** against C's hard cap of 2; the 14 mint shops sit at **16 items / 1 atlas / 1024²** and only + the one real POS shop earns 2048² (**120 items, 2 atlases, 1.2 MB**) under C §7.2's 60+ item rule. E's + validator enforces the ceilings from the committed files alone. Total: 344 items. +3. **RETIRED — the risk was designed out, not solved.** It assumed a **fuzzy-matching** problem ("names + drift, shops move") and demanded mismatches be counted. There is no matcher: identity is an **explicit + opaque key** (`godverseShopId`) that G emits, so there is nothing to mis-match. The predicted failure + couldn't occur in the predicted form — and the case that would have broken any name-matcher proves it: + **Monster Robot Party is in neither the census nor OSM**, so no matching strategy could ever have found + it; it is keyed by injection. Mis-stocking is fenced structurally instead: duplicate ids **error**, + uniqueness runs over defined ids, and the **orphaned-atlas gate** fails if a stocked shop isn't seated. +4. **SPLIT — the write half RETIRED by ruling, the read half CARRIED to F's #4.** *Write-back:* retired, and + retired properly — John's **A-then-B** ruling is recorded as **mechanism, not config**: `/reserve` and + `/buy` are **ABSENT, not stubbed**. Race conditions and reservation semantics cannot occur because the + verbs do not exist; "prove the absence" is a stronger guarantee than any sandbox flag, since a sandbox a + config typo can flip isn't a sandbox. *(Option B's reservation upgrade is chartered as v5.x, behind a + hold budget — it re-opens this line deliberately, when it is built.)* *Read (`gone`, real→game):* carried + — F's #4 asserts both directions this round. +5. **Unchanged, and extended by what the epoch settled:** static-atlas determinism proved in practice + (byte-identical re-bakes, including G's index-only sku re-emit that moved no `.webp` bytes); the + fail-soft ladder proved on every rung; and the **id-space fences** (`sku_`/`mint_`, plan-id vs + godverse-id) now have case law behind them rather than good intentions. +6. **NEW, CARRIED — the orphaned atlas.** The lift legitimately drops shops (overlap-resolve, counted since + R19); dropping one that carries a **committed atlas** means real stock keyed to a shop that isn't in the + town. Gated in `selfcheck` since R25 and **currently green** — and the gate armed itself this round + without anyone touching it: it SKIPped on `newtown_godverse` while no atlas keyed there, and **began + binding the moment G's mint atlases landed**. Live near-miss on the books: `redhill_godverse`'s lift drops + keyed shop **2286 "Empire Revival"**; G stocked its numeric neighbour **2287** instead. Carried because + the hazard grows with every shop stocked — **stocking 2286 would orphan it today.** +7. **NEW, CARRIED — "real" is one shop wide.** 14 of 15 keyed atlases are **mint**; exactly one is a POS + snapshot, because exactly one shop has a POS. That is honest and marked (`sourcing`), not a defect — but + the epoch's headline claim rests on **one** shop, and any future claim of scale needs either more POS + shops (v5.x: "if monsterrobot ever gets siblings") or continued care that `sourcing` stays legible to + humans, not just gates.