Skip to content

fix(attractionsio): trust an explicit IsOpen for attraction live status (Djurs Sommerland mass-CLOSED)#259

Open
TimBroddin wants to merge 1 commit into
ThemeParks:mainfrom
TimBroddin:fix/djurs-attractions-closed
Open

fix(attractionsio): trust an explicit IsOpen for attraction live status (Djurs Sommerland mass-CLOSED)#259
TimBroddin wants to merge 1 commit into
ThemeParks:mainfrom
TimBroddin:fix/djurs-attractions-closed

Conversation

@TimBroddin

Copy link
Copy Markdown
Contributor

Problem

Djurs Sommerland publishes most of its attractions as CLOSED even while the park is open. Snapshot from production on 2026-07-17 (park open 10:00–20:00, Aqua Park 12:00–18:00 per djurssommerland.dk): 47 of 100 live entities CLOSED, including the Vandland water park, Water Slides, Junior Aqua Park, and dozens of family rides and playgrounds. Every CLOSED attraction had no wait time; every attraction with a wait time was OPERATING — which pointed at queue metering, not actual closures.

Root cause

The Djurs live feed (live-data.attractions.io/<key>.json) only sets IsOperational: true on its ~21 queue-metered headline rides. Every other open attraction reports:

{"IsOperational": false, "IsOpen": true, "OpeningTimes": "{\"type\":\"range\",\"start\":\"2026-07-17 10:00:00\",\"end\":\"2026-07-17 20:00:00\"}"}

At scan time the feed contained 44 tracked attractions in this state (open with today's hours) and exactly 1 genuinely closed attraction (IsOpen: false — a meet & greet). The attraction branch of buildLiveData() derived status purely from IsOperational (IsOperational ? OPERATING : CLOSED), so all 44 were published as CLOSED. The dining branch already treated an explicit boolean IsOpen as authoritative — attractions just never got the same rule.

Fix

For attractions, an explicit boolean IsOpen now wins; IsOperational remains the fallback when IsOpen is absent (Merlin feeds omit it on non-operating rides). Status truth table:

IsOperational IsOpen Before After
true true OPERATING OPERATING
true absent OPERATING OPERATING
true false CLOSED CLOSED
false true CLOSED OPERATING ← the fix
false absent CLOSED CLOSED
false false CLOSED CLOSED

Only one combination changes, so a park can only be affected if its feed explicitly asserts IsOpen: true on a non-operational attraction.

Cross-park impact analysis

Scanned the live feeds of every park on this base class with a publicly recoverable feed key (10 of 16), joined against tracked entities via the production API:

Park Tracked attractions in (IsOperational:false, IsOpen:true) Output change
Djurs Sommerland 44 47 CLOSED → 3 CLOSED (the fix)
Legoland Windsor 5 see below
Alton Towers 0 none
Thorpe Park 0 none
Chessington 0 none
Gardaland 0 none
Heide Park 0 none
Legoland Billund 0 none
Legoland California 0 (scanned while park closed — night state is clean) none
Legoland Deutschland 0 none

Legoland Windsor also gets fixed

Windsor has 5 attractions that flip CLOSED → OPERATING: Pirate Goldwash, LEGO® Studios 4D, The Brick, LEGO Ferrari Build & Race, LEGOLAND® Adventure Golf. These are exactly the Djurs-style unmetered walk-through/experience attractions; their records carried IsOpen: true with today's opening hours while the park was open. They appear to have been wrongly CLOSED all day until now — same bug, second park.

Breakdown semantics verified live

The main regression worry was Merlin breakdowns being masked as OPERATING. Directly disproven during the scan:

  • Legoland Windsor's Jolly Rocker was broken down at scan time (QueueStatusMessage: "BACK SOON") and reported IsOperational: false, IsOpen: false → stays CLOSED under the new logic.
  • Chessington had a ride in TEMPORARY DELAY — it kept IsOperational: true.
  • Heide's running rides all report "Geöffnet" with both flags true.

So no observed attractions.io feed leaves IsOpen: true on anything that isn't actually open — including closed-park (California at night) and broken-down states.

Verification

  • New test an attraction with IsOpen:true but IsOperational:false is OPERATING failed before the fix, passes after; two guard tests pin the unchanged combos (IsOpen:false still closes, absent IsOpen still falls back to IsOperational).
  • Full suite: 1482/1482 passing, tsc clean.
  • End-to-end (npm run dev -- djurssommerland with the park's public app config): 96 OPERATING / 3 CLOSED, all 21 wait times intact — vs 53/47 in production at the same time.
  • End-to-end Alton Towers as Merlin control: 38 OPERATING / 48 CLOSED / 34 wait times vs production's 39 / 46 / 34 at the same moment — identical semantics, drift explained by rides changing state between snapshots.

Not covered / follow-ups

  • Six parks have no publicly recoverable feed key (Legoland Orlando / Japan / New York / Korea, Peppa Pig Florida, Knoebels) and couldn't be scanned. For them to regress, their feed would have to assert IsOpen: true on a closed attraction — behavior no examined feed exhibits in any state. Comparing OPERATING counts before/after deploy for those six would settle it conclusively.
  • Separate pre-existing issue, deliberately not touched here: Merlin walk-through attractions with no IsOpen field at all (e.g. Alton's Haunted Hollow, CBeebies photo studio) still show CLOSED all day. Fixing that would need the OpeningTimes window fallback (like the dining branch) and its own verification pass.

🤖 Generated with Claude Code

Djurs Sommerland's live feed only sets IsOperational:true on its ~21
queue-metered headline rides; every other open attraction (playgrounds,
the Vandland water park, unmetered family rides) reports
IsOperational:false with IsOpen:true and a concrete opening window for
the day. The attraction branch of buildLiveData() derived status purely
from IsOperational, so 44 open attractions were published as CLOSED.

Treat an explicit boolean IsOpen as the authoritative live signal for
attractions — mirroring the dining branch, which already worked this
way — and fall back to IsOperational when IsOpen is absent (Merlin
feeds omit it on non-operating rides).

Merlin semantics are preserved: across 8 checkable parks, zero tracked
attractions sit in the (IsOperational:false, IsOpen:true) combo, and a
live breakdown (Legoland Windsor's Jolly Rocker, "BACK SOON") reports
IsOpen:false, so breakdowns still surface as CLOSED. The only other
park whose output changes is Legoland Windsor, where 5 unmetered
walk-through attractions (4D cinema, Adventure Golf, …) were wrongly
CLOSED all day for the same reason.
@TimBroddin

Copy link
Copy Markdown
Contributor Author

Generated with Claude Code but reviewed by me. I double checked for breakages.

@TimBroddin
TimBroddin marked this pull request as ready for review July 17, 2026 12:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant