feat(tools): count aircraft in an area by airline

OpenSky, the default civil feed, reports no operator, so group_by: operator
said "no operator reported". aircraft_in_area now also takes
group_by: 'airline', read from the ICAO designator in each callsign: three
letters followed by a flight number that starts with a digit (SWA1234,
UAL12A). Registrations used as callsigns (N123AB) count as unknown. Rows are
unchanged; the designator is derived for the breakdown only.

Live, Texas: "785 aircraft ...; most by airline: AAL (89), SWA (65), UAL (52);
283 unknown."

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
quanticsoul4772andClaude Opus 5.5 committed 2026-10-17 14:32:46 -07:00
1 parent db73c6908e
commit aec4f67ca9
5 files changed
+80 -13

No files matched your search

+23 -2
View File
@@ -36,11 +36,29 @@ const MILITARY_SCHEMA = Object.freeze({
});
const MAX_TRACK_POINTS = 200;
const GROUP_LABELS = Object.freeze({
airline: 'airline',
operator: 'operator',
origin_country: 'country',
type_code: 'type',
});
/**
* The ICAO airline designator a callsign flies under: three letters, then a
* flight number that starts with a digit (SWA1234, UAL12A, BAW1). Registrations
* used as callsigns (N123AB, GABCD) have no designator.
*/
export function airlineDesignator(callsign) {
const match = /^([A-Z]{3})\d[0-9A-Z]{0,4}$/.exec(
String(callsign ?? '')
.trim()
.toUpperCase(),
);
return match ? match[1] : null;
}
const groupValue = (field) =>
field === 'airline' ? (row) => airlineDesignator(row.callsign) : undefined;
const round = (value, digits) =>
Number.isFinite(value) ? Number(value.toFixed(digits)) : null;
@@ -91,7 +109,8 @@ export const aircraftInArea = defineTool({
description:
'Aircraft currently reported inside an area, nearest the center first. ' +
'Optionally military aircraft only, airborne only, or within an altitude band. ' +
'group_by counts every matched aircraft by operator, country or type, and ' +
'group_by counts every matched aircraft by airline (the ICAO designator ' +
'in its callsign), operator, country or type, and ' +
'stats summarizes airborne altitude and speed; both cover all matches, not ' +
'just the rows returned.',
inputSchema: {
@@ -151,7 +170,9 @@ export const aircraftInArea = defineTool({
...(regional ? [`regional feed: ${snapshot.coverage}`] : []),
...(snapshot.freshness === 'stale' ? ['data may be stale'] : []),
];
const groups = args.group_by ? breakdown(rows, args.group_by) : null;
const groups = args.group_by
? breakdown(rows, args.group_by, groupValue(args.group_by))
: null;
return {
summary:
`${rows.length} ${kind} in ${area.label}` +
+41
View File
@@ -1,6 +1,7 @@
import assert from 'node:assert/strict';
import test from 'node:test';
import { composeCatalog, coreTools } from '../index.js';
import { airlineDesignator } from './aviation.js';
import { LiveSourceError } from '../../sources/live/contract.js';
const record = (id, latitude, longitude, extra = {}) => ({
@@ -504,3 +505,43 @@ test('altitude bands require a reported altitude from normalized OpenSky records
});
assert.equal(minimum.data.total, 3);
});
test('an airline designator is read from an ICAO flight callsign only', () => {
for (const [callsign, designator] of [
['SWA1234', 'SWA'],
['ual12a', 'UAL'],
[' BAW1 ', 'BAW'],
['RCH123', 'RCH'],
['N123AB', null],
['GABCD', null],
['SWA', null],
['SWAX123', null],
['', null],
[null, null],
])
assert.equal(airlineDesignator(callsign), designator, String(callsign));
});
test('aircraft in an area can be counted by airline from their callsigns', async () => {
const fleet = [
record('a1', 37.6, -122.3, { callsign: 'SWA100' }),
record('a2', 37.61, -122.3, { callsign: 'SWA2' }),
record('a3', 37.62, -122.3, { callsign: 'UAL9' }),
record('a4', 37.63, -122.3, { callsign: 'N123AB' }),
];
const catalog = composeCatalog({
tools: coreTools,
services: { aircraft: feed(fleet) },
});
const result = await catalog.call('aircraft_in_area', {
area: bay,
group_by: 'airline',
});
assert.equal(
result.summary,
'4 aircraft in 60 km around 37.600, -122.300; most by airline: SWA (2), UAL (1); 1 unknown.',
);
assert.equal(result.data.breakdown.field, 'airline');
// Rows are unchanged: the designator is derived, not added to each row.
assert.equal('airline' in result.data.rows[0], false);
});