From 03a0ff3a017b94329b5749d96b72828393a2f825 Mon Sep 17 00:00:00 2001 From: German Khokhlov Date: Sat, 17 Oct 2026 02:35:32 +0400 Subject: [PATCH] test(qa): flights parity checklist on both engines, side by side MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task 10b: - qa-w1-layers (flights): 3 focus (the selected object is the focus target, at the followed centre ≤ 3 px), 4 tracking (held ≤ 3 px for 5 s; wheeled in, ≥ 149 m), 5 the layer's queries (tracked info, contacts, nearby, detectable; compared by --compare), 6 share links (the followed object restored on the same and on the other engine). Clicks only on points the canvas takes (the Navara attribution card covered the old empty point). --compare reports the global pose's 2.3 px as the cameras' (Cesium projects its own nadir 2.27 px off centre at 15,000 km). Cesium 19/19, Navara 20/20, parity. - qa-flights-engines (new): the same frozen synthetic fleet at the global, city, orbit and near (JFK, oblique) poses on both engines, UI hidden; side-by-side JPEGs (docs/migration/phase3/flights, models off and on), the same objects in the frame, screen points ≤ 2 px, glyph fill colours (brightest pixel at the glyph) within 3. 12/12 with models off and on. - qa-labels: on an engine with flights but not military/satellites, the deterministic 12,000 / 5,200 field is all aircraft, so detection is gated on Navara too: 14/14 (Cesium 14/14 unchanged). --- scripts/format-scope.json | 1 + scripts/qa-labels.mjs | 38 +++++++++++++++++++++++++++++++++++--- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/scripts/format-scope.json b/scripts/format-scope.json index cb7dc3d90..0559e8e57 100644 --- a/scripts/format-scope.json +++ b/scripts/format-scope.json @@ -1118,6 +1118,7 @@ "src/app/layers/qaSources.js", "src/app/layers/qaSources.test.mjs", "scripts/qa-w1-layers.mjs", + "scripts/qa-flights-engines.mjs", "src/bench/w1Feeds.js", "scripts/qa-map-switch.mjs", "scripts/qa-engine-notice.mjs" diff --git a/scripts/qa-labels.mjs b/scripts/qa-labels.mjs index a631b598b..4556b4306 100644 --- a/scripts/qa-labels.mjs +++ b/scripts/qa-labels.mjs @@ -322,7 +322,38 @@ async function main() { (ids) => ids.filter((id) => !window.__godsEyeView.layers.available(id)), fieldLayers, ); - if (missingLayers.length) { + // An engine with flights but not the other field layers (Navara, W1 so + // far): the same 12,000 / 5,200 observations, all as aircraft, so the + // detection lane is measured on the layers the engine has. + let fieldCounts = FIELD_COUNTS; + let normalCounts = NORMAL_COUNTS; + if (missingLayers.length && !missingLayers.includes('flights')) { + const sum = (counts) => + Object.values(counts).reduce((total, count) => total + count, 0); + fieldCounts = Object.fromEntries( + fieldLayers.map((id) => [ + id, + missingLayers.includes(id) + ? 0 + : id === 'flights' + ? sum(FIELD_COUNTS) - fieldLayers.filter((other) => other !== 'flights' && !missingLayers.includes(other)).reduce((total, other) => total + FIELD_COUNTS[other], 0) + : FIELD_COUNTS[id], + ]), + ); + normalCounts = Object.fromEntries( + fieldLayers.map((id) => [ + id, + missingLayers.includes(id) + ? 0 + : id === 'flights' + ? sum(NORMAL_COUNTS) - fieldLayers.filter((other) => other !== 'flights' && !missingLayers.includes(other)).reduce((total, other) => total + NORMAL_COUNTS[other], 0) + : NORMAL_COUNTS[id], + ]), + ); + console.log( + ` [INFO] the field as ${JSON.stringify(fieldCounts)} (no ${missingLayers.join(', ')} on ${ENGINE})`, + ); + } else if (missingLayers.length) { console.log(` [SKIP] the deterministic field checks — no ${missingLayers.join(', ')} on ${ENGINE}`); skippedChecks += 1; record( @@ -370,7 +401,8 @@ async function main() { window.__LABEL_QA_NORMAL_COUNTS = normalCounts; for (const layerId of layerIds) { const entry = dataManager.layers.get(layerId); - entry.module.getDetectableObjects = () => window.__LABEL_QA_FIELD[layerId]; + if (entry) + entry.module.getDetectableObjects = () => window.__LABEL_QA_FIELD[layerId]; } // The global camera, orbiting west to east (the old rotateRight about @@ -446,7 +478,7 @@ async function main() { }; requestAnimationFrame(sample); return Object.fromEntries(layerIds.map((layerId) => [layerId, field[layerId].length])); - }, { fieldCounts: FIELD_COUNTS, normalCounts: NORMAL_COUNTS }); + }, { fieldCounts, normalCounts }); record( 'deterministic field contains exactly 12,000 observations',