Issue #3615824: Read a booker's own basket over the shared availability list, so seats taken or given back show on the map at once

The seat map's shared half (which seats are gone) is held for availability_max_age seconds, so a session that has just written to a slot is the one reader it is wrong for. It was wrong in both directions.

Taking. mergePayload() in venue-map.js promoted a seat to the booker's own only when the shared list already called it gone. A seat just taken is in the live mine map and not yet in taken, so it fell through to available until the lifetime lapsed. The resync path a few hundred lines up had always consulted mine first; the two readers of mine disagreed.

Releasing. Releasing leaves nothing behind to read, so a seat given back stayed in the shared list, came back drawn as somebody else's, and was then unclickable (toggle() acts only on available and mine) while a hold would have been granted under the slot lock.

The fix

One rule: the shared answer is corrected by what this session itself has just done, and by nothing else.

  • Taking needs no record; the basket is the record, and mergePayload() now prefers it.
  • ReleasedPlaceRecord notes released place ids in the private tempstore; VenueMapBuilder::state() subtracts the notes younger than the lifetime. The initial render and the resync feed both read state().
  • ReleasedPlaceSubscriber keeps the record in step from BookingEvents::HELD/RELEASED, so a seat given back from the cart or the operator UI corrects the map too.

Notes prune on every read and write. Nothing shared is invalidated: forgetMovingState() on every release is exactly the per-booking invalidation the lifetime exists to avoid.

Tests

Two browser tests in VenueMapPickerTest. The fold of state onto seats lives twice, in PHP (withState(), via build()) and in the JS the browser runs; build() has no caller outside the test suite, so the kernel test pinning this rule was asserting on the copy no request executes. Both new tests widen the lifetime first so a slow run cannot rebuild the shared list and pass for the wrong reason.

Docs updated for both directions. No new translatable strings.

Two follow-ups noted on the issue: pooled areas have the same defect but need a signed count delta, and build()/withState() should go.

Merge request reports

Loading
Loading