docs(cyclones): tighten shared-context comments, changelog and notes

This commit is contained in:
German Khokhlov committed 2026-11-06 20:07:56 +04:00
1 parent ea22d16c1a
commit 5e64e599e1
5 files changed
+13 -19

No files matched your search

+3 -4
View File
@@ -1,4 +1,3 @@
- Explicit cyclone selections publish only the currently selected NHC/CPHC - Let the voice assistant read the storm you select in Cyclone advisories:
storm into shared context. Switching storms removes the previous identity its official advisory, position, intensity and movement. Clearing the
without a false eviction event. Deliberate clears remain distinct from feed selection and the storm leaving the feed are reported apart (kvnloo, #847).
disappearance (kvnloo, #847; reviewed by quanticsoul4772).
+6 -7
View File
@@ -742,13 +742,12 @@ geographic seams and releases on disable; forecast animation is not implied.
NHC movement speed is converted from miles per hour to rounded knots by the NHC movement speed is converted from miles per hour to rounded knots by the
proxy; advisory wind intensity is already in knots and is passed through. proxy; advisory wind intensity is already in knots and is passed through.
Cyclone markers, labels, tracks and cones are hidden beyond the horizon on every map source. Cyclone markers, labels, tracks and cones are hidden beyond the horizon on every map source.
Explicit cyclone selections publish one shared `weather-cyclones` record Explicitly selecting a storm publishes one shared `weather-cyclones` record:
with official advisory provenance, source position, the English classification advisory provenance, source position, the English classification name and,
name and, while the proxy serves its cache, the cache fetch time. Switching while the proxy serves its cache, the cache fetch time. The automatic row
storms selects the replacement before pruning the old record; automatic row selection does not claim shared context; refreshes do not re-announce it.
selection never claims global context, and refreshes do not re-announce Clear or disable reports `deliberate`; a storm leaving the feed reports
selection. Deliberate clear/disable reports `deliberate`; losing the selected `evicted`, with no fallback.
storm from the feed reports `evicted` and assigns no fallback.
Consult the linked official advisory for safety decisions. Consult the linked official advisory for safety decisions.
Voice and HUD snapshots reuse the existing feedState classifier. Analyst follow-ups retain their original data provenance; current-view results append provenance without replacing legacy fields. HUD context and deterministic telemetry include non-nominal feed state. Voice and HUD snapshots reuse the existing feedState classifier. Analyst follow-ups retain their original data provenance; current-view results append provenance without replacing legacy fields. HUD context and deterministic telemetry include non-nominal feed state.
+1 -1
View File
@@ -1,7 +1,7 @@
import { createCyclonesLayer } from '../../layers/cyclones/index.js'; import { createCyclonesLayer } from '../../layers/cyclones/index.js';
import * as context from '../../data/contextStore.js'; import * as context from '../../data/contextStore.js';
/** Wire cyclone selection into the application shared-context owner. */ /** Wire cyclone selection to the application shared context. */
export function createApplicationCyclones(options) { export function createApplicationCyclones(options) {
const browserContext = typeof window !== 'undefined' ? { context } : {}; const browserContext = typeof window !== 'undefined' ? { context } : {};
return createCyclonesLayer({ return createCyclonesLayer({
+1 -3
View File
@@ -116,14 +116,12 @@ export function createCyclonesLayer({
layerId: 'weather-cyclones', layerId: 'weather-cyclones',
layerName: 'Cyclone advisories', layerName: 'Cyclone advisories',
source: 'NOAA NHC / CPHC', source: 'NOAA NHC / CPHC',
// Keep official storm names verbatim; layerName identifies the layer.
label: storm.name, label: storm.name,
latitude: storm.position.latitude, latitude: storm.position.latitude,
longitude: storm.position.longitude, longitude: storm.position.longitude,
// At most 12 properties reach the voice summary; keep the list short. // At most 12 properties reach the voice summary; keep the list short.
properties: { properties: {
classification: storm.classification, classification: storm.classification,
// English source meaning; unknown codes stay unexpanded.
classificationName: Object.hasOwn( classificationName: Object.hasOwn(
CLASSIFICATION_NAMES, CLASSIFICATION_NAMES,
storm.classification, storm.classification,
@@ -140,7 +138,7 @@ export function createCyclonesLayer({
movementDirectionDegrees: storm.movement?.directionDegrees, movementDirectionDegrees: storm.movement?.directionDegrees,
movementSpeedKt: storm.movement?.speedKt, movementSpeedKt: storm.movement?.speedKt,
advisoryUrl: storm.advisoryUrl, advisoryUrl: storm.advisoryUrl,
// Present only while the server serves its cache with NHC unreachable. // Only while the proxy serves its cache because NHC is unreachable.
staleCacheFetchedAt: staleCacheFetchedAt:
snapshot.stale && Number.isFinite(snapshot.fetchedAt) snapshot.stale && Number.isFinite(snapshot.fetchedAt)
? new Date(snapshot.fetchedAt).toISOString() ? new Date(snapshot.fetchedAt).toISOString()
+2 -4
View File
@@ -405,8 +405,7 @@ function harness(
}, },
}; };
} }
// Runs a test body against the real shared-context store on a stand-in window, // Real shared-context store on a stand-in window; the voice runner reads it.
// with the voice runner reading the same store.
async function withSharedContext(t, body) { async function withSharedContext(t, body) {
const previousWindow = Object.getOwnPropertyDescriptor(globalThis, 'window'); const previousWindow = Object.getOwnPropertyDescriptor(globalThis, 'window');
const host = new EventTarget(); const host = new EventTarget();
@@ -657,8 +656,7 @@ test('cyclone clears leave another layer selection and its records alone', async
assert.equal(store.selectedEntityId, 'flight:abc123'); assert.equal(store.selectedEntityId, 'flight:abc123');
assert.equal(events.length, before); assert.equal(events.length, before);
// A foreign record removed without clearing its selection: a cyclone // A cyclone feed failure does not evict a dangling foreign selection.
// feed failure must not report that selection as evicted by cyclones.
store.entities.delete('flight:abc123'); store.entities.delete('flight:abc123');
let fail = false; let fail = false;
const other = open({ const other = open({