HardYards/web/world/js
m3ultra 942709d2e9 Site-proof the ladder ahead of site_02, and test the real rule not a copy
SPRINT9 §Lane D: "play site_02 cold and log where the verbs break (the ladder
assumes fascia height; the carport may not have one)". site_02 isn't landed yet,
so I audited the verb against it instead of waiting.

The seam is real but it isn't height — it's that `needsLadder` is spelled
`type === 'house'`, and contracts.js types anchors as a closed enum
('house'|'tree'|'post') that E's carport doesn't fit. The failure mode is what
makes it worth fixing now: if needsLadder says false, interact's canReach returns
TRUE UNCONDITIONALLY, so the player re-rigs a 2.6 m bracket standing on the grass
and the mechanic silently stops existing. Same disease as StumbleBack's dead
threshold and the camera-less shadow grid — a rule keyed on the wrong thing,
failing open with no error.

A pure height test is NOT the fix: posts (3.95 m) and tree limbs (5.05 m) are
higher than the fascia and need no ladder, because you work the CLOTH there and
the bracket here. So needsLadder now reads data first —
`anchor.worksAtBracket` — exactly like anchor.ratingHint already does from the
GLB's userData, and falls back to site_01's type. Nothing on site_01 carries the
flag, so it's a no-op there (asserted). Lane A/E: set it in the site JSON and the
ladder follows the site with no code change.

Also made ladder.js headless-importable (lazy GLTFLoader, same as broom.js),
because d.test.js was testing fakeLadder's hand-copied duplicate of needsLadder
rather than the rule itself — a rule the suite re-implements is one it cannot
catch drifting. Verified the ladder's GLB still loads in the browser.

62 Lane D asserts headless, 275/0/0 in the browser.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 14:32:06 +10:00
..
tests Site-proof the ladder ahead of site_02, and test the real rule not a copy 2026-07-17 14:32:06 +10:00
broom.js Lane D: calibrate the douse to B's real ponds; fix the sagging-belly refusal 2026-07-17 09:23:17 +10:00
camera.js Add graybox yard, third-person camera and game shell 2026-07-16 21:33:42 +10:00
contracts.js Land ponding v1: rainwater pools on flat sails and kills them 2026-07-17 03:25:46 +10:00
debris.js Fix debris ground friction, cloud seam and yard coords 2026-07-16 21:50:41 +10:00
hud.js Merge Sprint 8; the week is live; balance harness stabilized 2026-07-17 14:02:53 +10:00
interact.js Lane D: calibrate the douse to B's real ponds; fix the sagging-belly refusal 2026-07-17 09:23:17 +10:00
ladder.js Site-proof the ladder ahead of site_02, and test the real rule not a copy 2026-07-17 14:32:06 +10:00
main.js The week: five nights, one wallet, and an ending that tells the truth 2026-07-17 13:13:44 +10:00
player.js Lane D: the broom, greyed prompts, and the label pass 2026-07-17 03:03:02 +10:00
player.sim.js Lane D: the ladder sub-system (decision 12) 2026-07-17 02:34:49 +10:00
rigging.js Land ponding v1: rainwater pools on flat sails and kills them 2026-07-17 03:25:46 +10:00
rigging.selftest.js Land ponding v1: rainwater pools on flat sails and kills them 2026-07-17 03:25:46 +10:00
sail.js Guard pond accessors before attach; caught driving the live game 2026-07-17 03:32:02 +10:00
sail.selftest.js Guard pond accessors before attach; caught driving the live game 2026-07-17 03:32:02 +10:00
skyfx.js Kill the headless-zero-shadow trap at its source (skyfx) 2026-07-17 13:10:53 +10:00
testkit.js Gate 0: name the harness dispute's cause; make skips real (testkit) 2026-07-17 10:21:01 +10:00
weather.core.js Land hailBlockFor(size, porosity) — the honest fabric-hail rule for B 2026-07-17 11:30:37 +10:00
weather.js Ship forecast uncertainty to the card (carried twice — now visible) 2026-07-17 13:10:53 +10:00
week.js The week: five nights, one wallet, and an ending that tells the truth 2026-07-17 13:13:44 +10:00
world.js Merge Sprint 6 lanes; wire hidden_by_default; document the balance harness dispute 2026-07-17 09:47:29 +10:00