docs(drone-airspace): correct the share token, voice support and coverage

The changelog fragment named share-link token 6 (sea marks); the layer
reserves 8. CURRENT-STATE said voice could toggle and query the layer and
listed it among the analyst record sources, but it is in VOICE_OFF_LAYERS.
Say voice is off for now, and that the layer covers FAA prohibited and
restricted special-use airspace only, not the UAS Facility Map / LAANC grids
or TFRs. A test pins these claims to the token ledger and the voice manifest.
This commit is contained in:
Sameh Khamis committed 2026-11-03 14:35:59 -08:00
1 parent 585392cbcf
commit add905e6b9
4 files changed
+47 -5

No files matched your search

@@ -5,4 +5,4 @@
prohibited, orange restricted); selection shows name, altitude range, times prohibited, orange restricted); selection shows name, altitude range, times
of use and agency, and the row legend states the layer is informational only of use and agency, and the row legend states the layer is informational only
and does not include the UAS Facility Map or UAS flight restrictions. Off by and does not include the UAS Facility Map or UAS flight restrictions. Off by
default; share-link token `6` (mvanhorn, #1086). default; share-link token `8` (mvanhorn, #1086).
+6 -4
View File
@@ -112,9 +112,11 @@ Selecting a zone shows name, an altitude range built from the
agency, agency,
plus a notice that the layer is informational only and not a substitute for plus a notice that the layer is informational only and not a substitute for
official UAS flight-planning tools. Pick ownership is unregistered so sibling official UAS flight-planning tools. Pick ownership is unregistered so sibling
layer cards still work over a zone. Voice can toggle the layer and query the layer cards still work over a zone. Voice is off for this layer for now
loaded records. The layer covers P and R zones only, not the FAA UAS Facility (`VOICE_OFF_LAYERS`: the Realtime prompt has no room), so neither voice nor the
Map or National Security UAS Flight Restrictions; the label and legend say so. analyst can toggle or query it. The layer covers FAA prohibited and restricted
special-use airspace only, not the UAS Facility Map / LAANC grids, National
Security UAS Flight Restrictions or TFRs; the label and legend say so.
See the live-layers table below. See the live-layers table below.
Vessel sources can report healthy empty coverage using a current, complete Vessel sources can report healthy empty coverage using a current, complete
@@ -591,7 +593,7 @@ 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.
Analyst records come on demand from each layer's `getAnalystRecords`: flights, military, local ADS-B, vessels, satellites, launches, earthquakes, FIRMS (VIIRS and MODIS, with a `sensor` field), fire perimeters, drone restrictions, cyclones, transit, bikeshare, ALPR cameras, mapped installations, datacenters and dams. `analyst_query` counts the whole loaded set (up to 250,000 records per layer; past that `coverage.records` reports `returned`, `total` and `truncated: true` and the result carries `complete: false`). Ranking keeps a top-k and scans in 20,000-row slices that yield to the page and stop when superseded. It refuses unknown fields, operators, units that do not convert (`altitudeM(ft)` converts), wrong-typed values, invalid centres, unknown scope kinds and sort fields with `code` and `allowed`, refuses a follow-up with no previous answer (`NO_RESULT_CONTEXT`) or naming other layers than that answer (`FOLLOW_UP_MISMATCH`), and tells `LAYER_OFF`, `NOT_READY` and `FEED_UNAVAILABLE` apart from a real zero; when only some layers can answer the result is `partial` with `unanswered` ids. The Contacts-window path applies the same filters, ranking and item shape to one immutable panel snapshot. Each aircraft layer retains at most 20,000 rows; reaching that bound sets `complete: false` and the spoken/card count becomes “At least”, never an exact claim. A superseded query never replaces follow-up memory, while sibling analyst calls from one assistant response do not cancel one another. Items carry `lat`/`lon`; the feed window (earthquakes and FIRMS: last 24 h), the precise scope and any caveat sit in `display`, which is on-screen detail rather than something the model recites. "In view" is still a radius around the view centre, not the visible footprint. Satellite distance is ground distance. Analyst records come on demand from each layer's `getAnalystRecords`: flights, military, local ADS-B, vessels, satellites, launches, earthquakes, FIRMS (VIIRS and MODIS, with a `sensor` field), fire perimeters, cyclones, transit, bikeshare, ALPR cameras, mapped installations, datacenters and dams. `analyst_query` counts the whole loaded set (up to 250,000 records per layer; past that `coverage.records` reports `returned`, `total` and `truncated: true` and the result carries `complete: false`). Ranking keeps a top-k and scans in 20,000-row slices that yield to the page and stop when superseded. It refuses unknown fields, operators, units that do not convert (`altitudeM(ft)` converts), wrong-typed values, invalid centres, unknown scope kinds and sort fields with `code` and `allowed`, refuses a follow-up with no previous answer (`NO_RESULT_CONTEXT`) or naming other layers than that answer (`FOLLOW_UP_MISMATCH`), and tells `LAYER_OFF`, `NOT_READY` and `FEED_UNAVAILABLE` apart from a real zero; when only some layers can answer the result is `partial` with `unanswered` ids. The Contacts-window path applies the same filters, ranking and item shape to one immutable panel snapshot. Each aircraft layer retains at most 20,000 rows; reaching that bound sets `complete: false` and the spoken/card count becomes “At least”, never an exact claim. A superseded query never replaces follow-up memory, while sibling analyst calls from one assistant response do not cancel one another. Items carry `lat`/`lon`; the feed window (earthquakes and FIRMS: last 24 h), the precise scope and any caveat sit in `display`, which is on-screen detail rather than something the model recites. "In view" is still a radius around the view centre, not the visible footprint. Satellite distance is ground distance.
Keyless terrain tiles retry when Re:Earth throttles them. The browser fetches Keyless terrain tiles retry when Re:Earth throttles them. The browser fetches
`terrain.reearth.land/cesium-mesh/ellipsoid/{z}/{x}/{y}.terrain` directly; no `terrain.reearth.land/cesium-mesh/ellipsoid/{z}/{x}/{y}.terrain` directly; no
+1
View File
@@ -413,6 +413,7 @@
"src/layers/droneAirspace/source.test.mjs", "src/layers/droneAirspace/source.test.mjs",
"src/layers/droneAirspace/cards.test.mjs", "src/layers/droneAirspace/cards.test.mjs",
"src/layers/droneAirspace/ownership.test.mjs", "src/layers/droneAirspace/ownership.test.mjs",
"src/layers/droneAirspace/docs.test.mjs",
"src/data/firmsHeatmap.js", "src/data/firmsHeatmap.js",
"src/data/fireAnchors.js", "src/data/fireAnchors.js",
"src/layers/firms/anchors.js", "src/layers/firms/anchors.js",
+39
View File
@@ -0,0 +1,39 @@
import test from 'node:test';
import assert from 'node:assert/strict';
import { readFileSync } from 'node:fs';
import { VOICE_OFF_LAYERS } from '../../voice/layerManifest.js';
import { ANALYST_LAYERS } from '../../data/analystEngine.js';
const read = (path) =>
readFileSync(new URL(`../../../${path}`, import.meta.url), 'utf8');
const currentState = read('docs/CURRENT-STATE.md');
const section = currentState.slice(
currentState.indexOf('## Prohibited & Restricted Airspace'),
currentState.indexOf('\n## ', currentState.indexOf('## Prohibited')) + 1,
);
const tokens = JSON.parse(read('src/data/layerStateTokenReservations.json'));
test('the changelog fragment names the reserved share-link token', () => {
const token = JSON.stringify(tokens).match(
/\["drone-airspace","([^"]+)"\]/,
)?.[1];
assert.ok(token, 'drone-airspace has a reserved token');
const fragment = read('changelog.d/1086-prohibited-restricted-airspace.md');
assert.match(fragment, new RegExp(`share-link token \`${token}\``));
assert.match(section, new RegExp(`share-link token \`${token}\``));
});
test('CURRENT-STATE matches the layer being outside voice and the analyst', () => {
assert.ok(Object.hasOwn(VOICE_OFF_LAYERS, 'drone-airspace'));
assert.ok(!Object.hasOwn(ANALYST_LAYERS, 'drone-airspace'));
assert.doesNotMatch(section, /Voice can toggle/);
assert.match(section, /Voice is off for this layer for now/);
const analyst = currentState.match(/Analyst records come on demand[^\n]*/)[0];
assert.doesNotMatch(analyst, /drone/i);
});
test('CURRENT-STATE states what the layer does not cover', () => {
assert.match(section, /UAS Facility Map/);
assert.match(section, /LAANC/);
assert.match(section, /TFRs/);
});