[bug] Mission 2 (Rooftop Relay) does not unlock after clearing Mission 1 #15
Labels
No labels
blocked:needs-attention
blocked:needs-decision
blocked:needs-decompose
blocked:needs-design
blocked:needs-triage
blocked:unclassified
bug
documentation
enhancement
gsd-spec
in-progress
needs-decompose
priority:high
priority:low
priority:medium
quickfix
test
triage-approved
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Mark/cybertactics#15
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Bug found during play test.
Repro:
cd web && python3 -m http.server, then load/).localStorage.clear()to start fresh.Save & Title.Expected: Mission 02 Rooftop Relay unlocks (no longer shows
LOCKED — clear the previous mission).Actual:
localStorage.ct_missionsreads"1"(mission 1 marked complete), but the mission 02 button still has classmission lockedanddisabledattribute. Found via Playwright:Suspect: the unlock predicate reads
ct_missionsbut the value is being compared as a string vs number, OR a separatemissions_unlockedkey is the source of truth and isn't being written on auto-end (only on explicitSave & Settlefrom the strategic view).Acceptance:
localStorageshows the unlocked set, not just a single counter.Refs: Playwright play test 2026-09-23.
Fixed in
268d1c4on main.Root cause:
ct_unlockedwas being written inside theif (G.over.win)branch of the mission-end handler inweb/js/ui.js, so a loss never advanced the unlock index even thoughct_missionsbumped at mission start (game.js). Reload after a loss →ct_unlockedstayed at 1 → mission 02 still rendered withclass="mission locked" disabled.Fix: hoist the
ct_unlockedwrite outside the win branch so it fires on any mission conclusion. The best-time record stays win-only because a loss has no meaningful time to record.Regression test added:
tools/playwright_smoke.pysection 1d — clears localStorage, deploys mission 0, forcesendMission(false, ...), reloads, and asserts (a) the mission-01 button no longer has thelockedclass and (b)localStorage.ct_unlocked === '2'. Verified the test catches the regression by re-gating the unlock write (FAIL) then restoring the fix (PASS). All 9make cigates green on the push.