Commit Graph
100 Commits
Author SHA1 Message Date
German Khokhlov b5cc4feacb Restore the conditions eight converted QA scripts were waiting for
The harness conversion replaced pauses that stood in for real conditions
with camera readiness: the cables and infrastructure idle checks started
measuring while the overlay was still fading in after moveEnd, directions
sampled before its maneuver dots had ground cells, three scripts clicked
before the loading cover was gone, the credits check hit-tested during UI
transitions, and the oblique traffic flight lost its height cap. Each now
waits for its condition; idle checks observe without requesting frames
and record the reasons of the frames they count; readiness waits for the
startup cover and no longer requests frames while polling.
2026-11-10 20:14:50 +04:00
German Khokhlov 2c62e1e378 Merge branch 'german/refactor-navara-tiles-drape' into german/navara-refactor 2026-11-10 19:12:25 +04:00
German Khokhlov b3daed4a9b Drape a 'tiles' ground set only on 3D tiles on Navara
Navara's ground pass took a pixel for a tile whenever its depth lay in
front of the saved globe depth, without checking which buffer the visible
depth came from; the scene buffer can be cleared apart from the globe
depth, so a set draped on 'tiles' also drew on bare terrain, which Cesium
never does. The pass now matches the visible depth to the globe or the
tiles before it drapes. A contract check compares a 'tiles' set hidden,
shown and hidden again over terrain, with a mutant.
2026-11-10 19:12:25 +04:00
German Khokhlov 087adc6dc9 Count a running mission replay as the camera's owner in readiness
A Space Missions replay flies the camera until it ends, so waiting for a
still camera after a switch let the replay finish before the scenario
looked at it. While a replay runs, readiness no longer asks for enabled
inputs or a still pose, as for the cockpit and a followed target.
2026-11-10 19:11:08 +04:00
German Khokhlov d3433f66c9 Merge branch 'german/refactor-e8-replay-switch' into german/navara-refactor 2026-11-10 19:11:07 +04:00
German Khokhlov 2dcec2195e Check that a running mission replay survives an engine switch
The session test now switches engines in both directions with the replay
running, paused and resumed, and checks it stays active, unpaused and
advancing.
2026-11-10 19:11:07 +04:00
German Khokhlov facc9541ab Merge branch 'german/refactor-e1-readiness-fixes' into german/navara-refactor 2026-11-10 18:41:42 +04:00
German Khokhlov f288b6ba1e Merge branch 'german/refactor-e8-switch-regressions' into german/navara-refactor 2026-11-10 18:41:42 +04:00
German Khokhlov b73fe82e27 Let readiness waits know when the app owns the camera
While the cockpit holds camera inputs or the camera follows a target,
whenSettled no longer waits for enabled inputs or a still pose; it still
waits for the engine, the restored view, drawn frames and no flight, and
its timeout now prints what it saw (inputs, following, cockpit, last pose
change). Scenarios that waited for the camera where they needed the
picture wait for it instead: weather and Nepal imagery for their tiles
and frames, imagery capture while a box drag holds inputs, and pixel and
pick polling for drawn frames. The vessel click retries at the vessel's
rendered position.
2026-11-10 18:31:45 +04:00
German Khokhlov 39206ef4c3 Keep Space Missions and the cockpit through an engine switch
Retaining a disabled layer that was never initialised replayed its
parameters, and the change notice it sent restored the Context snapshot,
which ended the Space Missions mode on every switch. Such layers are
retained as they are again.

The tracked aircraft's handle is rebuilt only once the view is restored,
so the share restore's earlier trackById found nothing to follow and the
cockpit did not come back after a failed switch rolled back. The scene
switcher now takes the aircraft up again after the camera owners resume
and then restores the cockpit and its vision mode. Both are covered by
tests on the real session modules.
2026-11-10 18:29:03 +04:00
German Khokhlov 417890b862 Merge branch 'german/refactor-e8-cold-start' into german/navara-refactor 2026-11-10 17:47:30 +04:00
German Khokhlov 8caff876cb Merge branch 'german/refactor-e12b-fake-engine-tests' into german/navara-refactor 2026-11-10 17:47:29 +04:00
German Khokhlov 560b72c3f7 Merge branch 'german/refactor-e6-tiles-heights' into german/navara-refactor 2026-11-10 17:47:29 +04:00
German Khokhlov 00153acbeb Keep Navara's 3D Tiles where the tileset puts them
Navara's 3D Tiles source defaults to model.height 1, which moves a
transformed tileset by a metre along Earth-fixed X: on the synthetic set
flat roofs read 0.12 m high and a sloping roof 0.68 m off, and the drawn
meshes move with them. The adapter sets the height to 0 and records the
package behaviour in WORKAROUNDS.md, with a test that loads the real
package. The downward surface ray now takes its direction from the
place's own normal, so it no longer drifts sideways.

qa-tiles-fixture gains --report (heights and drape pixels per engine,
without asserting), starts on Cesium, and checks each drape hidden, shown
and hidden again; qa-surface-heights uses the plan's 0.5 m tolerance under
tiles and names the point that misses.
2026-11-10 17:16:23 +04:00
German Khokhlov 7c5ebf4814 Check that an engine switch draws what a cold start from the share link draws
qa-switch-equals-cold-start switches engines in both directions with each
layer on deterministic fixtures, then opens the share link of the same
state in a new page on the target engine, and compares the draw ledgers
and the probe's view of the layer. It runs as 19 acceptance groups
covering all 38 layers.

State a layer keeps through a switch but the share link does not carry is
declared as sessionState (the directions route, Radio's selected station
and audio state, the wind reading, local ADS-B's and OSM Places' local
toggles and results); a test checks each declaration against what the
layer really retains, so a declaration cannot hide a regression.
2026-11-10 17:08:05 +04:00
German Khokhlov 225c1c25c7 Build test engines from the shared fake instead of literals
Tests that made their own engine object now use createFakeEngine() with
its scripting hooks or an override of the one member under test, so they
follow the contract when it changes. 125 such literals in 74 test files
go down to two that are not globe engines on purpose; report-qa-harness
counts them, and the baseline keeps the number from growing.
2026-11-10 17:07:27 +04:00
German Khokhlov 3c304502a0 Merge branch 'german/refactor-e12-qa-harness-2' into german/navara-refactor
# Conflicts:
#	scripts/qa-harness-baseline.json
#	src/layers/satellites/cockpitSubject.test.mjs
2026-11-10 16:45:38 +04:00
German Khokhlov df02033465 Share copied test fixtures through src/testSupport
Environment overrides, manual timers, a cancellable streaming response,
GhostMaps KML/KMZ fixtures and the satellite service doubles move into
five shared helpers; 21 tests drop 418 lines of copies.
2026-11-10 16:43:58 +04:00
German Khokhlov 6c416f3fe6 Move QA scripts to the shared harness, batch 4 of 4
As in the previous batches. Scripts launching Chrome themselves go from
99 to 8 (all outside this conversion), fixed pauses from 86 to 69 and
Cesium-only reads from 75 to 46; the QA harness baseline records them.
2026-11-10 16:43:58 +04:00
German Khokhlov 53b07ba91f Move QA scripts to the shared harness, batch 3 of 4
Each script launches and closes Chrome through scripts/qa/browser.mjs,
waits on the application through scripts/qa/ready.mjs instead of the
loading screen and fixed pauses, and reads the contract instead of
Cesium where the check is not about Cesium itself.
2026-11-10 16:43:58 +04:00
German Khokhlov 373edf2989 Move QA scripts to the shared harness, batch 2 of 4
Each script launches and closes Chrome through scripts/qa/browser.mjs,
waits on the application through scripts/qa/ready.mjs instead of the
loading screen and fixed pauses, and reads the contract instead of
Cesium where the check is not about Cesium itself.
2026-11-10 16:43:58 +04:00
German Khokhlov ee697422c9 Move QA scripts to the shared harness, batch 1 of 4
Each script launches and closes Chrome through scripts/qa/browser.mjs,
waits on the application through scripts/qa/ready.mjs instead of the
loading screen and fixed pauses, and reads the contract instead of
Cesium where the check is not about Cesium itself.
2026-11-10 16:43:58 +04:00
German Khokhlov 731eadc34a Give QA scripts one launch, readiness and geometry helper
scripts/qa/browser.mjs launches headless Chrome with QA_ANGLE and the
shared Chrome lookup; scripts/qa/ready.mjs adds frame, tile and transition
readiness and bounded polling; scripts/qa/geometry.mjs hands page
evaluations the engine-neutral geometry without dev-only source URLs.
CODE-BOUNDARIES gains the rule for new QA scripts.
2026-11-10 16:43:58 +04:00
German Khokhlov 08d5c86e80 Merge branch 'german/refactor-e7-height-datum' into german/navara-refactor 2026-11-10 16:42:50 +04:00
German Khokhlov dd56cba2f3 Measure the heights the surface-bound layers place their points at
qa-surface-heights loads deterministic fixtures for import pins,
infrastructure bases, ALPR markers, directions A/B, bikeshare stations
and Bhote Koshi story points, waits for the app to settle on each engine
and records every placed point through the mover contract. --compare
fails when a point moved by more than 0.1 m on terrain; --tiles checks
the points land on the synthetic tileset's 50 m block.
2026-11-10 16:42:50 +04:00
German Khokhlov 59ff0b38a2 Merge branch 'german/refactor-e8-switch-protocol' into german/navara-refactor
# Conflicts:
#	scripts/engine-coupling-baseline.json
#	src/layers/wind/index.test.mjs
2026-11-10 16:35:39 +04:00
German Khokhlov a2905eb700 Move the engine switch protocol from the layers into the scene binding
attachRenderer takes one context { engine, signal, viewRestored, ... } and
bindCatalog no longer takes a viewer; no layer module receives Cesium's
viewer any more, and a rehearsal check fails if one reads it.

The handoff between engines is one typed object (layers, camera owners,
selection, director) created when the old scene leaves, replacing the
session's handoffLayers, restoringView and selectionContext. viewRestored
resolves where the camera is restored, and the nine layers that kept
their own restoring-view flag wait on it instead. After attach the
binding applies a disabled layer's visibility, registers the picks each
module declares, and resumes the camera owners, so engineSwitch.js no
longer names directions or satellites.
2026-11-10 16:33:29 +04:00
German Khokhlov d51e4140b7 Merge branch 'german/refactor-e10-layers-without-viewer' into german/navara-refactor
# Conflicts:
#	scripts/package-boundaries.json
2026-11-10 16:16:32 +04:00
German Khokhlov bcff542b16 Merge branch 'german/refactor-e7-surface-placement' into german/navara-refactor
# Conflicts:
#	scripts/package-boundaries.json
2026-11-10 16:15:09 +04:00
German Khokhlov aac65c21c4 Open the orbital cockpit on Navara
The orbital view, sensor zoom, ground focus and satellite switching run on
the contract: camera.setFovy sets the vertical lens on both engines and the
fake, including sub-degree angles on Navara through the guarded core
bridge, with a contract check and mutants. Cesium's imagery look-ahead
stays inside its adapter. KNOWN-ISSUES keeps the two parts Navara still
lacks: imagery prefetch for the orbital view and finest-detail meshes for
the ship bridge waterline.
2026-11-10 16:14:14 +04:00
German Khokhlov 6727aaadcd Fly, follow and draw the celestial ring through the contract
The Bhote Koshi event flies with engine.camera instead of the viewer's
camera, tools listens to camera.followChanged instead of the viewer's
tracked entity, and the celestial ring uses the engine's host, frames,
pose and render requests. The embedded story media no longer imports
Cesium, which removes one of the three import exceptions.
2026-11-10 16:14:14 +04:00
German Khokhlov 4f654df3c0 Inspect the wind field through the engine contract
The inspection marker and the centre probe use the engine's host,
projection, frame events, ellipsoid pick and render requests instead of
Cesium's scene, so they behave the same on Navara.
2026-11-10 16:14:14 +04:00
German Khokhlov e0d3e93a28 Move the wind's Cesium rendering into the Cesium adapter
The particle canvas, its GPU path and the relief shading move unchanged
from src/layers/wind/ to src/globe/cesium/; the adapter reads the Cesium
viewer itself, so the layer no longer hands one in.
2026-11-10 16:14:14 +04:00
German Khokhlov 82ed68f443 Place every surface-bound layer through the shared placement
Import pins, infrastructure, ALPR, directions markers, bikeshare and the
Bhote Koshi story use createSurfacePoints instead of their own sampling,
budgets and partial triggers; ground snap, the mesh floor sampler,
traffic, transit, Street Level, the camera ground guard, wildlife and the
cockpit host read heights through readSurface or surfaceTriggers.
Per-layer offsets and floor policies stay as options. The import no
longer re-places pins on every camera move from the UI.

Calls to engine.surface outside src/globe go from 41 sampling calls to
10, each a raycast, a one-shot fly-to height or an asynchronous detailed
sample.
2026-11-10 16:13:06 +04:00
German Khokhlov ef104aaac3 Move surface placement into the globe and give it the fourth trigger
src/globe/surfacePlacement.js takes over the shared surface placer and
adds readSurface (tiles through sampleHeight, otherwise terrain, with a
plausibility range), surfaceTriggers (one subscription to camera moves,
tile loads, the photoreal switch and terrain revisions) and a forced full
pass. Points now re-place when the terrain provider changes, which they
did not before. GhostMaps, cables, OSM Places and Street Level move to the
new module unchanged.
2026-11-10 16:13:06 +04:00
German Khokhlov 50e486ceec Merge branch 'german/refactor-e11-boundary-catalogs' into german/navara-refactor
# Conflicts:
#	scripts/package-boundaries.json
2026-11-10 16:08:08 +04:00
German Khokhlov 75cf0aeaf9 Merge branch 'german/refactor-e4-model-retry' into german/navara-refactor 2026-11-10 16:04:06 +04:00
German Khokhlov a07d9f5d85 Retry a failed 3D model inside the engine instead of in the layers
A mover set whose glTF or atlas fails to load retries by itself after
retryAfterMs (1,500 ms by default), at most three attempts, on Cesium,
Navara and the fake engine alike: failed() is true while the latest
attempt failed and stays true after the last, ready() turns true when a
retry loads, and an instance given another pickId loads again. Healthy
models of the same class no longer load again when one fails.

The layers drop what they did instead: moverBank's rebuilds, the loops
that dropped failed handles in flights, military and local ADS-B, and the
tracked-model backoff in the aircraft display. The contract suite checks
the one behaviour on both engines, with a mutant that never retries.
2026-11-10 16:04:01 +04:00
German Khokhlov 27939a2d84 Own shared foundations by directory and check the manifest both ways
src/i18n/, src/geo/ and the engine-neutral part of src/globe/ are owned by
directory entries, and aggregate groups use a directory wherever their
list covered it, so a new shared module no longer needs a manifest edit.
Small groups keep explicit lists, now checked as a snapshot: the check
fails on a reached module that is not declared and on a declared one no
longer reached, and prints both per group. --write keeps directory
entries as they are.

The manifest goes from 4,737 entries to 3,494; src/i18n accounts for 87
of them instead of 666.
2026-11-10 15:59:43 +04:00
German Khokhlov 1ac9f28c4a Merge branch 'german/refactor-e6-tiles-fixture' into german/navara-refactor
# Conflicts:
#	scripts/qa-harness-baseline.json
2026-11-10 15:54:13 +04:00
German Khokhlov e9ba5e9859 Check the photoreal paths in the browser on a synthetic 3D Tiles set
A generated tileset (a plate at ellipsoid level, 50 m and 200 m blocks and
a pitched roof, 27 KB) replaces Google's tiles when a QA page passes
?qaTileset=/path; only a root-relative path on the page origin is
accepted, and the Google credit is not shown for it. The strict harness
serves the set from disk, so nothing reaches Google.

qa-tiles-fixture checks on both engines that sampleHeight reads the block
at 50 m, clampToHeight lands on the roof, tiles and terrain drapes draw
where they should, tilesLoaded turns true, surface points land on the
roof within their budget, and pick renders per pass stay within it.
2026-11-10 15:49:52 +04:00
German Khokhlov 37263a3e2b Give the draw ledger test a drawn mover instance
A mover set lists as shown only once one of its drawn instances is.
2026-11-10 15:48:49 +04:00
German Khokhlov 18da76e8d8 Merge branch 'german/refactor-e1-qa-readiness' into german/navara-refactor
# Conflicts:
#	scripts/qa-harness-baseline.json
#	scripts/qa-strict-harness.mjs
2026-11-10 15:47:21 +04:00
German Khokhlov 60f9de8511 Wait for the application, not the clock, in the strict QA set
The probe exposes settled() and the first-frame outcome; scripts/qa/ready.mjs
waits for drawn frames with the camera at rest and for a pick at the click
position, with a deadline and its reason in the error. The strict scenarios
use these instead of fixed pauses and loading-screen polling, and the
hidden-switch scenario checks how the loading screen was lifted instead of
how long it took.

Each switch scenario now records a draw ledger per engine and runs a
contract monitor; both write to the scenario's evidence file only, with an
empty allowlist until browser runs show what differs on purpose.
2026-11-10 15:46:26 +04:00
German Khokhlov 5b27f26e14 Merge branch 'german/refactor-e5-navara-mesh-colour' into german/navara-refactor 2026-11-10 15:45:37 +04:00
German Khokhlov 28f3030c31 Draw Navara world meshes in the overlay pass after tone mapping
Meshes now go through the same overlay as sprites and lines, so their
colours are the ones asked for without undoing the view's exposure. The
contract suite no longer carries the mesh colour check as a known
failure on Navara.
2026-11-10 15:45:26 +04:00
German Khokhlov a90407d547 Count the Navara canary script in the QA harness baseline
It drives a bare Navara view outside the app to test the package itself, so it launches Chrome and paces its fixture on its own.
2026-11-10 15:30:09 +04:00
German Khokhlov 33ccef9662 Merge branch 'german/refactor-e3-contract-behaviour' into german/navara-refactor 2026-11-10 15:27:12 +04:00
German Khokhlov 49b180f1fd Merge branch 'german/refactor-e9-import-plan' into german/navara-refactor 2026-11-10 15:27:12 +04:00
German Khokhlov 233c4def5b Merge branch 'german/refactor-e2-layer-lifecycle' into german/navara-refactor 2026-11-10 15:27:12 +04:00
German Khokhlov 0953287c3d Merge branch 'german/refactor-e13-navara-workarounds' into german/navara-refactor 2026-11-10 15:27:12 +04:00
German Khokhlov b03edaaf2b Check the globe contract by behaviour on every engine
The contract suite is split into one module per area and grows from 87
to 114 checks, each named after the member it exercises: a gesture during
a flight does not cut it, a render request inside a frame draws the next
one, a pure rotation raises changed, ground corridors are as wide in CSS
pixels at device scale 2, imagery replans on resize, drapes draw only on
their surface, sampleTerrainMostDetailed keeps order and passes on a
rejection, terrainRevision changes on a new terrain and on fallback,
follows raise followChanged on retarget, and a mesh, a ground fill and an
imagery pixel draw the colour asked for. In the browser Cesium passes all
113 it runs at device scale 1 and 2; Navara passes 110 of 111 and reports
its single-colour mesh, drawn before tone mapping, as a known failure.

scripts/contract-mutants.test.mjs breaks one promise of the fake engine
at a time, 30 mutants in all, and names the check that catches each; the
list of contract members the suite never calls is down to five.

maps.errors reports tile and terrain errors where an engine has them
(the tileErrors capability: Cesium yes, Navara no), and the map
controller falls back to another map only where it does; movers.list()
rows tell whether a set is shown, as the other families do; FollowHandle
.name and PickResult.primitive are marked deprecated. qa-contract-suite
takes --dpr and the ANGLE backend from QA_ANGLE.
2026-11-10 15:26:55 +04:00
German Khokhlov 9ae7dea918 Plan KML and KMZ drawing in one pure function, checked against Cesium
src/data/geoImportPlan.js decides what an imported file draws and with
what: raised or clamped geometry, rings and holes, rotation near the
poles and across 360 degrees, absolute and relative altitudes, draw
order, canvas budgets and the vertex and ring limits, with no engine and
no DOM. drawImportedFile draws that plan through the globe contract and
keeps pin placement, yielding and cancellation. Every limit of the import
lives in src/data/geoImportLimits.js with what it protects.

scripts/fixtures/geo-import holds 13 files covering those cases, and
reference.json what Cesium's own KML and GeoJSON data sources make of
them; scripts/qa-geo-import-reference.mjs records it and compares the
plan with it. Property tests on seeded random polygons check area,
bounds, ring closure and winding. Writing the plan fixed three cases:
overlays below the ellipsoid kept a negative height, raised plain-colour
overlays now draw, and the vertex limit no longer depends on whether a
ring repeats its first point.
2026-11-10 15:26:10 +04:00
German Khokhlov ffbceb977c Register the Navara package workarounds and check them against the package
src/globe/navara/WORKAROUNDS.md lists every place the adapter works
around @navaramap/three 0.2.1: what the package does wrong or lacks, how
it is detected and what to delete once it is fixed.
scripts/qa-navara-canaries.mjs confirms three of the bugs on the real
package in the browser (batch ids never released, events of a deleted
vector layer kept queued, idle reported before a raster tile arrives) and
names the workaround to delete when one is gone.

The private members the adapter reads are probed when the engine starts,
with an error naming the member and the pinned version instead of a
silent fallback, and the test that only internals.js reaches private
members now scans the adapter's subfolders too.
2026-11-10 15:22:43 +04:00
German Khokhlov 20ad9b41b3 Rehearse every catalog layer across two engines in the unit tests
lifecycleRehearsal.test.mjs takes each of the 38 catalog layers from
attach on one fake engine through enable, detach and that engine's
destruction to attach on a second engine, resume and disable. It checks
that the engine left keeps no drawn sets, listeners, credits, input
suspensions, continuous renders or follows; that nothing writes to it
afterwards; that a layer waiting for the camera restore reads no source
before resumeViewport; that a disabled layer stays hidden after attach;
and which layers still read the viewer argument, a list that may only
shrink.

The catalog takes the displays and scene services a test supplies, and
the pick registry lists its owners. Two defects it found are fixed:
Active Fires loaded its heatmap before the camera restore it was told to
wait for, and the wind inspection marker asked Cesium's scene for a
render on any engine instead of the engine's render request.
2026-11-10 15:01:59 +04:00
German Khokhlov bd4f9eaee4 Keep the strict scenarios in step with main's photos and satellite groups
Main's flight photos ask Planespotters for every tracked aircraft, which
the strict network policy counted as a violation; the harness now answers
those lookups with no photos, as the other QA scripts already do. Main
also reads five more TLE groups (resource, weather, planet, SAR and
science): the satellite fixture serves them, and the space switch expects
all twelve groups and derives its catalog sizes from the fixture.
2026-11-10 15:01:39 +04:00
German Khokhlov 9c2a2d6951 Measure engine coupling, QA harness use and contract coverage
Counters that may only fall, each with a committed baseline and a test
that fails on growth:

- report-engine-coupling.mjs gains layer modules that take the viewer
  in attachRenderer (33), layer folders with their own "view being
  restored" flag (9), engine.surface calls outside src/globe (41) and
  layer ids named in the engine switch (3).
- report-qa-harness.mjs counts QA scripts that launch Chrome themselves
  (98), wait with fixed sleeps (117), take the hidden loading screen as
  readiness (9), read Cesium-only objects (75) or define their own
  waitFor helpers (19).
- withCallLog records every contract member the contract suite calls on
  the fake engine; contractCoverage.test.mjs fails when a member outside
  contract-uncalled-baseline.json goes uncalled, and when a listed one
  is called now, so the list of 12 only shrinks.
2026-11-10 14:23:29 +04:00
German Khokhlov ba04ceaa32 Describe the strict page clock as the nearest 18:30 UTC 2026-11-10 14:23:29 +04:00
German Khokhlov ed6ae54ef6 Stop the strict acceptance from waiting for itself
A scenario whose body ran past about 19 s idled until 45 s after its
start, and twice one never exited and hit the runner's 300 s timeout
after it had passed: something of Chrome outlived Browser.close and kept
its stdout and stderr open.

- scripts/qa/browser.mjs closes Chrome within 5 s, kills its process
  group and closes its pipes; the harness then finishes and exits with
  the scenario's code. QA_EXIT_DIAGNOSTICS=1 keeps the old ending and
  prints the open handles and Chrome's process tree 5 s after finish.
- Every strict page starts with its clock at the 18:30 UTC nearest to
  the real time, so Navara's sun is up over the test cities whenever the
  acceptance runs; a scenario can ask for its own instant or the real
  clock (Wildlife does, for its freshness fixtures).
- The runner records a scenario that passed but did not exit as hung,
  kills the whole process group on a timeout, runs a failed scenario
  once more and reports one that passes then as flaky, and appends each
  run to --history=FILE; scripts/report-acceptance-flake.mjs reads it.
2026-11-10 14:10:46 +04:00
German Khokhlov a913e5466e Fill raised KML polygons up to 32,768 vertices
A raised polygon past 4,096 vertices lost its fill, which main drew.
Triangulating 32,768 vertices takes about 58 ms on a fast laptop, so the
fill limit moves there; 128 rings stay the hole limit, since holes make
earcut quadratic. The polygon loop yields to the event loop after 8 ms of
work, and the import cancels a draw whose globe went away while it
yielded, without reporting the file as unreadable.

KNOWN-ISSUES names the fill limit and two Navara limits: an expired
terrain token is not refreshed while the page is open, and a failing map
source does not fall back to another map.
2026-11-10 14:03:35 +04:00
German Khokhlov 2a761aa5eb Merge origin/main into german/navara
Main's work since the last merge runs on the globe contract where this
branch draws through it:

- Satellites take main's classes, sensors, ground-track bearings and
  world time through contract points and rings; launches take the world
  timeline. The satellite's cockpit subject dims, copies positions and
  refocuses through the contract.
- Flights, military and vessels keep main's photos, retry cool-downs,
  world-clock motion and the ship bridge. Trail seeding in the shared
  aircraft tracking reads each layer's clock.
- Traffic's flow lines and single build draw as ground sets; transit
  keeps dated credits and the new cities; CCTV opens the nearest camera,
  and the Quebec overlay projects and tests the horizon through the
  contract. Bikeshare's manager cleanup moved into its current lifecycle.
- Draw keeps main's mark actions across engine switches.
- The world clock in src/time is plain numbers again: Julian dates come
  from src/geo, the frame loop is injected, and the binding to Cesium's
  viewer clock lives in src/globe/cesium/worldTime.js. Navara's sky and
  sun follow the world time; live feeds keep the real time.
- The cockpit's orbital view, with its sensor zoom, ground focus and
  satellite switching, stays Cesium-only for now: Navara hides its entry.
  Its Cesium calls live in src/globe/cesium/orbital.js. The ship bridge's
  finest-detail waterline sampling is Cesium-only too; Navara samples
  loaded geometry and detailed terrain. Both are in KNOWN-ISSUES.
- Main's tests that built a Cesium scene by hand run on the fake engine.
- The boundary manifest is regenerated, the coupling baseline records
  the orbital and bridge code, and the main-chunk baseline is raised to
  the merged size: main itself grew its main chunk by 93,959 bytes
  (gzip -9) since the previous merge base.
2026-11-10 13:52:52 +04:00
German Khokhlov f437c615a0 Add a --write mode to the package boundary check
`node scripts/check-package-boundaries.mjs --write` regenerates each
group's module list in scripts/package-boundaries.json from what the
group's build reaches: entries that own nothing reached are removed, newly
reached modules are appended in sorted order, and the order of kept
entries stays. The check without the flag is unchanged.
2026-11-10 12:56:36 +04:00
German Khokhlov 60fb8fee07 Fix the follow-up review findings in import, layers, startup and engines
- KML/KMZ import: a per-file canvas budget and cache for ground overlays,
  limits on rings and vertices of raised polygons, overlays across 360° and
  near the poles, degenerate holes, polar and single-latitude fills,
  absolute overlays at their altitude, overlay order by drawOrder as on
  Cesium, and pins on tiles keep their measured height.
- Points on the surface: OSM Places and Street Level cones share the
  surface sampler and sit on the terrain before they are measured, within
  a sampling budget per pass; Cockpit's contact-dot bank keeps the dot
  atlas, and a failed fleet model loads again after a pause.
- Startup: the loading screen lifts after the share-link view is restored,
  the retry screen names the failed engine and takes focus, and the
  fallback toast stays for 6 s.
- Engines: an engine switch lands a running camera flight at its
  destination (camera.completeFlight on both engines), the sighting card
  leaves focus on the engine picker after a switch, and a Cesium model
  error stays with the instance that failed.
- The MCP panel builds again: its wind-mesh alias resolves to the stub.
- QA: the wildlife switch waits for the camera to rest, GBFS --w2 says it
  needs the dev server, and test fixtures are shared instead of copied.
2026-11-10 01:57:11 +04:00
German Khokhlov 10784fa9c9 Merge pull request #1552 from IMBrandao/fix/firms-drop-snpp
fix(firms): stop requesting the retired Suomi NPP source
2026-11-09 21:52:09 +04:00
German Khokhlov fce5ee6381 docs(firms): tighten the Suomi NPP notes 2026-11-09 21:44:09 +04:00
German Khokhlov d90da158ea Merge branch 'main' into fix/firms-drop-snpp
# Conflicts:
#	docs/CURRENT-STATE.md
2026-11-09 21:41:01 +04:00
German Khokhlov b04fcf191c docs(firms): count two VIIRS sources in the layer table and test note 2026-11-09 21:38:07 +04:00
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
German Khokhlov 581ef7eef4 Merge pull request #766 from BreezeDelegate/fix/node26-allocation-gates
fix(ci): run allocation gates on Node 26
2026-11-09 20:35:28 +04:00
German Khokhlov 015e3ff7fc Merge branch 'main' into fix/node26-allocation-gates 2026-11-09 20:19:29 +04:00
German Khokhlov 72a240ba6f Merge pull request #762 from monwiss/refactor/tile-budget
refactor(providers): move the tile budget helpers out of the TomTom module
2026-11-09 20:00:55 +04:00
German Khokhlov 77df600329 Merge branch 'main' into refactor/tile-budget 2026-11-09 19:52:40 +04:00
German Khokhlov e22348a8e1 Merge branch 'main' into refactor/tile-budget 2026-11-09 19:43:58 +04:00
German Khokhlov 75e8e7ddbd refactor(data): describe tile budgets per period, drop a duplicate test, add the changelog entry 2026-11-09 19:41:51 +04:00
German Khokhlov 45108a0b0b Merge pull request #794 from daikaginza/fix/api-method-guard
fix(server): declare the method contract on the three read-only query proxies
2026-11-09 19:17:49 +04:00
German Khokhlov cdf52ab290 test(server): drop unused fields from the /track hand-off stub 2026-11-09 19:07:14 +04:00
German Khokhlov c3738c0fdb docs(server): tighten the method-guard comments and changelog 2026-11-09 19:07:14 +04:00
German Khokhlov ace88172d3 Merge branch 'main' into fix/api-method-guard 2026-11-09 18:51:02 +04:00
German Khokhlov 6a7a09372a Merge pull request #795 from daikaginza/feat/opensky-compress-cached-body
feat(server): compress the cached OpenSky snapshot for clients that accept gzip
2026-11-09 18:40:19 +04:00
German Khokhlov 9d7fe8fcaa Merge branch 'main' into feat/opensky-compress-cached-body 2026-11-09 18:30:32 +04:00
German Khokhlov a45d6af5f7 Merge pull request #1611 from abiyeenzo/fr-fixes
i18n(fr): typography, terminology and wording fixes
2026-11-09 18:22:18 +04:00
German Khokhlov caad795fa2 refactor(server): drop the null and String paths from gzipBody 2026-11-09 18:15:13 +04:00
German Khokhlov 09bf01630b docs(server): tighten compression comments and docs 2026-11-09 18:14:30 +04:00
German Khokhlov 2ea4a78e75 Fix the fr review follow-ups
- "destination refresh" is the refresh at the place the camera flew to,
  so restore "son actualisation à destination".
- Radio note: "que vous la demandez par la voix", "Votre adresse IP".
- "{count} / 30D": "30 J", like "{days} j".
- Starlink: "la couche complète", as in the active-state tooltip.
- "Show {name} sighting": colon form, so names starting with a vowel
  do not break the elision after "de".
- Wildlife note: Acartia is the source, not a kind of marine mammal.
- Straight apostrophes in the five strings added on main since.
2026-11-09 18:12:48 +04:00
German Khokhlov 61e9cf87f9 Merge branch 'main' into fr-fixes
# Conflicts:
#	src/i18n/locales/fr.json
2026-11-09 18:12:09 +04:00
German Khokhlov a5b40dfc3d Merge pull request #1569 from rudycelekli/fix/perimeters-sub-acre-size
fix(perimeters): show a 0.25-acre fire as 0.25 ac, not 0 ac
2026-11-09 17:39:29 +04:00
German Khokhlov be9c37bee2 Merge remote-tracking branch 'origin/main' into fix/perimeters-sub-acre-size 2026-11-09 17:07:05 +04:00
German Khokhlov 394f3216f8 Drop the sub-acre rounding comment 2026-11-09 17:06:56 +04:00
German Khokhlov c62f7ef00e Merge pull request #1524 from quanticsoul4772/upstream/tools-heading-wrap
fix(tools): wrap whole-degree headings at 360 to 0
2026-11-09 17:00:58 +04:00
German Khokhlov da6b63b6fd docs(tools): tighten the heading-wrap changelog, comments and overview 2026-11-09 16:45:11 +04:00
German Khokhlov 3150a460aa Merge pull request #1547 from quanticsoul4772/upstream/nominatim-cache-mode-windows
test(nominatim): check cache file modes only where POSIX modes exist
2026-11-09 16:44:00 +04:00
German Khokhlov c2bff536a5 Merge branch 'main' into upstream/nominatim-cache-mode-windows 2026-11-09 16:07:00 +04:00
German Khokhlov 69fbf5b38d Check hidden lines behind the Earth and open the picker panel by keyboard
Cesium culls a line the globe hides whole and does not depth-test lines
against the near side of a keyless globe, so the contract check runs the
hidden line round the back of the Earth to a visible end. The wildlife
switch scenario opens VISUAL PRESETS from the keyboard before tabbing to
the engine picker and reports the page state when no switch follows.
2026-11-09 13:03:13 +04:00
German Khokhlov 68845a4977 Start Navara's camera model from a placed pose only
Navara's camera sits at the Earth's centre until it is first placed. The
model took that as the pose, so camera.height() threw while a layer
attached to a starting Navara (wildlife sightings asks for it), and
switching to Navara with that layer on rolled back to Cesium.
2026-11-09 13:03:13 +04:00
German Khokhlov b4556f9763 Test layers on one engine and share selection and shader helpers
Layer display tests no longer re-check Cesium primitives in every layer:
they run on the fake engine, and one Cesium translation check per ground
kind lives in the Cesium engine's ground tests. Their harnesses are shared,
and the fake-engine, Cesium-engine and flights tests that repeated the
contract suite are gone, 340 tests in all.

The press-travel measurement is shared by the selection dispatcher and
CCTV, which loses its ScreenSpaceEventHandler shim and world-click module.
ALPR, installations and bikeshare share one selection keeper and selected
marker write. Layers with their own click rules keep their handlers.

Navara's pulse is a class like the ground pass, the ground and imagery
passes share the surface uniforms, and the colour, log-depth and occlusion
GLSL lives in one chunk module, each caller keeping its depth bias. The
ground suite runs inside the contract suite (--only=ground:), and fixture
and script names say what they test.

Behaviour is unchanged on both engines.
2026-11-08 17:06:10 +04:00
German Khokhlov 7f478e3815 Remove always-true layer availability and leftover viewer paths
Every layer draws on both engines, so the per-engine availability
machinery always answered yes. The renderer manifest is now the id to
display map plus the wind flow backend; the catalog filter, the voice and
QA-probe refusals and the engine-kind checks go with it. The Navara
notice lists the same layers in the same words.

Paths that read the Cesium viewer behind an engine that is always there
are gone: the Recent Imagery viewer fallbacks, the shell's imagery-host
service (one shared host module remains), the engineless map controller,
viewer gates in voice actions, world packets and camera verbs, the
orientation controls' tracked-entity fallback, and the Bhote Koshi and
FIRMS Cesium-shaped paths. setCameraInputs, which nothing called, leaves
the contract; suspensions remain.

Smaller duplicates go too: one tracker-release helper for navigation and
location, the no-op frame latch, missing-engine guards, one name for the
injected display, flat bikeshare and installations displays, one overlay
host and binder, one name per world-overlay method, and stub-viewer
guards in the Cesium engine. Layers that still read the viewer keep the
shared init(viewer, context) entry.

Behaviour is unchanged on both engines. Viewer lines fall from 849 to
750 and engine-name literals from 32 to 27.
2026-11-08 17:06:01 +04:00
German Khokhlov 371d848eec Delete dead render code and consolidate QA helpers
Remove code that nothing in the app, the runners or CI uses:
- the one-off migration compare, look and bench scripts and the vector
  ground prototype they measured, with the bench tables in the docs;
- the unused Navara-named shared render modules (polygons, ground picks,
  mover bank, ground ring);
- the Cesium-shaped aircraft and vessel test renderers, and the trail,
  engineFromViewer and horizon-occluder helpers only they kept alive.
  Their tests now run on the production displays over the fake engine;
- Navara's unread diagnostics, fallback ports, dead exports and
  parameters, stale effect-chain anchors and the unread capability flags.

The QA scripts share one keyless guard and readiness wait, the session
harness reuses the strict harness's browser flags and block list, and the
harness honours QA_ANGLE and QA_RESERVED_PORTS. The bikeshare fixture
keeps only what its scenario reads. The docs name the engine picker where
it is (VISUAL PRESETS) and drop dated run results.

No behaviour changes on either engine. Navara layer renderer lines fall
from 189 to 0 and viewer lines from 891 to 849.
2026-11-08 17:05:38 +04:00
German Khokhlov 18f69c2699 Follow, credits, embed views and FPS through the engine on Navara
Five places still read the Cesium viewer and so did nothing, or the wrong
thing, on Navara. Each now goes through the globe contract, and Cesium
behaves as before.

- The Navara ground floor stands aside while the camera inputs are
  suspended, not only while they are switched off. The cockpit suspends
  them, so its eye 12 m up no longer jumps to the floor's 30 m between
  updates. A follow's own suspension keeps the floor on, as before.
- Follow state comes from engine.camera.following() and followChanged
  instead of viewer.trackedEntity. Enabling CCTV during a follow no longer
  flies away and ends it, a new follow stamps navigation, Director cards
  wait while a subject is followed, and an explicit navigation stops the
  follow on both engines.
- Navara registers every data credit, as Cesium does. The allowlist left
  out the layers that moved to Navara later (CCTV agencies, street-level
  imagery, GIBS, routing, bike feeds and others).
- Annotation links and embed mode attach on every engine; their camera
  flights use engine.camera.flyTo. Only Cesium adds the timer that keeps
  an inline panel drawing.
- The FPS readout counts engine.frames.postRender, so it shows on Navara.

Each fix has a test that fails without it.
2026-11-08 17:05:27 +04:00
German Khokhlov e1095ee553 Document radial pads, draped trail reveals and input options
Describe the radial disc envelope, corridor backing and reveal control,
rectangular input pick windows and optional horizon ellipsoid. Record the
launch-pad and Transit restoration and the Street Level and CCTV callers.
Explain synchronous Transit and reveal construction and surface readiness
for classified ground materials after camera changes.
Cesium remains the appearance and interaction reference; this documentation
changes no behaviour. All eleven coupling counts remain unchanged.
2026-11-08 00:30:36 +04:00
German Khokhlov aa6959c97b Restore ground, picking and horizon parity through the globe contract
Draw launch-pad zones as radial ground discs with the original fill, rim,
transitions, emission and depth bias. Drape Transit history and its backing
on ground corridors. Keep the current age bands and once-per-second updates;
advance the active head with a reveal fraction and rebuild only at segment
crossings. Its wider dark edge and colour core blend once, as on Cesium.
Navara composes these looks after tone mapping.

Build reveal corridors and dynamic Transit history synchronously once shared
terrain bounds are loaded. Keep requesting frames until the visible globe
tiles and committed primitives are ready: classification needs current
surface depth after a camera move. Retain the reference radial material,
its alpha envelope and the head's material-only reveal updates.

Remove the empty Navara ground effect from the render chain when the last
shown set is hidden or destroyed. It otherwise remains as the insertion
anchor for later pulse effects after its packed textures have been disposed.
Cover reveal, destruction and replacement with fresh-state comparisons for
corridors, polygons, discs and cells. Cesium drawing is unchanged by this fix.

Keep the radial pixel check at a 500 metre radius and 4 kilometre view,
sample the brightest of six inner points around the native fill gap, and
sample across the rim width. Restore its view during arrival flights and
run it last among ground checks. Both suite launchers wait for the linked
view to arrive before checking. Keep these checks with the radial look.

Pass rectangular pick windows and drill limits through input subscriptions.
Street Level uses its 9 pixel window and CCTV uses its 14 pixel window and
six-result drill. Down picks stay synchronous, moves coalesce per frame and
Navara clicks keep the GPU answer from their gesture. Add a projector
ellipsoid option and use WGS84 radii reduced by 1,000 metres for Street Level.

These changes restore the original Cesium pad fill and ground trail rather
than the temporary ring and raised lines. Navara follows the same appearance
and horizon policy, and now honours explicit CPU pick windows. Existing
callers without these options retain their defaults. The four debts share
the contract, suite and engine implementations, so keep them together.

No coupling count grew or fell: renderer lines remain 0 and 189, external
Cesium imports 3, external viewer lines 891, engine-kind checks 1, engine
resolution calls 0, extension reads 3, ground passes 1, SDK loads 3, screen
handler files 4 and engine-name lines 32.

The contract and ground suites now wait until the camera has reached the
view in their link before checking, because the app's restore flight could
land in the middle of a check; that was also the cause of the intermittent
camera-events failure. The radial check uses a launch pad's size and samples
the fill at several inner points: Cesium's own old pad leaves the same gap in
a small ground disc's fill. The pulse-band check takes its base frame once
the surface has settled.

Checked in the browser, keyless: the contract suite passes on both engines
(84 and 85 checks), the ground suite passes on both, CCTV v2 passes 58
checks, and the space, transit, Street Level and CCTV engine switches pass.
The transit and Street Level scripts fail as they do before this change.
2026-11-08 00:30:36 +04:00