fix(voice): detach nested contacts snapshots

deep-clone retained aircraft items, provenance and subject data

add a regression for nested mutation across repeated snapshot reads
This commit is contained in:
manjunath22466 committed 2026-10-02 23:21:14 +05:30
1 parent 095981eee7
commit e57b60e511
2 files changed
+17 -20

No files matched your search

+11 -10
View File
@@ -2608,17 +2608,18 @@ test('the voice query snapshot is a detached copy of the rendered aircraft cohor
assert.equal(first.cohorts.flights.provenance.enabled, true); assert.equal(first.cohorts.flights.provenance.enabled, true);
assert.equal(first.cohorts.flights.items[0].icao24, 'nearby'); assert.equal(first.cohorts.flights.items[0].icao24, 'nearby');
first.cohorts.flights.items[0].icao24 = 'mutated'; first.cohorts.flights.items[0].icao24 = 'mutated';
first.cohorts.flights.items[0].position.x = 99;
first.cohorts.flights.provenance.source = 'mutated'; first.cohorts.flights.provenance.source = 'mutated';
assert.equal( first.cohorts.flights.provenance.stats.coverage = { radiusM: 1 };
militaryAwarenessLayer.getAircraftQuerySnapshot().cohorts.flights.items[0] first.subject.position.x = 77;
.icao24, const second = militaryAwarenessLayer.getAircraftQuerySnapshot();
'nearby', assert.equal(second.cohorts.flights.items[0].icao24, 'nearby');
); assert.equal(second.cohorts.flights.items[0].position.x, nearbyPosition.x);
assert.notEqual( assert.notEqual(second.cohorts.flights.provenance.source, 'mutated');
militaryAwarenessLayer.getAircraftQuerySnapshot().cohorts.flights assert.notDeepEqual(second.cohorts.flights.provenance.stats.coverage, {
.provenance.source, radiusM: 1,
'mutated', });
); assert.equal(second.subject.position.x, subjectPosition.x);
} finally { } finally {
runtime.restore(); runtime.restore();
restoreCollections(); restoreCollections();
+6 -10
View File
@@ -105,23 +105,19 @@ export function createControls({ state: layerState, services, parts, source }) {
truncated: truncated:
!Number.isFinite(cohort.summary?.count) || !Number.isFinite(cohort.summary?.count) ||
cohort.summary?.truncated === true, cohort.summary?.truncated === true,
items: (cohort.summary?.navigationNearest || []).map((item) => ({ // These records carry structured values such as Cartesian positions.
...item, // A shallow spread would let a voice consumer mutate the retained
})), // Contacts cohort through the advertised read-only snapshot.
items: structuredClone(cohort.summary?.navigationNearest || []),
source: cohort.source || null, source: cohort.source || null,
provenance: cohort.provenance provenance: cohort.provenance
? { ? structuredClone(cohort.provenance)
...cohort.provenance,
stats: cohort.provenance.stats
? { ...cohort.provenance.stats }
: undefined,
}
: null, : null,
reason: cohort.summary?.reason || null, reason: cohort.summary?.reason || null,
}; };
} }
return { return {
subject: { ...layerState.results.subject }, subject: structuredClone(layerState.results.subject),
evaluatedAt: layerState.results.evaluatedAt, evaluatedAt: layerState.results.evaluatedAt,
radiusM: layerState.results.radiusM, radiusM: layerState.results.radiusM,
cohorts, cohorts,