# Planning browser-presentation telemetry — 2026-09-20 ## Purpose Instrument the time from a fresh planning cloud package reaching the browser to its admission by the existing native Rerun channel and two subsequent browser animation-frame opportunities. The purpose is to investigate the operator's observation that a new cloud appears substantially slower than an ordinary session cloud, without changing registration, route following, device control, or the visible LAB surface. ## Exact boundary The browser reports one bounded, best-effort sample only after: 1. `channel.send_rrd` has resolved for a live cloud package; 2. one browser animation frame has run (or timed out after 500 ms); and 3. a second browser animation frame has run (or timed out after 500 ms). The report stores metric summaries and at most 4,096 in-memory samples for the selected run. Browser posts contain at most eight samples, have no retry queue, and use an exact `run_id`, `display_epoch`, cloud revision, and cloud sequence fence. A stale, terminal, or foreign packet is ignored. The final run report receives only the summary. `source_to_second_animation_frame_upper_bound_ms` is deliberately conservative: server-reported cloud age + browser request time + Rerun admission duration + post-admission two-frame delay. This is not proof of a GPU canvas-paint receipt, physical scanner-to-pixel clock synchronization, registration truth, route-following quality, navigation, or safety authority. ## Implementation - `apps/control-station/src/core/missions/planningSceneStream.ts` forwards the exact live display identity and holds the native cadence until the bounded delivery callback finishes. - `apps/control-station/src/components/missions/PlanningLiveScene.tsx` records the browser-side admission/two-frame proxy without adding controls, panels, labels, or debug UI. - `apps/control-station/src/core/missions/planningPresentationTelemetry.ts` batches bounded best-effort browser reports. - `src/k1link/web/planning_live_api.py`, `src/k1link/missions/live_tests.py`, and `src/k1link/missions/planning_browser_presentation.py` validate, fence, and summarize those reports. ## Existing physical context The operator deliberately starts the scanner about 1–3 m away from the prior start and walks an offset trajectory. In the registered reference frame, the two accepted repeat runs do not collapse into one exact line: | Run | Measured path | nearest-route median | nearest-route p95 | | --- | ---: | ---: | ---: | | `ja-sun-006` | 35.30 m | 1.12 m | 3.11 m | | `ja-sun-007-100m` | 102.59 m | 0.95 m | 1.23 m | The transformed path origins are about 0.79 m and 0.65 m from the reference route start, and about 0.51 m apart in XY. Those figures support that the recorded passes are not identical traces, but they cannot independently survey the operator's physical 1–3 m offset because registration maps each query into the reference frame. ## Verification and deployment - `pytest -q tests/test_planning_fast_display.py` — 4 passed. - Focused frontend streaming/reporter tests — 8 passed. - `npm run typecheck` — passed. - `npm run test:unit` — 871 passed. - `npm run build` — passed (only the established chunk-size warning). - Planning Python suite rerun — 13 passed. One earlier stationary-start timing assertion was repeated successfully; it does not cover this reporter path. - Canonical LaunchAgent reloaded only after the selected run was terminal. Health is `ok`, exactly one listener is bound to `127.0.0.1:8000`, no listener is bound to 8765, and the new observation endpoint is mounted. ## Next physical check Run a fresh planning pass using the normal deliberate offset; no special placement, UI mode, or debug control is needed. A 30–40 m repeat is enough to validate recording and inspect the new report. Keep the Planning scene open; after the run finishes, review sample count, request/admission/frame percentiles and frame-timeout count alongside the already existing registration evidence.