fix(events): the public phase label finds the phase by key (runicnpc D314)
All checks were successful
PR Checks / bot-tests (pull_request) Successful in 36s
PR Checks / client-build (pull_request) Successful in 7m50s
PR Checks / server-tests (pull_request) Successful in 13m50s

eventPublic.phaseLabel matched a run's current_phase against p.id, but spec.js
validates and the engine writes the phase's `key`, so every live run's public
page read "Under way" since Events Phase 14a, UO's events included. It now
matches `key` first and still accepts `id` second. The test fixture moves to
`key`, as real specs are, and a unit test covers a UO-shaped spec, the id
fallback, key-before-id and an unknown phase.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY
This commit is contained in:
2026-10-06 16:57:46 -05:00
parent 0a37a44164
commit ef93c73d2c
2 changed files with 33 additions and 8 deletions

View File

@@ -92,16 +92,22 @@ const isLive = (status) => publicStatus(status) === 'live'
/**
* The label of the phase a run is in, resolved from the PINNED version's spec.
*
* A phase id is a slug an author typed and the label is what they meant it to
* read as, so a page rendering the id would show `phase-2` to the public. A
* A phase key is a slug an author typed and the label is what they meant it to
* read as, so a page rendering the key would show `phase-2` to the public. A
* phase the spec does not name answers null and the page shows nothing, which is
* the right answer for a version edited since: the run pinned the old spec and
* the old spec is what it is executing.
*
* **A run's `current_phase` is the phase's `key`**, which is what `spec.js`
* validates and the engine writes. This matched `id` until RunicNPC stage 9
* (D314), so every live run read "Under way" since Events Phase 14a; `id` is
* still accepted second, for a spec stored in that older shape.
*/
function phaseLabel(spec, phaseId) {
if (!phaseId || !spec || !Array.isArray(spec.phases)) return null
const phase = spec.phases.find((p) => p && p.id === phaseId)
return (phase && (phase.label || phase.id)) || null
function phaseLabel(spec, phaseKey) {
if (!phaseKey || !spec || !Array.isArray(spec.phases)) return null
const phase =
spec.phases.find((p) => p && p.key === phaseKey) || spec.phases.find((p) => p && p.id === phaseKey)
return (phase && (phase.label || phase.key || phase.id)) || null
}
/**