From e12614a13a3706809837d7f763da00e83c7a9fb8 Mon Sep 17 00:00:00 2001 From: Said Turksever Date: Thu, 29 Oct 2026 11:29:20 +0000 Subject: [PATCH] Pin the retired Operator code and test the live HUD fallback qa-radio cycles Minimal, off, on, then Tactical, so the HUD toggle must restore a non-default layout, and expects that sequence instead of the removed Operator step. The share-link test pins the exact hudVariant codes, so dropping or moving operator's reserved code fails it. A live IntelHUD test checks that a retired Operator layout falls back to Tactical, and the Cyber test stub themes from the normalized value. The share-link table marks operator as retired, and the zh-CN glossary drops the removed string. --- docs/SHARE-LINK-FORMAT.md | 2 +- docs/translations/zh-CN.md | 2 +- scripts/qa-radio.mjs | 10 ++++++---- src/hudAltitudeDatum.test.mjs | 22 ++++++++++++++++++++++ src/share/viewCodec.test.mjs | 8 +++++++- src/ui/cyberTheme.test.mjs | 2 +- 6 files changed, 38 insertions(+), 8 deletions(-) diff --git a/docs/SHARE-LINK-FORMAT.md b/docs/SHARE-LINK-FORMAT.md index 6e1129830..23a143c1c 100644 --- a/docs/SHARE-LINK-FORMAT.md +++ b/docs/SHARE-LINK-FORMAT.md @@ -107,7 +107,7 @@ probability of about 255 in 256 (many of them already fail as base64url). | 13 | thing | LEN | none | sub-message, see thing views | | 14 | `style` | enum | `normal` | normal, retro, surveillance, thermal, anime, noir, snow | | 15 | `mapStack` | enum | `photoreal` | photoreal, bing-aerial, bing-labels, esri-imagery, osm | -| 16 | `hudVariant` | enum | style | tactical, operator, minimal, cyber | +| 16 | `hudVariant` | enum | style | tactical, operator (retired), minimal, cyber | | 17 | `bloomIntensity` | uint | style | | | 18 | `bloomVersion` | uint | 2 | | | 19 | `sharpenIntensity` | uint | style | | diff --git a/docs/translations/zh-CN.md b/docs/translations/zh-CN.md index e3b7bcad1..b3a3f973a 100644 --- a/docs/translations/zh-CN.md +++ b/docs/translations/zh-CN.md @@ -43,7 +43,7 @@ Translation sources: abiyeenzo (#914) and EDIT-Aeterna (#979). | briefing / panel / dock | 简报 / 面板 / 停靠栏 | | preset / visual preset | 预设 / 视觉预设 | | Display / HUD layout | 显示 / HUD 布局 | -| Tactical / Operator / Minimal / Cyber | 战术 / 操作员 / 精简 / 赛博 | +| Tactical / Minimal / Cyber | 战术 / 精简 / 赛博 | | Scope (circular viewport mask) / keyhole | 视域 | | Clean UI | 纯净界面 | | cockpit | 座舱 | diff --git a/scripts/qa-radio.mjs b/scripts/qa-radio.mjs index 98aa95fda..ec95046db 100644 --- a/scripts/qa-radio.mjs +++ b/scripts/qa-radio.mjs @@ -2158,11 +2158,13 @@ async function main() { for (let index = 0; index < 5; index += 1) { recordLayoutStep(); if (index < 4) { - if (index < 2) { + // Off and back on in Minimal, so the toggle must restore a + // non-default layout before the cycle returns to Tactical. + if (index === 1 || index === 2) { + hudToggle.click(); + } else { hudLayout.value = index === 0 ? 'minimal' : 'tactical'; hudLayout.dispatchEvent(new Event('change', { bubbles: true })); - } else { - hudToggle.click(); } await waitForHudSettle(); } @@ -2331,7 +2333,7 @@ async function main() { scenesHidden, mapProviderUtilityStable, hudInteractionsExact: layoutSteps.map((step) => step.hud).join('>') - === 'TACTICAL>OPERATOR>MINIMAL>OFF>MINIMAL', + === 'TACTICAL>MINIMAL>OFF>MINIMAL>TACTICAL', // The accordion clears the topline, Cockpit cards, and Cesium credits // across every HUD layout. Its list owns any overflow internally. leftLaneClearAcrossHudCycle: layoutSteps.every((step) => ( diff --git a/src/hudAltitudeDatum.test.mjs b/src/hudAltitudeDatum.test.mjs index ca14569e5..18ed56f92 100644 --- a/src/hudAltitudeDatum.test.mjs +++ b/src/hudAltitudeDatum.test.mjs @@ -575,3 +575,25 @@ test('a summary interrupted while typing can retry unchanged context', async (t) env.restore(); } }); + +// ── Retired layouts ───────────────────────────────────────────────────────── +// +// Share links keep the retired Operator code, so old links still name it. The +// real HUD, not a caller, is what turns it into the default Tactical layout. + +test('a retired Operator layout falls back to Tactical in the live HUD', () => { + const env = installHudEnvironment(); + let hud; + try { + hud = new IntelHUD(env.viewer); + hud._el = { dataset: {} }; + hud.setVariant('minimal'); + assert.equal(hud.getVariant(), 'minimal'); + hud.setVariant('operator'); + assert.equal(hud.getVariant(), 'tactical'); + assert.equal(hud._el.dataset.variant, 'tactical'); + } finally { + hud?.destroy(); + env.restore(); + } +}); diff --git a/src/share/viewCodec.test.mjs b/src/share/viewCodec.test.mjs index 4bd685047..670a58f20 100644 --- a/src/share/viewCodec.test.mjs +++ b/src/share/viewCodec.test.mjs @@ -437,8 +437,14 @@ test('defaults travel as frozen meanings that match today’s app defaults', () assert.equal(defaults.bloomIntensity, BLOOM_INTENSITY_DEFAULT); assert.equal(defaults.bloomVersion, BLOOM_SCALE_VERSION); assert.equal(defaults.hudVariant, HUD_LAYOUTS[0]); - // Codes are append-only: the retired Operator layout keeps its code so old + // Codes are append-only: the retired Operator layout keeps code 1 so old // links still parse, and the app restores them as Tactical. + assert.deepEqual(SHARE_VIEW_ENUMS.hudVariant, [ + 'tactical', + 'operator', + 'minimal', + 'cyber', + ]); assert.deepEqual( SHARE_VIEW_ENUMS.hudVariant.filter((variant) => variant !== 'operator'), [...HUD_LAYOUTS], diff --git a/src/ui/cyberTheme.test.mjs b/src/ui/cyberTheme.test.mjs index 340dd0204..b75874390 100644 --- a/src/ui/cyberTheme.test.mjs +++ b/src/ui/cyberTheme.test.mjs @@ -56,7 +56,7 @@ function styleOwner(t, initialVariant = 'cyber') { setVariant: (value) => { // Normalize like the real HUD so retired layouts fall back. variant = normalizeHudLayout(value); - applyHudUiTheme(root, value); + applyHudUiTheme(root, variant); }, setMode: (value) => calls.push(['mode', value]), onStyleChange: (value) => calls.push(['style', value]),