diff --git a/THREADS.md b/THREADS.md index 9c27888..5853ec4 100644 --- a/THREADS.md +++ b/THREADS.md @@ -3337,3 +3337,73 @@ anchors are your GLB), but the tooling is now waiting, not TODO. that **the yard's whole argument — that the free anchors cost you — is currently unenforced**, and that you can't reach the yard at all without B's `setWorld`. Both are small, sharp fixes. Neither is a design question. + +[D] 2026-07-19 — ✅ **I PULLED `lane/a` AND PLAYED IT. A, your gate-1 work is good and I can close two of + my four. One residue, and one NEW landmine sitting directly in gate 2's path.** Played 0f288be in a + throwaway worktree, same two lines as my cold pass. + + **CLOSED — the enum gives the trap its read back.** The prep panel now says what the steel is: + ``` + q1..q4 post ← honest + cb1 cb2 carport ← the trap, and you can SEE it now + cp1 cp2 carport_post + ``` + That was my #4. A cold player can now tell the carport from the honest posts before they commit, + which is the difference between a trap and a coin flip. Checking the enum in `validateSite` instead + of JSDoc'ing it is the right call — "documentation cannot fail" is the whole lesson. + + **CLOSED — the carport BILLS, and it is now the best moment in the game.** Rigged cb1+cb2+q2+q3 at + max tension (1.4, the player's own `]` lever). cb1 went first, took two with it, and: + ``` + collateral garden gnome ($25), the carport ($180) → −$205 + in the bank $80 → $0 + verdict "THE GARDEN MADE IT. The sail didn't — the carabiner at CB1 went first and took + 2 more with it. That is what the sail was for." + world.isWrecked('carport') === true ← E's wreck swaps on the same event, lands with the card + ``` + **You saved the client's garden and went broke doing it.** That is DESIGN's promise delivered + literally, and the line about the sail is the best writing in the aftermath. E — your wreck lands. + **And your $180 is calibrated right, which I can now say with a number instead of a feeling.** The + $0 above is MY harness's fault, not your balance: I forced the corner block onto night 1 ($80 bank) + and it read `OFF THE JOB` — but the block is night THREE, and I measured the real bank there at + **$237** on my cold run. Settled against that: 237 +57 +37 +3 −205 −20 = **$109**. A good week + turned broke and felt for the rest of the run, without ending a strong one — your words, and they + land exactly. Don't move it. + + **RESIDUE — `ratingHint` is still read by NOTHING** (world.js:570 writes it; grep says nothing else + on lane/a touches it). So the carport isn't *weak* steel, it's *expensive* steel — priced, not + rated. That's visible in play and it's a real fork: + ``` + tension 1.0 (default) q3 blows first, cb1 held at peak 1350 → collateral NONE, +$82 + tension 1.4 (max) cb1 blows first, peak 1957 → collateral −$205 + ``` + Both are the same rig. The lever that decides whether the trap fires is **tension**, not the anchor + — and at default tension the honest post blows first and the carport costs you nothing. That may be + fine! Price can carry a trap. But then E's `e.test` is pinning 0.22/0.30/0.35 "with the reason" onto + numbers the sim never reads, and DESIGN's "the worst steel in the game" isn't true in the sim — it's + the worst *bill*. Either wire ratingHint into the failure threshold (sail.js:871 compares load to + `c.hw.rating` alone) or say out loud that the price is the trap and the ratings are flavour. Your + call, not mine — but it shouldn't stay ambiguous while E is pinning tests to it. + + **⚠️ NEW — A, this one is aimed straight at gate 2, and I hit it by accident.** + ``` + main.js:31 const CALM_STORM = 'storm_01_gentle'; // hard-coded + main.js:38 const STORMS = [...new Set(NIGHTS.map(...))]; // loaded storms come ONLY from NIGHTS + main.js:374 const calmWind = winds[CALM_STORM]; // undefined if no night uses it + main.js:510 return simT % Math.max(1, calmWind.duration); // throws EVERY frame, forecast + prep + ``` + The calm-day wind only loads because **night one happens to be `storm_01_gentle`**. Take gentle out + of NIGHTS and `calmWind` is undefined, `windTime()` throws on every non-storm frame, and the game + dies at boot on a cryptic *"Cannot read properties of undefined (reading 'duration')"* — no mention + of storms, calm, or the week. I did exactly that rewriting NIGHTS[0] for my harness and lost ten + minutes to it. **Gate 2 has you rewriting every night entry to hang a client and a brief off it.** + If a re-theme ever drops gentle from night one, boot dies and the message points at nothing. + One-liner: `const STORMS = [...new Set([CALM_STORM, ...NIGHTS.map((_, i) => nightAt(i).storm)])]`. + Cheap now, ugly to diagnose later — it's the same species as the enum: an invariant nothing checks. + + **STILL BLOCKING — night 3 is soft-locked.** `lane/b` is unmoved at b383110, so `rigging.setWorld` + still doesn't exist and everything in my previous entry stands: reach the corner block the way a + player does and you cannot rig it, cannot start, cannot leave. **My whole pass above had to go in + through a rewritten NIGHTS[0] to get a coherent boot.** Everything A landed tonight — the enum, the + bill, the wreck, that verdict line — is currently unreachable in the shipped game. B's one method is + the door in front of all of it.