SAVE SKY provenance + sky→hex (not sky→sea) transition — TDD
Some checks failed
ci/woodpecker/push/pyswiss Pipeline was successful
ci/woodpecker/push/main Pipeline failed

- drama.GameEvent.SKY_SAVED verb + to_prose branch: "X beholds the skyscape of {poss} birth, which yields {obj} a unique {Cap} capacity."; tied highest scores switch "a unique" → "equal", join w. "and" (2-way) or Oxford comma (3+), and pluralize "capacity" → "capacities"; pronouns resolved from actor.pronouns at render time, same machinery as SIG_READY/ROLE_SELECTED
- epic.utils.ELEMENT_CAPACITOR_NAMES + ELEMENT_ORDER + top_capacitors(elements) helper: maps Fire→Ardor Stone→Ossum Time→Tempo Space→Nexus Air→Pneuma Water→Humor; tolerates both flat-int and enriched-dict (`{count, contributors}`) chart_data shapes; returns capacitor names tied for highest count, ordered by canonical wheel ring
- epic.natus_save: on action=confirm, records GameEvent.SKY_SAVED w. top_capacitors=[…] before _notify_sky_confirmed; per-room billscroll AND billboard Most Recent Scroll pick up the new prose
- _natus_overlay.html _onSkyConfirmed: removed sea-partial fetch+inject; now calls closeNatus() + window.location.reload() so the gamer lands on the table hex w. the PICK SKY → PICK SEA btn swap (server-side, driven by sky_confirmed=True), then opts into the sea overlay manually. The auto-launch via 39e12d6 was buried by FTs that were pinning the wrong contract — gamer never had a chance to witness PICK SEA on the hex
- test_room_sea_select.py: three FTs renamed/rewired from auto-launch assertions (sea_overlay_appears_without_page_refresh, natus_overlay_not_visible_after_sky_confirm, sea_open_class_on_html_after_confirm) to (pick_sea_btn_visible_after_sky_confirm, natus_overlay_closed_after_sky_confirm, clicking_pick_sea_btn_opens_sea_overlay) — sea overlay now requires explicit PICK SEA click

Code architected by Disco DeDisco <discodedisco@outlook.com>
Git commit message Co-Authored-By:
Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Disco DeDisco
2026-05-04 01:57:35 -04:00
parent 5413e63585
commit c9563308d8
7 changed files with 238 additions and 53 deletions

View File

@@ -38,7 +38,9 @@ def _make_sky_confirmed_room(live_server_url, user, earthman):
@tag("channels")
class PickSeaAsyncTransitionTest(ChannelsFunctionalTest):
"""After sky confirm, PICK SEA overlay appears without a page refresh."""
"""After sky confirm, the natus overlay closes and the room reloads to the
table hex w. the PICK SEA btn visible — the gamer must opt into the sea
overlay rather than be auto-launched into it."""
def setUp(self):
super().setUp()
@@ -89,51 +91,55 @@ class PickSeaAsyncTransitionTest(ChannelsFunctionalTest):
}});
""")
def test_sea_overlay_appears_without_page_refresh(self):
"""Confirming sky replaces the natus overlay with the sea overlay in-place."""
def test_pick_sea_btn_visible_after_sky_confirm(self):
"""Confirming sky reloads the room to the hex w. PICK SEA replacing
PICK SKY; the sea overlay is NOT auto-opened."""
self.create_pre_authenticated_session("founder@test.io")
self.browser.get(self.room_url)
# Sky not yet confirmed — PICK SKY btn present, no sea overlay
# Sky not yet confirmed — PICK SKY btn present.
self.wait_for(lambda: self.browser.find_element(By.ID, "id_pick_sky_btn"))
self.assertEqual(self.browser.find_elements(By.ID, "id_sea_overlay"), [])
self._confirm_sky()
# Sea overlay appears without page refresh
# Page reloads → hex shows PICK SEA in place of PICK SKY.
self.wait_for(lambda: self.browser.find_element(By.ID, "id_pick_sea_btn"))
self.assertEqual(self.browser.find_elements(By.ID, "id_pick_sky_btn"), [])
# Sea overlay is NOT auto-opened — it only appears once the gamer
# clicks PICK SEA.
has_sea_open = self.browser.execute_script(
"return document.documentElement.classList.contains('sea-open');"
)
self.assertFalse(has_sea_open)
def test_natus_overlay_closed_after_sky_confirm(self):
"""Natus overlay is gone (page reloaded) after sky confirm."""
self.create_pre_authenticated_session("founder@test.io")
self.browser.get(self.room_url)
self.wait_for(lambda: self.browser.find_element(By.ID, "id_pick_sky_btn"))
self._confirm_sky()
self.wait_for(lambda: self.browser.find_element(By.ID, "id_pick_sea_btn"))
natus = self.browser.find_elements(By.ID, "id_natus_overlay")
self.assertTrue(not natus or not natus[0].is_displayed())
def test_clicking_pick_sea_btn_opens_sea_overlay(self):
"""The gamer's explicit click on PICK SEA is what opens the sea overlay."""
self.create_pre_authenticated_session("founder@test.io")
self.browser.get(self.room_url)
self.wait_for(lambda: self.browser.find_element(By.ID, "id_pick_sky_btn"))
self._confirm_sky()
pick_sea = self.wait_for(lambda: self.browser.find_element(By.ID, "id_pick_sea_btn"))
self.browser.execute_script("arguments[0].click()", pick_sea)
sea_overlay = self.wait_for(
lambda: self.browser.find_element(By.ID, "id_sea_overlay")
)
self.assertTrue(sea_overlay.is_displayed())
def test_natus_overlay_not_visible_after_sky_confirm(self):
"""Natus overlay is removed from the DOM after sky confirm."""
self.create_pre_authenticated_session("founder@test.io")
self.browser.get(self.room_url)
self.wait_for(lambda: self.browser.find_element(By.ID, "id_pick_sky_btn"))
self._confirm_sky()
# Sea overlay must appear first (confirms transition happened)
self.wait_for(lambda: self.browser.find_element(By.ID, "id_sea_overlay"))
natus = self.browser.find_elements(By.ID, "id_natus_overlay")
self.assertTrue(not natus or not natus[0].is_displayed())
def test_sea_open_class_on_html_after_confirm(self):
"""html.sea-open is set after sky confirm, giving the sea overlay its backdrop."""
self.create_pre_authenticated_session("founder@test.io")
self.browser.get(self.room_url)
self.wait_for(lambda: self.browser.find_element(By.ID, "id_pick_sky_btn"))
self._confirm_sky()
self.wait_for(lambda: self.browser.find_element(By.ID, "id_sea_overlay"))
has_sea_open = self.browser.execute_script(
"return document.documentElement.classList.contains('sea-open');"
)
self.assertTrue(has_sea_open)
# ── Helpers for PICK SEA deal tests ──────────────────────────────────────────