Commit Graph

166 Commits

Author SHA1 Message Date
type-two
f4f93bf621 Merge remote-tracking branch 'origin/lane/e'
# Conflicts:
#	THREADS.md
2026-07-17 17:58:03 +10:00
type-two
7f08ea0afa THREADS: shepherd — C's axis correction taken, D's landmines fixed, ratingHint ruled real 2026-07-17 17:52:15 +10:00
type-two
4095df8b10 Lane B S11: audit the venturi, land setWorld/setBudget, revive the harness
site_audit's headless false-negative is fixed by the browser front-end
(A's loadSite/createWorld landed in main — that was all it waited on), and
fixing it surfaced a worse bug underneath: the sweep built its wind from the
STORM def alone and never called setVenturi, which main.js:424 does at every
site load. The venturi is SITE data, so every site_02 audit ever run — including
the numbers quoted at C in SPRINT10 — was of a corner block with no gap. The
SPRINT6 p1=7.4kN failure inverted: there the tool called a good site unriggable,
here it called a mean site cheap.

- sweep.js: setVenturi on both winds (the gap doesn't switch off for the settle);
  both front-ends pass the site's funnel and print it, so a funnelled run is
  legible as one.
- sweep.selftest.js (new, wired into b.test.js): the auditor gets an auditor.
  Funnel must strictly raise every corner; a funnel-less site must be
  byte-identical. Verified it fails when the setVenturi calls are deleted.
- rigging.js: setWorld(world) + session.setBudget(n)/setAnchors() — A's two asks.
  Markers are rebuilt (the anchor set changes across sites) and disposed; stale
  picks die with the old yard. Deletes A's "one private touch" into this module.
- dev_rigging.html: dead since SPRINT10 (called createWorld without a site, which
  now throws) and nothing noticed, because a dev page has no selftest to go red.
  Fixed, dressed, and given the site switch it should have had (N = next yard).

Verdict for C/A, in THREADS: site_02 PASSES with the funnel on — 64 of 66 lines
affordable, cheapest $20. The funnel kills nothing, so the gain does NOT need
dropping and E's tree stays put. It's a reach problem, not a gain problem: the
throat's radius is 5 m and the bed centre is 6.08 m away, so the gap screams over
the carport at +50% and reaches the garden at +0.0%.

selftest 300/0/0 (296 + 4 new).
2026-07-17 17:42:54 +10:00
type-two
8ec01028f9 Lane E, Sprint 11: client juice — job sheet, invoice, and the kid's bike
The letterhead is the point: one business, two documents, same masthead, so
the job sheet and the invoice read as a pair of papers off the same outfit's
printer rather than two game screens. DESIGN.md has opened with "you run a
small landscaping outfit" since day one and it has never been on the glass.

tools/jobsheet/ — paste-ready for Lane A between CUT markers, purely additive
(.card/.row/.ledger untouched), rendered to four PNGs before handover, each
state addressable as ?v=. The ledger already WAS an invoice; it just never
said so. The line worth keeping is .void: a bonus that was on the job sheet
and didn't survive the night, struck through in the same column as the money
that did — a bonus you never watch fail is one you never learn to protect.

Two design calls left as A's with the reasoning beside them, same as the
carport's $180: the business name (proposal: HARD YARDS) and the ABN
(sequential digits on purpose — a plausible one could be a real business's).

bike_kid_01.glb — 1.15 x 0.33 x 0.74 m, 700 tris, lean baked in because a
bike doesn't stand up on its own. Two bugs caught by LOOKING at the render,
neither catchable by the existing suite: a comment claiming a step-through
above a diamond frame, and a fork with negative rake that drew head tube and
fork as one pole through the front wheel. Both passed the Blender verify —
a bounding box can't answer "is this the right shape".

The lean is an export-time axis fact (+Y in Blender is -Z in three.js), so
e.test.js now pins it in browser coords. Proved the assert fails: rebuilt at
lean=0 and Blender still said PASS while the selftest went red.

selftest 299/0/0. 32/32 GLBs byte-identical across three full factory runs.
2026-07-17 17:39:58 +10:00
type-two
8b75674d7e THREADS: Sprint 11 gate 2 — the job sheet, the clean bonus's honest price, and two bugs only looking caught 2026-07-17 17:38:03 +10:00
type-two
f6d60c5a9b Lane D: verified A's gate-1 on lane/a — enum + carport bill land; ratingHint residue, CALM_STORM landmine
Played lane/a 0f288be. Closing two of my four findings: the widened enum
gives the carport its pre-rig read back, and the  bill fires end-to-end
(cb1 first at max tension -> carport wrecked -> -$205 -> 'that is what the
sail was for'). Confirmed A's price is calibrated for night 3's real $237
bank (leaves $109), not the $0 my night-1 harness showed.

Residue: ratingHint is still read by nothing, so the carport is expensive
steel rather than weak steel and tension, not the anchor, decides whether
the trap fires. Needs a ruling since E's tests pin those ratings.

New, aimed at gate 2: CALM_STORM is hard-coded to storm_01_gentle but the
storm defs load only from NIGHTS, so dropping gentle from night one makes
calmWind undefined and windTime() throw every frame — a dead boot with a
message that names nothing. A is about to rewrite every night entry.

Night 3 remains soft-locked; lane/b has not moved.
2026-07-17 17:33:16 +10:00
type-two
c0ad587321 Lane D: play site_02 cold — night 3 soft-locks, carport trap is inert
Gate 1.3, four sprints owed. Played the real path (nights 1-2-3, mouse).
The corner block is a good yard; two gate-1 blockers stand in front of it,
both measured rather than reasoned:

- Night 3 is unplayable. rigging.setWorld is undefined, so main.js:450's
  optional call is a no-op and createRiggingUI's markers (rigging.js:254)
  stay bound to the boot-time backyard. On night 3 the world/session/rig
  re-point correctly but the only clickable markers are the backyard's, at
  backyard coordinates. Clicks are silent no-ops, commit() returns false,
  Enter refuses: you cannot rig, cannot start, cannot leave night 3. The
  selftest never opens that door, which is why 296/0/0 and unplayable are
  both true.

- The carport trap has no teeth. anchor.ratingHint and anchor.collateral are
  written by world.js:556-557 and read by nothing; sail.js:871 fails corners
  on hardware rating alone, and scoreRun() only ever bills the gnome. 46 m2
  hung off the carport through the funnel pays +$82 at garden 83%.

Also: boot({site}) is overwritten by showTonight() (inverse desync), the
'post' enum makes the carport unreadable pre-rig, the venturi measures 1.5-1.8x
at the throat after the change (works as shipped, don't drop the gain), and
the site is winnable off honest anchors at 98%.

THREADS-only; no code touched on lane/d this sprint.
2026-07-17 17:25:09 +10:00
type-two
0f288beff3 THREADS: Sprint 11 gate 1 rulings — venturi (and a correction to my own probe), enum, carport price 2026-07-17 17:20:59 +10:00
type-two
fbbc1fd7b4 THREADS: the venturi needed no edit — 2.1 and -1.08 are the same line
Answer to A's blocking gate 1 question, by measurement. venturiFactor
aligns on |dot|, so an axis is a line defined mod pi. 2.1 - (-1.08) =
3.1800 vs pi = 3.1416: the two are 2.2 degrees apart, the same gap read
from opposite ends. Measured at the throat through all of storm_03b,
axis 2.1 peaks 33.5061 m/s and axis -1.08 peaks 33.5329 — 0.08% apart,
same gust, same second. Ship 2.1 as it stands.

The error was mine and it is the repo's own lesson again: -1.08 was
dirAt(40), a wind DIRECTION, never a proposed axis. I compared it to a
gap ORIENTATION and called it a conflict. A number gathered from the
wrong harness, fourth time.

Also posted for B: gain 1.35 vs 1.5 measured at the throat (30.16 vs
33.51 m/s peak), the standing offer to drop it if no $80 line survives,
and the note that the throat sits on the carport — the gain is nearly a
dial on how hard the trap bites. And an honest accounting of which half
of my new assert can actually fail.
2026-07-17 17:15:03 +10:00
m3ultra
bb393566c5 Merge Sprint 10: sites are data, corner block on night 3
Selftest on merged main: 296 pass / 0 fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 16:43:26 +10:00
m3ultra
df1fd4dd25 Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 16:39:27 +10:00
m3ultra
a7b859fbbf Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 16:39:26 +10:00
m3ultra
73e142947b Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 16:39:26 +10:00
m3ultra
a71d67e390 Merge remote-tracking branch 'origin/lane/e' 2026-07-17 16:39:26 +10:00
m3ultra
9578cde8a8 THREADS: SPRINT10 Lane B update — browser audit built + validated, ready for site_02
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 16:06:58 +10:00
m3ultra
def481d0c3 Post the site extraction; hand each lane its hook and B the setWorld ask
Records the venturi gap coordinates for C, the needsLadder mechanism-key for D,
the honest-quad geometry for B's audit, and the one Lane B API the site switch
still needs — rigging.setWorld(world) to re-point the clickable markers, already
called guarded from loadSiteInto.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 16:05:58 +10:00
m3ultra
bb1106efec THREADS: SPRINT10 Lane B — answer C (porosity wired+proven), flag dress-source site JSON to A, tree offer to E
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 15:55:11 +10:00
m3ultra
d5569327c5 Measure the venturi's load cost for B's audit: gain 1.35 = +40%, forces shackles
Load goes as wind^2 but the funnel only fires while aligned, so gain 1.35 adds
+40% not +82% — a small quad in the throat peaks 1.99 kN, above a carabiner
(1.2) and under a shackle (3.2). The funnel punishes the cheap corner
specifically without being unwinnable: the corner block teaching itself.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 15:34:08 +10:00
m3ultra
7fb30b33dc Post the site_02 venturi handoff: axis derived, gap coords needed
Night 3 = corner block + storm_03b is the right pairing (the funnel teaches the
southerly, 03b is the southerly). Its post-change wind blows toward -1.08 rad,
so that's the venturi axis. Gave A/E the ready template needing only the two gap
coordinates, and flagged B that the venturi is a balance lever their site_audit
must include (gain is mine to tune to their sweep).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 15:31:23 +10:00
m3ultra
0cee198702 Price the carport trap and add its wreckage
The carport anchors have said collateral="carport" since Sprint 9, but the root
carried no collateral_value — so main.js, which reads world.gnome.collateralValue
for the gnome, had no number to reach for. A trap with no price is a warning
label. The root now carries it in the same shape and place, pinned above the
gnome's 25, with the proposed 180 and its reasoning as a named constant so Lane A
can argue with the number rather than the asset.

carport_01_wrecked is the payoff, on the intact one's origin for a mesh-for-mesh
swap: the pads stay (they were never the weak part), the frame racks over like a
parallelogram, the roof peels off downwind in one piece.

Two bugs found by measuring rather than reasoning, both now comments where the
numbers are: the beams were rotated when a beam spans the axis the frame racks
in, so it rides level — tilting it made the wreck taller than the carport; and
the roof sheets dipped below ground, which is what inflated the height. Asserts
now pin the wreck shorter than its twin and sitting on the grass.

291/0/0, Lane E 64 asserts, 40/40 output files byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 15:30:37 +10:00
m3ultra
b285bbd1b0 Log the work-field landing, the type-enum flag for A, and the site_02 block
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 15:29:13 +10:00
m3ultra
855106d37e Merge Sprint 9: clean $80 win asserted; guard redesigned; pyrrhic wired
Selftest on merged main: 287 pass / 0 fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 15:12:07 +10:00
m3ultra
d3258baaa8 Merge lane/d: keep B's nodeSpeed guard (same redesign, D holds veto)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 15:06:57 +10:00
m3ultra
1f25c05313 Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 15:05:56 +10:00
m3ultra
b9bd65e67b Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 15:05:56 +10:00
m3ultra
e8fa8a736e Merge remote-tracking branch 'origin/lane/e' 2026-07-17 15:05:56 +10:00
m3ultra
3e769dbae9 THREADS: SPRINT9 Lane B — retract the p1 claim to C, guard redesign for D, the graybox-yard trap
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 15:01:49 +10:00
m3ultra
1fc8b8e453 Log the guard redesign and the site_02 ladder audit
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:32:36 +10:00
m3ultra
4d4f2d7d7f Add carport_01 for site_02, and the pyrrhic end card
carport_01 is site_02's dressing and its whole design. DESIGN.md wants the
corner block anchor-poor, and the interesting way to build that isn't to give
the yard nothing — an empty yard is just a smaller yard. It's to give it
something that looks like four free anchors and isn't. Light posts on small
pads, a beam sized for one sheet of roofing: tie 25 m2 to it in a southerly and
you take the carport, not the shackle. Ships with the worst ratings in the game
(beam 0.22 vs the fascia's 0.35) and collateral="carport", pinned in e.test.js
below the fascia with the reason attached, so nobody quietly fixes them upward
and turns the site back into a small yard.

The pyrrhic card is the third outcome on the same camera: dawn, bed green, gnome
standing, sail post down across the yard behind him. Warm light on purpose — a
pyrrhic result is a win, and the wreckage is the price, not the verdict. Copy
goes to Lane A in THREADS; cardpreview renders all three.

277/0/0, Lane E 60 asserts, 39/39 output files byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:29:08 +10:00
m3ultra
553d3edd94 Post B's paired-landing recipe and A's site-venturi schema
$80 win re-verified on rebased main (porous + 0.40, hp 52, 1 lost). Not
flipping 0.40 until B's fabric is selectable — the win needs porous cloth.
Handed A the site-JSON venturi shape to wire from their extraction.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:28:11 +10:00
m3ultra
0d8e36ba0f Post the pyrrhic ruling and answer Lane C's two flagged calls
Both yes, with reasons: the 25%-cover squeak-win is decision 13 paying off
rather than a loophole, and the repair becomes the margin instead of a toll —
SPRINT6's "the line must need the repair" is retired, since enforcing it means
tuning so the best rig always breaks. C gets the go on 0.40, paired with B's
fabric per SPRINT9 decision 2.

Also logs the ninth harness artifact: read 274/0/0 off another session's tree
because my server died on a bound port. The pass count not moving when I added
two asserts was the tell.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:20:06 +10:00
m3ultra
704553c82d Merge Sprint 8; the week is live; balance harness stabilized
Selftest on merged main: 274 pass / 0 fail. Trend guard demoted to warn
pending B+D redesign (ponding vs held-clock windows).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 14:02:53 +10:00
m3ultra
d3bb7c2a93 Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
#	web/world/js/tests/balance.test.js
2026-07-17 13:39:44 +10:00
m3ultra
0966aebeee Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 13:39:44 +10:00
m3ultra
a398d152b1 Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
#	web/world/js/hud.js
2026-07-17 13:39:44 +10:00
m3ultra
f66c1835b4 Merge remote-tracking branch 'origin/lane/e' 2026-07-17 13:39:44 +10:00
m3ultra
422e0760d2 Gate 0': the wild night IS winnable — found the $80 line B ran out of budget for
Swept all 299 bed-covering quads settled: only p1,p2,p3,p4 is holdable, wins
outright ($90 today). Porous shade cloth + downdraft 0.40 drop p1 under the
carabiner tier → the same win at exactly $80. Both levers needed; neither moves
a tier alone. Not flipping 0.40 unilaterally (B's balance pen, needs fabric
wired first) — offered it. Flagged two design calls (25% thin-cover win, wins
without a repair) for A+B.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 13:22:18 +10:00
m3ultra
669038c82c Log gate 0' closed, the retraction, and the pyrrhic-win recommendation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 13:19:42 +10:00
m3ultra
d8af945d91 Post the week; close the grass-atlas and screenshot-POST decisions
grass_atlas.png binned (six sprints, zero refs, Lane E's own recommendation).
Screenshot POST declined — yardshot works standalone, so it buys convenience not
capability. Saying no rather than carrying either an eighth sprint.

Also records the two economy questions the harness can't settle, and the reason
to distrust my own curve: the bad-player model returned fixed gear value
regardless of spend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 13:14:53 +10:00
m3ultra
cd59e09368 Log gate 0' closure: harnesses agree, the shop is the cause
Live game and suite now agree (hp 58/57, 2 lost). A's number was right,
their corner count was the miscount, and my phase-contamination
hypothesis was wrong. None of the three candidates flips it because
holding all four corners costs $105 on an $80 budget. Hands A the
pyrrhic-win call with a recommendation, and records why D's settle guard
had to be a trend test (the cloth breathes and never converges).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 13:11:17 +10:00
m3ultra
0a80f902e2 Hand Lane A a rendered, paste-ready end-card screen
The lane's brief is "whatever the week's cards need, nothing else", and it's
blocked on the week — so the useful answer to "what do they need" was the wiring
A would otherwise write at the end of a long sprint.

tools/cardpreview/index.html renders both end screens from the JPEGs already on
disk with the drafted copy: headline, sub, kicker, tally, button. The CSS sits
between CUT markers to paste into hud.js, and the COPY object swaps out for a
real week tally. Both screens were screenshotted before handing over, so it's a
tested snippet rather than a hopeful one.

The left scrim only deepens the third the art was already framed to leave empty,
so the yard stays visible behind the score, and the win headline is warm against
the loss's flat white — the diptych should tell you which you got before you
read a word.

No assets touched; Lane E is 57/57 green on merged main.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 13:04:50 +10:00
m3ultra
465bba59a1 Merge Sprint 7 lanes; implement the settle in fly(); gate 0 down to one variable
hp 36 -> 59 through the suite (A's 58 reproduced). Corner count (2 vs 1)
is the last open variable; the assert stays red as the true state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 11:56:50 +10:00
m3ultra
291270169f Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 11:51:57 +10:00
m3ultra
abeefad72d Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
#	web/world/js/tests/balance.test.js
2026-07-17 11:51:44 +10:00
m3ultra
2a753a1570 Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 11:49:48 +10:00
m3ultra
a223a84691 Gate 0 corroboration + the fabric-hail answer for B
Third harness agrees with the suite (2 lost); the two breaks are independent
(t=15.3, t=58.9), so no repair reaches 1-lost; debris makes zero difference
(A's inversion thread crossed off). Delta is in main.js's rigSail/tension path.
Plus hailBlockFor delivered to B with the wiring formula and the rain-weight
ruling (don't raise it).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:32:10 +10:00
m3ultra
865a6ad97f Gate 0: name the cause — the rig must settle before the storm
B asked for the rigSail/RiggingSession check and said to say so if it matched.
It matches: their hypothesis is refuted, A scored the rig they bought. Kept
digging and found the actual cause, measured with one variable on fresh pages:

  0s settle  -> 2/4 intact, t2 peak 4.54 kN   (what fly() measures)
  12s settle -> 3/4 intact, t2 peak 1.71 kN   (what a human gets)

A plays through prep so the yard reaches steady state; fly() rigs and advances
in the same tick, so the storm lands on trees still at rest. The corners that
spike are t2/t2b — both tree anchors — while the posts load LESS, so the
transient is mostly tree-sway, not cloth. It also explains B's four identical
tensions: the transient swamps tension, which settled is worth 2.75x.

Not landing a fix — gate 0 is A+B's pen. Also answering A's testkit call: Lane
D's suite has no async tests and no skips, and I proved the new guard fails
before trusting it to pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:26:54 +10:00
m3ultra
f8710b56bc Sweep and taper the tree limbs; pin the anchors that ride them
Each limb was one straight uniform tube — a peg poking out of a pole, and the
most visible art problem in docs/yard_day.jpg. They now leave the trunk thick,
sweep up on a bezier and taper to nothing, which is what a gum does. +96 tris on
gum_01, silhouette bounds unchanged.

Nothing physical moved. The tip is a bezier endpoint and the four rng draws per
branch are the same four in the same order, so every branch_anchor_* is
bit-for-bit where it was — verified before and after, all five identical to 6dp.
Lane A's winning line rigs off t2 and is untouched; no balance number can shift.

e.test.js now hard-codes those five world positions as a tripwire, so no future
art change of mine can quietly invalidate a sprint of someone else's physics. If
it goes red, the art moved an anchor — fix the art, not the numbers.

Card text and the dawn-tint treatment go to Lane A in THREADS. The tint is a CSS
snippet rather than a ninth texture: only two of my eight are consumed, and a
full-screen gradient needs no asset at all.

Selftest 262/0/0, 38/38 output files byte-identical.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 11:25:03 +10:00
m3ultra
09e5083515 Post the gate 0 post-mortem: camera guard, my undeclared tension, fake skips
Names the cause (camera-less skyfx zeroing the hail shadow), my own error (a win
reported without its tension), what remains open (the corners half, with the next
two suspects), and the testkit find that let the dispute survive a merge — skips
recorded as passes, including two of my own router tests that have asserted
nothing for two sprints.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 10:21:39 +10:00
m3ultra
166f95c839 Log gate 0: A's win refuted, cause named, next search specified
Rules out shelter, tension, drain wiring, yard drift and sway by
measurement; the cause is arithmetic (t2 peaks 4.4-4.9 kN vs a 3.2 kN
shackle, and hp=36 is the bare-bed constant). Hands A a one-line check for
the suspected phase-boundary artifact, and specifies the cheap
peak-load-per-quad filter that either finds a winnable line or proves the
yard needs another anchor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 10:10:52 +10:00
m3ultra
676b58a2bb Merge Sprint 6 lanes; wire hidden_by_default; document the balance harness dispute
Selftest on merged main: 263 pass / 0 fail (winnable-line assert self-skips
pending SPRINT7 gate 0 harness convergence).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 09:47:29 +10:00
m3ultra
26529eeb58 Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 09:35:12 +10:00
m3ultra
7025ea847e Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 09:35:12 +10:00
m3ultra
4180e188e2 Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 09:35:12 +10:00
m3ultra
903e1d5f95 Merge remote-tracking branch 'origin/lane/e' 2026-07-17 09:35:12 +10:00
m3ultra
a0cf23dec8 Log gate-1 lever sweep (declining the downdraft), the porosity ruling, variants
Independently corroborates A's p4 finding: downdraft is the weakest lever
(-4.9% vs porosity's -15%), so storm_02 stays at 0.45. Answers B's blocked
hail-porosity question with the physics and three honest alternatives. Hands A
the week's variants and forecast uncertainty.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:32:42 +10:00
m3ultra
08a1d95903 Add night dressing and end cards; fix the hide_render bug
hide_render does not survive glTF export — verified in three r175, every node
arrives visible:true. So garden_bed has been drawing plants_full, tattered AND
dead superimposed since Sprint 1, and my THREADS note told Lane A the opposite.
The asserts missed it by checking the nodes existed rather than that only one
was on. The flag now rides in extras, which does export, and consumers apply it
in one line; e.test.js pins the flag instead of the node.

Night dressing: house_yardside gains window_glow, an unlit emissive pane marked
hidden_by_default, plus window_light_anchor. A warm window means someone is
inside, which is why the player is out in the dark keeping the sail on. Plus a
moon sprite whose halo, not its disc, is the part that survives cloud.

End cards are rendered from the game's own props as a diptych: identical camera
and yard, only the night's outcome differs. The left third is left empty for
Lane A's text.

Cards are opt-in behind --cards because EEVEE's shadow pass is not
byte-reproducible across processes in 5.1 — proven with a minimal repro, not
PYTHONHASHSEED, and present even with a hard sun. The dawn shadow is the art, so
the cards become committed art rather than build output. Everything the game
loads stays byte-identical: 38/38 verified.

Selftest 241/0/0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:28:26 +10:00
m3ultra
96cd9f0f97 Log gate 1's real blocker, correct my own bad number, brief D and C
The wild night's blocker is geometry, not drain weights: the best
bed-covering quad puts 7.4 kN on p1, above the 6.5 kN rated shackle, so
no loadout at any price holds it. Re-orders the lever list toward load.

Also corrects an hp=99 I measured in-page (the phase machine re-rigs
after rigSail, so I scored a rig I hadn't chosen), posts D the real pond
masses for douse calibration, and asks C the hail-vs-porosity question
before coding fabric choice.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:26:34 +10:00
m3ultra
a002422aa7 Log the douse calibration, the sagging-belly bug, and the gate-1 dependency
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:23:45 +10:00
m3ultra
a53837208d Post gate 1 results: the wild night is winnable on the anchor alone
Tells B and C to re-measure before spending the drain-weight and downdraft
levers — stacking them blind makes attribution impossible. Includes the p4
position sweep and the "do not pull it closer" boundary, since a.test.js's
>45 m2 floor is the tradeoff's only guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 09:22:03 +10:00
m3ultra
b1acbd6668 Merge Sprint 5 lanes; wire decision 13 garden drain; measure the balance gap
Selftest on merged main: 240 pass / 0 fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 08:52:58 +10:00
m3ultra
9010a2c784 Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 08:44:27 +10:00
m3ultra
1304be76f6 Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 08:44:27 +10:00
m3ultra
95b0917601 Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 08:44:27 +10:00
m3ultra
c92a7a1b13 Merge remote-tracking branch 'origin/lane/e' 2026-07-17 08:44:27 +10:00
m3ultra
97ea1b668c Log ponding v1, broom API, cliff resolution, and a yard finding
Freezes the pond API for D (broom) and A (HUD), resolves D's tn-1.04
cliff as real ponding load rather than solver instability, and flags that
flat rigs die to wind before water on the current yard — so ponding is a
twist-tax today unless the yard gets a non-collinear level anchor trio.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 03:32:55 +10:00
m3ultra
7dd77775da Log hail landing, decision-13 proof, and the router forward for A
Hail is the garden-score engine (4.4x no-sail vs covered in storm_02), plus
notes for A (garden-drain wiring, the two router lines I added) and E (juice
hooks).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 03:20:04 +10:00
m3ultra
f2527055a5 Add hail juice, plant shred, and a way to screenshot the game
Hail (SPRINT5 §E-1) ships two ways because Lane C's rain is a BoxGeometry with a
flat material and skyfx loads no external texture at all: hail_stone_01 as
geometry that drops into their existing InstancedMesh pattern, and hail_pips.png
as a 4-cell atlas for impacts. A flat quad can't be round and an impact is round
— that's the only reason the atlas is a texture. Both come with a copy-paste
recipe, because a grep showed exactly one of my five shipped textures is
consumed: sail_weave, the one I wrote a recipe for. grass_atlas has sat
unreferenced for four sprints.

plant_shred (§E-2) is elongated after the first pass came out radial and read as
green potatoes — it's the long axis plus the midrib that says "leaf".

tools/yardshot/ finally lands the DESIGN.md pictures, carried since Sprint 2. It
does NOT touch server.py or main.js: it's a Lane E stdlib server that serves the
repo and takes POST /shot, so the browser posts a Blob and bytes go straight to
disk instead of base64 through a console. do_POST is ~25 lines and Lane A is
welcome to lift it and delete this.

Three traps found on the way, all documented: toBlob is async so the WebGL buffer
is already cleared (toDataURL is sync); a backgrounded tab lays the canvas out at
0x0 and toDataURL then returns "data:,"; rAF is paused there so step() must be
driven by hand.

Selftest 209/0/0, 36 output files byte-identical across two runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 03:03:54 +10:00
m3ultra
4e8a98fca5 Log the broom landing, the B seam status, greyed prompts for A, and the feel pass
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 03:03:50 +10:00
m3ultra
cfe80e2837 Post the router tripwire warning and Lane A's Sprint 5 dependencies
The tripwire is aimed at Lane C's incoming hailAt(): the router swallowed C's
rain API silently once already, and decision 13 hangs the whole garden score off
hail, so the same omission would recreate the exact problem Sprint 5 exists to
fix. Also records that Sprint 4's headline finding was re-measured against a true
control and survived.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:56:03 +10:00
m3ultra
718f011e36 Post the broom↔pond API ask to Lane B early, per SPRINT5 §Lane B-2
The broom is this sprint's gate and B's spec says the two lanes meet in the
middle. Posting the shape now rather than at the end so B can land it while I
build against it: ponds[] with a live world pos (I have to walk under the
belly), and drainPondAt returning the kg dumped (that number decides splash vs
stagger vs flat on your back).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:52:36 +10:00
m3ultra
f7d747a578 Merge Sprint 4 lanes; fix wind router rain passthrough; rule decision 13 (hail)
Selftest on merged main: 207 pass / 0 fail. Gate 1 verified by playing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 02:43:10 +10:00
m3ultra
0b4dd0d0bd Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 02:39:41 +10:00
m3ultra
34712bf297 Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 02:39:41 +10:00
m3ultra
da35a954e0 Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 02:39:40 +10:00
m3ultra
ce8d22cb60 Merge remote-tracking branch 'origin/lane/e' 2026-07-17 02:39:40 +10:00
m3ultra
0ceff91d5a Lane D: the ladder sub-system (decision 12)
New ladder.js. The whole mechanic is 200 mm: the fascia bracket sits at 2.48 m,
a 1.72 m person's hands reach 2.20, and E's ladder tops out at 2.90. The asset
and the yard were already built for each other; this is the verb between them.

Carry-ladder is a second carry type, so the ladder and the spare compete for the
same pair of hands and a fascia repair costs two trips while a post repair costs
one — DESIGN.md's "limited hands" rule doing real work, and the reason the house
is the expensive anchor to depend on (which E's ratingHint 0.35 / collateral
"gutter" was already saying in the data).

Climb height is code-driven with ClimbLadder playing on top — the knockdown
precedent, since _rotOnly strips the root and a clip can no more lift the body
than Falling could lay it down. You can't brace up there (both hands on the
rungs), the wind's bar drops to 0.6x, and being blown off is a fall that feeds
straight into the existing get-up chain.

needsLadder is scoped to the fascia on purpose: a height test would have roped in
the 3.95 m posts and 5.05 m limbs, made every repair a two-trip job, and silently
invalidated the recorded §7 run — and it isn't true to rigging either.

Landed with no change to main.js: createLadder self-wires from createPlayer,
which Lane A already hands the scene, world and interact.

Two bugs found by building on my own API, both now asserted: a canUse that reads
player.state cancels its own hold (starting a hold sets busy) — it ate the climb
AND the reach gate before I keyed both on physical height instead; and onLadder
had to become height-based for the same reason. Documented on register().

Selftest 194/0/0 (was 184). Full loop driven by hand in the real game.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:34:49 +10:00
m3ultra
966dda9590 Post Sprint 4 gate 1 and the garden-HP finding
The face's first act was to expose that garden HP barely responds to rigging: a
perfect rig scores 53% on storm_02 and rigging nothing at all scores 48%. Cause
is measured (rain shadow decays 0.38 -> 0.04 as wind builds) and it is not a bug
in anyone's lane — but it means decision 7's headline score is nearly
independent of the game. Flagged for Lane C with the numbers; the design call
about whether garden HP is even the right storm score is left open.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:32:44 +10:00
m3ultra
acb35752ee Log ponding data, the router gap, decision 7 helper and the night pass
Leads with the router allowlist gap: rig.step() gets the router, which doesn't
forward rainMmPerHour, so B's ponding would pass every assert and do nothing
in-game. Two lines in main.js.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:29:17 +10:00
m3ultra
4bb0efcfd1 Add the pond visual, the broom, and rename the snapped panel
Pond (SPRINT4 §E-1, decision 10): pond_water.png and pond_normal.png, for a
patch Lane B builds from the cloth's own nodes — same ride-the-nodes rule as the
tears, since a rigid disc would sit still while the belly moves under it. Alpha
is a radial feather and RGB darkens toward the centre, both encoded radially so
the shading survives being scaled per pondMass (radius ~ sqrt(mass)). Water is
grey-green, not blue: rain caught in a sail is shallow, murky and mirrors an
overcast sky.

Both at 256², not 512²: smooth low-frequency content, and at 512 they were
256 KB + 320 KB against ~20 KB for every other texture here. The chop is seven
waves at golden-angle directions rather than three crossed sines, which
interfered into a lattice and read as basketweave; the normal map gets six
integer-frequency waves for the same reason, and still asserts its own tiling.

broom_01 (§E-2): poke_tip sits on the bristle end deliberately — a broomstick
jabbed at a loaded sail holes it.

Renames fence_panel_broken to fence_panel_snapped to match SPRINT4 §A-4/§E-3.
Lane A's dress() guards every load, so the mismatch would not have crashed —
the wreckage would silently never have appeared, which is worse.

All 21 assets pass, 33 output files byte-identical across two runs, 186/0/0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:27:55 +10:00
m3ultra
ea128e1307 Log decision 11: concede the bar, post the numbers, flag what's open
The 60% bar passes on the real yard at every value tested. My
"unachievable" verdict was measured against a 16.7-degree reference rig
the game cannot build; the yard is 4.8 degrees, where it clears easily.
Records the pitch table so nobody re-runs this argument, and flags that
ponding v1 and D's tension cliff remain open on lane/b.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 02:22:01 +10:00
m3ultra
89fd4e60b9 Merge Sprint 3 lanes; rule on the downdraft dispute; green-light ponding
Selftest on merged main: 184 pass / 0 fail. Gate 3 met (on-record §7 run).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 02:02:09 +10:00
m3ultra
997ea0bab1 Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 01:58:30 +10:00
m3ultra
ecb1ee7f43 Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 01:58:30 +10:00
m3ultra
44a4a3e6ec Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 01:58:30 +10:00
m3ultra
6880ec7d8e Merge remote-tracking branch 'origin/lane/e' 2026-07-17 01:58:30 +10:00
m3ultra
9b97bcfd00 Log decision-8 landing, the 0.45 target proof, and the B re-point ask
Semantic done + both-gates measurements + the finding that A's anchors alone
don't unblock 0.45 (B's §7 rig is still 141 m²). storm_02 held at 0.12 to keep
main green until B re-points to a small quad.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:53:56 +10:00
m3ultra
135b3dcda5 Log the on-record §7 hand-run, the failure-envelope finding, and the ladder deferral
The §7 loop is closed by hand on the merged game: pick up a spare at the shed,
carry it across the storm, the carabiner weak-link blows on its own, chase the
flogging corner (prompt tracks it live), hold-E re-rig → 4/4, ride out → survives
with full coverage. Definition of done met with a real storm break, not induced.

Also logged for B+C: the sail's failure envelope is a cliff — 4/4 up to tn 1.03
(~1.2kN peaks), instant ~10kN double-cascade at tn 1.04. Good rigs survive, flat
rigs cascade; the thesis holds and the decision-8 downdraft semantic won't move
the cliff (it's a cloth-stability ceiling). Ladder stretch goal deferred to
Sprint 4 with reasoning — it's a second carry type + placement + code-driven
climb height, bigger than what's left of this sprint.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:43:49 +10:00
m3ultra
9f83fd4f20 Report that decisions 3 and 8 are unachievable, with the algebra
Implemented and swept fraction-of-total downdraft: it pincers exactly
like gust-only did. The cause is not the semantics, it's the bar. A
pitched sail's normal is still 96% vertical, so a downdraft loads it too,
and on its worst heading pitch and downdraft add: |d| = 0.287 + 0.958f
against the horizontal sail's f. The ratio asymptotes at 109% and needs
f=0.86 (28 m/s of falling air) to reach 60%. No value works under any
semantics.

Recommend retiring it as a wind problem. DESIGN.md's own answer is
ponding, and the arithmetic dwarfs wind (1250 kg vs 8 kg of fabric vs
1 kN of wind) — but it can't bite in 90 s without a ~40x time-compression
fiat, so it's an M4 item with an owner, not a Sprint 3 fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:30:54 +10:00
m3ultra
a34cbd6d19 Log the decision-2 result and the full-coverage finding in THREADS
Records the measured before/after for Lane B (their pre-tension cascade is gone),
and flags that full bed coverage costing >=59 m2 is deliberate design rather than
a tuning miss — with an assert in both directions so nobody optimises the
tradeoff away by accident.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:30:53 +10:00
m3ultra
446ed2f14a Log shed dressing verified in-game
Booted merged main and looked at Lane A's dress(): shed and workbench are
standing, scale reads against the fence, and world.shedTable.pos resolves to my
baked pickup_anchor rather than the fallback. First Lane E GLB in the running
game with the contract intact end-to-end.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:28:42 +10:00
m3ultra
fccbeb9319 Add aftermath wreckage props and verify glTF extras survive
The aftermath screen needs something to point at (SPRINT3 §Lane E-2).
garden_gnome_01_broken snaps at the ankles with the base left where the player
last saw him, head rolled clear with the beard still on, hat off — recognisably
him rather than a shattered pile, because wreckage nobody can identify is just
gravel. fence_panel_broken loses a few palings and hangs one off a nail; most of
it stays standing, which is what makes the hole read as damage rather than as a
design choice. Both keep their intact twin's origin and ground plane so Lane A
swaps mesh-for-mesh with no offsets, asserted both ways.

Also asserts something claimed since Sprint 1 and never checked: that glTF
extras reach three's userData. They do — the gnome's collateral_value, the
canopy's sway_amp, branch_anchor rating_hint and the bin's mass_hint all arrive
as numbers. Had that silently dropped, Lane A's gnome would score $0 and every
anchor would rate identical, which reads as a gameplay decision rather than a
missing field.

Contact-sheet framing now keys the capsule off height, not max(dims): the broken
gnome is 0.39 m across but stands 0.11, so spread-based framing buried it the
same way it once buried the shackle.

Selftest 175/0/0, 30 output files byte-identical across two runs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:24:19 +10:00
m3ultra
823dbb942b Post Sprint 3 gate 1 in THREADS — Lane D unblocked
Also records the KeyboardInput.holding getter trap: assigning to it from a probe
silently no-ops and looks identical to broken interact wiring. Cost me a nearly
false bug report; Lane D needs it for the on-record §7 run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 01:21:02 +10:00
m3ultra
1ace50da0f Merge Sprint 2 lanes; wire debris into sail step; settle downdraft dispute as documented skip
Selftest on merged main: 169 pass / 0 fail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 01:09:51 +10:00
m3ultra
cd173d1ce0 Merge remote-tracking branch 'origin/lane/d'
# Conflicts:
#	THREADS.md
2026-07-17 01:01:48 +10:00
m3ultra
3f6fc27d00 Merge remote-tracking branch 'origin/lane/b'
# Conflicts:
#	THREADS.md
2026-07-17 01:01:48 +10:00
m3ultra
ac5021d279 Merge remote-tracking branch 'origin/lane/c'
# Conflicts:
#	THREADS.md
2026-07-17 01:01:48 +10:00
m3ultra
0f5f4d8368 Make rake_pivot a real pivot; log Sprint 2 in THREADS
rake_pivot shipped as a childless empty, so rotating it moved nothing — and
rotating the whole GLB instead, which is the only alternative, tips the concrete
footing out of the ground along with the post. DESIGN.md makes raking away from
the load a player decision, so the handle has to actually work.

It now holds post + pad_eye + top_anchor, with footing left on the root: rake it
8° and the post leans while the concrete stays planted. Asserted both directions
in e.test.js — the head must travel over 0.3 m and the footing under 0.01.

Same class as the canopy bug, found the same way: by driving the handle in a
test instead of eyeballing the model. Exported dims unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:56:15 +10:00
m3ultra
fd6dfc77da Log Sprint 2 landing, and block Lane C's decision 3 on real numbers
Decision 3 doesn't clear its own 60% bar: measured against lane/c over 8
headings and the full 90 s, flat-horizontal is 34% of flat-pitched, not
>=60%. The downdraft is 0.3 of the GUST component only, so storm_02's
strongest is -4.5 m/s against a 32.6 m/s horizontal peak, and pressure
goes as v^2. Needs ~0.55-0.6, or a fraction of total speed.

Also flags for A: rig.step needs the 4th debris arg or crates fly through
the sail; and the cheap-rig cascade fires at t=0.4s from pre-tension on
the 192 m2 quad, which decision 2 fixes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:26:38 +10:00
m3ultra
43ab43d3fb Log the proven §7 loop and the exact seams A and B need
Stood in for world.shedTable and rig.repair/cornerPos in the live game and drove
the whole scenario through the real sim, real interact and real rig: take a
spare, carry it to a blown corner, hold to re-rig, spare consumed, corner back.
Lane D's half of gate 3 is done; the gap is two small seams, now specified with
working code rather than a request.

Selftest 136/0/0 across all five lanes (was 121) — no other suite moved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 00:12:29 +10:00