gods-eye-view/TESTING.md

221 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# God's Eye View — Testing Guide (voice map-annotation whiteboard + live tracking)
> [!NOTE]
> This is a **manual field-test scenario script** for the June-2026 whiteboard +
> tracking work. The AUTOMATED gates live elsewhere: `npm test` (unit),
> `npm run test:track` (tracking invariants), and the headless harnesses under
> `scripts/qa-*.mjs` — together these are the full automated test surface.
This guide covers the work hardened over **4 adversarial-review batches** on
`feat/annotate-hybrid`. Record a voice note + screenshots as you go; each scenario
lists what **✅ pass** looks like and (where it applies) the **❌ old bug** it replaces.
## Focus/horizon moving evidence
With the Vite development server already running on port 4173, capture all four
focus/recession scenarios with a deterministic virtual frame clock:
```sh
node scripts/qa-focus-evidence.mjs --url http://localhost:4173 \
--screenshots-dir qa-shots/focus-evidence \
--json qa-shots/focus-evidence/report.json
```
For a quick operator loop, `--smoke` captures only S1 in six frames. For visual
sign-off, add `--headful`; this removes the SwiftShader launch flags and uses
the machine's real GPU. The harness brings its page to the foreground at the
start of every scenario so a headful Chromium run keeps streaming tiles.
Google 3D remains the default basemap. If its tile stream is the bottleneck
rather than the behavior under test, select an existing map stack explicitly:
```sh
--basemap bing-aerial
--basemap osm
```
Accepted values are `photoreal`, `bing-aerial`, `bing-labels`, and `osm`; Bing
stacks still require the app's usual Cesium ion token.
Tune both systems without editing source by adding, for example:
```sh
--params '{"focus":{"dimFloor":0.35,"nearerBehavior":"partial"},"horizon":{"scaleFloor":0.5,"alphaFloor":0.4}}'
```
The script never starts the server. During scenarios it pauses Cesium's default
render loop, advances focus time explicitly, and renders each frame before the
screenshot, so computed alpha/scale sequences repeat for identical parameters.
Headless Chromium still forces SwiftShader, so its pixels are relative CI/A-B
evidence only; headful real-GPU output is the sign-off surface. Screenshots use
scenario/frame names and the JSON report records effective tuning plus
per-contact alpha, scale, and screen data. Before each scenario's first capture,
the harness gives the active Google photoreal tileset up to 45 seconds to reach
Cesium's `tilesLoaded`/`allTilesLoaded` condition. Every frame records
`tilesSettled: true|false` and whether that gate applied; a timeout is recorded
as false, never promoted to a pass. Non-photoreal stacks record the gate as
settled and not applicable because no Google 3D tileset is active.
> [!IMPORTANT]
> Do not use a screenshot for visual judgment unless its report frame records
> `tilesSettled: true`.
## Setup
- **URL:** http://localhost:4173 — auto-flies to Austin on load. Give photoreal tiles ~10s.
- **Voice (the real feature):** click **GEV MIC** (bottom of screen) → wait for **LISTENING**
just talk. It marks the map *as it talks*, without announcing that it's drawing. Click
**STOP** when done. (Needs `OPENAI_API_KEY`; `dev-fresh.sh` injects it from Keychain.)
- **Console (deterministic, no mic/live-data needed):** open DevTools (**Cmd-Opt-J**) and use:
- `window.__gevAnnotations.tour()` — self-running narrated SF tour (camera + marks in sequence)
- `window.__gevAnnotations.demo()` — lays the SF set down at once
- `window.__gevAnnotations.clear()` — erase all marks
- `window.__gevAnnotations.count()` — how many marks are live
---
## What changed (the list)
**Live aircraft tracking & camera (Batch D)** — civilian + military, mirrored:
- **R14** warm-up: tracked plane glides immediately (no freeze-then-jump / backward snap),
via a display-layer reconciliation that smooths any position discontinuity over ~0.9s.
- **R15** framing: calibrated initial follow distance (altitude-scaled, 330 km).
- **R16** trail: head stays glued to the moving icon per-frame; never trails ~1s behind or
pokes out in front of the nose.
- **R13** z-order: screen annotations fade where they'd cover the **tracked** plane + its label.
**Voice annotation — scoping & honesty (Batch B):**
- **R1** resolver scope: a place name resolves to the *right* thing (building vs neighborhood
vs natural feature vs city) instead of an oversized admin blob.
- **R2** boundary stitching: complex outlines no longer close with bay-spanning chords.
- **R6** route honesty: a routing outage draws a *labeled* straight "direct line", never a
silently faked road.
- **R12** partial honesty: if some targets fail, it says so — no masking partial as success.
- **R10** cache: transient failures aren't negative-cached for the whole session.
**Annotation rendering & motion (Batch C):**
- **R8** route flow: route dashes **animate** (flow along the path).
- **R9 / R17** perf: idle annotations stop their animation loop; height cache is bounded.
- **R11** no-freeze: large/complex boundaries simplify without locking the UI.
**Abuse guards (Batch A)** — mostly internal: input caps on `annotate_map`, clear/new-topic
cancellation, hardened Overpass + route proxies. Not much to see by hand (see §4).
---
## 1. Live aircraft tracking (Batch D) — the 3 issues you reported + z-order
> Needs a live plane. Track by **clicking a plane icon**; **Esc** (or click empty space) untracks.
> If you see no planes, scroll out once — Texas airspace is busy.
**1a · Warm-up smoothness (your issue #1 → R14)**
1. Click a moving plane. 📸 Snap the instant it locks, then watch ~23s.
- ✅ Starts gliding smoothly *immediately*. ❌ *Was:* froze ~1s, then jumped forward.
**1b · Initial framing (your issue #2 → R15)**
1. On the same lock-on, look at how the camera frames the plane. 📸 Snap the initial view.
- ✅ Plane + label readable with context, no scrolling. ❌ *Was:* jammed in too tight.
**1c · Trail glued to the plane (your issue #3 → R16)**
1. Keep tracking ~10s. 📸 Snap the cyan trail while it moves.
- ✅ Trail tail stays attached to the plane; nothing pokes out *in front* of the nose; no ~1s lag.
*Was:* trail lagged a beat behind.
**1d · Military layer (same fixes, mirrored)**
1. Enable the **Military** layer (left column). Track an **amber** plane. Repeat 1a1c.
- ✅ Identical smooth behavior.
**1e · Z-order: tracked plane stays on top (→ R13, trickiest to stage)**
1. While tracking a plane over Austin, GEV MIC: *"annotate downtown Austin."*
2. Orbit/zoom so the plane crosses the annotation's outline or label. 📸 Snap the overlap.
- ✅ The annotation **dims** where it covers the plane/label — plane stays visible on top.
*Was:* the annotation drew over and hid the plane.
---
## 2. Voice annotation — scoping & honesty (Batch B)
> All from the Austin default view (no camera move needed). Click GEV MIC, then speak.
**2a · Scope: building vs region (→ R1)** — say each, watch what gets outlined:
- *"annotate the Texas State Capitol"* → ✅ the **Capitol building**, not the whole state.
- *"annotate Barton Creek"* → ✅ the **creek / greenbelt**, not Barton Creek *Mall* or the city.
- *"annotate downtown Austin"* → ✅ the **downtown district**, a sensible neighborhood-size area.
- *"annotate the University of Texas at Austin"* → ✅ the **campus**, not the city.
- 📸 Snap each outline. ❌ *Was:* incidental names ballooned into giant county/state blobs.
**2b · Classic SF set (optional)** — first say *"take me to San Francisco,"* then:
- *"annotate the Mission District"* → neighborhood. *"...the Presidio"* → the full former-base
outline (not a single point, not a bay-spanning blob → R2). *"...Chinatown"* → the district.
**2c · Route honesty (→ R6)**
1. *"draw a route from Austin-Bergstrom airport to the Texas Capitol."*
- ✅ A real **road** route with a flowing dashed line + a labeled callout.
- If a route ever comes back as a **straight** line, it should be **labeled** as a direct/approx
line (not pretending to be a road). ❌ *Was:* silent fake straight-line "routes."
**2d · Partial-failure honesty (→ R12)**
1. *"annotate the Texas Capitol and the Flibbergibbet Building."*
- ✅ It annotates the Capitol **and tells you** it couldn't find the other one.
*Was:* reported success and silently dropped the missing one.
**2e · Clear / new-topic race (→ R4)**
1. *"annotate downtown Austin"* and, right as it starts, *"actually, clear everything."*
- ✅ Marks clear and **stay** cleared (the in-flight one doesn't pop back a second later).
- Sanity in console: `window.__gevAnnotations.count()``0` after a clear.
---
## 3. Annotation rendering & motion (Batch C) — deterministic, no mic
**3a · Full experience (smoke test)**
1. Console: `window.__gevAnnotations.tour()`. 📸 A couple of frames as it runs.
- ✅ Camera flies to SF; Palace highlight → arrow → Presidio **draped** outline → ILM pin →
Crissy Field **route** appear in sequence; marks stay glued as the camera moves.
**3b · Route dashes animate (→ R8)**
1. During/after `tour()` (or `demo()`), watch the **route** line (Crissy Field shoreline).
- ✅ The dashes **flow** along the path (animated), not static. ❌ *Was:* dashes never moved.
**3c · Draping & persistence**
1. After `demo()`, orbit the camera around the Presidio outline.
- ✅ The footprint **drapes onto** the 3D ground/buildings and conforms; callouts/rings/arrows
are the hand-drawn SVG style and stay anchored to their real spot.
**3d · Large boundary, no freeze (→ R11)**
1. Console:
`window.__gevAnnotations.annotate([{type:'area',target:'Travis County, Texas',label:'Travis County',color:'green',footprint:true}],{flyTo:true,persist:true})`
- ✅ The complex county boundary simplifies and draws **without** freezing/janking the UI.
---
## 4. Robustness / guards (Batch A) — mostly internal
These are server-side / defensive and don't have a clean visual tell. Light checks only:
- Rapid-fire several annotate commands, then a clear — UI should stay responsive and end clean
(`count()` → `0`).
- Nothing here should change normal behavior; flag it only if something feels *broken* (stuck
spinner, marks that won't clear, errors in the console).
---
## 5. General feel — open feedback
While recording, call out anything in these areas — this is the feedback I most want:
- **Tracking feel:** does follow motion feel smooth/natural, or floaty/laggy/overshooting?
- **Framing:** is the initial tracked view a good "hero" shot, or too close/far?
- **Annotations:** do outlines land on the *right* thing? Are labels readable / well-placed /
not overlapping? Does the hand-drawn style read well over photoreal tiles?
- **Voice:** does it mark things *as it talks* (not after), and confirm only what actually
happened? Any command it misunderstood?
- **Anything that looks wrong, janky, or surprising** — screenshot it; that's the gold.
## If something looks off
- **Grey globe / slow tiles:** wait a few seconds after a camera flight; photoreal streams in.
- **A voice mark didn't land:** the place may not geocode — try a more specific name
(e.g. "Palace of Fine Arts, San Francisco").
- **No planes:** OpenSky data may be momentarily sparse; scroll out or wait a poll cycle.
- **No GEV MIC button / voice errors:** `OPENAI_API_KEY` didn't load — use the console API for
the annotation tests and skip the voice-only ones (§2).