fix(military): retire unavailable history and keep local trails

This commit is contained in:
Said committed 2026-10-20 00:43:47 +01:00
1 parent de2138e84c
commit 5f3d1eaa2f
6 files changed
+40 -34

No files matched your search

+1 -1
View File
@@ -593,7 +593,7 @@ export function createTracking({
}
/**
* Fire-and-forget adsb.lol readsb trace backfill (PRD F2). Trace points are
* Fire-and-forget optional source history backfill (PRD F2). Trace points are
* stride-thinned to the remaining vertex budget, then spliced strictly older
* than the oldest seeded fix AHEAD of the locally accumulated fine segment,
* capped at TRAIL_MAX_POINTS (newest kept). Any failure (404/timeout/
+4 -5
View File
@@ -214,11 +214,10 @@ test('construction is inert; adapters preserve routes, viewport query, cache epo
assert.equal(mil.observedAtMs, now - 60000);
assert.equal(mil.records[0].positionTimeMs, now - 75000);
assert.equal(mil.stale, true);
const track = await military.getTrack('abc123');
assert.equal(track.complete, false);
assert.equal(track.records[0].observedAtMs, now - 50000);
assert.equal(track.records[0].baroAltitudeM, 304.8);
assert.equal(track.records[0].ellipsoidAltitudeM, null);
assert.equal(military.getTrack, undefined);
assert.ok(
requests.every(({ url }) => !url.startsWith('/api/military/track')),
);
});
test('cancellation after slow body parsing rejects even with a transport that ignores abort', async () => {
+2 -20
View File
@@ -159,26 +159,8 @@ export function createMilitarySource({
status: response.status,
};
},
async getTrack(reference, { signal } = {}) {
const { response, payload } = await readResponse(
fetchImpl,
'/api/military/track?hex=' + encodeURIComponent(reference),
{ signal },
'Military aircraft',
);
if (!response.ok) throw httpError(response, 'Military aircraft');
const baseTimeMs = epoch(payload?.timestamp, 1000);
return {
records:
baseTimeMs == null
? []
: normalizeAircraftTrack(payload?.trace, {
baseTimeMs,
readsb: true,
}),
complete: false,
};
},
// ADSB.lol does not expose a supported live-history endpoint. Omitting
// optional getTrack keeps the tracking layer on its accumulated trail.
};
}
+18
View File
@@ -583,3 +583,21 @@ test('track backfill proxy returns 502 on an oversized upstream body and caches
assert.equal(res2.statusCode, 502);
assert.equal(callCount, 1);
});
test('retired military history refuses without upstream I/O while validating identifiers', async (t) => {
t.mock.method(globalThis, 'fetch', async () => {
assert.fail('retired history must not contact the upstream');
});
const route = install(providers.trackBackfillProxies());
for (const hex of ['abc123', 'abc456']) {
const response = await route('/api/military/track', '?hex=' + hex);
assert.equal(response.statusCode, 503);
assert.equal(JSON.parse(response.body).code, 'history_unavailable');
assert.equal(response.headers['retry-after'], '1800');
assert.equal(response.headers['cache-control'], 'no-store');
}
assert.equal(
(await route('/api/military/track', '?hex=invalid')).statusCode,
400,
);
});