release: v0.1.0 — one-click install, keyless boot, in-app Provider Settings (#142)

The first formal release.

- One-click install via Pinokio; keyless boot lands on a live Esri World
  Imagery satellite globe with keyless terrain, with automatic OSM fallback
  and graceful degradation when terrain is unavailable.
- Provider Settings (the POWER UP panel): add, replace, or remove API keys
  inside the app; credential files made owner-only before any secret is
  written; external keys shown read-only; the panel refuses shared or proxied
  servers.
- Keyless capability responses for the optional HUD summary and place search.
- Aircraft-identity voice answers cover operator, type, and route, and say so
  plainly when enrichment is unavailable.
- README rewritten keyless-first; concise 0.1.0 changelog section; CI
  workflow included.

Gates: 2,672 unit tests pass / 0 fail, build clean, tracking regression
108/108, map-source tray QA pass, setup doctor ready.
This commit is contained in:
Bilawal Sidhu authored and GitHub committed 2026-08-31 17:49:45 -05:00
1 parent 6d83bb6008
commit b6da93b8ac
170 files changed
+5800 -853

No files matched your search

+2 -2
View File
@@ -163,7 +163,7 @@ export function createAnnotationEngine({
* reach — and the next annotate of the same geometry would then stack a fresh
* mark over the orphan. remove() tolerates partial and absent state, so this
* is safe to call unconditionally; it must never mask the original failure.
* (second review)
* (review round 2)
* @param {object} anno
* @returns {void}
*/
@@ -1027,7 +1027,7 @@ function pendingAnimation(anno, now) {
// Region-scale viewports (a mountain range, sea, or desert can span thousands of km)
// must not launch the assist flight to space: frameAnnotation flies at range × 2.4,
// so this cap keeps the camera at ≈290 km — the same regional swath scale the
// fly_to_location natural-region heuristic uses (field test 2026-07-23).
// fly_to_location natural-region heuristic uses (owner field test 2026-07-23).
const VIEWPORT_ASSIST_RANGE_CAP_M = 120000;
/** flyTo range from a Places viewport box (low/high lat-lng corners), or null. */
+1 -1
View File
@@ -575,7 +575,7 @@ test('fresh path: a renderer throw is rolled back the same way', async (t) => {
);
});
// ── Rollback must also unwind PARTIAL renderer state (second review) ──────────
// ── Rollback must also unwind PARTIAL renderer state (review round 2) ──────────
//
// The harness above throws on the FIRST statement of add(), so a rollback that
// only deletes the engine's map entry looked complete. The real renderers build
+6 -6
View File
@@ -270,7 +270,7 @@ export async function resolveAnnotationTarget({
const baseScope = refineScope(scopeFromTypes(geocodeTypes), entityKind);
// Point-like targets (monuments/statues/memorials/…) resolve POINT-FIRST: only an
// (almost) exactly-named, monument-scale polygon may replace the point; a nearby polygon
// sharing locality words must not.
// sharing locality words must not (docs/field-test-rootcause-2026-06-30.md §1).
const pointLike = isPointLikeTarget(target, entityKind, placeTypes, labelHint);
// Grounds/compound asks (target OR label wording, or entityKind fact) go outline-first:
// they reach the real enclosing-polygon sweep even under `around_the_thing` phrasing.
@@ -306,7 +306,7 @@ export async function resolveAnnotationTarget({
// BYPASSES the compound/building scope caps and the centroid drift bound
// below: the region IS the asked scope ("outline the Alps"), the 60 km²
// compound cap is for campuses (the meadow bug,
// the resolver's verified live-data contract), and a continental ring's
// docs/voice-engine-evaluation-2026-07-23.md §3), and a continental ring's
// centroid legitimately sits far from any anchor. Admin and street scopes
// are excluded — "Texas" must keep resolving as an admin boundary.
if (!isAdmin && scope !== 'street' && !around) {
@@ -343,7 +343,7 @@ export async function resolveAnnotationTarget({
// FIRST: a bundled neighborhood polygon (reliable, deterministic, OFFLINE — no live
// Overpass). Covered neighborhoods (e.g. SF: Chinatown/Marina/Mission/Presidio)
// resolve here instantly to a REAL boundary, sidestepping the slow/flaky live-Overpass
// path that times out and falls back to points.
// path that times out and falls back to points (see docs/field-test-2-analysis.md).
const ext = await lookupNeighborhoodRing(lat, lon, matchName);
if (ext) fp = { ring: ext.ring, kind: 'area', heightM: null };
// Else fall through to the OSM admin/place → named-landuse → synthesis ladder. Each
@@ -400,7 +400,7 @@ export async function resolveAnnotationTarget({
// primary footprint above returns the BUILDING (the dome) or null — neither is the grounds. The
// real enclosing polygon (e.g. "Capitol Square", leisure=park) IS in OSM but only surfaces via a
// radius sweep for NAMED non-building polygons, taking the SMALLEST that geometrically contains
// the point. So when a grounds-like
// the point (research docs/compound-containment-research.md §1.4–1.5). So when a grounds-like
// query produced a building or no polygon, prefer that REAL enclosing outline; fall to a
// synthesized disc only when OSM DEFINITIVELY has none.
if (groundsLike && (fp === null || fp?.kind === 'building')) {
@@ -522,7 +522,7 @@ const MIN_DRIFT_FLOOR_KM = 50;
// cover a large compound's monuments seen from an oblique view (Text Search is biased to 6 km here).
const PLACES_MAX_DISTANCE_M = 8000;
// Synthesis radii (m) for cases where OSM has only
// Synthesis radii (m) per osm-place-resolution-research.md §8.5. Used when OSM has only
// a label point (most US neighborhoods) or the user asks for the area AROUND a landmark.
const NEIGHBORHOOD_RADIUS_M = 750; // urban-neighborhood blob (600–900 m band)
const AROUND_LANDMARK_RADIUS_M = 400; // "the area around X" — a few blocks (300–500 m)
@@ -1281,7 +1281,7 @@ const ENCLOSING_RADIUS_M = 600; // sweep this far for an enclosing named non-bui
* leisure=park). OSM has no deterministic "parent polygon" call and the canonical
* compound name is rarely what the user utters ("grounds", not "Capitol Square"),
* so SELECTION is by containment → smallest area, with a name-match only as a
* tiebreak BONUS (never a filter).
* tiebreak BONUS (never a filter). See docs/compound-containment-research.md §1.4–1.5.
*
* Modeled on fetchLocalMonument: a 12 s fail-fast (an enrichment, not worth blocking
* narration — and narration no longer waits on it since outlines went progressive, so
+1 -1
View File
@@ -1,6 +1,6 @@
// Footprint-selection contract tests — pure fixtures, no network, no browser.
//
// Locks the monument-resolution regression:
// Locks the field-test-7 monument fix (docs/field-test-rootcause-2026-06-30.md §1):
// a POINT-LIKE target ("Tejano Monument, Austin") must never adopt a nearby
// polygon that merely shares locality/context words ("Austin", "History").
// The fixtures replicate the REAL Overpass candidates captured over the Texas
@@ -359,7 +359,7 @@ test('hybrid outline upgrade preserves the screen group and adds world geometry'
renderer.destroy();
});
// ── Partial-add rollback (second review) ─────────────────────────────────────
// ── Partial-add rollback (review round 2) ─────────────────────────────────────
//
// The hybrid builds a mark across TWO sub-renderers. It used to record the
// route only after both had run, so a throw in the second one left the first
+2 -2
View File
@@ -6,9 +6,9 @@ import { createHybridAnnotationRenderer } from './hybridAnnotationRenderer.js';
* for manual/dev use via `window.__gevAnnotations`.
*
* This module is the single swap point between annotation rendering strategies.
* The HYBRID renderer uses world-space draping for
* This branch (Direction C) uses the HYBRID renderer: world-space draping for
* footprints + screen-space SVG for callouts/rings/arrows. The engine, resolver,
* and voice tool wiring are shared across rendering strategies.
* and voice tool wiring are identical to the other two branches.
*/
export function initAnnotations({ viewer, tileset = null }) {
// World-space footprint draping; clamped marks can use the photoreal tiles.
@@ -259,7 +259,7 @@ test('annotation fade consumes the actual tracked host paint rectangle after lay
renderer.destroy();
});
// ── Partial-add unwind (second review) ───────────────────────────────────────
// ── Partial-add unwind (review round 2) ───────────────────────────────────────
//
// add() inserts the group and records it, then does more live-document work
// (draw-on wiring, the first projection pass). A throw in that tail used to