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.
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.