mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
Merge pull request #313: finish browser QA renderer portability
Complete Tom-Neverwinter's deferred browser QA portability fixes, with renderer evidence, attribution keyboard and 2D floor-hold setup corrections.
This commit is contained in:
6 files changed
+70
-17
No files matched your search
@@ -13,6 +13,17 @@ of current runtime behavior, see [`docs/CURRENT-STATE.md`](docs/CURRENT-STATE.md
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Fixed
|
||||
|
||||
- Complete the first-run, view-target prewarm, cockpit-plates and floor-hold
|
||||
browser harness renderer portability fixes contributed by Tom-Neverwinter.
|
||||
macOS retains Metal; other platforms default to SwiftShader. Cockpit renderer
|
||||
assertions and evidence labels follow the actual selected mode. Floor-hold
|
||||
explicitly selects its measured 2D billboard mode and keeps its mesh and terrain assertions; software runs are not real-GPU evidence.
|
||||
First-run QA now checks the existing attribution Escape-close/focus-return
|
||||
behavior while preserving the launcher-underneath regression checks.
|
||||
|
||||
|
||||
- Datacenter and dam factories are available through scoped package exports with
|
||||
explicit context, overlay and render callbacks. The standalone app uses the
|
||||
same implementation and bundled datasets.
|
||||
|
||||
+13
@@ -218,3 +218,16 @@ While recording, call out anything in these areas — this is the feedback I mos
|
||||
- **No planes:** OpenSky data may be momentarily sparse; scroll out or wait a poll cycle.
|
||||
- **No GEV MIC button / voice errors:** `OPENAI_API_KEY` didn't load — use the console API for
|
||||
the annotation tests and skip the voice-only ones (§2).
|
||||
|
||||
|
||||
## Browser harness renderers
|
||||
|
||||
The first-run, view-target prewarm, cockpit-plates and floor-hold harnesses
|
||||
select Metal on macOS and SwiftShader on other platforms. Cockpit-plates also
|
||||
accepts `--swiftshader` on macOS; floor-hold retains `--angle=<backend>`.
|
||||
Floor-hold explicitly selects 2D aircraft mode because it measures billboard
|
||||
positions; the tracking suite covers the 3D handoff.
|
||||
Software runs validate their assertions but do not establish real-GPU visual
|
||||
correctness. Floor-hold retains both mesh and DEM checks: an unavailable mesh
|
||||
oracle fails the run even when the DEM check passes. Record the backend with
|
||||
any screenshots and run GPU visual checks separately when needed.
|
||||
@@ -46,7 +46,7 @@
|
||||
* node scripts/qa-cockpit-plates.mjs --url http://localhost:4268 --tag before
|
||||
* node scripts/qa-cockpit-plates.mjs --url http://localhost:4268 --teeth
|
||||
*
|
||||
* Defaults to the real GPU (ANGLE/Metal). `--swiftshader` selects software GL,
|
||||
* Defaults to ANGLE/Metal on macOS and software GL elsewhere. `--swiftshader` selects software GL,
|
||||
* which is deterministic but is NOT real-GPU evidence; the banner says which
|
||||
* backend actually ran and the run records it alongside the results.
|
||||
*/
|
||||
@@ -64,7 +64,7 @@ const APP_ORIGIN = new URL(APP_URL).origin;
|
||||
const TAG = getOpt('--tag', 'after');
|
||||
const HEADFUL = argv.includes('--headful');
|
||||
const TEETH = argv.includes('--teeth');
|
||||
const SWIFTSHADER = argv.includes('--swiftshader');
|
||||
const SWIFTSHADER = argv.includes('--swiftshader') || process.platform !== 'darwin';
|
||||
const SHOT_DIR = path.resolve('qa-shots/cockpitplates');
|
||||
|
||||
/** Mirrors `SKY_PLATE_SCALE` in src/overlays/worldOverlayTokens.js. */
|
||||
@@ -222,6 +222,8 @@ async function main() {
|
||||
args: [
|
||||
'--no-sandbox',
|
||||
'--disable-setuid-sandbox',
|
||||
// Metal is a macOS-only ANGLE backend; off-Mac the GPU branch has to fall
|
||||
// back to the software rasterizer or WebGL init fails outright.
|
||||
...(SWIFTSHADER
|
||||
? ['--use-gl=angle', '--use-angle=swiftshader']
|
||||
: ['--use-angle=metal', '--enable-gpu', '--ignore-gpu-blocklist']),
|
||||
@@ -292,7 +294,7 @@ async function main() {
|
||||
console.log(` GL : ${renderer}\n`);
|
||||
record(
|
||||
SWIFTSHADER
|
||||
? 'running on software GL as requested (structural checks, not GPU evidence)'
|
||||
? 'running on software GL (structural checks, not GPU evidence)'
|
||||
: 'running on the real GPU, so the screenshots are real-GPU evidence',
|
||||
SWIFTSHADER ? softwareRenderer : !softwareRenderer,
|
||||
renderer,
|
||||
|
||||
+12
-6
@@ -332,14 +332,17 @@ async function runArbitrationSection(page, { shots, consoleErrors }) {
|
||||
`session=${escUnderLightbox.session}`,
|
||||
);
|
||||
record(
|
||||
'the lightbox keeps its OWN ESC semantics (Cesium binds none, so it stays)',
|
||||
lightboxAfterEsc.shown,
|
||||
'ESC closes attribution without dismissing the launcher underneath',
|
||||
!lightboxAfterEsc.shown,
|
||||
`overlay shown=${lightboxAfterEsc.shown}`,
|
||||
);
|
||||
|
||||
// The guard disarms the launcher; it must never break it. Close the overlay
|
||||
// the way a visitor does and the key comes straight back.
|
||||
await page.evaluate(() => document.querySelector('.cesium-credit-lightbox-close')?.click());
|
||||
// The attribution keyboard handler closes the overlay and restores focus.
|
||||
// A second Escape belongs to the now-uncovered launcher.
|
||||
const attributionFocusRestored = await page.evaluate(() => (
|
||||
document.activeElement === document.querySelector('#cesium-credits .cesium-credit-expand-link')
|
||||
));
|
||||
record('closing attribution restores its disclosure focus', attributionFocusRestored);
|
||||
await sleep(300);
|
||||
const uncovered = await launcherState();
|
||||
record('closing the lightbox hands the card back the key',
|
||||
@@ -491,7 +494,10 @@ async function main() {
|
||||
...(executablePath ? { executablePath } : {}),
|
||||
args: [
|
||||
'--no-sandbox', '--disable-setuid-sandbox',
|
||||
'--use-angle=metal', '--enable-gpu', '--ignore-gpu-blocklist',
|
||||
// Metal is a macOS-only ANGLE backend; anywhere else it fails WebGL init.
|
||||
...(process.platform === 'darwin'
|
||||
? ['--use-angle=metal', '--enable-gpu', '--ignore-gpu-blocklist']
|
||||
: ['--use-gl=angle', '--use-angle=swiftshader']),
|
||||
'--disable-dev-shm-usage', '--disable-background-timer-throttling',
|
||||
'--disable-renderer-backgrounding', '--window-size=1440,900',
|
||||
],
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* The contact must stay ON the mesh through phase B. Without the hold it falls
|
||||
* to the geoid, which at an inland field is ~150 m of burial.
|
||||
*
|
||||
* node scripts/qa-floor-hold.mjs # real GPU (ANGLE/Metal)
|
||||
* node scripts/qa-floor-hold.mjs # Metal on macOS, SwiftShader elsewhere
|
||||
* node scripts/qa-floor-hold.mjs --headful # watch it
|
||||
* QA_BASE_URL=http://localhost:4257 node scripts/qa-floor-hold.mjs
|
||||
*
|
||||
@@ -25,10 +25,11 @@
|
||||
* under Metal — a backend comparison at one point, not to be confused with the
|
||||
* same-backend run-to-run spread (122.1 m vs 20.6 m on a cell centre) that
|
||||
* retired the hold chain's unvalidated tier. The
|
||||
* default is the real GPU. Under `--angle=swiftshader` the rendered-mesh oracle
|
||||
* is reported as unavailable rather than trusted, and the run falls back to the
|
||||
* bare-earth DEM (fetched server-side, so the simulated outage cannot reach
|
||||
* it) — a weaker but still decisive check, since the geoid sits ~150 m below it.
|
||||
* default is Metal on macOS and SwiftShader elsewhere; `--angle` overrides it.
|
||||
* Mesh samples describe the selected backend, not another GPU's rendered LOD.
|
||||
* An unavailable rendered-mesh oracle remains a failed check, even if the
|
||||
* separate bare-earth DEM check passes. Software evidence does not establish
|
||||
* real-GPU visual correctness.
|
||||
*/
|
||||
import puppeteer from 'puppeteer';
|
||||
import fs from 'node:fs';
|
||||
@@ -37,7 +38,8 @@ import path from 'node:path';
|
||||
const APP_URL = process.env.QA_BASE_URL || 'http://localhost:4173';
|
||||
const argv = Object.fromEntries(process.argv.slice(2)
|
||||
.map((a) => a.replace(/^--/, '').split('=')).map(([k, v]) => [k, v ?? true]));
|
||||
const ANGLE = String(argv.angle || 'metal');
|
||||
// Metal is a macOS-only ANGLE backend; defaulting to it off-Mac fails WebGL init.
|
||||
const ANGLE = String(argv.angle || (process.platform === 'darwin' ? 'metal' : 'swiftshader'));
|
||||
const HEADFUL = !!argv.headful;
|
||||
// Austin airport apron by default — the site qa-floor-verify pins, where the
|
||||
// mesh sits ~150 m above the geoid and burial is unmistakable.
|
||||
@@ -108,6 +110,10 @@ await page.goto(APP_URL, { waitUntil: 'domcontentloaded', timeout: 120000 });
|
||||
await page.waitForFunction(() => window.__godsEyeView?.viewer && window.__godsEyeView?.dataManager,
|
||||
{ timeout: 150000 });
|
||||
await sleep(12000); // let the boot fly-to settle before pinning
|
||||
await page.evaluate(() => {
|
||||
document.querySelector('#first-run-launcher:not([hidden]) [data-first-run-choice="explore"]')?.click();
|
||||
});
|
||||
await sleep(600); // let the launcher dismissal finish before taking evidence
|
||||
|
||||
await page.evaluate((site) => { window.__SITE = site; }, SITE);
|
||||
const pin = () => page.evaluate(() => {
|
||||
@@ -123,7 +129,16 @@ const pin = () => page.evaluate(() => {
|
||||
v.camera.moveEnd.raiseEvent();
|
||||
});
|
||||
await pin();
|
||||
await page.evaluate(async () => { await window.__godsEyeView.dataManager.toggle('flights'); });
|
||||
const billboardMode = await page.evaluate(async () => {
|
||||
const manager = window.__godsEyeView.dataManager;
|
||||
const flights = manager.layers.get('flights').module;
|
||||
// This harness measures billboard positions. A ready 3D model deliberately
|
||||
// hides its billboard; that handoff is covered by track-regression instead.
|
||||
flights.setParams({ models3d: false });
|
||||
await manager.toggle('flights');
|
||||
return flights.getParams().models3d === false;
|
||||
});
|
||||
record('the billboard floor test is explicitly in 2D aircraft mode', billboardMode);
|
||||
|
||||
/** Reads the contact's rendered height and the rendered mesh beneath it. */
|
||||
const measure = () => page.evaluate(async (icao) => {
|
||||
|
||||
@@ -39,7 +39,13 @@ const executablePath = chromeCandidates.find((candidate) => fs.existsSync(candid
|
||||
const browser = await puppeteer.launch({
|
||||
headless: headful ? false : 'new',
|
||||
...(executablePath ? { executablePath } : {}),
|
||||
args: ['--use-angle=metal', '--enable-gpu', '--no-sandbox'],
|
||||
// Metal is a macOS-only ANGLE backend; anywhere else it fails WebGL init.
|
||||
args: [
|
||||
...(process.platform === 'darwin'
|
||||
? ['--use-angle=metal', '--enable-gpu']
|
||||
: ['--use-gl=angle', '--use-angle=swiftshader']),
|
||||
'--no-sandbox',
|
||||
],
|
||||
});
|
||||
const page = await browser.newPage();
|
||||
const failures = [];
|
||||
|
||||
Reference in new issue
Block a user