diff --git a/src/layers/satellites/catalog.js b/src/layers/satellites/catalog.js index 097d9e3be..008b2a19d 100644 --- a/src/layers/satellites/catalog.js +++ b/src/layers/satellites/catalog.js @@ -114,6 +114,8 @@ export function createCatalog({ state: layerState, services, parts, source }) { const entry = entries[i]; const satrec = twoline2satrec(entry.line1, entry.line2); if (!satrec || satrec.error !== 0) continue; + // satellite.js omits the designator the launch-year match reads. + satrec.intldesg = entry.line1.slice(9, 17).trim(); const noradId = noradIdFromSatnum(satrec.satnum); if (layerState._catalog.has(noradId)) continue; // core catalog keeps priority const pos = parts.orbits.propagatePosition(satrec, now); diff --git a/src/layers/satellites/ingestion.js b/src/layers/satellites/ingestion.js index 01653611c..168a5903b 100644 --- a/src/layers/satellites/ingestion.js +++ b/src/layers/satellites/ingestion.js @@ -119,6 +119,8 @@ export function createIngestion({ for (const entry of allEntries) { const satrec = twoline2satrec(entry.line1, entry.line2); if (!satrec || satrec.error !== 0) continue; + // satellite.js omits the designator the launch-year match reads. + satrec.intldesg = entry.line1.slice(9, 17).trim(); const noradId = noradIdFromSatnum(satrec.satnum); if (seen.has(noradId)) continue; diff --git a/src/layers/satellites/ingestion.test.mjs b/src/layers/satellites/ingestion.test.mjs index 313d999ee..7605b318c 100644 --- a/src/layers/satellites/ingestion.test.mjs +++ b/src/layers/satellites/ingestion.test.mjs @@ -2,6 +2,7 @@ import test from 'node:test'; import assert from 'node:assert/strict'; import { parseTleText } from '../../sources/tle.js'; import { createIngestion } from './ingestion.js'; +import { createOrbits } from './orbits.js'; // The ISS set (1 January 2024) with its catalog field swapped per satellite. const ISS_LINE1 = @@ -78,3 +79,22 @@ test('every Alpha-5 satellite keeps its own catalog entry through dedupe', async assert.deepEqual([...state._points.keys()], [100000, 110001, 339999]); assert.equal(state._count, 3); }); + +test('a mission payload does not match a loaded satellite from another launch year', async (t) => { + t.mock.method(console, 'log', () => {}); + t.mock.method(console, 'warn', () => {}); + // SXM-11, international designator 2026-148A. + const { state, update } = ingestionFor( + [ + 'SXM-11', + '1 69728U 26148A 26208.65166678 .00000015 00000+0 00000+0 0 9990', + '2 69728 0.0784 264.9826 0001797 240.4588 273.9506 1.00271527 440', + ].join('\n'), + ); + await update(); + const { getSatelliteOrbitTrack } = createOrbits({ state }); + const track = (launchTime) => + getSatelliteOrbitTrack('Sirius SXM-11', { launchTime }); + assert.equal(track('2026-06-29T02:25:00Z')?.noradId, 69728); + assert.equal(track('2030-06-29T02:25:00Z'), null); +}); diff --git a/src/layers/satellites/stale.test.mjs b/src/layers/satellites/stale.test.mjs index 89b4d2dbf..9cca23610 100644 --- a/src/layers/satellites/stale.test.mjs +++ b/src/layers/satellites/stale.test.mjs @@ -235,6 +235,20 @@ test('dense provenance belongs to its admitted records and clears on removal', a ); }); +test('dense extras keep their launch year for mission orbit matching', async (t) => { + const f = await fixture(t); + await f.update(); + f.state._params.catalog = 'dense'; + assert.equal((await f.parts.catalog._loadDenseCatalog()).status, 'ready'); + // Every fixture set carries the 1998-067A designator. + const track = (launchTime) => + f.parts.orbits.getSatelliteOrbitTrack('OWNED ORBIT FIXTURE 25551', { + launchTime, + }); + assert.equal(track('1998-11-20T06:40:00Z')?.noradId, 25551); + assert.equal(track('2026-06-29T02:25:00Z'), null); +}); + test('cancelling dense replacement preserves admitted stale extras until rebuild', async (t) => { const f = await fixture(t); await f.update();