Files
gods-eye-view/src/data/localGeojsonLod.test.mjs
T
Sameh Khamis b5568de9fa fix(infrastructure): stop idle republishing and respect settled terrain
Skip unchanged overlay cohorts while detecting moved positions and lifecycle changes. Defer ground sampling until visible terrain settles, retain the loaded surface as a floor, and preserve roof heights and bounded retries. Keep regression and idle-render gates intact.
2026-09-11 08:59:32 -07:00

380 lines
16 KiB
JavaScript

// src/data/localGeojsonLod.test.mjs
// Pure LOD-engine tests for the bundled local-infrastructure layers:
// camera-height budget bands (inverted sense vs CCTV), importance+proximity
// ranking with an incumbency bonus, in-view filtering, dedupe, and the
// ported eviction-grace planner.
import { test } from 'node:test';
import assert from 'node:assert/strict';
import {
INFRA_LOD_ACTIVE_MIN,
INFRA_LOD_ACTIVE_MID,
INFRA_LOD_ACTIVE_MAX,
INFRA_LOD_GLOBAL_HEIGHT_M,
INFRA_LOD_REGIONAL_HEIGHT_M,
INFRA_LOD_INCUMBENT_BONUS,
INFRA_LOD_FAR_M,
INFRA_LOD_MAX_DISTANCE_PENALTY,
INFRA_LOD_GRACE_PASSES,
INFRA_LOD_GRACE_MS,
infraLodBudget,
infraRankScore,
selectInfraLod,
applyInfraEvictionGrace,
INFRA_LOD_MOTION_PROBE_INTERVAL_MS,
INFRA_LOD_MOTION_EPSILON_RATIO,
INFRA_LOD_MOTION_EPSILON_MIN_M,
infraLodMotionEpsilonM,
shouldRecomputeInfraLod,
} from './localGeojsonLod.js';
/**
* `count` in-view candidates. index 0 is the most important (highest priority)
* and the nearest; importance and distance both worsen with index.
*/
function candidates(count, options = {}) {
return Array.from({ length: count }, (_, index) => ({
id: `f-${String(index).padStart(3, '0')}`,
priority: 1000 - index,
distanceM: index * 1000,
inView: options.hiddenAt !== index,
}));
}
/* ----------------------------- budget ----------------------------- */
test('infraLodBudget clamps hardest at global height and opens up as you zoom in', () => {
assert.equal(INFRA_LOD_ACTIVE_MIN, 80);
assert.equal(INFRA_LOD_ACTIVE_MID, 200);
assert.equal(INFRA_LOD_ACTIVE_MAX, 420);
assert.deepEqual(infraLodBudget(9_000_000), { activeLimit: INFRA_LOD_ACTIVE_MIN });
assert.deepEqual(infraLodBudget(1_000_000), { activeLimit: INFRA_LOD_ACTIVE_MID });
assert.deepEqual(infraLodBudget(50_000), { activeLimit: INFRA_LOD_ACTIVE_MAX });
});
test('infraLodBudget band boundaries are inclusive at the lower edge', () => {
assert.deepEqual(infraLodBudget(INFRA_LOD_GLOBAL_HEIGHT_M), { activeLimit: INFRA_LOD_ACTIVE_MIN });
assert.deepEqual(infraLodBudget(INFRA_LOD_GLOBAL_HEIGHT_M - 1), { activeLimit: INFRA_LOD_ACTIVE_MID });
assert.deepEqual(infraLodBudget(INFRA_LOD_REGIONAL_HEIGHT_M), { activeLimit: INFRA_LOD_ACTIVE_MID });
assert.deepEqual(infraLodBudget(INFRA_LOD_REGIONAL_HEIGHT_M - 1), { activeLimit: INFRA_LOD_ACTIVE_MAX });
});
test('infraLodBudget uses the global band for non-finite height and clamps negative height to zero', () => {
assert.deepEqual(infraLodBudget(undefined), { activeLimit: INFRA_LOD_ACTIVE_MIN });
assert.deepEqual(infraLodBudget(NaN), { activeLimit: INFRA_LOD_ACTIVE_MIN });
assert.deepEqual(infraLodBudget(Number.POSITIVE_INFINITY), { activeLimit: INFRA_LOD_ACTIVE_MIN });
assert.deepEqual(infraLodBudget(-1), { activeLimit: INFRA_LOD_ACTIVE_MAX }); // max(0,-1) -> 0 -> closest band
});
/* ------------------------------ rank ----------------------------- */
test('infraRankScore is priority minus a bounded distance penalty', () => {
assert.equal(infraRankScore(1000, 0, false), 1000);
assert.equal(infraRankScore(1000, INFRA_LOD_FAR_M, false), 1000 - INFRA_LOD_MAX_DISTANCE_PENALTY);
// half-way to FAR -> half the penalty
assert.equal(infraRankScore(1000, INFRA_LOD_FAR_M / 2, false), 1000 - INFRA_LOD_MAX_DISTANCE_PENALTY / 2);
// beyond FAR the penalty is capped, not extrapolated
assert.equal(infraRankScore(1000, INFRA_LOD_FAR_M * 10, false), 1000 - INFRA_LOD_MAX_DISTANCE_PENALTY);
});
test('infraRankScore incumbency bonus reorders within a tier but never beats a name gap', () => {
// Two similarly-important features: incumbency flips the order.
const freshNear = infraRankScore(900, 0, false);
const incumbentFar = infraRankScore(900, INFRA_LOD_FAR_M, true);
assert.ok(incumbentFar > freshNear);
// An unnamed incumbent (priority ~60) must NOT outrank a fresh named feature
// (priority ~1000): the incumbency bonus is smaller than that gap.
const unnamedIncumbent = infraRankScore(60, 0, true);
const namedFresh = infraRankScore(1000, INFRA_LOD_FAR_M, false);
assert.ok(namedFresh > unnamedIncumbent);
assert.ok(INFRA_LOD_INCUMBENT_BONUS < 700);
});
test('infraRankScore normalizes garbage inputs to a finite number', () => {
assert.equal(infraRankScore(NaN, NaN, false), 0 - INFRA_LOD_MAX_DISTANCE_PENALTY); // priority 0, distance -> FAR
assert.equal(Number.isFinite(infraRankScore('x', -5, true)), true);
assert.equal(infraRankScore(500, -5, false), 500 - INFRA_LOD_MAX_DISTANCE_PENALTY); // negative dist -> FAR
});
/* --------------------------- selectInfraLod ---------------------- */
test('selectInfraLod returns everything in view when under budget', () => {
const { activeIds, budget } = selectInfraLod(candidates(10), { cameraHeightM: 9_000_000 });
assert.equal(budget.activeLimit, INFRA_LOD_ACTIVE_MIN);
assert.equal(activeIds.length, 10);
assert.deepEqual(activeIds.slice(0, 3), ['f-000', 'f-001', 'f-002']);
});
test('selectInfraLod caps at the global budget and keeps the most important', () => {
const { activeIds } = selectInfraLod(candidates(500), { cameraHeightM: 9_000_000 });
assert.equal(activeIds.length, INFRA_LOD_ACTIVE_MIN);
assert.equal(activeIds[0], 'f-000');
assert.equal(activeIds.at(-1), `f-${String(INFRA_LOD_ACTIVE_MIN - 1).padStart(3, '0')}`);
});
test('selectInfraLod cap follows the zoom band', () => {
assert.equal(selectInfraLod(candidates(600), { cameraHeightM: 9_000_000 }).activeIds.length, INFRA_LOD_ACTIVE_MIN);
assert.equal(selectInfraLod(candidates(600), { cameraHeightM: 1_000_000 }).activeIds.length, INFRA_LOD_ACTIVE_MID);
assert.equal(selectInfraLod(candidates(600), { cameraHeightM: 50_000 }).activeIds.length, INFRA_LOD_ACTIVE_MAX);
});
test('selectInfraLod excludes out-of-view records', () => {
const input = candidates(20, { hiddenAt: 0 });
const { activeIds } = selectInfraLod(input, { cameraHeightM: 50_000 });
assert.equal(activeIds.includes('f-000'), false);
assert.equal(activeIds.length, 19);
});
test('selectInfraLod orders by score: a near unnamed node never displaces a far named one', () => {
const input = [
{ id: 'named-far', priority: 1000, distanceM: INFRA_LOD_FAR_M, inView: true },
{ id: 'unnamed-near', priority: 60, distanceM: 0, inView: true },
];
const { activeIds } = selectInfraLod(input, { cameraHeightM: 9_000_000 });
assert.deepEqual(activeIds, ['named-far', 'unnamed-near']);
});
test('selectInfraLod proximity breaks ties among equally important features', () => {
const input = [
{ id: 'far', priority: 500, distanceM: 5_000_000, inView: true },
{ id: 'near', priority: 500, distanceM: 1_000, inView: true },
];
const { activeIds } = selectInfraLod(input, { cameraHeightM: 9_000_000 });
assert.deepEqual(activeIds, ['near', 'far']);
});
test('selectInfraLod incumbency keeps a budget-edge stem that would otherwise be cut', () => {
const base = candidates(INFRA_LOD_ACTIVE_MIN + 5, {});
// The record that sits just past the cap:
const edgeId = `f-${String(INFRA_LOD_ACTIVE_MIN).padStart(3, '0')}`;
const withoutIncumbency = selectInfraLod(base, { cameraHeightM: 9_000_000 });
assert.equal(withoutIncumbency.activeIds.includes(edgeId), false);
const withIncumbency = selectInfraLod(base, {
cameraHeightM: 9_000_000,
incumbentIds: new Set([edgeId]),
});
assert.equal(withIncumbency.activeIds.includes(edgeId), true);
assert.equal(withIncumbency.activeIds.length, INFRA_LOD_ACTIVE_MIN);
});
test('selectInfraLod accepts an array or a Set of incumbent ids', () => {
const base = candidates(INFRA_LOD_ACTIVE_MIN + 3, {});
const edgeId = `f-${String(INFRA_LOD_ACTIVE_MIN).padStart(3, '0')}`;
const viaArray = selectInfraLod(base, { cameraHeightM: 9_000_000, incumbentIds: [edgeId] });
assert.equal(viaArray.activeIds.includes(edgeId), true);
});
test('selectInfraLod collapses duplicate ids to their best-scoring representative', () => {
const input = [
{ id: 'dup', priority: 100, distanceM: INFRA_LOD_FAR_M, inView: true },
{ id: 'dup', priority: 900, distanceM: 0, inView: true },
{ id: 'other', priority: 500, distanceM: 0, inView: true },
];
const { activeIds } = selectInfraLod(input, { cameraHeightM: 9_000_000 });
assert.deepEqual(activeIds, ['dup', 'other']);
assert.equal(activeIds.filter((id) => id === 'dup').length, 1);
});
test('selectInfraLod is defensive about junk input', () => {
assert.deepEqual(selectInfraLod(null, {}).activeIds, []);
assert.deepEqual(selectInfraLod(undefined).activeIds, []);
assert.deepEqual(
selectInfraLod([null, {}, { id: '' }, { id: 'x', inView: false }], { cameraHeightM: 1000 }).activeIds,
[],
);
});
test('selectInfraLod produces a deterministic order for score+distance ties', () => {
const input = [
{ id: 'b', priority: 500, distanceM: 1000, inView: true },
{ id: 'a', priority: 500, distanceM: 1000, inView: true },
{ id: 'c', priority: 500, distanceM: 1000, inView: true },
];
const { activeIds } = selectInfraLod(input, { cameraHeightM: 50_000 });
assert.deepEqual(activeIds, ['a', 'b', 'c']);
});
/* ---------------------- applyInfraEvictionGrace ------------------ */
test('applyInfraEvictionGrace keeps every selected id and starts no grace for them', () => {
const out = applyInfraEvictionGrace({
selectedIds: ['a', 'b'],
builtIds: ['a', 'b'],
nowMs: 1000,
});
assert.deepEqual(out.keepIds.sort(), ['a', 'b']);
assert.deepEqual(out.evictIds, []);
assert.equal(out.graceState.size, 0);
});
test('applyInfraEvictionGrace holds a dropped stem through the grace window then evicts it', () => {
let grace = new Map();
// pass 1: 'x' built but not selected -> graced (miss 1)
let out = applyInfraEvictionGrace({ selectedIds: ['a'], builtIds: ['a', 'x'], graceState: grace, nowMs: 0 });
assert.deepEqual(out.keepIds.sort(), ['a', 'x']);
assert.deepEqual(out.evictIds, []);
grace = out.graceState;
// pass 2: still missing -> miss 2, still within gracePasses (2)
out = applyInfraEvictionGrace({ selectedIds: ['a'], builtIds: ['a', 'x'], graceState: grace, nowMs: 10 });
assert.equal(out.keepIds.includes('x'), true);
grace = out.graceState;
// pass 3: miss 3 > gracePasses -> evicted
out = applyInfraEvictionGrace({ selectedIds: ['a'], builtIds: ['a', 'x'], graceState: grace, nowMs: 20 });
assert.deepEqual(out.evictIds, ['x']);
assert.equal(out.keepIds.includes('x'), false);
assert.equal(out.graceState.has('x'), false);
});
test('applyInfraEvictionGrace evicts on wall-clock even before the pass count', () => {
const grace = new Map([['x', { misses: 1, since: 0 }]]);
const out = applyInfraEvictionGrace({
selectedIds: [],
builtIds: ['x'],
graceState: grace,
nowMs: INFRA_LOD_GRACE_MS,
gracePasses: 99,
});
assert.deepEqual(out.evictIds, ['x']);
});
test('applyInfraEvictionGrace never exceeds the cap: oldest-in-grace evicted first', () => {
const grace = new Map([
['old', { misses: 1, since: 0 }],
['mid', { misses: 1, since: 5 }],
['new', { misses: 1, since: 9 }],
]);
const out = applyInfraEvictionGrace({
selectedIds: ['s1', 's2'],
builtIds: ['s1', 's2', 'old', 'mid', 'new'],
graceState: grace,
nowMs: 10,
activeLimit: 3, // room for only ONE graced stem on top of s1,s2
});
assert.deepEqual(out.keepIds.slice(0, 2).sort(), ['s1', 's2']);
assert.equal(out.keepIds.includes('new'), true);
assert.deepEqual(out.evictIds.sort(), ['mid', 'old']);
});
test('applyInfraEvictionGrace does not mutate the graceState it was given', () => {
const grace = new Map([['x', { misses: 1, since: 0 }]]);
const snapshot = JSON.stringify([...grace]);
applyInfraEvictionGrace({ selectedIds: [], builtIds: ['x'], graceState: grace, nowMs: 5 });
assert.equal(JSON.stringify([...grace]), snapshot);
});
test('applyInfraEvictionGrace tolerates missing / malformed input', () => {
const out = applyInfraEvictionGrace();
assert.deepEqual(out.keepIds, []);
assert.deepEqual(out.evictIds, []);
assert.equal(out.graceState instanceof Map, true);
const out2 = applyInfraEvictionGrace({ selectedIds: ['a', '', null], builtIds: [null, 'a', 3] });
assert.deepEqual(out2.keepIds, ['a']);
});
test('grace constants are the documented defaults', () => {
assert.equal(INFRA_LOD_GRACE_PASSES, 2);
assert.equal(INFRA_LOD_GRACE_MS, 4_000);
});
/* -------------------------- motion fallback ------------------------- */
test('infraLodMotionEpsilonM scales with camera height above a fixed floor', () => {
assert.equal(INFRA_LOD_MOTION_EPSILON_RATIO, 0.02);
assert.equal(INFRA_LOD_MOTION_EPSILON_MIN_M, 250);
// Well above the floor: pure ratio.
assert.equal(infraLodMotionEpsilonM(3_000_000), 60_000);
assert.equal(infraLodMotionEpsilonM(1_000_000), 20_000);
// Near the surface the floor wins, so a low camera still needs real travel.
assert.equal(infraLodMotionEpsilonM(5_000), INFRA_LOD_MOTION_EPSILON_MIN_M);
assert.equal(infraLodMotionEpsilonM(0), INFRA_LOD_MOTION_EPSILON_MIN_M);
});
test('infraLodMotionEpsilonM falls back to the floor (most eager) on unreadable height', () => {
// Opposite polarity to infraLodBudget on purpose: a missed recompute empties
// the layer, a surplus one costs a single bounded pass.
assert.equal(infraLodMotionEpsilonM(undefined), INFRA_LOD_MOTION_EPSILON_MIN_M);
assert.equal(infraLodMotionEpsilonM(NaN), INFRA_LOD_MOTION_EPSILON_MIN_M);
assert.equal(infraLodMotionEpsilonM(Number.POSITIVE_INFINITY), INFRA_LOD_MOTION_EPSILON_MIN_M);
assert.equal(infraLodMotionEpsilonM(-9_000), INFRA_LOD_MOTION_EPSILON_MIN_M);
});
test('shouldRecomputeInfraLod recomputes once the camera has moved far enough', () => {
const out = shouldRecomputeInfraLod({
nowMs: 10_000,
lastProbeMs: 0,
movedSqM: 500_000 ** 2, // 500 km >> the 60 km epsilon at 3,000 km up
cameraHeightM: 3_000_000,
});
assert.equal(out.recompute, true);
assert.equal(out.lastProbeMs, 10_000, 'the window re-arms at this pass');
});
test('shouldRecomputeInfraLod holds the window shut inside the probe interval', () => {
const out = shouldRecomputeInfraLod({
nowMs: 500,
lastProbeMs: 0,
movedSqM: 9_000_000 ** 2, // enormous motion, but the rate limit comes first
cameraHeightM: 3_000_000,
probeIntervalMs: INFRA_LOD_MOTION_PROBE_INTERVAL_MS,
});
assert.equal(out.recompute, false);
assert.equal(out.lastProbeMs, 0, 'a shut window does not re-arm');
});
test('shouldRecomputeInfraLod spends nothing on a parked camera', () => {
const out = shouldRecomputeInfraLod({
nowMs: 60_000,
lastProbeMs: 0,
movedSqM: 0,
cameraHeightM: 3_000_000,
});
assert.equal(out.recompute, false);
assert.equal(out.lastProbeMs, 60_000, 'the window still re-arms, so the probe stays on a fixed cadence');
});
test('shouldRecomputeInfraLod ignores sub-epsilon jitter but accumulates real travel', () => {
const height = 1_000_000; // epsilon 20,000 m
const jitter = shouldRecomputeInfraLod({
nowMs: 5_000, lastProbeMs: 0, movedSqM: 19_999 ** 2, cameraHeightM: height,
});
assert.equal(jitter.recompute, false);
// Travel is measured from the last SELECTION, so a creeping camera keeps
// closing on the epsilon across windows instead of resetting every pass.
const crept = shouldRecomputeInfraLod({
nowMs: 10_000, lastProbeMs: 5_000, movedSqM: 20_001 ** 2, cameraHeightM: height,
});
assert.equal(crept.recompute, true);
});
test('shouldRecomputeInfraLod opens on first use and tolerates missing / malformed input', () => {
// No prior probe: the window is open immediately.
const first = shouldRecomputeInfraLod({ nowMs: 1_000, movedSqM: 5_000 ** 2, cameraHeightM: 50_000 });
assert.equal(first.recompute, true);
assert.equal(first.lastProbeMs, 1_000);
const empty = shouldRecomputeInfraLod();
assert.equal(empty.recompute, false, 'no motion reported means no recompute');
assert.equal(empty.lastProbeMs, 0);
const garbage = shouldRecomputeInfraLod({
nowMs: NaN, lastProbeMs: NaN, movedSqM: NaN, cameraHeightM: NaN, probeIntervalMs: NaN,
});
assert.equal(garbage.recompute, false);
// An explicit epsilon overrides the height scale.
const explicit = shouldRecomputeInfraLod({
nowMs: 2_000, lastProbeMs: 0, movedSqM: 300 ** 2, cameraHeightM: 9_000_000, motionEpsilonM: 100,
});
assert.equal(explicit.recompute, true);
});
test('motion-fallback constants are the documented defaults', () => {
assert.equal(INFRA_LOD_MOTION_PROBE_INTERVAL_MS, 1_000);
assert.equal(INFRA_LOD_MOTION_EPSILON_RATIO, 0.02);
assert.equal(INFRA_LOD_MOTION_EPSILON_MIN_M, 250);
});