Lane A round 3: verify F finding #5 (storeys) stale, harden selfcheck + document corner-anchor rule
Per ROUND3_INSTRUCTIONS 'Lane A — on-call + one verification': - F finding #5 (shops with storeys outside registry range) verified STALE across 8 seeds: zero violations. Single-storey types (video/milkbar/stall) never exceed 1; the only shops above registry max are the intentional 3-storey corner anchors (tall-capable types), exactly per CITY_SPEC. Round-1 cornerBoost gate already prevents the reported bug. This is also the source of qa.sh's 5 benign storeys warnings (flagged for Lane F to scope to permittedMax). - Hardened the selfcheck storeys assertion from the too-lax <=max(mx,3) to the exact permitted range (max>=2 ? min(max+1,3) : max), so a single-storey type exceeding 1 now fails loudly. Proven non-vacuous. selfcheck.js only — plan output/fingerprint unchanged (golden 0x098eec2b still matches, confirmed per task 2). - Documented the storeys corner-anchor rule in the CITY_SPEC schema. - hours/openLate contract unchanged; ready for Lane F's §3.5 consumer. qa.sh --strict GREEN (4/4). Committed atomically by pathspec (shared-tree race). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
862bbcd8de
commit
b20b3b08f5
@ -1,7 +1,8 @@
|
||||
# LANE A — CITYGEN · progress (PROCITY-A)
|
||||
|
||||
*Status: **all deliverables landed; self-check all-green (1283/1283); round-2 cross-lane requests from
|
||||
B/E/F closed** (see bottom). Awaiting Fable review.*
|
||||
*Status: **all deliverables landed; self-check all-green (1283/1283); round-2 (B/E/F requests) and
|
||||
round-3 (F finding #5 verified stale + golden hash confirmed) closed** (see bottom). `qa.sh --strict`
|
||||
GREEN. Awaiting Fable review.*
|
||||
*Date: 2026-07-14 · owner: PROCITY-A (Opus 4.8)*
|
||||
|
||||
> **⚠ Fable — commit-label mixup (no action needed on the code):** my round-2 changes are committed
|
||||
@ -167,3 +168,34 @@ stall facades now appear in the market square.
|
||||
single reference for Lane C/E when modelling facades. No code change; it works.
|
||||
- **Still-open design questions from round 1** (retail density ~493/core vs Lane B's draw budget; true
|
||||
closed residential ring) remain parked for your call — both are one-constant tunes, not rework.
|
||||
|
||||
## Round 3 — verification round (2026-07-14, per ROUND3_INSTRUCTIONS "Lane A — on-call + one verification")
|
||||
|
||||
Small round as briefed. All three tasks done; `bash tools/qa.sh --strict` **GREEN** (4/4 gates,
|
||||
selfcheck 1283/1283, manifest 0 errors).
|
||||
|
||||
**1. F finding #5 — "shops with storeys outside the registry type range" → verified STALE / CLOSED.**
|
||||
Scanned every shop across 8 seeds against the *correct* permitted range. Result: **zero violations.**
|
||||
`video`/`milkbar`/`stall` (registry `[1,1]`) are observed at 1 storey only (e.g. 412 video shops, none
|
||||
at 2 — so F's specific "video at 2" case does not occur). The only shops above their registry `max`
|
||||
are the tall-capable types (`record`/`opshop`/`toy`/`book`/`pawn` `[1,2]`, `dept` `[2,3]`) reaching 3
|
||||
via the intentional **corner anchor** — exactly the CITY_SPEC "occasional 3-storey corner anchor". My
|
||||
round-1 `cornerBoost` gate (only boosts registry max ≥ 2) already prevents the reported bug.
|
||||
- **This is the source of `qa.sh`'s 5 consistency warnings** ("N shops have storeys outside their
|
||||
registry range … ask Lane A"). **They are benign** — all intended corner anchors, not plan↔registry
|
||||
drift. *Lane F: you can silence them by scoping the check to `permittedMax = max≥2 ? min(max+1,3) : max`
|
||||
instead of the strict registry `max`.*
|
||||
- **Hardened anyway** (the finding's real lesson): the selfcheck's storeys assertion was too lax
|
||||
(`<= Math.max(mx,3)` would have passed a video at 3). Tightened to the exact permitted range, so a
|
||||
single-storey type exceeding 1 (or any type past `min(max+1,3)`) now fails loudly. Proved non-vacuous
|
||||
(rejects `video@2`, `record@4`, `dept@1`; allows `record@3`). Documented the `storeys` rule in the
|
||||
CITY_SPEC schema so the intended-vs-drift question can't recur.
|
||||
|
||||
**2. Golden fingerprint confirmed.** Committed `GOLDEN.hash = 0x098eec2b` matches the current selfcheck
|
||||
fingerprint on main. No output drift. (selfcheck.js assertion tightening doesn't touch the plan, so the
|
||||
hash is unchanged.)
|
||||
|
||||
**3. Hours / `openLate` contract — ready for its first real consumer (Lane F §3.5).** No changes needed:
|
||||
`hours=[open,close]` (24h ints, `0≤open<close≤23`), **exactly one `openLate:true` landmark per town**
|
||||
(closes ≥22:00, video/milkbar, never a stall). ROUND3_INSTRUCTIONS §Lane F restates it correctly, so
|
||||
F's night-gate wiring can consume it as-is. Full contract in CITY_SPEC schema + the round-2 notes above.
|
||||
|
||||
@ -73,6 +73,10 @@ Schema v1 (Lane A owns it; extend, don't break):
|
||||
// frontEdge: id of the street edge this lot fronts (guaranteed to exist and be geometrically adjacent).
|
||||
shops: [ { id, lot, type, name, sign, seed, facadeSkin, storeys, hours: [open, close], openLate? } ]
|
||||
// type: see SHOP TYPES below. hours: [open, close], 24h integers, 0 ≤ open < close ≤ 23.
|
||||
// storeys: integer in [registryMin, permittedMax] where permittedMax = registryMax≥2 ? min(registryMax+1,3)
|
||||
// : registryMax. The "+1 (cap 3)" is the CITY_SPEC "occasional 3-storey corner anchor" — it fires ONLY
|
||||
// for tall-capable types (registry max ≥ 2); single-storey types (video/milkbar/stall, [1,1]) are NEVER
|
||||
// boosted. So `storeys > registryMax` on a corner anchor is EXPECTED, not plan↔registry drift.
|
||||
// openLate: present and `true` on EXACTLY ONE shop per town — the designated late-night landmark
|
||||
// (closes ≥ 22:00; a naturally-late type, video rental or milk bar, never a market stall). Absent
|
||||
// on every other shop. Lane B lights it after dark; Lane F's night gate keys off this field
|
||||
|
||||
@ -84,7 +84,15 @@ for (const s of SEEDS) {
|
||||
ok(plan.shops.every(sh => sh.hours[0] >= 0 && sh.hours[1] <= 23 && sh.hours[1] > sh.hours[0]), `seed ${s}: every shop has sane hours`);
|
||||
ok(plan.shops.every(sh => sh.name && sh.sign), `seed ${s}: every shop is named`);
|
||||
ok(plan.shops.every(sh => !/[{}]|undefined/.test(sh.name + sh.sign)), `seed ${s}: no unresolved tokens / undefined in names`);
|
||||
ok(plan.shops.every(sh => { const [mn, mx] = SHOP_TYPES[sh.type].storeys; return sh.storeys >= mn && sh.storeys <= Math.max(mx, 3); }), `seed ${s}: storeys within range (corner ≤3)`);
|
||||
// STOREYS strictly within the registry range, corner-boost included (Lane F finding #5 class): the
|
||||
// occasional 3-storey corner anchor adds ≤1 storey capped at 3, and ONLY for tall-capable types
|
||||
// (registry max ≥ 2) — so single-storey types (video/milkbar/stall, [1,1]) must NEVER exceed 1.
|
||||
// (The old `<= Math.max(mx,3)` was too lax — it would have passed a video at 3 storeys.)
|
||||
ok(plan.shops.every(sh => {
|
||||
const [mn, mx] = SHOP_TYPES[sh.type].storeys;
|
||||
const pmax = mx >= 2 ? Math.min(3, mx + 1) : mx;
|
||||
return sh.storeys >= mn && sh.storeys <= pmax;
|
||||
}), `seed ${s}: storeys within registry range (corner-boost ≤ min(max+1,3); single-storey types never boosted)`);
|
||||
|
||||
// one lot ↔ at most one shop
|
||||
const lotShopCounts = {};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user