Commit Graph
100 Commits
Author SHA1 Message Date
German Khokhlov af0dc2e2ec Wait for the traffic state the layer reaches in an oblique view
Roads the view cannot sample may keep their pending surface heights, as
before the refactoring; the oblique wait now asks for current coverage,
drawn traffic, finished loading and no scheduled refinement, and prints
every loading field when it times out.
2026-11-11 02:27:40 +04:00
German Khokhlov ed68be0610 Share the traffic refinement deadline across passes
Each refinement pass renewed the ten-second deadline, so changing
surface readiness could keep the layer refining, and loading, without
end. The passes now share one deadline, and the scheduled surface work is
reported as surfaceWaiting.
2026-11-11 02:27:40 +04:00
German Khokhlov b870f446c6 Let the cold-start comparison excuse a field within a bound
Field entries in the ledger allowlist now apply to every difference row,
in the ledger and in the probe alike, and may carry maxDelta. The traffic
fill gets one with a bound of three: its simulated vehicles enter and
leave every frame, so two pages snapshotted moments apart differ by a
vehicle or two.
2026-11-11 02:15:52 +04:00
German Khokhlov 49b2849528 Wait for the directions route flight instead of three seconds
The FLY check slept a fixed 3 s and then expected a route flight, which
passed or failed on the same commit. It now waits, up to 15 s, for the
layer to report the route motion and the camera to move.
2026-11-11 02:07:36 +04:00
German Khokhlov 00cb44ad2c Stop refining traffic surfaces that make no progress
An oblique view kept roads whose samples could not resolve from it, and
the refinement retried them without end, leaving the layer loading with
work pending. A refinement pass that resolves nothing new stops, and work
still pending at the existing deadline is dropped.
2026-11-11 02:07:36 +04:00
German Khokhlov ed6b6114cf Enable the Bhote Koshi event on Cesium while 3D tiles are shown
Under photoreal tiles Cesium hides the globe, so its imagery layers never
request tiles and the event's imagery install waited for a frame that
never came: turning the story on with 3D tiles on never finished. The
decoded images are installed hidden and shown afterwards by the same rule
as the presentation mode.
2026-11-11 02:07:36 +04:00
German Khokhlov c1795c7dc3 Sample the released-tileset check over open ocean
Under the camera and at 20°E 10°N other contract checks leave meshes and
models; Cesium's scene sample hits them, so the check failed in the full
suite and passed alone. It now samples two places none of them draws at.
2026-11-11 01:51:34 +04:00
German Khokhlov 69617af7ef Count only the placer's samples against its budget in the tiles scenario
The scenario counted every sampleHeight call in a task as the placer's
pass, so a single sample from elsewhere in the app that landed in the
same task pushed a full pass to 17. Calls that are neither a fixture
point nor the one camera estimate are now counted apart.
2026-11-11 00:45:36 +04:00
German Khokhlov 9e2c424030 Share the surface sample budget between placements in one task
Two triggers firing together (tiles loaded and a camera move end) ran two
passes in the same task, each within 16 samples but 17 or more together.
Placements in one task now share the budget; a placement that finds it
spent continues in the next task, and that continuation starts a fresh
budget.
2026-11-11 00:40:45 +04:00
German Khokhlov 982d197111 Check the surface pass's time budget right before each tile sample
The 4 ms budget was checked at the top of each point, but projecting the
point and reading the terrain came before its sample, so on Cesium a pick
render could start after the deadline. The time is checked again just
before the sample once the pass has taken one.
2026-11-11 00:25:31 +04:00
German Khokhlov 3ab0bbf7c1 Hide a selected radio station beyond the horizon, also after a switch
Re-adding the selected station's marker reset it to visible, and the
horizon check skips a still camera, so a station selected on the far side
of the Earth showed through the globe until the camera moved. The marker
now starts with the station's current horizon visibility, and the layer
recomputes it once the view is restored after an engine switch.
2026-11-11 00:21:45 +04:00
German Khokhlov 697dc91e81 Check a released tileset by height, not by the source label
Cesium labels every scene hit, the globe included, as tiles, so asking
that no answer is labelled tiles after leaving photoreal failed on the
reference engine. The check now asks that no tile geometry answers above
the terrain: a tile-labelled height must match the terrain height.
2026-11-10 23:39:36 +04:00
German Khokhlov e98bf9c485 Merge branch 'german/refactor-traffic-surface-pending' into german/navara-refactor 2026-11-10 22:31:21 +04:00
German Khokhlov be395f0f52 Finish traffic surface sampling with the camera still
Road samples that were not ready, or left over when a pass ran out of its
slice, waited for the next camera move; with the camera at rest they
stayed pending and part of the network never settled on the ground. The
flow now requests the frame it needs and continues the unresolved samples
within the same 12 ms slice and station budget.
2026-11-10 22:31:20 +04:00
German Khokhlov d83f06755f Merge branch 'german/refactor-cold-start-fixes-2' into german/navara-refactor 2026-11-10 22:31:14 +04:00
German Khokhlov 34b4fdce57 Release hidden CCTV geometry and excuse level-of-detail path counts
CCTV kept the coverage and projection geometry of every camera the
opening view passed on its way to the restored one; after each visibility
update it now releases the coverage of cameras out of view and the planes
of inactive cameras, keeping decoded media for reselection.

The cold-start comparison accepts a field entry in the ledger allowlist
that excuses one field of one set with a reason, and uses it for the
infrastructure footprint counts: that level of detail keeps features
chosen on the way to a view so they do not flicker while panning, which a
cold start cannot reproduce. Presence checks ignore field entries. The
fixtures give recent imagery a matching scene and date and traffic its
deterministic starts, and traffic counts as drawn without every loaded
vehicle visible.
2026-11-10 22:31:13 +04:00
German Khokhlov ed47de6a2c Let the tiles scenario allow the page's web fonts
The check for requests to Google and Cesium ion caught the Google Fonts
stylesheet the page loads on every run, which the map policy allows; it
now looks only for tiles, credits and ion.
2026-11-10 22:28:15 +04:00
German Khokhlov ee87482f07 Count the camera ground estimate within the surface sample budget
A pass checked its budget of 16 tile samples before each point, but a
point that needed the estimate of the ground under the camera took two
samples, so a pass could reach 17. The point is now left for the next
pass when the estimate used the last sample.
2026-11-10 22:28:14 +04:00
German Khokhlov 1d10ba242d Merge branch 'german/refactor-navara-photoreal-release' into german/navara-refactor 2026-11-10 22:15:50 +04:00
German Khokhlov cd571dfb32 Remove a released 3D tileset from Navara's scene and surface queries
With its cache budget on, Navara 0.2.1 deletes a source without emitting
the model-removal events, so the meshes of a released photoreal tileset
stayed in the scene: after switching to another map the buildings were
still drawn, and sampleHeight, clampToHeight, the shared surface
placement and ground drapes still answered from them. The adapter now
disposes the deleted layer's meshes, registry entries and retained
geometry itself, also for tiles that finish decoding afterwards, and
WORKAROUNDS.md records it. A contract check fails when a surface query
still reports tiles after leaving photoreal, with a mutant.
2026-11-10 22:15:50 +04:00
German Khokhlov ab41c765cc Merge branch 'german/refactor-e12-script-regressions-2' into german/navara-refactor 2026-11-10 22:05:58 +04:00
German Khokhlov 6b0d3f4675 Fix the camera picker and oblique traffic waits in two QA scripts
The CCTV camera check lost camera B from the picker when the flight to
camera A changed the cameras in view; the picker now keeps focus while A
is held. The oblique traffic wait compared exact seven-decimal view keys
that a settled camera never reproduced; it compares the coverage with the
current view within small tolerances and prints both keys on timeout.
2026-11-10 21:51:54 +04:00
German Khokhlov 4bbf9949d5 Merge branch 'german/refactor-navara-tiles-drape-2' into german/navara-refactor 2026-11-10 21:36:39 +04:00
German Khokhlov 88f434ded7 Merge branch 'german/refactor-cold-start-fixes' into german/navara-refactor 2026-11-10 21:36:39 +04:00
German Khokhlov 7c03d68a2f Report the depths behind each drape sample in the tiles scenario
With --report the scenario prints, on Navara, the scene, globe and
combined depths at the sample pixel with the drape hidden, shown and
hidden again, the buffer the ground pass classifies it as, and whether a
shown tile lies on the ray, so a drape on the wrong surface explains
itself.
2026-11-10 21:36:38 +04:00
German Khokhlov 705b7a5314 Make the cold-start comparison wait for the same data and attribute it
Both pages now get the same deterministic SATCAT, NASA image and wildlife
data and advance animation clocks alike; the scenario waits until each
display has published and the registries stay unchanged for two seconds,
and late-created content is attributed to its registered owner. Known
allocation counters are normalised; every slot, count and visibility is
still compared.

Infrastructure drew on attach before the camera was restored, seeding its
level of detail at the incoming engine's default view; it now draws when
the view is restored.
2026-11-10 21:36:38 +04:00
German Khokhlov 97e192ebce Request frames again while waiting for tiles and transitions
A request-mode globe updates its tile state only on drawn frames, so tile
and UI readiness that never asked for one waited until something else
drew: imagery, weather and ground scenarios took several times longer.
The idle checks measure through their own passive observer and are not
affected.
2026-11-10 21:25:08 +04:00
German Khokhlov 555906da6b Merge branch 'german/refactor-e12-script-regressions' into german/navara-refactor 2026-11-10 20:58:16 +04:00
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