Sprint 13 gate 1.4 RE-RULED on B's skew finding: the pin measures the game now, and the target is restated
- a.test's separation flight had the phantom 12 s settle B caught (SailRig samples wind at its INTERNAL clock; the storm flew 12 s off the authored curve). Settle deleted — commit->attach->storm from t=0, C's corrected bench pattern; venturi wired from site data so the flight can never assume a yard. - Game-true the line reads 63.6, not 68.3 — FULL (>66) was met by the harness, not the game, and the re-sweep says nothing buyable reaches 66 (the twin-post covering quad tears at 6.9 kN). Target RESTATED to the game's real stakes, with headroom: held >60 and 0/4 (win line 50; measured 63.6), bare <50 (35.7), separation >=25 (27.9). Field names kept — B's gardenfly reads them. - DESIGN CANON in the site block: the wild night's garden is WON SCARRED, never FULL; the week's arc is full/full/full, won-tattered, beyond-saving. - p5 _why table corrected to game-true numbers (first sweep ran ~4 HP hot).
This commit is contained in:
parent
b5643922a4
commit
1c0fcc757b
@ -115,38 +115,46 @@
|
||||
"",
|
||||
"WHY (5.5, -2) at h 2.6 and not somewhere kinder: the LOW top is the point - it twists the",
|
||||
"p1+p2+p3+p5 quad so it spills the gusts (small+twisted survives, DESIGN.md), and the",
|
||||
"position is swept against the $80 wallet:",
|
||||
"position is swept against the $80 wallet. NUMBERS CORRECTED to the game-true chain after",
|
||||
"B's 12s-skew finding (no phantom settle; the first sweep's hp column ran ~4 HP hot):",
|
||||
" (4.5,-2) h2.6 -> p1 3.35 kN, needs RATED, line costs $90 DO NOT",
|
||||
" (5,-2.5) h2.8 -> p5 6.20, p1 3.75 -> $90 DO NOT",
|
||||
" (5.5,-2) h2.8 -> p2 3.08, p1 3.06 (4% margin on shackle) - legal but knife-edged",
|
||||
" (5.5,-2) h2.6 -> p5 4.88, p2 3.14, p1 2.91, p3 1.82 -> $75, hp 68.3 FULL <- here",
|
||||
" (6,-2) h2.6 -> shadow drops, hp 65.8 tattered DO NOT",
|
||||
"The separation block below pins the recipe; a.test flies it. Full cover STAYS unbuyable:",
|
||||
"the covering quads (p1+p2+p4+p5 and up) still pull 6.4-6.9 kN and still tear - the",
|
||||
"smallest full-cover quad stays >45 m2 (a.test's floor holds), so the tradeoff decision 2",
|
||||
"protects is intact. And the ICE night still refuses the $80 wallet: same line needs $105",
|
||||
"there (p1 3.25, p2 3.22 vs a shackle's 3.20 - the same few-hundredths miss as C's q3),",
|
||||
"so night 5 stays the night the bank pays for, exactly as ruled in SPRINT9."
|
||||
" (5.5,-2) h2.6 -> p5 5.10, p2 3.08, p1 2.96, p3 1.81 -> $75, hp 63.6 WIN <- here",
|
||||
" (6,-2) h2.6 -> shadow drops DO NOT",
|
||||
"A second, LOWER-still or wider post cannot buy FULL either: the twin-post covering quad",
|
||||
"(p6 at (-3,-2) h2.6 + p5 + p1 + p2, 100% cover) pulls 6.9/6.7/6.2 kN and tears - full",
|
||||
"cover honestly exceeds the wild night at ANY buyable price, which is decision 2's tension",
|
||||
"doing its job. The separation block below pins the recipe; a.test flies it game-true.",
|
||||
"The smallest full-cover quad stays >45 m2 (a.test's floor holds). And the ICE night still",
|
||||
"refuses the $80 wallet: same line needs $105 there (p1 3.25, p2 3.22 vs a shackle's 3.20",
|
||||
"- the same few-hundredths miss as C's q3), so night 5 stays the night the bank pays for."
|
||||
]
|
||||
} ],
|
||||
|
||||
"separation": {
|
||||
"_why": [
|
||||
"SPRINT13 gate 1.4 — A's ruling on C's proposed target, AMENDED to the numbers the real game",
|
||||
"measures (ruled on D's funnel-corrected picture, not C's original headline). C proposed:",
|
||||
"'on a wild night the best buyable line reads FULL (>66) and a bare bed reads DEAD (<33)'.",
|
||||
"Adopted in spirit, amended in both halves:",
|
||||
" - The bare half becomes 'a bare bed LOSES the night (hp < 50, the win line)'. Nowhere in",
|
||||
" the shipped game does a bare bed read DEAD on the wild night (35.7, tattered) — D's",
|
||||
" check — and tuning storm_02's damage budget until a slogan lands is exactly the fudge",
|
||||
" gate 1 exists to kill. The felt boundary is the WIN line, and 35.7 fails it honestly.",
|
||||
" - The FULL half binds THIS yard, because the shipped week's only wild night is here",
|
||||
" (week.js night 4). C's passing example was site_02, whose wild night the corner block",
|
||||
" never plays — and with its venturi live the example dies anyway (D's landmine).",
|
||||
"This block is the pin: the recipe below is the measured best $80 line, a.test flies it",
|
||||
"through the real chain (session -> commit -> attach -> skyfx) every run, and B's audit can",
|
||||
"read the same recipe instead of inventing one. A target nothing checks is decoration —",
|
||||
"the repo's oldest lesson, and the reason this is data and not a THREADS sentence."
|
||||
"SPRINT13 gate 1.4 — A's ruling on C's proposed target, RULED TWICE and honest the second",
|
||||
"time. C proposed: 'on a wild night the best buyable line reads FULL (>66) and a bare bed",
|
||||
"reads DEAD (<33)'. First ruling amended the bare half (nowhere does a bare bed read DEAD;",
|
||||
"35.7 is tattered, and tuning storm_02 until a slogan lands is the fudge gate 1 exists to",
|
||||
"kill) and kept FULL — then B's audit rewrite caught that FULL was only ever met through the",
|
||||
"assert's own 12 s phantom settle (SailRig samples wind at its INTERNAL clock: game-true",
|
||||
"63.8/63.6, skewed 68.4/68.3). The geometry was re-swept game-true: nothing buyable reaches",
|
||||
"66 (the twin-post covering quad tears at 6.9 kN; every FULL-flavoured candidate is also",
|
||||
"knife-edged under B's 15% margin rule). So the target is RESTATED to the boundaries the",
|
||||
"game actually stakes, with real headroom, instead of pinning another knife edge:",
|
||||
" - the best buyable line HOLDS (0/4) and WINS COMFORTABLY: hp > 60 (win line is 50;",
|
||||
" game-true 63.6 - a red means the wild night's best line regressed, not noise),",
|
||||
" - a bare bed LOSES: hp < 50 (game-true 35.7),",
|
||||
" - the spread reads as most of a plant state: >= 25 HP (game-true 27.9).",
|
||||
"DESIGN CANON, written down on purpose: the wild night's garden is WON SCARRED, never FULL.",
|
||||
"The week's garden arc is full/full/full on nights 1-3, won-but-tattered on night 4, and",
|
||||
"beyond saving on night 5 (see week.js night 5) - the state bands are the yard's face, but",
|
||||
"the stakes the player plays for are the WIN line and the invoice, and those are what pin.",
|
||||
"This block is the pin: a.test flies the recipe through the real chain (session -> commit ->",
|
||||
"attach -> skyfx, NO settle, from t=0) every run, and B's audit reads the same recipe",
|
||||
"(heldMustExceed/bareMustLoseBelow are B's field names too - renaming them breaks gardenfly).",
|
||||
"A target nothing checks is decoration - the repo's oldest lesson."
|
||||
],
|
||||
"stormKey": "storm_02_wildnight",
|
||||
"tension": 1.0,
|
||||
@ -156,8 +164,9 @@
|
||||
{ "anchor": "p2", "hw": "shackle" },
|
||||
{ "anchor": "p3", "hw": "shackle" }
|
||||
],
|
||||
"heldMustExceed": 66,
|
||||
"bareMustLoseBelow": 50
|
||||
"heldMustExceed": 60,
|
||||
"bareMustLoseBelow": 50,
|
||||
"separationAtLeast": 25
|
||||
},
|
||||
|
||||
"shed": { "model": "shed_01_v1", "x": 11.8, "z": 6.2, "rotYDeg": -90 },
|
||||
|
||||
@ -221,6 +221,10 @@ export default async function run(t) {
|
||||
assertEq(nightAt(4).storm, 'storm_02b_icenight', 'night five is the ice night');
|
||||
assertEq(nightAt(2).site, 'site_02_corner_block', 'night three moves to the corner block');
|
||||
assertEq(nightAt(0).site, 'backyard_01', 'the rest are the backyard');
|
||||
// SPRINT13 gate 1.4: the unsavable-garden flag is night 5's alone, and a
|
||||
// night without it is presumed savable — new nights can't inherit the excuse.
|
||||
assertEq(nightAt(4).gardenBeyondSaving, true, 'night 5 is beyond saving BY DESIGN — canon, ruled');
|
||||
for (let i = 0; i < 4; i++) assertEq(nightAt(i).gardenBeyondSaving, false, `night ${i + 1} is savable`);
|
||||
const w = createWeek();
|
||||
assertEq(w.night, 1); assertEq(w.bank, 80);
|
||||
assertEq(w.site, 'backyard_01', 'week.site tracks the ladder');
|
||||
@ -797,6 +801,39 @@ export default async function run(t) {
|
||||
assert(hailed.verdict !== rained.verdict, 'hail and rain deaths must not read identically');
|
||||
});
|
||||
|
||||
t.test("night 5's loss is TAUGHT, not blamed: beyondSaving rewrites the garden verdicts only", () => {
|
||||
// SPRINT13 gate 1.4, the night-5 ruling. Measured game-true (B's pay table,
|
||||
// my probe agreeing): the icenight garden cannot reach the win line at any
|
||||
// price — bare 0.0, best buyable 27.7. So week.js flags the night, and the
|
||||
// verdict must stop implying a better rig existed. The worst liar was
|
||||
// 'uncovered' ("the hail fell where your sail wasn't") on a night where no
|
||||
// WHERE saves it.
|
||||
const dmg = { hail: 90, rain: 5 };
|
||||
const held = verdictFor({ hp: 25, lost: [], win: false, dmg, pondPeak: 0, pondDumped: 0, beyondSaving: true });
|
||||
assertEq(held.mode, 'beyond-saving');
|
||||
assert(/BEYOND SAVING/.test(held.verdict), `says so plainly: "${held.verdict}"`);
|
||||
assert(/held|did it/i.test(held.verdict), 'and a 4/4 hold is CREDITED — keeping the steel was the job');
|
||||
assert(!/wasn't|skimp/i.test(held.verdict), 'no placement-blame, no skimp-blame');
|
||||
|
||||
// Losing your sail on the unsavable night is still yours to own.
|
||||
const shackle = { name: 'shackle', rating: 3200 };
|
||||
const torn = verdictFor({ hp: 5,
|
||||
lost: [{ hw: shackle, anchorId: 'p1', anchor: { ratingHint: 1 } }],
|
||||
win: false, dmg, pondPeak: 0, pondDumped: 0, beyondSaving: true });
|
||||
assertEq(torn.mode, 'beyond-saving');
|
||||
assert(/shackle at P1/.test(torn.verdict), `still names the steel that went: "${torn.verdict}"`);
|
||||
|
||||
// The flag defaults OFF and changes nothing anywhere else: the two garden
|
||||
// deaths keep their opposite sentences (mutation check — delete the branch
|
||||
// and the first assert above reds; pass the flag everywhere and THIS one does).
|
||||
const uncov = verdictFor({ hp: 20, lost: [], win: false, dmg: { hail: 70, rain: 10 }, pondPeak: 0, pondDumped: 0 });
|
||||
assertEq(uncov.mode, 'uncovered', 'a savable night keeps its honest placement lesson');
|
||||
// And a WIN on a flagged night ignores the flag — week.js says the flag
|
||||
// would be stale, and a stale excuse must never eat a real win.
|
||||
const win = verdictFor({ hp: 90, lost: [], win: true, dmg, pondPeak: 0, pondDumped: 0, beyondSaving: true });
|
||||
assertEq(win.mode, 'clean');
|
||||
});
|
||||
|
||||
t.test('a clean hold reads as a clean hold, and the broom gets its credit', () => {
|
||||
const clean = verdictFor({ hp: 96, lost: [], win: true, dmg: { hail: 2, rain: 2 }, pondPeak: 0, pondDumped: 0 });
|
||||
assertEq(clean.mode, 'clean');
|
||||
@ -1016,19 +1053,33 @@ export default async function run(t) {
|
||||
|
||||
// --- SPRINT13 gate 1.4: THE PINNED SEPARATION TARGET ----------------------
|
||||
//
|
||||
// The ruling (THREADS [A], on D's funnel-corrected picture): on the shipped
|
||||
// week's wild night — night 4, THIS yard — the best line START_BUDGET can buy
|
||||
// must read FULL (>66) and WIN, and a bare bed must LOSE (<50). The recipe is
|
||||
// DATA (site.separation) so B's audit reads the same one, and this flight is
|
||||
// the pin: real shop at the real budget, real commit()->attach() (D's
|
||||
// skipped-attach landmine — session.commit(rig) IS the attach path, verified
|
||||
// by C's probe2 agreement), real skyfx exposure, the real garden model out of
|
||||
// garden.js. Flown OUTSIDE t.test() because Suite.test cannot await — the
|
||||
// two async-test ghosts above are the precedent.
|
||||
// The ruling, RESTATED after B's skew finding (THREADS [A], twice — read the
|
||||
// second entry): on the shipped week's wild night — night 4, THIS yard — the
|
||||
// best line START_BUDGET can buy must HOLD and WIN comfortably (>60), a bare
|
||||
// bed must LOSE (<50), and the spread must read as most of a plant state
|
||||
// (≥25 HP), because the win line and the invoice are the game's real stakes.
|
||||
// FULL (>66) was the first ruling and it died honestly: it was only ever met
|
||||
// through this flight's own 12 s phantom settle — SailRig samples wind at its
|
||||
// INTERNAL clock, so a settled rig flies the storm 12 s off the authored
|
||||
// curve while the sky flies t=0..90 (B's three-way probe: game-true 63.8 /
|
||||
// skewed 68.4 / shape-only 64.3). The settle is GONE: in the real game the
|
||||
// rig does not exist before commit, and commit→attach→storm is one keypress
|
||||
// (C's bench correction, same day, same bug).
|
||||
//
|
||||
// The recipe is DATA (site.separation) so B's audit reads the same one, and
|
||||
// this flight is the pin: real shop at the real budget, real
|
||||
// commit()->attach() (D's skipped-attach landmine — session.commit(rig) IS
|
||||
// the attach path), real skyfx exposure, the real garden model out of
|
||||
// garden.js. Wind is wired the way main.js wires a site (venturi from site
|
||||
// data — backyard's list is empty, but the wiring must not ASSUME that — plus
|
||||
// tree shelters); switch to C's windForSite at integration, it is the same
|
||||
// wiring behind one door. Flown OUTSIDE t.test() because Suite.test cannot
|
||||
// await — the two async-test ghosts above are the precedent.
|
||||
//
|
||||
// Sway is frozen (balance.test's reasoning): the recipe is all posts, whose
|
||||
// real sway is constant anyway, so frozen here means "identical to the game",
|
||||
// not "conveniently calm".
|
||||
// not "conveniently calm". (C's landmine 2 — a frozen TREE under-reads — is
|
||||
// exactly why the pinned recipe staying post-only matters to this harness.)
|
||||
const sep = site.separation;
|
||||
let sepRun = null;
|
||||
if (sep && typeof document !== 'undefined') {
|
||||
@ -1039,7 +1090,6 @@ export default async function run(t) {
|
||||
});
|
||||
const trees = frozen.filter((a) => a.type === 'tree');
|
||||
const stormDef = await loadStorm(sep.stormKey);
|
||||
const calmDef = await loadStorm(CALM_STORM);
|
||||
|
||||
const session = new RiggingSession({ anchors: frozen }); // the REAL budget
|
||||
const shopLog = [];
|
||||
@ -1056,16 +1106,12 @@ export default async function run(t) {
|
||||
session.setTension(sep.tension);
|
||||
const spent = START_BUDGET - session.budget;
|
||||
const rig = session.commit(new SailRig({ anchors: frozen, gridN: 10 }));
|
||||
|
||||
const calmWind = createWind(calmDef);
|
||||
calmWind.setSheltersFromTrees(trees);
|
||||
let prepT = 0;
|
||||
for (let i = 0; i < Math.round(12 / FIXED_DT); i++) {
|
||||
rig.step(FIXED_DT, calmWind, prepT % 3); prepT += FIXED_DT;
|
||||
}
|
||||
// NO settle here, deliberately — see the header. The rig flies the storm
|
||||
// from t=0 on a fresh internal clock, exactly like a committed rig does.
|
||||
|
||||
const flyNight = (sail) => {
|
||||
const wind = createWind(stormDef);
|
||||
wind.setVenturi(site.wind?.venturi ?? []); // main.js:‘the funnel is SITE data’
|
||||
wind.setSheltersFromTrees(trees);
|
||||
const camera = new THREE.PerspectiveCamera(60, 1.6, 0.1, 400);
|
||||
camera.position.set(0, 2, 8);
|
||||
@ -1092,7 +1138,7 @@ export default async function run(t) {
|
||||
}
|
||||
}
|
||||
|
||||
t.test('PINNED: the wild night separates — best buyable line FULL and winning, bare bed losing', () => {
|
||||
t.test('PINNED: the wild night separates — best buyable line holds and wins, bare bed loses', () => {
|
||||
if (!sep) throw new Error('backyard_01 lost its separation block — the target is decoration again');
|
||||
if (typeof document === 'undefined') return t.skip('needs DOM (skyfx)');
|
||||
if (sepRun.err) throw new Error(`separation flight died: ${sepRun.err}`);
|
||||
@ -1100,16 +1146,17 @@ export default async function run(t) {
|
||||
assert(sepRun.spent <= START_BUDGET, `recipe costs $${sepRun.spent} — must be buyable night 1`);
|
||||
assertEq(sepRun.lost, 0, 'the pinned line HOLDS the wild night — 0/4 lost');
|
||||
assert(sepRun.held.hp > sep.heldMustExceed,
|
||||
`held bed reads ${sepRun.held.hp.toFixed(1)} — the target is FULL (>${sep.heldMustExceed}). ` +
|
||||
`Measured 68.3 at landing; a red here means a retune moved the wild night and the ` +
|
||||
`separation ruling needs re-litigating in THREADS, not a quiet threshold bump.`);
|
||||
assertEq(sepRun.held.state, 'full', 'and the plants SAY full — the state the player sees');
|
||||
`held bed reads ${sepRun.held.hp.toFixed(1)} — the target is comfortably WON ` +
|
||||
`(>${sep.heldMustExceed}; the win line is 50). Game-true 63.6 at landing — FULL (>66) was the ` +
|
||||
`first ruling and it was only ever met through this flight's own 12 s clock skew (B's finding). ` +
|
||||
`A red here means a retune moved the wild night: re-litigate in THREADS, no quiet threshold bump.`);
|
||||
assert(sepRun.held.state !== 'dead', 'the held bed is ALIVE — tattered is the wild night speaking');
|
||||
assertLess(sepRun.bare.hp, sep.bareMustLoseBelow,
|
||||
`bare bed must LOSE the night (<${sep.bareMustLoseBelow}) — measured 35.7 at landing`);
|
||||
`bare bed must LOSE the night (<${sep.bareMustLoseBelow}) — game-true 35.7 at landing`);
|
||||
// The felt spread, stated so a red prints the whole story:
|
||||
assert(sepRun.held.hp - sepRun.bare.hp > 25,
|
||||
`separation ${(sepRun.held.hp - sepRun.bare.hp).toFixed(1)} — rigging must matter by a full state, ` +
|
||||
`not a garden-bonus margin (measured 32.6 at landing)`);
|
||||
assert(sepRun.held.hp - sepRun.bare.hp >= (sep.separationAtLeast ?? 25),
|
||||
`separation ${(sepRun.held.hp - sepRun.bare.hp).toFixed(1)} — rigging must matter by most of a ` +
|
||||
`plant state, not a garden-bonus margin (game-true 27.9 at landing)`);
|
||||
});
|
||||
|
||||
t.test('sway() returns an absolute position, not an offset', () => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user