mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 18:34:02 +00:00
feat(layers): highlight aircraft broadcasting a transponder emergency
Flights and Military Flights tint aircraft red while the latest poll carries squawk 7500/7600/7700 or an adsb.lol ADS-B emergency status (general/unlawful/nordo/downed). Minimum-fuel and lifeguard priorities are reported but not tinted. The Cockpit HUD aircraft-meta line names the broadcast code in red. The status is not sticky: a cleared code stops highlighting on the next refresh. The analyst/voice query engine gains squawk, emergency and emergencyKind fields. No new source or request: OpenSky state vectors already carry the squawk and adsb.lol/readsb carries both fields. Built by the Hex project (Crew Leo Agile dev team). Co-Authored-By: Claude <[email protected]>
This commit is contained in:
1 parent
9beadbda63
commit
eb7f059750
26 files changed
+1174
-107
No files matched your search
+285
-49
@@ -1,18 +1,89 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createAnalystEngine, applyScope, haversineKm } from './analystEngine.js';
|
||||
import {
|
||||
createAnalystEngine,
|
||||
applyScope,
|
||||
haversineKm,
|
||||
} from './analystEngine.js';
|
||||
|
||||
// Stub world: a square "Texland" region, flights + ships + fires around it.
|
||||
const TEXLAND = { name: 'Texland', ring: [[-100, 28], [-94, 28], [-94, 33], [-100, 33]] };
|
||||
const TEXLAND = {
|
||||
name: 'Texland',
|
||||
ring: [
|
||||
[-100, 28],
|
||||
[-94, 28],
|
||||
[-94, 33],
|
||||
[-100, 33],
|
||||
],
|
||||
};
|
||||
const FLIGHTS = [
|
||||
{ id: 'SWA1', lat: 30.2, lon: -97.7, altitudeM: 11000, speedMps: 240, military: false, onGround: false, routeOrigin: 'AUS', routeDestination: 'LAX' },
|
||||
{ id: 'RCH01', lat: 31.0, lon: -97.0, altitudeM: 13500, speedMps: 250, military: true, onGround: false, routeOrigin: null, routeDestination: null },
|
||||
{ id: 'N123', lat: 45.0, lon: -122.0, altitudeM: 2000, speedMps: 80, military: false, onGround: false, routeOrigin: null, routeDestination: null },
|
||||
{ id: 'GND1', lat: 30.19, lon: -97.66, altitudeM: 150, speedMps: 5, military: false, onGround: true, routeOrigin: null, routeDestination: null },
|
||||
{
|
||||
id: 'SWA1',
|
||||
lat: 30.2,
|
||||
lon: -97.7,
|
||||
altitudeM: 11000,
|
||||
speedMps: 240,
|
||||
military: false,
|
||||
onGround: false,
|
||||
routeOrigin: 'AUS',
|
||||
routeDestination: 'LAX',
|
||||
},
|
||||
{
|
||||
id: 'RCH01',
|
||||
lat: 31.0,
|
||||
lon: -97.0,
|
||||
altitudeM: 13500,
|
||||
speedMps: 250,
|
||||
military: true,
|
||||
onGround: false,
|
||||
routeOrigin: null,
|
||||
routeDestination: null,
|
||||
},
|
||||
{
|
||||
id: 'N123',
|
||||
lat: 45.0,
|
||||
lon: -122.0,
|
||||
altitudeM: 2000,
|
||||
speedMps: 80,
|
||||
military: false,
|
||||
onGround: false,
|
||||
squawk: '7700',
|
||||
emergency: true,
|
||||
emergencyKind: 'general',
|
||||
routeOrigin: null,
|
||||
routeDestination: null,
|
||||
},
|
||||
{
|
||||
id: 'GND1',
|
||||
lat: 30.19,
|
||||
lon: -97.66,
|
||||
altitudeM: 150,
|
||||
speedMps: 5,
|
||||
military: false,
|
||||
onGround: true,
|
||||
routeOrigin: null,
|
||||
routeDestination: null,
|
||||
},
|
||||
];
|
||||
const SHIPS = [
|
||||
{ id: 'EVERGIVEN', lat: 29.5, lon: -94.9, speedKts: 12, shipType: 'Cargo', destination: 'OAKLAND', navStatus: 'under way' },
|
||||
{ id: 'SLOWBOAT', lat: 29.6, lon: -95.0, speedKts: 0.2, shipType: 'Tanker', destination: 'HOUSTON', navStatus: 'anchored' },
|
||||
{
|
||||
id: 'EVERGIVEN',
|
||||
lat: 29.5,
|
||||
lon: -94.9,
|
||||
speedKts: 12,
|
||||
shipType: 'Cargo',
|
||||
destination: 'OAKLAND',
|
||||
navStatus: 'under way',
|
||||
},
|
||||
{
|
||||
id: 'SLOWBOAT',
|
||||
lat: 29.6,
|
||||
lon: -95.0,
|
||||
speedKts: 0.2,
|
||||
shipType: 'Tanker',
|
||||
destination: 'HOUSTON',
|
||||
navStatus: 'anchored',
|
||||
},
|
||||
];
|
||||
const FIRES = [
|
||||
{ id: 'FIRE-1', lat: 30.5, lon: -98.2, frp: 1500 },
|
||||
@@ -22,7 +93,10 @@ const FIRES = [
|
||||
|
||||
function makeEngine() {
|
||||
return createAnalystEngine({
|
||||
getRecords: (key) => ({ flights: FLIGHTS, 'ais-live-vessels': SHIPS, 'local-firms': FIRES }[key] || []),
|
||||
getRecords: (key) =>
|
||||
({ flights: FLIGHTS, 'ais-live-vessels': SHIPS, 'local-firms': FIRES })[
|
||||
key
|
||||
] || [],
|
||||
resolveRegionRing: async (name) => (/texland/i.test(name) ? TEXLAND : null),
|
||||
getViewContext: () => ({ lat: 30.27, lon: -97.74, viewRadiusKm: 150 }),
|
||||
});
|
||||
@@ -31,7 +105,10 @@ function makeEngine() {
|
||||
/** Same world, but Contacts is up with a subject far from the parked camera. */
|
||||
function makeContactsEngine(subject) {
|
||||
return createAnalystEngine({
|
||||
getRecords: (key) => ({ flights: FLIGHTS, 'ais-live-vessels': SHIPS, 'local-firms': FIRES }[key] || []),
|
||||
getRecords: (key) =>
|
||||
({ flights: FLIGHTS, 'ais-live-vessels': SHIPS, 'local-firms': FIRES })[
|
||||
key
|
||||
] || [],
|
||||
resolveRegionRing: async (name) => (/texland/i.test(name) ? TEXLAND : null),
|
||||
// Parked far away, as a high-altitude camera often is.
|
||||
getViewContext: () => ({ lat: 45.0, lon: -122.0, viewRadiusKm: 150 }),
|
||||
@@ -52,7 +129,11 @@ test('analyst: a radius query centers on the active contact, not the parked came
|
||||
assert.equal(r.ok, true);
|
||||
// Austin-area flights, not the Oregon one the camera is parked over.
|
||||
assert.equal(r.count, 3);
|
||||
assert.equal(r.centeredOn, 'SWA1', 'the answer names the centre it measured from');
|
||||
assert.equal(
|
||||
r.centeredOn,
|
||||
'SWA1',
|
||||
'the answer names the centre it measured from',
|
||||
);
|
||||
assert.ok(r.coverage.scope.includes('@SWA1'));
|
||||
});
|
||||
|
||||
@@ -63,7 +144,11 @@ test('analyst: an explicit center still wins over the active contact', async ()
|
||||
scope: { kind: 'radius', km: 250, center: { lat: 45.0, lon: -122.0 } },
|
||||
limit: 50,
|
||||
});
|
||||
assert.equal(r.count, 1, 'only the Oregon flight is within 250 km of the given center');
|
||||
assert.equal(
|
||||
r.count,
|
||||
1,
|
||||
'only the Oregon flight is within 250 km of the given center',
|
||||
);
|
||||
assert.equal(r.centeredOn, undefined, 'an explicit center is not relabelled');
|
||||
});
|
||||
|
||||
@@ -73,7 +158,11 @@ test('analyst: with Contacts off, radius still centers on the view', async () =>
|
||||
scope: { kind: 'radius', km: 250 },
|
||||
limit: 50,
|
||||
});
|
||||
assert.equal(r.count, 1, 'view-centred behaviour is unchanged outside Contacts');
|
||||
assert.equal(
|
||||
r.count,
|
||||
1,
|
||||
'view-centred behaviour is unchanged outside Contacts',
|
||||
);
|
||||
assert.equal(r.centeredOn, undefined);
|
||||
assert.equal(r.coverage.scope, 'radius:250km');
|
||||
});
|
||||
@@ -83,13 +172,25 @@ test('analyst: a subject without usable coordinates cannot lend its name to a ca
|
||||
// number. A subject present but position-less fell back to the camera and
|
||||
// kept the contact's name on the answer, so a camera-centred count read as
|
||||
// contact-centred with nothing in the payload to catch it.
|
||||
const r = await makeContactsEngine({ lat: null, lon: null, label: 'SWA1' }).query({
|
||||
const r = await makeContactsEngine({
|
||||
lat: null,
|
||||
lon: null,
|
||||
label: 'SWA1',
|
||||
}).query({
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'radius', km: 250 },
|
||||
limit: 50,
|
||||
});
|
||||
assert.equal(r.count, 1, 'the count is the camera-centred one it actually measured');
|
||||
assert.equal(r.centeredOn, undefined, 'and it must not claim a centre it did not use');
|
||||
assert.equal(
|
||||
r.count,
|
||||
1,
|
||||
'the count is the camera-centred one it actually measured',
|
||||
);
|
||||
assert.equal(
|
||||
r.centeredOn,
|
||||
undefined,
|
||||
'and it must not claim a centre it did not use',
|
||||
);
|
||||
assert.equal(r.coverage.scope, 'radius:250km');
|
||||
assert.equal(r.scopeLabel, 'within 250 km');
|
||||
});
|
||||
@@ -99,33 +200,47 @@ test('analyst: every scope names itself in words', async () => {
|
||||
// answers look like a contradiction, so each scope carries its own phrasing.
|
||||
const subject = { lat: 30.2, lon: -97.7, label: 'DYNO11' };
|
||||
const centred = await makeContactsEngine(subject).query({
|
||||
layers: ['flights'], scope: { kind: 'radius', km: 250 }, limit: 1,
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'radius', km: 250 },
|
||||
limit: 1,
|
||||
});
|
||||
assert.equal(centred.scopeLabel, 'within 250 km of DYNO11');
|
||||
|
||||
const plainRadius = await makeContactsEngine(null).query({
|
||||
layers: ['flights'], scope: { kind: 'radius', km: 250 }, limit: 1,
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'radius', km: 250 },
|
||||
limit: 1,
|
||||
});
|
||||
assert.equal(plainRadius.scopeLabel, 'within 250 km');
|
||||
|
||||
const inView = await makeEngine().query({
|
||||
layers: ['flights'], scope: { kind: 'view' }, limit: 1,
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'view' },
|
||||
limit: 1,
|
||||
});
|
||||
assert.equal(inView.scopeLabel, 'in view');
|
||||
|
||||
const region = await makeEngine().query({
|
||||
layers: ['flights'], scope: { kind: 'region', name: 'Texland' }, limit: 1,
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'region', name: 'Texland' },
|
||||
limit: 1,
|
||||
});
|
||||
assert.equal(region.scopeLabel, 'over Texland');
|
||||
|
||||
const anywhere = await makeEngine().query({
|
||||
layers: ['flights'], scope: { kind: 'anywhere' }, limit: 1,
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'anywhere' },
|
||||
limit: 1,
|
||||
});
|
||||
assert.equal(anywhere.scopeLabel, 'anywhere in the loaded data');
|
||||
});
|
||||
|
||||
test('analyst: count flights over a region', async () => {
|
||||
const r = await makeEngine().query({ layers: ['flights'], scope: { kind: 'region', name: 'Texland' }, limit: 50 });
|
||||
const r = await makeEngine().query({
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'region', name: 'Texland' },
|
||||
limit: 50,
|
||||
});
|
||||
assert.equal(r.ok, true);
|
||||
assert.equal(r.count, 3, 'Oregon flight excluded');
|
||||
assert.ok(r.coverage.scope.includes('Texland'));
|
||||
@@ -133,32 +248,65 @@ test('analyst: count flights over a region', async () => {
|
||||
|
||||
test('analyst: attribute filter — above 40,000 ft (~12,192 m)', async () => {
|
||||
const r = await makeEngine().query({
|
||||
layers: ['flights'], scope: { kind: 'anywhere' },
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'anywhere' },
|
||||
filters: [{ field: 'altitudeM', op: 'gt', value: 12192 }],
|
||||
});
|
||||
assert.deepEqual(r.items.map((i) => i.id), ['RCH01']);
|
||||
assert.deepEqual(
|
||||
r.items.map((i) => i.id),
|
||||
['RCH01'],
|
||||
);
|
||||
});
|
||||
|
||||
test('analyst: military flag + region compose', async () => {
|
||||
const r = await makeEngine().query({
|
||||
layers: ['flights'], scope: { kind: 'region', name: 'Texland' },
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'region', name: 'Texland' },
|
||||
filters: [{ field: 'military', op: 'eq', value: true }],
|
||||
});
|
||||
assert.equal(r.count, 1);
|
||||
assert.equal(r.items[0].id, 'RCH01');
|
||||
});
|
||||
|
||||
test('analyst: aircraft broadcasting an emergency are filterable by flag and code', async () => {
|
||||
const flagged = await makeEngine().query({
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'anywhere' },
|
||||
filters: [{ field: 'emergency', op: 'eq', value: true }],
|
||||
});
|
||||
assert.deepEqual(
|
||||
flagged.items.map((i) => i.id),
|
||||
['N123'],
|
||||
);
|
||||
const coded = await makeEngine().query({
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'anywhere' },
|
||||
filters: [{ field: 'squawk', op: 'eq', value: '7700' }],
|
||||
});
|
||||
assert.deepEqual(
|
||||
coded.items.map((i) => i.id),
|
||||
['N123'],
|
||||
);
|
||||
});
|
||||
|
||||
test('analyst: ships headed to Oakland (destination contains)', async () => {
|
||||
const r = await makeEngine().query({
|
||||
layers: ['ais-live-vessels'], scope: { kind: 'anywhere' },
|
||||
layers: ['ais-live-vessels'],
|
||||
scope: { kind: 'anywhere' },
|
||||
filters: [{ field: 'destination', op: 'contains', value: 'oakland' }],
|
||||
});
|
||||
assert.deepEqual(r.items.map((i) => i.id), ['EVERGIVEN']);
|
||||
assert.deepEqual(
|
||||
r.items.map((i) => i.id),
|
||||
['EVERGIVEN'],
|
||||
);
|
||||
});
|
||||
|
||||
test('analyst: superlative — biggest fire in view radius', async () => {
|
||||
const r = await makeEngine().query({
|
||||
layers: ['local-firms'], scope: { kind: 'view' }, sortBy: 'frp', limit: 1,
|
||||
layers: ['local-firms'],
|
||||
scope: { kind: 'view' },
|
||||
sortBy: 'frp',
|
||||
limit: 1,
|
||||
});
|
||||
assert.equal(r.items[0].id, 'FIRE-1', 'BC monster is out of view scope');
|
||||
assert.equal(r.summary.frpMax, 1500);
|
||||
@@ -166,7 +314,10 @@ test('analyst: superlative — biggest fire in view radius', async () => {
|
||||
|
||||
test('analyst: nearest sorting attaches distanceKm ascending', async () => {
|
||||
const r = await makeEngine().query({
|
||||
layers: ['flights'], scope: { kind: 'view' }, sortBy: 'distance', limit: 3,
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'view' },
|
||||
sortBy: 'distance',
|
||||
limit: 3,
|
||||
});
|
||||
assert.ok(r.items[0].distanceKm <= r.items[1].distanceKm);
|
||||
assert.ok(Number.isFinite(r.items[0].distanceKm));
|
||||
@@ -266,7 +417,10 @@ test('analyst: failed pre-commit work cannot replace follow-up memory', async ()
|
||||
});
|
||||
|
||||
test('analyst: unresolved region is an honest failure, not empty success', async () => {
|
||||
const r = await makeEngine().query({ layers: ['flights'], scope: { kind: 'region', name: 'Atlantis' } });
|
||||
const r = await makeEngine().query({
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'region', name: 'Atlantis' },
|
||||
});
|
||||
assert.equal(r.ok, false);
|
||||
assert.match(r.error, /Atlantis/);
|
||||
});
|
||||
@@ -274,10 +428,17 @@ test('analyst: unresolved region is an honest failure, not empty success', async
|
||||
test('analyst: a region lookup timeout is reported as region-timeout', async () => {
|
||||
const eng = createAnalystEngine({
|
||||
getRecords: () => FLIGHTS,
|
||||
resolveRegionRing: async (name) => ({ name, ring: null, error: 'region-timeout' }),
|
||||
resolveRegionRing: async (name) => ({
|
||||
name,
|
||||
ring: null,
|
||||
error: 'region-timeout',
|
||||
}),
|
||||
getViewContext: () => ({ lat: 30.27, lon: -97.74, viewRadiusKm: 150 }),
|
||||
});
|
||||
const r = await eng.query({ layers: ['flights'], scope: { kind: 'region', name: 'Texas' } });
|
||||
const r = await eng.query({
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'region', name: 'Texas' },
|
||||
});
|
||||
assert.equal(r.ok, false);
|
||||
assert.equal(r.code, 'region-timeout');
|
||||
assert.match(r.error, /Texas/);
|
||||
@@ -319,32 +480,84 @@ test('analyst: region lookup receives and obeys the owning action signal', async
|
||||
|
||||
test('analyst: route fields queryable from cached enrichment only', async () => {
|
||||
const r = await makeEngine().query({
|
||||
layers: ['flights'], scope: { kind: 'anywhere' },
|
||||
layers: ['flights'],
|
||||
scope: { kind: 'anywhere' },
|
||||
filters: [{ field: 'routeDestination', op: 'eq', value: 'LAX' }],
|
||||
});
|
||||
assert.deepEqual(r.items.map((i) => i.id), ['SWA1'], 'null route fields never match');
|
||||
assert.deepEqual(
|
||||
r.items.map((i) => i.id),
|
||||
['SWA1'],
|
||||
'null route fields never match',
|
||||
);
|
||||
});
|
||||
|
||||
test('analyst: satellites and local infrastructure are queryable layers', async () => {
|
||||
const SATS = [
|
||||
{ id: 'ISS (ZARYA)', noradId: '25544', name: 'ISS (ZARYA)', lat: 30.3, lon: -97.7, altitudeM: 410000, satelliteClass: 'STATION · ISS', group: 'stations' },
|
||||
{ id: 'GPS BIIR-2', noradId: '24876', name: 'GPS BIIR-2', lat: 51.0, lon: 0.0, altitudeM: 20200000, satelliteClass: 'NAV · GPS', group: 'gps-ops' },
|
||||
{
|
||||
id: 'ISS (ZARYA)',
|
||||
noradId: '25544',
|
||||
name: 'ISS (ZARYA)',
|
||||
lat: 30.3,
|
||||
lon: -97.7,
|
||||
altitudeM: 410000,
|
||||
satelliteClass: 'STATION · ISS',
|
||||
group: 'stations',
|
||||
},
|
||||
{
|
||||
id: 'GPS BIIR-2',
|
||||
noradId: '24876',
|
||||
name: 'GPS BIIR-2',
|
||||
lat: 51.0,
|
||||
lon: 0.0,
|
||||
altitudeM: 20200000,
|
||||
satelliteClass: 'NAV · GPS',
|
||||
group: 'gps-ops',
|
||||
},
|
||||
];
|
||||
const DAMS = [
|
||||
{ id: 'Austin Dam', name: 'Austin Dam', lat: 30.27, lon: -97.74, operator: 'LCRA', river: 'Colorado', output: '2 MW' },
|
||||
{ id: 'Far Dam', name: 'Far Dam', lat: 45.0, lon: -122.0, operator: 'USACE', river: 'Columbia', output: '1000 MW' },
|
||||
{
|
||||
id: 'Austin Dam',
|
||||
name: 'Austin Dam',
|
||||
lat: 30.27,
|
||||
lon: -97.74,
|
||||
operator: 'LCRA',
|
||||
river: 'Colorado',
|
||||
output: '2 MW',
|
||||
},
|
||||
{
|
||||
id: 'Far Dam',
|
||||
name: 'Far Dam',
|
||||
lat: 45.0,
|
||||
lon: -122.0,
|
||||
operator: 'USACE',
|
||||
river: 'Columbia',
|
||||
output: '1000 MW',
|
||||
},
|
||||
];
|
||||
const DCS = [
|
||||
{ id: 'AUS-1', name: 'AUS-1', lat: 30.28, lon: -97.75, operator: 'Example Cloud', capacity: '27 MW' },
|
||||
{
|
||||
id: 'AUS-1',
|
||||
name: 'AUS-1',
|
||||
lat: 30.28,
|
||||
lon: -97.75,
|
||||
operator: 'Example Cloud',
|
||||
capacity: '27 MW',
|
||||
},
|
||||
];
|
||||
const eng = createAnalystEngine({
|
||||
getRecords: (key) => ({ satellites: SATS, 'local-dams': DAMS, 'local-datacenters': DCS }[key] || []),
|
||||
getRecords: (key) =>
|
||||
({ satellites: SATS, 'local-dams': DAMS, 'local-datacenters': DCS })[
|
||||
key
|
||||
] || [],
|
||||
resolveRegionRing: async (name) => (/texland/i.test(name) ? TEXLAND : null),
|
||||
getViewContext: () => ({ lat: 30.27, lon: -97.74, viewRadiusKm: 150 }),
|
||||
});
|
||||
|
||||
const sats = await eng.query({
|
||||
layers: ['satellites'], scope: { kind: 'view' }, sortBy: 'distance', limit: 2,
|
||||
layers: ['satellites'],
|
||||
scope: { kind: 'view' },
|
||||
sortBy: 'distance',
|
||||
limit: 2,
|
||||
});
|
||||
assert.equal(sats.ok, true);
|
||||
assert.equal(sats.count, 1, 'GPS sat is out of the Austin view radius');
|
||||
@@ -352,20 +565,28 @@ test('analyst: satellites and local infrastructure are queryable layers', async
|
||||
assert.ok(Number.isFinite(sats.items[0].distanceKm));
|
||||
|
||||
const nav = await eng.query({
|
||||
layers: ['satellites'], scope: { kind: 'anywhere' },
|
||||
layers: ['satellites'],
|
||||
scope: { kind: 'anywhere' },
|
||||
filters: [{ field: 'satelliteClass', op: 'contains', value: 'NAV' }],
|
||||
});
|
||||
assert.deepEqual(nav.items.map((i) => i.id), ['GPS BIIR-2']);
|
||||
assert.deepEqual(
|
||||
nav.items.map((i) => i.id),
|
||||
['GPS BIIR-2'],
|
||||
);
|
||||
|
||||
const dams = await eng.query({
|
||||
layers: ['local-dams'], scope: { kind: 'view' }, sortBy: 'distance', limit: 5,
|
||||
layers: ['local-dams'],
|
||||
scope: { kind: 'view' },
|
||||
sortBy: 'distance',
|
||||
limit: 5,
|
||||
});
|
||||
assert.equal(dams.count, 1);
|
||||
assert.equal(dams.items[0].id, 'Austin Dam');
|
||||
assert.equal(dams.items[0].river, 'Colorado');
|
||||
|
||||
const dcs = await eng.query({
|
||||
layers: ['local-datacenters'], scope: { kind: 'region', name: 'Texland' },
|
||||
layers: ['local-datacenters'],
|
||||
scope: { kind: 'region', name: 'Texland' },
|
||||
filters: [{ field: 'operator', op: 'contains', value: 'cloud' }],
|
||||
});
|
||||
assert.equal(dcs.count, 1);
|
||||
@@ -375,7 +596,11 @@ test('analyst: satellites and local infrastructure are queryable layers', async
|
||||
test('helpers: haversine sanity + scope radius', () => {
|
||||
const km = haversineKm(30.2672, -97.7431, 29.7604, -95.3698); // Austin→Houston
|
||||
assert.ok(km > 200 && km < 280, `Austin-Houston ~235km, got ${km}`);
|
||||
const scoped = applyScope(FLIGHTS, { kind: 'radius' }, { center: { lat: 30.27, lon: -97.74 }, km: 50 });
|
||||
const scoped = applyScope(
|
||||
FLIGHTS,
|
||||
{ kind: 'radius' },
|
||||
{ center: { lat: 30.27, lon: -97.74 }, km: 50 },
|
||||
);
|
||||
assert.deepEqual(scoped.map((f) => f.id).sort(), ['GND1', 'SWA1']);
|
||||
});
|
||||
|
||||
@@ -385,7 +610,11 @@ test('capped cohorts report returned/total/truncated and keep it on follow-up',
|
||||
getRecordCoverage: () => ({ total: 3000, truncated: true }),
|
||||
getViewContext: () => ({ lat: 0, lon: 0, viewRadiusKm: 25 }),
|
||||
});
|
||||
const result = await engine.query({ layers: ['local-dams'], scope: { kind: 'anywhere' }, sortBy: 'distance' });
|
||||
const result = await engine.query({
|
||||
layers: ['local-dams'],
|
||||
scope: { kind: 'anywhere' },
|
||||
sortBy: 'distance',
|
||||
});
|
||||
assert.equal(result.count, 1);
|
||||
const layer = result.coverage.layersQueried[0];
|
||||
assert.deepEqual({ returned: layer.returned, total: layer.total, truncated: layer.truncated }, { returned: 1, total: 3000, truncated: true });
|
||||
@@ -510,7 +739,11 @@ test('follow-up provenance stays attached to old rows after a feed recovers', as
|
||||
let state = 'stale';
|
||||
const engine = createAnalystEngine({
|
||||
getRecords: () => [{ id: 'A', lat: 0, lon: 0 }],
|
||||
getLayerSnapshot: () => ({ id: 'flights', enabled: true, feedState: state }),
|
||||
getLayerSnapshot: () => ({
|
||||
id: 'flights',
|
||||
enabled: true,
|
||||
feedState: state,
|
||||
}),
|
||||
getViewContext: () => ({ lat: 0, lon: 0, viewRadiusKm: 25 }),
|
||||
});
|
||||
const first = await engine.query();
|
||||
@@ -520,7 +753,10 @@ test('follow-up provenance stays attached to old rows after a feed recovers', as
|
||||
assert.equal(followUp.coverage.feedProvenance.overall, 'stale');
|
||||
engine.reset();
|
||||
assert.equal(engine.hasMemory(), false);
|
||||
assert.equal((await engine.query()).coverage.feedProvenance.overall, 'nominal');
|
||||
assert.equal(
|
||||
(await engine.query()).coverage.feedProvenance.overall,
|
||||
'nominal',
|
||||
);
|
||||
});
|
||||
|
||||
test('a large loaded set sorts and summarizes without overflowing the stack', async () => {
|
||||
|
||||
Reference in new issue
Block a user