Lane C S18 gate 1: the honesty gate walks A's EMERGENCIES — storm AND pairing
NIGHTS ∪ POOL grew a third member this sprint, and an emergency is the member with the most to hide: no forecast card, no quote, and a storm entered at a t nobody walked up to. Both arms checked per entry — dispatchHonest(def, arriveAt) for the storm-and-instant, pairingRefusal(storm, site) for the yard, because a read can be perfectly honest about a storm and still be an invitation to a night nobody can work, which is worse on a callout the player cannot decline once they are in it. Read through a NAMESPACE import (board.EMERGENCIES), not a named one, so this file survives the window where A's spine is on lane/a and not in my tree — a named import of a not-yet-exported symbol is a hard module error, not a graceful no-op. A's own reasoning for weather.midStormRead?.(), applied back at them. Walks a FIXTURE mirroring A's §6 as well as the real table, so the gate is exercised on known data TODAY rather than reading green off an absent import — the calm-day vacuity that has now bitten this repo in three separate gates. Verified against A's actual lane/a tree out of band: their one shipped emergency (corner_block_emergency, night 5, storm_03_southerly x site_02_corner_block, arriveAt 30) passes both arms, so the walk binds clean at merge. Three vacuity guards, one per arm plus the late arrival. 533/0/0 (+1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
9506f6e79f
commit
062fd00758
@ -32,6 +32,11 @@ import { loadSite, createWorld } from '../world.js';
|
||||
// without a test edit the day D's pool yard lands.
|
||||
import { NIGHTS, nightAt } from '../week.js';
|
||||
import { POOL, exposureOf } from '../board.js';
|
||||
// SPRINT18 gate 1: A's EMERGENCIES table read through a NAMESPACE import, so this
|
||||
// file survives the window where A's spine is on lane/a and not yet in my tree —
|
||||
// a named import of a not-yet-exported symbol is a hard module error, not a
|
||||
// graceful no-op. A's own reasoning for `weather.midStormRead?.()`, applied back.
|
||||
import * as board from '../board.js';
|
||||
// GATE 2.3 — the GAME's own wind wiring, IMPORTED rather than re-typed. A pin
|
||||
// that copied main.js's two lines would agree with a copy of the game forever,
|
||||
// including on the day the game itself changed. "Two harnesses, one number"
|
||||
@ -1812,6 +1817,57 @@ export default async function run(t) {
|
||||
'a 2.6 stone was dispatched — the vocabulary ceiling stopped biting');
|
||||
});
|
||||
|
||||
t.test('GATE 1: every EMERGENCY is a storm that can be honestly dispatched over that yard', () => {
|
||||
// The honesty gate walking A's own table — NIGHTS ∪ POOL grew a third member
|
||||
// this sprint, and an emergency is the member with the most to hide: no
|
||||
// forecast card, no quote, and a storm entered at a t nobody walked up to.
|
||||
//
|
||||
// ⚠️ Read through a NAMESPACE import (`board.EMERGENCIES`), not a named one, so
|
||||
// this file does not hard-error in the sprint-window where A's spine is on
|
||||
// lane/a and not yet in my tree — the same reasoning A gave for calling
|
||||
// `weather.midStormRead?.()` that way, applied back at them. And it walks a
|
||||
// FIXTURE mirroring A's §6 as well as the real table, so the gate is exercised
|
||||
// on known data TODAY rather than reading green off an absent import: the
|
||||
// calm-day vacuity that has now bitten this repo in three separate gates.
|
||||
const fixture = [{
|
||||
id: 'fixture:corner_block_emergency', night: 5,
|
||||
storm: 'storm_03_southerly', site: 'site_02_corner_block',
|
||||
emergency: { arriveAt: 30 },
|
||||
}];
|
||||
const real = Array.isArray(board.EMERGENCIES) ? board.EMERGENCIES : [];
|
||||
const walk = [...fixture, ...real];
|
||||
assert(walk.length >= 1, 'the emergency walk found nothing at all');
|
||||
|
||||
for (const e of walk) {
|
||||
const at = e.emergency?.arriveAt;
|
||||
const def = storms[e.storm];
|
||||
assert(def, `${e.id}: emergency storm '${e.storm}' is not in the loaded storm set — `
|
||||
+ 'an emergency whose weather nobody can load cannot be dispatched');
|
||||
assert(Number.isFinite(at), `${e.id}: no numeric emergency.arriveAt`);
|
||||
|
||||
// (1) the storm-and-instant gate
|
||||
const r = dispatchHonest(def, at, e.id);
|
||||
assert(r.ok, `${e.id} cannot be honestly dispatched at arriveAt=${at}:\n ${r.errors.join('\n ')}`);
|
||||
|
||||
// (2) THE PAIRING LAW, extended to the new job type. A read can be perfectly
|
||||
// honest about a storm and still be an invitation to a night nobody can
|
||||
// work — and that is worse on a callout, which the player cannot decline
|
||||
// once they are standing in it.
|
||||
const why = pairingRefusal(e.storm, e.site);
|
||||
assert(why === null,
|
||||
`${e.id}: dispatching ${e.storm} over ${e.site} is refused by measurement — ${why}`);
|
||||
}
|
||||
|
||||
// VACUITY GUARDS — three, because a walk that only ever says yes is decoration.
|
||||
assert(pairingRefusal('storm_06_soaker', 'backyard_01') !== null,
|
||||
'the pairing arm of this walk cannot say no — an emergency on a refused yard would pass');
|
||||
assert(!dispatchHonest(storms[fixture[0].storm], 95, 'late').ok,
|
||||
'an emergency arriving after its storm ended was accepted');
|
||||
const sizeless = JSON.parse(JSON.stringify(storms.storm_06_soaker));
|
||||
delete sizeless.hail.size;
|
||||
assert(!dispatchHonest(sizeless, 30, 'sizeless').ok, 'the storm arm of this walk cannot say no');
|
||||
});
|
||||
|
||||
t.test('GATE 1: every line of the read is reachable, and each one is earned', () => {
|
||||
// A vocabulary with an unreachable word is a vocabulary that has never been
|
||||
// read. Walk the shipped storms and prove each key fires somewhere — and that
|
||||
|
||||
Loading…
Reference in New Issue
Block a user