Layer display tests no longer re-check Cesium primitives in every layer:
they run on the fake engine, and one Cesium translation check per ground
kind lives in the Cesium engine's ground tests. Their harnesses are shared,
and the fake-engine, Cesium-engine and flights tests that repeated the
contract suite are gone, 340 tests in all.
The press-travel measurement is shared by the selection dispatcher and
CCTV, which loses its ScreenSpaceEventHandler shim and world-click module.
ALPR, installations and bikeshare share one selection keeper and selected
marker write. Layers with their own click rules keep their handlers.
Navara's pulse is a class like the ground pass, the ground and imagery
passes share the surface uniforms, and the colour, log-depth and occlusion
GLSL lives in one chunk module, each caller keeping its depth bias. The
ground suite runs inside the contract suite (--only=ground:), and fixture
and script names say what they test.
Behaviour is unchanged on both engines.
Port the layer probes in twenty-six browser scripts to engine primitive
lists, drawn rows and layer diagnostics. Preserve Cesium as the reference
and keep the supported Navara paths on the same observations. This
changes QA observation only, with no application behaviour change.
Review the interrupted infrastructure group and retain its readiness,
drape, selection, label and floor checks. Match both installation outline
buffers. Frame each CCTV city before reading its visible coverage. Read
Radio colours and selected identities from actual mover writes. Retain
transit's GPU upload budgets using engine-owned line primitives rather
than substituting rebuild counts. Keep native inspection where a check
specifically measures GPU uploads, loaded meshes or ground readiness.
The preceding combined B/C commit owns all shared manifests, docs,
locale catalogs and the coupling baseline; this commit changes only its
own twenty-six QA scripts. Coupling remains unchanged at 344 Cesium
renderer lines, 1294 Navara renderer lines, 9 Cesium import files, 1026
viewer lines, 2 Navara kind checks, 0 engine sniff calls, 9 extension
reads, 1 ground pass, 3 SDK loads, 4 screen-handler files and 42 engine-name
lines.
The full unit suite and the boundary, format and coupling checks pass.
Browser validation remains to be run.
Browser checks to run
GOOGLE_MAPS_API_KEY= CESIUM_ION_TOKEN= npm run dev -- --port 4291
node scripts/qa-alpr-journey.mjs http://localhost:4291
node scripts/qa-alpr-journey.mjs 'http://localhost:4291/?engine=navara'
node scripts/qa-cables-overlay.mjs --url http://localhost:4291
node scripts/qa-cctv-v2.mjs --url http://localhost:4291 --fixture --terrain-globe
node scripts/qa-context-arrivals.mjs http://localhost:4291
node scripts/qa-directions.mjs --url http://localhost:4291
QA_BASE_URL=http://localhost:4291 node scripts/qa-draw-tool.mjs
QA_BASE_URL=http://localhost:4291 node scripts/qa-floor-hold.mjs
node scripts/qa-ghostmaps.mjs --url http://localhost:4291
node scripts/qa-gnss.mjs --url http://localhost:4291
node scripts/qa-height-datum.mjs --url http://localhost:4291
node scripts/qa-infra-lod.mjs --url http://localhost:4291
node scripts/qa-installation-navigation.mjs http://localhost:4291
node scripts/qa-military-names.mjs http://localhost:4291 --no-video
node scripts/qa-overpass-offload.mjs --url http://localhost:4291
node scripts/qa-radio.mjs --url http://localhost:4291
node scripts/qa-traffic-motion.mjs http://localhost:4291 --mode=osm
QA_BASE_URL=http://localhost:4291 node scripts/qa-transit-recovery.mjs
QA_BASE_URL=http://localhost:4291 node scripts/qa-transit.mjs
node scripts/qa-weather-teardown.mjs --url http://localhost:4291 --headless
for engine in cesium navara; do
node scripts/qa-enrich-ambient.mjs --url http://localhost:4291 --engine=$engine
QA_BASE_URL=http://localhost:4291 node scripts/qa-floor-verify.mjs --engine=$engine
node scripts/qa-heading-b3.mjs --url http://localhost:4291 --engine=$engine
node scripts/qa-overlay-baseline.mjs --url http://localhost:4291 --engine=$engine
node scripts/qa-sprites-b5.mjs --url http://localhost:4291 --engine=$engine
node scripts/qa-vessel-datum.mjs --url 'http://localhost:4291/?qaFeed=vessels:fixture' --engine $engine
done
The military-names driver exercises installation-polish; the transit
driver exercises transit-scenes. Use only the keyless server. Cases that
require photoreal tiles or unavailable providers remain unverified.
Conflict resolutions:
- src/main.js: upstream's PHOTON_URL place-search setting is read once at
module level and passed as geospatial: { endpoints: { photon } } by
createApplication(), so every engine start of the switch flow gets it; the
old single top-level createStandaloneApplication() call stays removed.
- src/layers/bikeshare/render/cesium/rendering.js: upstream's
publishedCapacity fix applied with this branch's
resolveCapacity(model, capacity, status) signature. The same fix is ported
to src/layers/bikeshare/render/navara.js (record.publishedCapacity, status
polls resolve from it), with a Navara regression test; upstream's
proxyRoute test imports the moved render/cesium/rendering.js.
- src/layers/traffic/flow.js: upstream's nextTask() yield and current()
check kept before the scene is taken from this branch's
_trafficScene?.() ?? _viewer?.scene with its missing-scene return.
- scripts/package-boundaries.json, scripts/format-scope.json: union of both
sides' file lists.
- src/voice/actionSchemas.test.mjs: both history comments kept, payload hash
recomputed for the merged schemas (Sentinel-2 map stack enum plus the
shorter layer alias hint).
- src/hudAltitudeDatum.test.mjs: this branch's engine-based IntelHUD
construction with upstream's placeLabels summary context.
A release that only selects a station now stops the looping noise source and suspends its AudioContext. The qa-radio dial scenarios start from an active stream, or expect a silent release from a stopped Radio.
Releasing the tuning dial always started the chosen station, plus tuning
static, even when nothing was playing. It now follows the Previous/Next
rule: the release plays only if a stream was loading, buffering or playing
when the drag began; otherwise it just selects the station.
The privacy note no longer lists finishing tuning as a way to connect and
now names voice instead, in all locales. Docs, changelog and comments are
tightened to match.
Preserve the camera, map source and layer selection across engine sessions. Restore the previous engine if startup fails and retain local history navigation.
main moved the Radio markup into Vue views and rebuilt the UI tests on
stores. Resolved:
- src/ui/templates/context.html: deleted in main; the new privacy note now
lives in src/ui/views/panels/RadioPanel.vue.
- src/ui/radioControls.test.mjs: main's store fixture; the Next/Previous
autoplay test drives store.act('cycleRadio').
- src/voice/gevRealtime.test.mjs: main's createTestVoiceUi; the stop and
select handoff cases stay one table-driven test.
- src/data/radioNextState.test.mjs reads the published gev-radio view.
- src/i18n/locales/ar.json: the new note translated for the Arabic locale.
A panel's collapsed, dock-pinned, dock-pinned-top, layout-auto-collapsed
and accordion-collapsed classes are drawn by its root's v-panel-state from
the gev-panel-chrome store. PanelChrome, its restore, the layout
controller, both rails and the side accordion present each panel's state
there instead of writing its classes; the rails call onCollapse(panel,
{collapsed, auto}). The directive applies a change in a synchronous
watcher, since the rails measure a panel in the task that opens or closes
it.
Destroying the chrome inside Cockpit now puts back the panels Cockpit's
entry closed while it can still present them. Without a shell, the voice
tools' set_panel_open reports that there is no panel to open. QA scripts
present the states they set instead of writing the classes.
RadioTuner renders the band label, readouts, slider and needle from the
Radio store. RadioControls keeps the drag and its slot and publishes what
the tuner shows; the component lays out the tick tape against the dial's
measured width, drawing no ticks before it has one, and lays out the
snapped needle before it drops the drag class so the needle does not
animate from where the drag let go.
The Display and Radio launchers, their popovers and the compact Radio
transport, Enable button and volume now render from the Radio store.
RadioControls owns the disclosure state; Cockpit Escape and the Display
reveal read that state instead of the DOM, and the Enable toggle guards
re-presses synchronously. The compact transport reuses the panel's
transport state and adds only its glyph and title.
ContextControls presents the selected mode, the transition busy state and the nearby sites search through a publish option, and ContextView renders them from the gev-context store. ./ui/context stays free of Vue. The Radio QA reads the search button's aria-busy, the state it actually carries.
RadioPanel, lifted from ContextView, renders the layer state, Enable, the tag filter, station card, transport, volume and playback line from the gev-radio store that RadioControls publishes to. The tuner, the local SDR card and the Cockpit radio controls keep their element bindings. Enable's busy mark and the dragged volume go through the owner so a render never leaves them stale, and the markup's tag option stands until the categories first change. ./ui/radio now imports Vue and Pinia.
The entry now lives in changelog.d/1471-context-panel-cleanup.md with
credit, as CONTRIBUTING asks, and CHANGELOG.md is back to main.
CURRENT-STATE no longer lists a compact Radio power control and scopes
the readability description to what Cyber keeps. The responsive glow
comment no longer cites the removed Radio popover, and qa-radio's
pick-buffer comment is back above settleRadioFrames.
Four test fixtures stop stubbing the removed launcher sync, and
PanelChrome drops the _syncRailPanelCollapseButton pass-through, wiring
the layout controller straight to _syncPanelCollapseButton.
The Next and Previous buttons cycled stations with the layer's default
autoplay, so a first press started buffering a broadcaster stream even
though the panel says audio connects only after Play. Stepping now only
selects until a stream is loading, buffering or playing; once one is,
playback follows the new station so the old broadcaster does not keep
playing under the new label.
The compact Next fallback scenario in qa-radio.mjs started from a stopped
stream and relied on the old behaviour, so it now starts from a playing
station.
Fixes HAL-722
Co-Authored-By: Claude Opus 5.5 <[email protected]>
CI failed at format:check: the format scope still listed the deleted
panelChrome.radioOwnership test, and panelRails.test.mjs needed Prettier
after its glow list shrank.
The new Context title colour outranked Cyber's red panel titles, and the
collapsed Context launcher came out brighter than its siblings; the rule
now applies only to the expanded panel outside Cyber. Cyber's layout-focus
standby card had relied on the old dashed border and centring, so it
drew a 3px frame with its text off the radar art; it now names its own
1px frame, padding and centring. Cyber also drops the shared segmented
track, which drew a third frame around its already framed mode buttons.
Tests now pin the Context header to its title and collapse control, the
segmented control, 10px type, the missing halo and the scoped title
colour, plus the Cyber standby and track overrides. Each fails on the
previous CSS or markup.
qa-radio enables Radio and starts the first Play from the visible
controls, expanding Context and Radio the way a person must, then puts
the panels back. The Escape test and its mutation describe what they
still protect. CURRENT-STATE no longer describes the removed Radio icon
or compact player.
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.
The Context header carried a Radio icon that opened a second, compact
Radio player on top of the panel, duplicating the Radio section that
already lives inside Context. Remove the icon, the compact player and
everything that kept the two in step. Radio stays in Context as its own
section with one Enable control; Cockpit's compact Radio is unchanged.
Context itself was hard to read: 7-8 px labels at low contrast, a dashed
placeholder box, and a glow halo. The two modes are now one segmented
control, labels and guidance are 10 px at higher contrast, the standby
hint is plain text, section titles use --text-secondary, and the panel
draws no glow.
Unused translations are pruned, tests and QA harnesses that pinned the
compact player are updated or retired, and CURRENT-STATE and the
changelog describe the new header.
Display > HUD > Layout and the set_hud voice action now offer Tactical,
Minimal and Cyber. The Operator option, its CSS and its QA coverage are
removed, and the unused "Operator" translations are pruned.
Share-link codes are append-only, so operator keeps its hudVariant code.
A link, scene or saved state that names it restores the default Tactical
layout. The voice schema pins keep their legacy digests by restoring the
retired value before comparing; the full-payload digest is re-derived.
Preserve native clustering, selection and direct-action playback through renderer ports. Record both-engine dev/preview, legacy, contract, shell and build evidence with remaining W2 limits.
An ESLint no-unused-vars scan over src, server, scripts, tools, build
and pinokio, repeated until it is stable, reported these.
Runtime modules keep every call and drop only the unread binding:
- src/ui/cockpitInput.js: the unread result of enter()/exit().
- src/layers/launches/rendering.js: the unread entity returned by
entities.add().
- src/layers/radio/rendering.js: the unread map key in the horizon scan,
which now iterates the map's values.
QA scripts and tools drop an unused helper, two unused in-page module
imports, unused counters and destructured fields, and an unread wait
result. Tests drop source files read into variables that no assertion
uses, redundant StyleManager imports (the shell-source helper already
imports it), and unused destructured fields.
The one remaining report is the `_` loop variable in src/tools/schema.js,
which counts iterations and is intentional.
The flight, military and vessel feeds were named after the providers the
bundled server uses (/api/opensky, /api/adsblol/mil, /api/ais-live and
their track routes; createOpenSkySource, createAdsbLolSource,
createAisStreamSource). Any server should be able to answer a feed from
its own provider, so the feeds are now:
/api/flights /api/flights/track?icao24=
/api/military /api/military/track?hex=
/api/vessels /api/vessels/track?mmsi=
with createFlightSource, createMilitarySource and createVesselSource. The
old routes are removed. Each server names its provider in X-Feed-Source
(the bundled server sends OpenSky Network, adsb.lol and AISStream, so its
attribution is unchanged) and the military feed's cache state and age in
X-Feed-Cache and X-Feed-Age-Ms. Sources report the provider the server
names and fall back to the feed's name.
The harness called the compatibility facade's private _refreshTogglePanel,
which the layer-lifecycle refactor removed; Transit and Directions call
refreshLayerStats() on the bare lifecycle, which lacked it, so their rows
only repainted on the next tick. Add refreshLayerStats() to the lifecycle
and use it from the harness. With the crash gone, two further checks ran:
the selected-entity paint wait now also waits for Radio's own reveal, and
on phones the title bar sits 16 px from the top so both broadcast waves
stay on-screen.
Co-authored-by: Bilawal Sidhu <[email protected]>