Compare commits
4 Commits
bb8451d12e
...
76ff175c03
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76ff175c03 | ||
|
|
d8466355e8 | ||
|
|
64fb25529f | ||
|
|
39701884e3 |
187
THREADS.md
187
THREADS.md
@ -8985,3 +8985,190 @@ anchors are your GLB), but the tooling is now waiting, not TODO.
|
||||
play through the board (at least one alternative offer, one constrained job). Gate 4
|
||||
(John plays the seven at partly.party) closes the sprint; deploy fires after D's pass
|
||||
integrates.
|
||||
|
||||
[D] 2026-07-21 — 🌊 **GATE 3.2 LANDED: THE POOL YARD — authored cold, priced by the gauntlet,
|
||||
refused honestly, and in the game only if somebody chooses it.** Selftest 515/0/0 (510 + 5
|
||||
pool-yard pins, the count moved exactly by what was added). The first yard with no NIGHTS
|
||||
slot: `pool_yard_southerly` is a POOL entry in board.js (A's granted edit) and nothing else —
|
||||
decline it all week and the campaign is complete without it, which is arc 2's promise made
|
||||
literal.
|
||||
|
||||
**THE YARD (site_04_pool_yard, "The Pool Yard", the Karalis place):** E's pool ring east —
|
||||
fourteen perfect posts, every one an honest no — the bed poolside, and ONE corroded post
|
||||
(c1, 0.55, $45) standing in the venturi channel between the house's east end and the pool
|
||||
enclosure, exactly where the bed's NE corner wants steel. Honest steel is scarce and west
|
||||
(gum t1/t1b, posts p1-p3, the familiar 0.35 fascia). Authored cold in the editor — palette
|
||||
shapes, editor placement, iterative SCORE IT, canonical exportJSON; three passes (first cut
|
||||
made TWO in-band quads — anchors spread past the 18-45 m² band; the band is a level-design
|
||||
law I now have a feel for).
|
||||
|
||||
**THE NUMBERS (SCORE IT card = audit.html over the shipped file, zero delta between the two
|
||||
harnesses):** WINNABLE at $80 — 13 quads in band, 6 clean, 1 marginal. Cheapest hold $40
|
||||
(h1,t1b,p2,p3 → 92.7 FULL, 58% cover, no rust in it). **Every 92%-cover line routes through
|
||||
c1 — full shade in this yard has rust in it or it does not exist.** And the tier does what E
|
||||
built it for: the SAME eye flies 1.9 kN (clean, $30 rated) on t1,p1,p2,c1 and 3.6-4.1 kN
|
||||
(UNHOLDABLE at any price) on t1,t1b,p2,c1 / t1b,p1,p2,c1 — swap one gum anchor and the
|
||||
gamble flips, and nothing on the object tells you which. **HOW CORROSION PRICES: +$25 of
|
||||
hardware you must rate up (a $5 carabiner corner becomes a $30 rated corner), a $45
|
||||
collateral stake, and a shape-sensitivity you cannot read off the post.** Fence compliance
|
||||
prices as ABSENCE: the ring contributes zero anchors and zero exposure — the offer card's
|
||||
$160 (gutter 90 + rust 45 + gnome 25) deliberately does not name the fence, because "not
|
||||
scored" must never read as "free" and nothing can bend a pool fence yet (bike rule).
|
||||
|
||||
**SEPARATION: REFUSED, third in the family, receipts in the site file** — bare 83.7 FULL
|
||||
vs best flown 92.7 (+9.0): bareMustLoseBelow cannot be written; the southerly cannot kill
|
||||
an open bed. First refusal authored AFTER A's 0.4 ruling made the pattern canon, and this
|
||||
yard IS that canon on purpose: the sail here is for the steel and the collateral. Flagged
|
||||
for B: when the garden-BONUS separation shape lands, this yard's +9.0-at-$40 is a
|
||||
bonus-stake candidate — re-measure then.
|
||||
|
||||
**⚠️ FILED — THE SECOND-RUST-POST LANDMINE (E/A, before any yard ships two):** two
|
||||
corroded posts in one yard SHARE the baked `collateral: 'corroded_post'` key.
|
||||
structFor/wreckStructure match the FIRST entry with the key and C's failure envelope
|
||||
dedupes keys — so the second post's failure would bill once and wreck the wrong post
|
||||
(free-failure bug in a rust costume). The pool yard ships ONE post on purpose and pins it
|
||||
(d.test). A second rung in one yard needs per-instance key plumbing first.
|
||||
|
||||
**PINS (+5, d.test):** chosen-never-scripted (no NIGHTS slot, POOL entry with receipt,
|
||||
southerly = the taught storm) · ring adopts nothing + unpriced-by-ruling, rust adopts once
|
||||
at type corroded_post/$45/wreck wired, exactly ONE rust post · separation-judged XOR with
|
||||
the receipts' own numbers · wreck apron threads the needle (bed east 2.5 ≤ shaft west
|
||||
2.84; shaft east 3.36 ≤ ring west 3.7 — E's +Z 3.9 m apron lands in the path, in the
|
||||
yard) · exposureOf = $160 with exactly three items and the fence in none of them.
|
||||
Cross-lane, flagged (revert-and-tell-me): gardenfly.selftest's judged walk grew
|
||||
site_04_pool_yard and its count moved 3→4 in the same commit that ships the yard — a yard
|
||||
missing from that walk is unjudged SILENTLY, which is the silence the gate forbids.
|
||||
|
||||
**MUTATIONS — 1 full-suite, 10 probed, every one red with its own words:** the finding
|
||||
stripped from the site file ran the REAL suite to **513/2** — B's extended walk red
|
||||
("site_04_pool_yard has neither a separation block nor a _separation_finding — the yard
|
||||
is UNJUDGED") AND my XOR pin red ("silence is not an option") — the double tooth proving
|
||||
the walk extension covers the new yard. Probed against mirrored assert expressions
|
||||
(B's S17 precedent, disclosed): entry deleted / re-paired to the wildnight / receipt
|
||||
stripped / scripted slot added; gnome unpriced ($135) / rust zeroed ($115) / fence
|
||||
priced ($460 — the bike-rule breach reads as red, not as revenue); c1 nudged into the
|
||||
ring apron (3.86 > 3.70) / bed widened under the shaft / c1 falling over the south
|
||||
fence. Controls green on the shipped data.
|
||||
|
||||
[D] 2026-07-21 — 🎮 **GATE 3.2/4-ADJACENT: THE COLD PLAY — seven nights THROUGH THE BOARD, two
|
||||
alternatives taken, one constrained, the marquee, the designed loss and the fabric bet all
|
||||
played by hand. Final tree selftest 515/0/0. The week ends THE WEEK HELD · 7/7 nights ·
|
||||
6/7 gardens · $401 · ★ 0.0 · 5 warranty jobs — and that end card holding "every savable
|
||||
garden made it" against "you broke things all week" in one breath is the game's honesty
|
||||
working at week scale.** Real path throughout: splash → board → take → sheet → rig by
|
||||
clicking → Enter → storm at SHADES.step(1/60) (the repo's own fast-forward) → invoice.
|
||||
Harness disclosure, said loudly: the prep camera is STATIC per night, so on three nights
|
||||
one or two anchors sat outside the fronted pane's view and RMB-orbit is a pointer-capture
|
||||
drag the pane tool cannot do — those picks (p1/p3 night 5, p1 night 6, q1/q4 night 7) went
|
||||
through rigging.session.rig()/setHardware(), the exact calls the click handler makes.
|
||||
Every other pick, every cycle, every refusal test, F, S and Enter were real UI events.
|
||||
|
||||
**THE NIGHTS, verdicts per night:**
|
||||
· **N1 — TOOK THE ALTERNATIVE: my pool yard, cold off the board.** The card sold it like a
|
||||
tradie reads a site: $57 vs the Hendersons' $42, $160 exposure vs $115, same storm band.
|
||||
Flew the gamble line t1,p1,p2,c1 at $65+spare. The rust corner CARRIED it — c1 peaked
|
||||
2.23 of its derated 3.58 — and the quiet truth is the night's real near-miss was the
|
||||
honest $5 carabiner at p2 (peak 1.12/1.2). Every corner held, garden 93 (audit said 92.0
|
||||
flown — played number 1.3 over, same ballpark), +$79, ★3.0→3.5. **Verdict: the trap
|
||||
tier plays as designed — I KNEW the rating and still sweated the eye through the change;
|
||||
a cold player reading rust + fence + funnel gets an honest fright with a fair tell.**
|
||||
· **N2 — spine, southerly × backyard.** Shackles on the post quad, held 4/4, 89, +$81.
|
||||
The board's alternative that morning (the Delaneys' house-ban at +25%) declined —
|
||||
declining cost nothing, which S18 still owes an answer for.
|
||||
· **N3 — spine, earlybuster × corner block.** Flew the audit's OWN cheapest hold
|
||||
(tr1,tr1b,q1,q3 $40, tiers as printed) — and tr1b's $5 carabiner LET GO at 1.17 of 1.2,
|
||||
inside the bench-vs-game under-read MANUAL carries as policy. Garden 88, +$88, but
|
||||
★4.0→3.5. ⚠️ **Filed for B/A: the card called this line CLEAN. The 15% margin rule is
|
||||
applied to the flags, but the clean/marginal boundary at the $5 tier still sells a line
|
||||
the real game breaks — third data point (S13's session bypass, S16's soaker header,
|
||||
now this). Maybe cleanHw should carry the margin policy the flags already know.**
|
||||
· **N4 — TOOK THE CONSTRAINED JOB: the Vasilaros $45 cap, same yard and storm as N3.**
|
||||
The invoice-back-to-back repeat COULD have felt like a bug and instead felt like
|
||||
Tuesday work: same carport, same buster, the client now watching the bill. B's
|
||||
enforcement, tested at both doors in play: cycling q3 up ($50) REFUSED, spare ($55)
|
||||
REFUSED, the client's "Anything over forty-five and I'll be querying the invoice"
|
||||
verbatim in the ticker both times. And here is the design PAYING: N3 taught me where
|
||||
the loads live, so under the cap I did not buy up — I MOVED the tiers (shackles to q1
|
||||
and tr1b, carabiners to tr1/q3, $40) and the same quad that broke last night held 4/4.
|
||||
Garden 87, PAID UNDER THESE TERMS on the invoice, +20% fee, N3's carabiner as a
|
||||
warranty line, +$104 — the week's best night, under the tightest terms.
|
||||
**Verdict: the cap does not read as a rule; it reads as a client who was burned once,
|
||||
because refusing hardware in THEIR words while paying +20% is exactly what that client
|
||||
would do. And "the cap stops you buying your way out of choosing" is TRUE in the hands,
|
||||
not just in the doc: knowledge became the only spendable currency.**
|
||||
· **N5 — spine, THE WILDNIGHT (my gate-0.1 restoration, first full play at seven).** Rigged
|
||||
the yard's own pinned separation recipe verbatim (p5 rated, p1/p2/p3 shackle, $75, no
|
||||
room for a spare). The marquee delivered the canon: p2 blown at the change (3.48/3.2),
|
||||
p3 followed (3.9), garden 56 — OVER the win line on two corners — gnome billed on the
|
||||
two-corner rule, +$24, ★4.0→2.0. "THE GARDEN MADE IT. The sail didn't. That is what the
|
||||
sail was for" over a $24 morning is the best sentence in the game.
|
||||
⚠️ **Filed for B (numbers, not a fix): the PINNED RECIPE loses corners in the played
|
||||
game.** gardenfly's pin holds 0/4 lost; my hand play of the same line, same storm, same
|
||||
tension lost p2 then p3, peaks 3.48/3.90 vs shackle 3.2. Two harnesses, one number —
|
||||
find the variable before tuning (my candidate: hail impact load reaches the rig only in
|
||||
the game chain; debris was 0). Garden-side the pin's INTENT held (56 > 50, bare loses).
|
||||
· **N6 — spine, the icenight, the designed loss.** Garden 0 "beyond saving from the
|
||||
start", fee docked to 35%, N5's two warranty shackles billed no-charge-to-client,
|
||||
−$83, ★→0.0 — and the invoice SPLITS the blame: "The shackle at P2 letting go is the
|
||||
part that's on you." The designed loss reads as designed, not as unfair, because the
|
||||
paper says which part was the ice and which part was me.
|
||||
· **N7 — spine, the soaker, the F key.** $75 ring rated-on-q1, membrane. q2 — the pond
|
||||
corner, the broom's job — let go LATE at 3.32/3.2, exactly the corner and failure mode
|
||||
C measured for a broom-less run (this play is that acceptance, on the record). Garden
|
||||
96 FULL, "held 391 kg of what it stopped. That is the membrane's price", +$28.
|
||||
|
||||
**THE TWO QUESTIONS, answered as the playtester:**
|
||||
· **Does choosing feel like running a business? YES — at the morning table, and it is the
|
||||
strongest new feeling in the game.** Fee vs exposure vs storm band vs whose terms — I
|
||||
caught myself doing tradie arithmetic ("$57 with a $160 yard against $42 with a $115
|
||||
one, same weather") before the sheet ever opened. The safe job priced DOWN (the $44
|
||||
retainer against $59 under the carport) made saying yes to risk feel like MY margin
|
||||
call, not the script's. What does NOT yet feel like a business: saying no. Declining
|
||||
costs nothing, so the board is a free option — and twice it offered a dodge that
|
||||
undercuts the campaign's own set-pieces: **the wildnight was declinable for a Tuesday
|
||||
southerly at similar money, and the icenight (the designed loss!) sat next to a
|
||||
winnable constrained job at the SAME $68.** A fee-maximizer skips the week's two
|
||||
hardest lessons and never knows. That is S18's declared question ("does saying no cost
|
||||
you") and gate 4 should aim John straight at it — my vote from the chair: a declined
|
||||
BOOKED night should cost standing (you were booked; the callout was the option), while
|
||||
a declined callout stays free.
|
||||
· **Does a constraint read as a client or a rule? A CLIENT, cleanly.** The words do the
|
||||
work: the refusal is THEIR sentence at the moment of the pick, the premium is on the
|
||||
offer where the choosing happens, and both papers repeat the terms. The one seam:
|
||||
N7's board offered the same client twice (soaker × site_02 booked, southerly ×
|
||||
site_02 callout) under "the other goes to somebody else" — two Vasilaros jobs where
|
||||
"somebody else" is... the Vasilaros place. Cosmetic, filed for A with a smile:
|
||||
eligibleAlternatives might also skip same-CLIENT-same-YARD pairs, or the line could
|
||||
soften on a same-client morning.
|
||||
|
||||
**Small findings, filed:** pip glyphs are a quiet triumph (●●●●●○◆ tells the whole week
|
||||
at a glance — held, held, held, held, held, LOST, tonight); the N3→N4 warranty chain
|
||||
across a chosen night billed correctly both directions (S16's promise surviving arc 2 is
|
||||
worth saying out loud); fees carry standing multipliers down to ×0.88 at ★0.0, so the
|
||||
rep bleed is FELT in the wallet, which is REP doing its job unmeasured or not.
|
||||
|
||||
[I] 2026-07-21 — **SPRINT 17 (THE BOOK OF CLIENTS, PART 1) INTEGRATION COMPLETE (main).** D's
|
||||
second pass merged fast-forward; selftest **515/0/0** on the final tree (510 part-1 + D's
|
||||
5 pins, the exact sum), verified in the browser. Deployed to partly.party/hardyards.
|
||||
The week is seven nights offered two at a time: THE BOARD every morning, client terms
|
||||
with teeth (the cap refuses in the client's own voice), the charter line on every SCORE
|
||||
IT card, the heal's second wire, the honesty gate over NIGHTS ∪ POOL, and THE POOL YARD
|
||||
— the first yard a player can only reach by choosing it — carrying E's corroded post as
|
||||
exactly the trap-with-a-tell the repo ships.
|
||||
|
||||
**D's cold-play verdicts, the short form:** choosing feels like running a business (the
|
||||
fee-vs-exposure-vs-terms arithmetic at the morning table is the strongest new feeling
|
||||
in the game); a constraint reads as a client, not a rule. The week ran 7/7 stood up,
|
||||
6/7 gardens, $401, ★0.0 with 5 warranty jobs — the ledger keeps every receipt.
|
||||
|
||||
**Filed forward (Sprint 18 seeds, all with live cases attached):** ⚖️ the sharpest —
|
||||
**should declining a BOOKED night cost standing?** The board twice let a fee-maximizer
|
||||
dodge the campaign's own set-pieces (the wildnight for a Tuesday southerly; the
|
||||
designed-loss icenight against a winnable $68) — "does saying no cost you" is no longer
|
||||
hypothetical. For B: the wildnight played-vs-gardenfly recipe disagreement (find the
|
||||
variable; candidate is hail impact load reaching the rig only in-game), and the $5-tier
|
||||
clean-boundary optimism (N3 broke the audit's own "clean" line at 1.17/1.2). For E/A:
|
||||
the second-rust-post landmine (shared collateral key; the yard ships ONE and pins it).
|
||||
For A: N7's same-client double offer reads odd under "the other goes to somebody else".
|
||||
Gate 4 is JOHN'S: partly.party/hardyards — seven nights, the board, the Vasilaros cap,
|
||||
and the Karalis pool yard in the pool. Your three sentences steer Sprint 18.
|
||||
|
||||
@ -119,7 +119,12 @@ export async function buildGardenflyTests() {
|
||||
let sepStates = null, sepStatesErr = null;
|
||||
try {
|
||||
sepStates = [];
|
||||
for (const name of ['backyard_01', 'site_02_corner_block', 'site_03_swing_lawn']) {
|
||||
// SPRINT17 gate 3.2 [D]: site_04_pool_yard added to the judged walk in the
|
||||
// same commit that ships it (B's file, flagged in THREADS, revert-and-tell-
|
||||
// me standard) — a yard missing from this list is UNJUDGED silently, which
|
||||
// is the exact silence the gate-2.3 rule forbids. It carries a refusal
|
||||
// finding (bare 83.7 FULL under its southerly; receipts in the site file).
|
||||
for (const name of ['backyard_01', 'site_02_corner_block', 'site_03_swing_lawn', 'site_04_pool_yard']) {
|
||||
const sd = await loadSite(name);
|
||||
sepStates.push({ name, pinned: !!sd.separation, finding: !!sd._separation_finding });
|
||||
}
|
||||
@ -204,7 +209,7 @@ export async function buildGardenflyTests() {
|
||||
// but silence is not an option, and holding both means the finding went
|
||||
// stale the day the pin landed and must be deleted (its own text says so).
|
||||
if (sepStatesErr) throw new Error(`site read died: ${sepStatesErr}`);
|
||||
assert(sepStates.length === 3, `expected 3 shipped yards, read ${sepStates.length}`);
|
||||
assert(sepStates.length === 4, `expected 4 shipped yards, read ${sepStates.length}`);
|
||||
for (const s of sepStates) {
|
||||
assert(s.pinned || s.finding,
|
||||
`${s.name} has neither a separation block nor a _separation_finding — the yard is UNJUDGED; ` +
|
||||
|
||||
237
web/world/data/sites/site_04_pool_yard.json
Normal file
237
web/world/data/sites/site_04_pool_yard.json
Normal file
@ -0,0 +1,237 @@
|
||||
{
|
||||
"id": "site_04_pool_yard",
|
||||
"name": "The Pool Yard",
|
||||
"blurb": "Fourteen perfect fence posts and not one of them is yours to use. The only steel standing where the shade wants a corner went in before the pool did.",
|
||||
"_design": [
|
||||
"THE YARD WHERE EVERYTHING SAYS NO EXCEPT THE THING THAT SHOULD NOT.",
|
||||
"ROADMAP arc-2 thesis: fence compliance + corroded cheap hardware. The pool ring is",
|
||||
"FOURTEEN honest noes (every post tie_off:false in the GLB — a certified pool barrier",
|
||||
"is not an anchor, at any rating, ever); the corroded post c1 is the one thing that",
|
||||
"DOES adopt on the east side, at 0.55, and it stands exactly where the bed's NE",
|
||||
"corner wants steel. That is not an accident, it is the whole level:",
|
||||
" - the bed is poolside; every 92%-cover quad in the band routes through c1.",
|
||||
" Full shade in this yard has rust in it, or it does not exist (measured, SCORE IT:",
|
||||
" the three 92% lines are t1,p1,p2,c1 / t1,t1b,p2,c1 / t1b,p1,p2,c1 — no others).",
|
||||
" - the honest steel (gum t1/t1b, posts p1,p2,p3, the familiar 0.35 fascia) tops out",
|
||||
" at 58% cover for $40 — the cheap safe rig leaves the bed's pool corner open.",
|
||||
" - c1 is SHAPE-SENSITIVE, and that is the corroded tier working: the same drooped",
|
||||
" eye is clean at $65 rated on t1,p1,p2,c1, and UNHOLDABLE AT ANY PRICE on the two",
|
||||
" quads that pull it harder (t1,t1b,p2,c1 and t1b,p1,p2,c1). You cannot read which",
|
||||
" off the object — E built the rung so you gamble rather than compute (their 0.55",
|
||||
" reasoning, THREADS S17), and this yard is that gamble with a fence around it.",
|
||||
"WIND: the venturi is the channel between the house's east end and the pool enclosure",
|
||||
"— real geometry, gate-side, running N-S (axis 1.571, gain 1.4, r 5, throat (3.1,-3.5)).",
|
||||
"It bites c1 and h3: the two lie-tiers are the two corners in the wind. The wreck",
|
||||
"apron is PAID FOR (E's placement facts): c1 falls +Z ~3.9 m and the shaft lands in",
|
||||
"the path between bed (x<=2.5) and ring (x>=3.7) — clear of both by ~0.3 m each side.",
|
||||
"One corroded post ON PURPOSE: two would share the baked collateral key",
|
||||
"(structFor/wreckStructure match the first entry; C's envelope dedupes keys), so the",
|
||||
"second failure would bill and wreck the wrong post. Filed in THREADS [D] S17 —",
|
||||
"a second rust rung in one yard needs its own key plumbing first."
|
||||
],
|
||||
"_why": [
|
||||
"Authored COLD in the yard editor, SPRINT17 gate 3.2 — palette shapes, editor",
|
||||
"placement, iterative SCORE IT (three passes: 2 quads -> tightened to band -> 13).",
|
||||
"Every number below is the SCORE IT card, storm_03_southerly, FUNNEL ON, 9 dressed",
|
||||
"anchors, export-clone world, 136.5 s flight. Confirmed by audit.html over the saved",
|
||||
"file (same engine, second route) before shipping.",
|
||||
" WINNABLE at $80 — 13 quads in band, 6 clean, 1 marginal.",
|
||||
" cheapest honest line h1,t1b,p2,p3 — $40 hardware (+$15 spare), 45 m2, 58% cover,",
|
||||
" garden 92.7 FULL, +9.0 HP over bare. No rust in it.",
|
||||
" the rust gate full cover exists ONLY through c1 (92% x3, above); cheapest",
|
||||
" clean rust line t1,p1,p2,c1 $65 — corrosion prices as +$25 of",
|
||||
" hardware you must rate UP, plus a $45 stake on a 0.55 eye.",
|
||||
" margin flags c1 4% headroom on h1,h2,p2,c1 (wrecks the corroded post $45);",
|
||||
" p1 2% / t1b 2% / t1 4% — the 15% rule, marginal is not PASS.",
|
||||
" collateral exposure gutter $90 (h1-h3) + corroded post $45 (c1) = $135 from",
|
||||
" anchors; board exposure $160 with the gnome (exposureOf).",
|
||||
" bare bed 83.7 FULL — the southerly cannot kill an open bed (its pea",
|
||||
" hail takes 10.7 HP). The sail here is for the STEEL and the",
|
||||
" collateral, per A's S17 gate-0.4 ruling — which is this",
|
||||
" yard's thesis said as canon."
|
||||
],
|
||||
"yard": {
|
||||
"width": 24,
|
||||
"depth": 16
|
||||
},
|
||||
"sun": {
|
||||
"elevationDeg": 55,
|
||||
"azimuthDeg": -125
|
||||
},
|
||||
"gardenBed": {
|
||||
"x": 0,
|
||||
"z": 1.5,
|
||||
"w": 5,
|
||||
"d": 3.5
|
||||
},
|
||||
"house": {
|
||||
"model": "house_yardside_v1",
|
||||
"wreckedModel": "house_yardside_wrecked_v1",
|
||||
"collateralKey": "gutter",
|
||||
"collateralValue": 90,
|
||||
"collateralLabel": "the gutter",
|
||||
"x": -3,
|
||||
"z": -6,
|
||||
"anchors": [
|
||||
{
|
||||
"id": "h1",
|
||||
"node": "fascia_anchor_01",
|
||||
"type": "house",
|
||||
"work": "bracket"
|
||||
},
|
||||
{
|
||||
"id": "h2",
|
||||
"node": "fascia_anchor_02",
|
||||
"type": "house",
|
||||
"work": "bracket"
|
||||
},
|
||||
{
|
||||
"id": "h3",
|
||||
"node": "fascia_anchor_03",
|
||||
"type": "house",
|
||||
"work": "bracket"
|
||||
}
|
||||
]
|
||||
},
|
||||
"structures": [
|
||||
{
|
||||
"id": "c1",
|
||||
"model": "sail_post_corroded_v1",
|
||||
"wreckedModel": "sail_post_corroded_wrecked_v1",
|
||||
"x": 3.1,
|
||||
"z": -2,
|
||||
"rotYDeg": 0,
|
||||
"solid": true,
|
||||
"collateralKey": "corroded_post",
|
||||
"collateralValue": 45,
|
||||
"collateralLabel": "the corroded post",
|
||||
"anchors": [
|
||||
{
|
||||
"id": "c1_a1",
|
||||
"node": "top_anchor",
|
||||
"type": "corroded_post",
|
||||
"work": "cloth"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "pool",
|
||||
"model": "pool_kit_01_v1",
|
||||
"x": 6.5,
|
||||
"z": 1.5,
|
||||
"rotYDeg": 0,
|
||||
"solid": true,
|
||||
"anchors": []
|
||||
}
|
||||
],
|
||||
"trees": [
|
||||
{
|
||||
"id": "t1",
|
||||
"model": "tree_gum_02_v1",
|
||||
"x": -6.8,
|
||||
"z": 2,
|
||||
"phase": 1.7,
|
||||
"trunkH": 3.8,
|
||||
"anchorY": 3.1,
|
||||
"anchors": [
|
||||
{
|
||||
"id": "t1",
|
||||
"node": "branch_anchor_01",
|
||||
"type": "tree",
|
||||
"work": "cloth"
|
||||
},
|
||||
{
|
||||
"id": "t1b",
|
||||
"node": "branch_anchor_02",
|
||||
"type": "tree",
|
||||
"work": "cloth"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"posts": [
|
||||
{
|
||||
"id": "p1",
|
||||
"x": -3.4,
|
||||
"z": 4.6,
|
||||
"h": 4,
|
||||
"type": "post",
|
||||
"work": "cloth"
|
||||
},
|
||||
{
|
||||
"id": "p2",
|
||||
"x": 3.4,
|
||||
"z": 4.6,
|
||||
"h": 4,
|
||||
"type": "post",
|
||||
"work": "cloth"
|
||||
},
|
||||
{
|
||||
"id": "p3",
|
||||
"x": -5.8,
|
||||
"z": -1.5,
|
||||
"h": 4,
|
||||
"type": "post",
|
||||
"work": "cloth"
|
||||
}
|
||||
],
|
||||
"fence": {
|
||||
"sides": [
|
||||
"north",
|
||||
"south",
|
||||
"east",
|
||||
"west"
|
||||
]
|
||||
},
|
||||
"shed": {
|
||||
"model": "shed_01_v1",
|
||||
"x": -9.5,
|
||||
"z": -5.5,
|
||||
"rotYDeg": -90
|
||||
},
|
||||
"shedTable": {
|
||||
"model": "shed_table_v1",
|
||||
"x": -6.5,
|
||||
"z": 7,
|
||||
"rotYDeg": -90,
|
||||
"pickupNode": "pickup_anchor"
|
||||
},
|
||||
"gnome": {
|
||||
"model": "garden_gnome_01_v1",
|
||||
"x": 4.6,
|
||||
"z": 4.4,
|
||||
"rotYDeg": 0,
|
||||
"collateralValue": 25
|
||||
},
|
||||
"wind": {
|
||||
"_venturi": [
|
||||
"The pool-terrace channel: house east end to pool enclosure, gate side, running N-S.",
|
||||
"Axis 1.571 is the channel's GEOMETRY (a line, mod pi — site_02's reconciled lesson),",
|
||||
"not a storm heading. Gain 1.4 / r 5 puts c1 (1.4 m off-throat) and h3 (3.7 m) in the",
|
||||
"wind: the corroded post is the venturi post, which is the temptation priced."
|
||||
],
|
||||
"venturi": [
|
||||
{
|
||||
"x": 3.1,
|
||||
"z": -3.5,
|
||||
"axis": 1.571,
|
||||
"gain": 1.4,
|
||||
"radius": 5,
|
||||
"sharp": 3
|
||||
}
|
||||
]
|
||||
},
|
||||
"_separation_finding": [
|
||||
"SPRINT17 gate 3.2 [D] — a separation pin was ATTEMPTED and honestly REFUSED, the",
|
||||
"third refusal in the family (site_02, site_03, now here) and the first authored",
|
||||
"AFTER A's gate-0.4 ruling made the pattern canon. Measured (SCORE IT, funnel ON,",
|
||||
"storm_03_southerly, 2026-07-21): bare bed 83.7 FULL (hail 10.7 + rain 5.6 HP);",
|
||||
"best flown 92.7 FULL (h1,t1b,p2,p3, $40); best gain +9.0 HP. bareMustLoseBelow",
|
||||
"cannot be written at any threshold — bare WINS the night by 33.7 over the win",
|
||||
"line. On this night the sail is for the steel and the collateral (A, S17 0.4,",
|
||||
"ruled canon, taught by the board's exposure line): what c1 separates is not the",
|
||||
"bed from the hail but $45 and your margin from your greed. When B's garden-BONUS",
|
||||
"separation shape lands (A ruled FOR it, deferred to its own gate), re-measure —",
|
||||
"this yard's +9.0 over bare at $40 is a bonus-stake candidate, not a win/lose one."
|
||||
]
|
||||
}
|
||||
@ -240,6 +240,29 @@ export const POOL = [
|
||||
+ 'working, it stops you buying your way out of choosing. The carport at $180 is the '
|
||||
+ 'tension — the rig this cap pushes you toward is the one with the least margin over it.',
|
||||
},
|
||||
{
|
||||
// SPRINT17 gate 3.2 [D] — THE POOL YARD. The first yard whose ONLY route
|
||||
// into the game is being chosen: it is in no NIGHTS slot, so declining it
|
||||
// forever is a complete campaign. That is the arc-2 promise made literal,
|
||||
// and it is why the entry lives here and not in week.js.
|
||||
id: 'pool_yard_southerly',
|
||||
storm: 'storm_03_southerly', site: 'site_04_pool_yard',
|
||||
client: 'the Karalis place', addr: '5 Clearwater Ct — the pool yard',
|
||||
brief: 'New pool, new fence, certified in March — and the certifier is back Thursday, so '
|
||||
+ 'nothing touches that fence. Not a rope, not a clamp. The old sail post from before '
|
||||
+ 'the pool went in is still standing, they say, and they say it like a selling point. '
|
||||
+ 'It has been breathing pool air for years. Tuesday\'s southerly, the bed\'s by the water.',
|
||||
_why: 'AUTHORED COLD + AUDITED (D, S17 gate 3.2 — SCORE IT card, funnel ON, confirmed by '
|
||||
+ 'audit.html over the shipped file): 13 quads in band, 6 clean, 1 marginal; cheapest '
|
||||
+ 'hold $40 (h1,t1b,p2,p3 → garden 92.7 FULL, 58% cover, no rust in it). The trap is '
|
||||
+ 'priced, not padded: every 92%-cover line routes through the corroded post c1 (0.55, '
|
||||
+ '$45 collateral, IN the venturi) — clean at $65 rated on t1,p1,p2,c1, UNHOLDABLE on '
|
||||
+ 'the two shapes that pull the eye harder. Southerly = the storm nights 2 and 4 teach; '
|
||||
+ 'the yard is the only new variable (one-variable law). Separation REFUSED with '
|
||||
+ 'receipts in the site file (bare 83.7 FULL — mild-night canon per A\'s 0.4 ruling); '
|
||||
+ 'exposure $160 (gutter 90 + corroded post 45 + gnome 25), the fence\'s fourteen '
|
||||
+ 'posts deliberately absent from that number because none of them can be tied to.',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
|
||||
@ -24,6 +24,13 @@ import { loadStorm, createWind } from '../weather.js';
|
||||
// file read the ladder. week.js is contracts-only underneath, so this stays
|
||||
// headless-safe.
|
||||
import { NIGHTS, nightAt } from '../week.js';
|
||||
// SPRINT17 gate 3.2: the pool-yard pins at the bottom read the board's POOL
|
||||
// (pure data, zero THREE) and loadSite (fetch + validateSite — the teeth; a
|
||||
// site file this suite merely fetch()ed raw could rot invalid and stay green).
|
||||
// loadSite pulls world.js which pulls THREE — browser-only, same as the GLB
|
||||
// facts everywhere else in this repo; the node runner never imports this file.
|
||||
import { POOL, exposureOf } from '../board.js';
|
||||
import { loadSite } from '../world.js';
|
||||
|
||||
const DT = FIXED_DT;
|
||||
|
||||
@ -1229,4 +1236,96 @@ export default async function run(t) {
|
||||
"the wildnight sits directly before the icenight — the icenight's brief says 'less wind than "
|
||||
+ "last night', and the paper never lies: re-order these and re-word that brief in the same commit");
|
||||
});
|
||||
|
||||
// ── SPRINT17 gate 3.2: THE POOL YARD — authored cold, entered through the ──
|
||||
// board, pinned by its author. These pins carry the yard's three claims:
|
||||
// it is CHOSEN or absent (never scripted), its fence is fourteen honest noes
|
||||
// and its rust is one priced yes, and its refusal + wreck apron are facts
|
||||
// with numbers, not vibes. The site file itself goes through loadSite here,
|
||||
// so a hand-edit that breaks validateSite goes red in THIS suite too, not
|
||||
// only at boot.
|
||||
let poolSite = null, poolSiteErr = null;
|
||||
try { poolSite = await loadSite('site_04_pool_yard'); }
|
||||
catch (err) { poolSiteErr = String((err && err.stack) || err); }
|
||||
|
||||
t.test('pool yard (S17 3.2): in the game ONLY through the board — chosen, never scripted', () => {
|
||||
const entry = POOL.find((p) => p.site === 'site_04_pool_yard');
|
||||
assert(entry, 'the pool yard has a POOL entry — its one door into the game');
|
||||
assertEq(entry.storm, 'storm_03_southerly',
|
||||
'it flies the southerly — the storm nights 2 and 4 teach, so the yard is the only new variable; '
|
||||
+ 'any other pairing needs its own gauntlet run FIRST (the _why receipt describes this one)');
|
||||
assert(entry._why && entry._why.includes('audit'),
|
||||
'the entry carries its audit receipt — an unmeasured pairing is a night the board is guessing about');
|
||||
const scripted = NIGHTS.map((_, i) => nightAt(i));
|
||||
assert(!scripted.some((n) => n.site === 'site_04_pool_yard'),
|
||||
'NO scripted night flies the pool yard — "the first yard whose only route in is being chosen" '
|
||||
+ 'is the arc-2 promise, and a week.js slot would quietly break it');
|
||||
});
|
||||
|
||||
t.test('pool yard (S17 3.2): the ring says no fourteen times, the rust says yes once', () => {
|
||||
if (poolSiteErr) throw new Error(`site load died: ${poolSiteErr}`);
|
||||
const ring = poolSite.structures.find((s) => s.model === 'pool_kit_01_v1');
|
||||
assert(ring, 'the pool ring is in the yard — it IS the thesis');
|
||||
assertEq((ring.anchors ?? []).length, 0,
|
||||
'the ring adopts NOTHING in site data — its fourteen noes are baked tie_off:false in the GLB, '
|
||||
+ 'and a site-level anchor here would override a certified fence into steel');
|
||||
assert(ring.collateralValue == null,
|
||||
'the ring is unpriced BY RULING (the bike rule) — nothing can bend a pool fence yet');
|
||||
const rust = poolSite.structures.find((s) => s.model === 'sail_post_corroded_v1');
|
||||
assert(rust, 'the corroded post stands');
|
||||
assertEq((rust.anchors ?? []).length, 1, 'exactly one adoptable eye');
|
||||
assertEq(rust.anchors[0].type, 'corroded_post', 'typed to E\'s tier so it rates 0.55, not 1.00');
|
||||
assertEq(rust.collateralValue, 45, 'the make-safe bill, E\'s number, adopted with its reasoning');
|
||||
assert(rust.wreckedModel === 'sail_post_corroded_wrecked_v1',
|
||||
'the wreck variant is wired — a trap that vanishes instead of falling is a free failure');
|
||||
const rusts = poolSite.structures.filter((s) => s.model === 'sail_post_corroded_v1');
|
||||
assertEq(rusts.length, 1,
|
||||
'ONE corroded post on purpose: two would share the baked collateral key and the second failure '
|
||||
+ 'would bill/wreck the wrong one (structFor matches first; filed in THREADS [D] S17)');
|
||||
});
|
||||
|
||||
t.test('pool yard (S17 3.2): separation-JUDGED — refused with receipts, XOR the pin', () => {
|
||||
if (poolSiteErr) throw new Error(`site load died: ${poolSiteErr}`);
|
||||
const pinned = !!poolSite.separation, finding = !!poolSite._separation_finding;
|
||||
assert(pinned || finding, 'the yard is JUDGED — silence is not an option (S16 gate 2.3)');
|
||||
assert(!(pinned && finding), 'both at once means the finding went stale in the pinning commit');
|
||||
assert(finding, 'today it is a REFUSAL: bare wins the southerly (mild-night canon, A\'s 0.4 ruling)');
|
||||
const text = poolSite._separation_finding.join(' ');
|
||||
assert(text.includes('83.7') && text.includes('92.7'),
|
||||
'the refusal carries its measured receipts (bare 83.7 / best flown 92.7) — a finding without '
|
||||
+ 'numbers is a shrug wearing a ruling\'s clothes');
|
||||
});
|
||||
|
||||
t.test('pool yard (S17 3.2): the wreck apron threads the needle between bed and ring', () => {
|
||||
if (poolSiteErr) throw new Error(`site load died: ${poolSiteErr}`);
|
||||
// E's placement facts (THREADS S17 gate 3.1): the corroded post falls +Z
|
||||
// ~3.9 m, shaft half-width ~0.26 m. The fallen shaft must land in the path
|
||||
// — clear of the bed's east edge AND the ring's west run — or the wreck
|
||||
// interpenetrates client property the moment the trap fires.
|
||||
const rust = poolSite.structures.find((s) => s.model === 'sail_post_corroded_v1');
|
||||
const ring = poolSite.structures.find((s) => s.model === 'pool_kit_01_v1');
|
||||
const bedEast = poolSite.gardenBed.x + poolSite.gardenBed.w / 2;
|
||||
const shaftWest = rust.x - 0.26, shaftEast = rust.x + 0.26;
|
||||
const ringWest = ring.x - 2.8; // ring proper 5.6 wide (E's measured bbox)
|
||||
assert(bedEast <= shaftWest,
|
||||
`bed east edge ${bedEast} overlaps the fallen shaft (west ${shaftWest.toFixed(2)}) — move c1 or the bed`);
|
||||
assert(shaftEast <= ringWest,
|
||||
`fallen shaft east ${shaftEast.toFixed(2)} reaches the ring (west ${ringWest.toFixed(2)}) — move c1 or the pool`);
|
||||
const apronTip = rust.z + 3.9;
|
||||
assert(apronTip <= poolSite.yard.depth / 2,
|
||||
`the shaft falls past the south fence (tip z ${apronTip}) — it must land IN the yard, that is the point`);
|
||||
});
|
||||
|
||||
t.test('pool yard (S17 3.2): the offer card prices the rust and never the fence', () => {
|
||||
if (poolSiteErr) throw new Error(`site load died: ${poolSiteErr}`);
|
||||
const { total, items } = exposureOf(poolSite);
|
||||
assertEq(total, 160, 'exposure $160 = gutter 90 + corroded post 45 + gnome 25');
|
||||
const labels = items.map((i) => i.what).sort().join(' · ');
|
||||
assertEq(labels, 'garden gnome · the corroded post · the gutter',
|
||||
'three priced items exactly — the fourteen fence posts are deliberately NOT exposure: '
|
||||
+ 'nothing can bend a pool fence yet (the bike rule), and a $0 line item would teach "free"');
|
||||
const rustItem = items.find((i) => i.what === 'the corroded post');
|
||||
assertEq(rustItem.cost, 45,
|
||||
'the rust is the cheapest structure you can break — the stake E sized the gamble in');
|
||||
});
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user