Files
gods-eye-view/scripts/qa-installation-polish.mjs
T
German Khokhlov 0ef29781e5 Fix the review findings across the engines, layers, data and QA
Navara now matches Cesium where the review found it diverging: a flight
holds the camera inputs, camera.changed counts turns as Cesium does,
render requests made during a frame survive it, follow pinches zoom,
ground widths follow the pixel ratio and Cyber sonar reaches glyph caches
and models. On Cesium, a staged imagery swap keeps loading tiles, setView
replaces a running flight, and a cleared weather detail goes away.

The contract gains MoverSet.failed, maps.terrainRevision,
render.maxTextureSize and surface.sampleTerrainMostDetailed on every
engine, so layers retry failed models, key road heights by terrain,
size weather textures to the GPU and place Bhote Koshi cards on detailed
terrain.

Engine switches keep the live view, follows, focus, layer options and
cards: a pick hands over the exact pose, applies no address options and
pans no carried-over card; a history visit still applies its entry.

Layers put GhostMaps pins, cable landings, OSM Places and directions on
the measured surface without per-frame sampling, draw the Cockpit contact
dot, hide disabled CCTV on attach, and keep ALPR running outside secure
contexts. KML imports draw raised polygon fills, rotated and coloured
ground overlays and north-referenced icon headings, and report files
with nothing to draw.

QA scripts read the contract instead of Cesium internals (test:track is
109/109 again), wait for the camera to rest before clicking, and give
cold switches and parked engines realistic time. Docs follow the code.
2026-11-09 21:34:42 +04:00

388 lines
14 KiB
JavaScript

/** Shared browser assertions for installation label persistence and selection. */
import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import { moveCamera, createScreencast } from './qa-journey-recorder.mjs';
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
export async function checkInstallationPan(page, dir) {
await page.evaluate(() =>
window.__godsEyeView.dataManager.setEnabled('local-datacenters', true),
);
await sleep(3000);
await page.evaluate(async () => {
const { getPaintRect } = (
await import('/src/overlays/worldOverlay.js')
).worldOverlayFor(window.__godsEyeView.engine);
const g = window.__godsEyeView;
const installations = g.dataManager.layers.get(
'military-installations',
).module;
// The datacenters' overlay entry ids: the layer draws through the globe
// contract and registers each reference row (its overlay entry's id) in
// the context store; it owns no Cesium entities.
const centerIds = [];
for (const record of window.__gevContextStore?.entities.values() ?? [])
if (record.layerId === 'local-datacenters' && record.entity?.id != null)
centerIds.push(record.entity.id);
window.__polishPanFrames = [];
window.__stopPolishPan = g.viewer.scene.postRender.addEventListener(() => {
const sites = [],
centers = [];
installations.visitNamedMarkers((id) => {
if (getPaintRect('military-installations', id)) sites.push(id);
});
for (const id of centerIds)
if (getPaintRect('local-datacenters', id)) centers.push(id);
window.__polishPanFrames.push({ t: performance.now(), sites, centers });
});
});
await moveCamera(page, { lon: -99, lat: 39, height: 6500000, pitch: -90 }, 8);
const frames = await page.evaluate(() => {
window.__stopPolishPan();
return window.__polishPanFrames;
});
const count = (key) => {
let appeared = 0,
disappeared = 0,
reappeared = 0;
const seen = new Set(frames[0][key]);
for (let i = 1; i < frames.length; i++) {
const previous = new Set(frames[i - 1][key]),
next = new Set(frames[i][key]);
frames[i][`${key}Appeared`] = [...next].filter((id) => !previous.has(id));
frames[i][`${key}Disappeared`] = [...previous].filter(
(id) => !next.has(id),
);
for (const id of frames[i][`${key}Appeared`]) {
appeared++;
if (seen.has(id)) reappeared++;
seen.add(id);
}
disappeared += frames[i][`${key}Disappeared`].length;
}
const mean =
frames.reduce((sum, f) => sum + f[key].length, 0) / frames.length;
return {
appeared,
disappeared,
reappeared,
mean,
eventsPerLabel: (appeared + disappeared) / mean,
};
};
const result = {
frames: frames.length,
installations: count('sites'),
datacenters: count('centers'),
};
await fs.writeFile(
`${dir}/slow-pan-frames.json`,
JSON.stringify(frames, null, 2),
);
await fs.writeFile(`${dir}/slow-pan.json`, JSON.stringify(result, null, 2));
assert.ok(frames.length > 100);
assert.ok(
result.installations.mean >= 5 && result.datacenters.mean >= 5,
'both real layers contribute visible labels on the same pan',
);
assert.ok(
frames.every((f) => f.sites.length <= 24),
'shared-domain budget cannot exceed the installation title cap',
);
assert.ok(
result.installations.eventsPerLabel <=
result.datacenters.eventsPerLabel + 0.1,
'installation label transitions per label match Data Centers on the same slow pan',
);
assert.ok(
result.installations.reappeared <= result.datacenters.reappeared,
'installation labels do not flicker off and back on more than Data Centers',
);
await page.screenshot({ path: `${dir}/slow-pan-side-by-side.png` });
await page.evaluate(() =>
window.__godsEyeView.dataManager.setEnabled('local-datacenters', false),
);
return result;
}
export async function checkInstallationSelection(
page,
dir,
{ video = true } = {},
) {
await page.evaluate(() => {
const ground = window.__godsEyeView.engine.ground;
const create = ground.createSet.bind(ground);
window.__polishGroundSets = new Map();
ground.createSet = (options) => {
const set = create(options);
window.__polishGroundSets.set(options.id, { set, drape: options.drape ?? 'both' });
return set;
};
window.__restorePolishGround = () => { ground.createSet = create; };
});
const result = [];
const recorder = video
? await createScreencast(page, `${dir}/selection-orbit`, { fps: 24 })
: null;
await recorder?.start();
try {
for (const site of [
{
key: 'mabry',
name: 'Camp Mabry',
lon: -97.765,
lat: 30.3125,
height: 3500,
},
{
key: 'naval',
name: 'Naval Base San Diego',
lon: -117.119,
lat: 32.684,
height: 6500,
},
]) {
await moveCamera(page, { ...site, pitch: -80 }, 1.5);
await page.waitForFunction(
() => {
const s = window.__godsEyeView.dataManager.layers
.get('military-installations')
.module.getStats();
return !s.loading && s.count > 0;
},
{ timeout: 60000 },
);
await sleep(1500);
const picked = await page.evaluate(async (site) => {
const C = await import('/node_modules/cesium/Build/Cesium/index.js');
const g = window.__godsEyeView,
layer = g.dataManager.layers.get('military-installations').module;
const record = layer
.getNearby(C.Cartesian3.fromDegrees(site.lon, site.lat), 100000, 1000)
.find((r) => r.name === site.name && r.footprints?.length);
if (!record) throw new Error(`No polygon for ${site.name}`);
let point;
layer.visitNamedMarkers((id, p) => {
if (id === record.id) point = p.position;
});
const screen = C.SceneTransforms.worldToWindowCoordinates(
g.viewer.scene,
point,
);
window.__polishSelectedId = record.id;
window.__polishTitlePaints = [];
const canvas = document.getElementById('world-overlay-canvas'),
ctx = canvas.getContext('2d');
const original = ctx.fillText;
const matches = (text) =>
String(text).toLowerCase() === site.name.toLowerCase();
ctx.fillText = function (text, ...args) {
if (matches(text))
window.__polishTitlePaints.push({ t: performance.now(), text });
return original.call(this, text, ...args);
};
window.__restorePolishPaint = () => {
ctx.fillText = original;
};
window.__polishSelectionFrames = [];
const { getSelectedEntityContext } =
await import('/src/data/contextStore.js');
const { getPaintRect, getDiagnostics } = (
await import('/src/overlays/worldOverlay.js')
).worldOverlayFor(window.__godsEyeView.engine);
// The selected site's fill is one engine.ground polygon set
// (render/display.js SELECTION_FILL_SET_ID), an item per footprint
// part; the layer owns no Cesium entities or ground primitives.
const fillSet = () =>
g.engine.ground
.list()
.find((set) => set.id === 'military-installations-selection-fill');
window.__polishFillProbe = () => {
const set = fillSet();
const items = set?.shown ? set.count : 0;
const captured = window.__polishGroundSets.get(set?.id);
// A retained fill may predate this probe. Its engine-owned batches
// prove readiness and classification on this Cesium-only check.
const batches = [];
const visit = collection => {
for (let i = 0; i < collection.length; i++) {
const primitive = collection.get(i);
if (primitive.gevGroundSet === set?.id) batches.push(primitive);
else if (typeof primitive.get === 'function') visit(primitive);
}
};
if (!captured && set) visit(g.viewer.scene.groundPrimitives);
const ready = captured ? captured.set.ready() : batches.length > 0 && batches.every(p => p.ready);
const drape = captured?.drape ?? ['terrain', 'tiles', 'both'][batches[0]?.classificationType];
return {
items,
readyItems: ready ? items : 0,
drape,
expectedDrape: g.engine.maps.photorealActive() ? 'tiles' : 'both',
selected: getSelectedEntityContext()?.id || null,
};
};
window.__stopPolishSelection =
g.viewer.scene.postRender.addEventListener(() => {
window.__polishSelectionFrames.push({
paints: window.__polishTitlePaints.splice(0).length,
own: Boolean(getPaintRect('military-installations', record.id)),
tracked: Boolean(
getPaintRect('tracked', `installations:${record.id}`),
),
selected: getSelectedEntityContext()?.id === record.id,
total:
getDiagnostics().paintedBySource['military-installations'] || 0,
});
});
return {
id: record.id,
x: screen.x,
y: screen.y,
parts: record.footprints.length,
};
}, site);
await page.screenshot({
path: `${dir}/after-${site.key}-unselected.png`,
});
await page.mouse.click(picked.x, picked.y);
await page
.waitForFunction(
() => {
const p = window.__polishFillProbe();
return p.selected === window.__polishSelectedId && p.readyItems > 0;
},
{ timeout: 20000 },
)
.catch(async (error) => {
await page.screenshot({ path: `${dir}/selection-failure.png` });
const diagnostic = await page.evaluate(() => {
const g = window.__godsEyeView;
return {
probe: window.__polishFillProbe(),
stats: g.dataManager.layers
.get('military-installations')
.module.getStats(),
ground: g.engine.ground.list(),
frames: window.__polishSelectionFrames.slice(-5),
};
});
await fs.writeFile(
`${dir}/selection-failure.json`,
JSON.stringify({ picked, ...diagnostic }, null, 2),
);
throw error;
});
await sleep(500);
const selected = await page.evaluate(() => window.__polishFillProbe());
await page.screenshot({ path: `${dir}/after-selection-${site.key}.png` });
// Close, oblique angles expose surface clipping and floating fills.
for (const heading of [30, 120]) {
await page.evaluate(
async (site, heading) => {
const C =
await import('/node_modules/cesium/Build/Cesium/index.js');
const g = window.__godsEyeView;
const target = C.Cartesian3.fromDegrees(
site.lon,
site.lat,
site.key === 'mabry' ? 180 : 10,
);
g.viewer.camera.lookAt(
target,
new C.HeadingPitchRange(
C.Math.toRadians(heading),
C.Math.toRadians(-30),
800,
),
);
g.viewer.camera.lookAtTransform(C.Matrix4.IDENTITY);
},
site,
heading,
);
await sleep(1700);
assert.ok(
(await page.evaluate(() => window.__polishFillProbe())).selected,
'orbit must preserve installation selection',
);
await page.screenshot({
path: `${dir}/after-${site.key}-orbit-${heading}.png`,
});
}
await moveCamera(page, { ...site, pitch: -80 }, 1);
await sleep(900);
const empty = await page.evaluate(() => {
const g = window.__godsEyeView;
for (let y = 250; y < 650; y += 75)
for (let x = 400; x < 850; x += 75) {
// Nothing drawn there: no mover, line or ground item's pickId.
const pick = g.engine.picker.pick({ x, y });
if (pick?.id == null) return { x, y };
}
throw new Error('No empty map point');
});
await page.mouse.click(empty.x, empty.y);
await page.waitForFunction(
() =>
window.__polishFillProbe().selected === null &&
window.__polishFillProbe().items === 0,
);
await sleep(600);
const deselected = await page.evaluate(() => {
window.__stopPolishSelection();
window.__restorePolishPaint();
return {
...window.__polishFillProbe(),
frames: window.__polishSelectionFrames,
};
});
assert.equal(selected.items, picked.parts);
assert.equal(selected.readyItems, picked.parts);
assert.equal(selected.drape, selected.expectedDrape, 'selection fill follows the map surface');
assert.equal(deselected.items, 0);
assert.equal(deselected.readyItems, 0);
const selectedFrames = deselected.frames.filter(
(f) => f.selected && f.own,
);
assert.ok(selectedFrames.length > 10);
assert.ok(
selectedFrames.every((f) => !f.tracked && f.paints === 1),
'selected record has exactly one painted overlay element',
);
assert.ok(
deselected.frames
.slice(-5)
.every((f) => !f.selected && f.own && !f.tracked && f.paints === 1),
'deselect restores the one ambient entry',
);
await page.screenshot({
path: `${dir}/after-${site.key}-deselected.png`,
});
result.push({ site, picked, selected, deselected });
}
} finally {
await page.evaluate(() => window.__restorePolishGround?.());
await fs.writeFile(
`${dir}/selection-checks.json`,
JSON.stringify(result, null, 2),
);
if (recorder)
await fs.writeFile(
`${dir}/selection-video.json`,
JSON.stringify(await recorder.stop(), null, 2),
);
}
return result.map(({ site, picked, selected, deselected }) => ({
site: site.name,
id: picked.id,
selected,
deselected: {
entities: deselected.items,
primitives: deselected.readyItems,
},
frames: deselected.frames.length,
}));
}