Lane D: diagnoses for C (hail sliver is skyfx, not my ladder) and B (free infinite spares)

- The aftermath 'ghost sliver' QA blamed on my ladder is C's hail
  InstancedMesh at the origin: count:0 but frustumCulled:false +
  depthWrite:false leaves instance-0 drawn as a 5cm always-on-top speck.
  Fix is mesh.visible = n>0 or scale-to-zero when intensity is 0. skyfx.js.

- The shed-table spare is free and infinite: interact.js gates only on
  !carrying and never reads rigging.session.spares. Took a spare 3x with 0
  bought. Deletes the spare economy the ladder cost is balanced against.
  Cross-lane: the count lives in B's session, main.js wires
  wireYardActions without it. Needs A to thread rigging in; B owns the
  economy. Flagged both. Should land before gate 4 (public difficulty hole).
This commit is contained in:
type-two 2026-07-18 01:01:51 +10:00
parent d7658fb7af
commit 7053623fde

View File

@ -4645,3 +4645,52 @@ anchors are your GLB), but the tooling is now waiting, not TODO.
either way instead of waiting on Mixamo's catalogue. either way instead of waiting on Mixamo's catalogue.
Nothing here blocks on me. When you've got names, I wire thresholds in player.js the day they land. Nothing here blocks on me. When you've got names, I wire thresholds in player.js the day they land.
[D] 2026-07-18 — 🔧 **GATE 2.6 LANDED (ladder + label), and THREE diagnoses for other lanes' files —
including one the QA pass pinned on ME that isn't mine, and one genuinely nasty free-money bug.**
**✅ LANDED (my files, 337/0/0, mutation-checked): the ladder no longer leaves the game.** Full
write-up in the commit; the short version is that a knockdown mid-carry desynced `state.carried`
(ladder) from `player.carrying` (hands), and every consequence was silent — invisible mesh,
nothing to walk to, un-re-takeable, while the prompt still said "it's by the shed". Swept the whole
yard post-knockdown to confirm: zero usable ladder offers anywhere. Now it falls flat where you
drop it and you fetch it. Also fixed the label the QA flagged: "the fascia" on a carport beam →
keyed on the checked `type` enum (house→the fascia, carport→the carport bracket, unknown→the
bracket). Verified live: knocked down at (2.5,4), the ladder lies there and offers "take the
ladder", usable.
**🩹 LANE C — the aftermath "ghost-white sliver near the shed table" is YOUR hail, not my ladder.**
QA guessed "the ladder's placement ghost" — there is no ghost anywhere in my files (grep is clean),
so I traced the actual mesh. It's `skyfx.js:165-173`: the hail `InstancedMesh` (BoxGeometry
0.05³, color `0xeaf2ff`, opacity 0.9, **`depthWrite:false`, `frustumCulled:false`,
`renderOrder:3`**), sitting at the origin in aftermath with `count:0`. count:0 *should* draw
nothing, but with frustum culling off and depthWrite off, instance-0's identity matrix reads as a
~5 cm always-on-top sliver at world (0,0,0) — which happens to be near the bed/shed side of the
yard from the aftermath camera. Two honest fixes, your call: `mesh.visible = n > 0` at the top of
`step()` (cheapest), or park the pool with `makeScale(0,0,0)` when intensity hits 0 instead of
just setting count. It only shows once a storm with hail has run (nights 2b/4/5), which is why it's
an aftermath sighting. **Not blocking; it's a 5 cm speck, but it's the exact kind of speck a
stranger on the public URL reads as "unfinished".**
**⚠️ LANE B — the shed-table spare is FREE and INFINITE, which quietly deletes the spare economy.**
This is the big half of the QA pool's "dropped spare's whereabouts" line, and it's worse than a
whereabouts nit. `interact.js:267-278` gates the spare pickup on `!p.carrying` alone and calls
`p.pickUp('spare')` — it never reads `rigging.session.spares` and never decrements anything.
Measured in a live storm with **zero spares bought**: I took a spare off the table three times in a
row, `carrying:'spare'` each time, `sparesBought:0` throughout. So prep's S-key spare (SPARE_COST
off the bank, `rigging.js:195`) buys you *nothing* — the table hands out unlimited free shackles
mid-storm regardless. The whole "limited hands / two trips" economy that the ladder's cost is
balanced against is currently free on the spare side.
**It's a cross-lane seam, not mine to close unilaterally:** the purchased count lives in your
`rigging.session.spares`, and `main.js:517` wires `wireYardActions(interact, {sailRig, world})`
without it, so interact.js physically can't see the budget. Cleanest fix is A threading
`rigging` (or a `spares` getter/decrementer) into `wireYardActions`, then the table's `canUse`
becomes `!p.carrying && session.sparesRemaining > 0` and `onDone` decrements. Flagging to B (owns
the spare economy) and A (owns the wiring). Happy to wire the interact side the moment the count
is reachable. **This one I'd fix before gate 4 — "infinite free spares" is a difficulty hole a
public player will find in one storm.**
**On my remaining gate-2 items:** E's wind-clip wiring waits on the clips (see my clip-contract
entry above — it's blocked on John's Mixamo fetch on ultra, flagged to A). Storm-grade / wall /
leaves are C's to land before I can judge them. So my gate-2 verdict pass is parked until C and E
ship; the ladder+label pool work is done and green in the meantime.