Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/facett

.nornir/handover-2026-09-29-navgraph-gpu.md

Handover 2026-09-29 — navgraph in dev mode, GPU graph lanes, 100k points in Streamlit

nornir:class=design · written on loki at the end of the 2026-09-28 session. It moves the work to dwarf's claude container (tmux session facett).

Owner orders that hold (read these first)

Done and on main

commit what
549dfbd Merge navgraph phase 1: facett-core/src/navgraph.rs (per-frame arena, numbering 1.2.3, ~ guessed, ? undeclared, top-layer overlay, Ctrl+G <n> Enter, to_json), plain-egui harvest (§10), facett-demo NavOrder, Streamlit dev mode (facet-wrapped/src/devmode.rs, facet_dev, facet_navgraph), charts.rs, more registry entries (wheel 0.1.19 = 36 components), 2-D map and graphpan GPU lanes installed, gallery_probe example, web_time clocks (std Instant panicked the osm3d GPU upload in the browser).
5b312f3 The navgraph demo snapshot (facett-demo/tests/snapshots/navgraph_demo.json), force-added because tests/snapshots/ is gitignored.
branch feat/wasm-threads-gatling @ 3b19509 100k graphs on the GPU: grid-pyramid layout kernel (facett-graphview/src/layout_grid.wgsl, GridLane, O(n log n) per step above GRID_MIN_NODES), resident graph cloud for graphnav above SCALE_NODES, per-model frame index, facet_state read on demand instead of serialised every frame, browser_bench.rs, frame_cost example. Merged with main (5 conflicts resolved: Cargo.toml features, two comments, the frame loop now calls devmode::draw on the RefCell facet, the lane guard has 8 rows). Merge to main only after its tests pass (see the status line at the end).

Test evidence from 2026-09-28: facett-core navgraph 11/11, navgraph_demo 4/4 (after the snapshot), lane guard 5/5, graphview (gpu) 160 passed, graphnav + facet-wrapped all green on the branch before the merge, wasm32 cargo check of facet-wrapped clean.

Open — helper A's lane (navgraph + Streamlit components)

  1. gallery_probe (headful Chrome, RTX) run at 20:45: osm2d fails — WebGPU renderer failed to start: No suitable graphics adapter found while osm3d on the same page got "nvidia lovelace". The 2-D map lane asks for its adapter differently from the 3-D one; make it take the host's device like the others.
  2. graph2d, lineage and geomap have no GPU lane (egui painter only). Per the GPU ruling that is a defect: give them the shared graphcloud / facett_map::gpu lane.
  3. Read the navgraph back from a live tab: robot_streamlit.py --gallery --dev (or the Rust gallery_probe) must assert facet_navgraph() numbers per frame.
  4. facett-demo registers one pane as ⟨unregistered⟩ graph (see the snapshot): give it a real id.
  5. Wire the one-call overlay into korp-ui and dwarves-gui (plain egui harvest), then design §6 phase 2 (korp NavOrder).
  6. Finish the inventory: every facett-* crate either in the Streamlit registry or listed with the reason it is not. Run cargo xtask test-demo and report the counts.

Lane A status (2026-09-29, branch lane-a/navgraph-streamlit, dwarf)

Blocker: loki is down (No route to host since ~22:25 UTC, same as lane B), so nothing that needs a GPU or a browser has run. Built and staged on dwarf in ~/runs/facett-0929/tmp/laneA-stage/: dist/ (wasm bundle of 7d203c7), index.html (loader), demo_payloads.json, gallery_probe, graph_gpu_cloud_lane, geomap_gpu_cloud_lane (stripped test binaries). Loki commands below.

# state what, with shas
1 osm2d adapter todo Not reproduced (loki). Read: the 2-D map lane does NOT request its own adapter — install_gpu_lanes (facet-wrapped/src/wasm.rs) installs facett_map::gpu on eframe's RenderState exactly like osm3d/graphcloud, and the failing text No suitable graphics adapter found is wgpu's RequestAdapterError::NotFound from WebRunner::start, i.e. navigator.gpu.requestAdapter() returned null for that iframe before any lane ran. With --groups graph,map the manifest order puts osm2d FIRST in the run, so the likelier cause is "the first mount in a fresh Chrome gets no adapter", not the map lane. gallery_probe --names osm3d,osm2d (7d203c7) tells the two apart in one run: if osm3d then fails and osm2d passes, it is first-mount; the fix is then a bounded retry in start(), not a lane change.
1b retry done, browser-unproven 7b362e5: start() retries ONLY NotFound — 4 attempts, 250/500/1000 ms, rebuilding the consumed component; final refusal no GPU: WebGPU gave this page no adapter after 4 attempts …; adapter_attempts in every facet_state() and in the probe line. Policy facet-wrapped/src/adapter_retry.rs, 5 unit tests. The staged dist/ predates it — rebuild with cargo xtask wrap-wasm before the loki run.
2 GPU lanes done, GPU-unproven fff05f6: graph2d (facett-graph new feature wgpu) and geomap (map-wgpu) push their cloud through graphcloud::cloud::draw_cloud; CPU painters kept, none added; state lane = lane::cloud_lane_json (gpu: "no GPU" when no renderer). lineage already rode graphnav's lane. GPU tests facett-graph/tests/gpu_cloud_lane.rs, facett-geomap/tests/gpu_cloud_lane.rs (lane_flag gpu + CloudRenderer frames > 0) built, unrun.
3 navgraph per frame done, browser-unproven 7d203c7: facet_navgraph() carries frame; gallery_probe --dev samples it 6× and asserts the spine on every sample and ≥ 2 distinct frames.
4 demo pane id done fff05f6: facet-graph-1 registers graph; pane is facett-demo.deck.graph/graph (1.2.2), snapshot re-blessed; navgraph_demo 4/4.
5 korp/dwarves done in code, uncompiled overlay: korp navgraph-overlay @ 76b7e4b, dwarves navgraph-overlay @ 0763014 (neither workspace resolves on dwarf: korp needs ../tunnr, dwarves ../gunnar). Phase 2 built generically in the scene renderer (b7859b9, navgraph-design §9 "Phase 2 as built"), facett-app/tests/navgraph_scene.rs 3/3; the korp-side robot test is designed there, not written.
6b atoms declared done 42c2a65: navgraph::declare_own_draw_order(ui) in 22 component views; navgraph_demo sweep over all 89 tabs: undeclared component atoms 198/210 → 8/210, CEILING 8.
6b' atoms to 0 done e6e5e3b: scene-in-a-pane, scene slots, widgets, GFX v2 and map3d declare too — sweep 0 undeclared of 210, CEILING 0.
6c forge seams done 25e23e1: cicd, brokkrview, holger wrapped (data seams + gallery payloads); inventory 35 wrapped / 40 entries / 13 'no data seam yet'.
6d more seams done 05d8b09 releaseview + binview, 76297f4 coderoom (component serde shapes; a malformed checksec or list is refused); 744645e sharper reasons: 38 wrapped / 43 entries / 34 listed, 5 'no data seam yet' (fleet-view next).
6e fleet + buildspace done 5f1c1d5 fleet (payload = FleetRunView, its own serde state); a87fc82 buildspace = GaloisPane over FeatureAxis (already serde in facett-buildthing; edda CrateAnalysis serde too — no sibling change), Facet impl added; robot.rs fixed for edda Toolchain drift. 40 wrapped / 45 entries / 3 'no data seam yet' (docview, manual, model3d).
t14s run done 2026-09-29 09:30–09:49 on the t14s (Radeon 890M RADV STRIX1, load 0.1–0.7, edge 33–35 °C, Tctl 34.5–36.9 °C), HEADLESS Chrome only (gallery_probe --headless, 9528e2b). GPU tests (9528e2b: facett adapter policy — kittest's default had opened llvmpipe): graph2d PASS (lane_flag gpu, 930 red node pixels), geomap PASS (CloudRenderer frames 1). --names osm3d,osm2d: 2/2, adapter "amd rdna-3", adapter_attempts 1 each. --dev graph+map: 10/10 after f5696bd (probe nudge fixed: iframe resize; graphview gpu-cloud feature on) — six distinct frames per component, spine 1 / 1.1 on every sample. FULL --groups all --dev: 45/45 PASS, every adapter "amd rdna-3", adapter_attempts 1 everywhere, ≥ 2 distinct navgraph frames on all 45. Not a failure but open for lane B: graphnav and lineage report canvas.layout_lane: cpu (the probe does not count layout lanes). Raw results: dwarf ~/runs/facett-0929/tmp/laneA-results/h1..h4.{json,txt,meta}. Headful runs earlier the same morning (X11/Wayland, windows on the owner's screen) gave null adapters and were stopped.
6 inventory done; test-demo not run fff05f6: facet-wrapped/tests/inventory.rs — 72 facett-* crates, 32 wrapped behind 37 entries (+progress = facett-pop), 40 listed with a reason (16 "no data seam yet"). cargo xtask test-demo NOT RUN: it pip-installs from a holger index on 127.0.0.1:8455; none runs on dwarf, and holger does not build there (its manifest needs edda/crates/appliance-grow, absent from the depth-50 edda).

Loki, when it is back (ports 8601-8619, nothing compiled there):

rsync -a ~/runs/facett-0929/tmp/laneA-stage/ rickard@192.168.1.102:runs/facett-0929-laneA/
# on loki, in ~/runs/facett-0929-laneA:
./graph_gpu_cloud_lane --nocapture; ./geomap_gpu_cloud_lane --nocapture
WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/run/user/1000 ./gallery_probe --dist dist --loader index.html \
  --payloads demo_payloads.json --port 8601 --dev --out probe.json            # graph + map groups
WAYLAND_DISPLAY=wayland-0 XDG_RUNTIME_DIR=/run/user/1000 ./gallery_probe --dist dist --loader index.html \
  --payloads demo_payloads.json --port 8602 --names osm3d,osm2d               # item 1: first-mount or lane?

Open — helper B's lane (100k points, benches)

  1. Measure 100k nodes in Streamlit in headful Chrome: time to first frame, layout time to settle, fps while panning, memory; GPU lane on the RTX 5080 and on an integrated GPU (dwarf has a Radeon 680M, but the container has no /dev/dri).
  2. Parity test: GridLane against the O(n²) GPU lane and the CPU lane on the same small graph (positions within tolerance), plus a timing row.
  3. Testmatrix + benches: rows for layout 1k/10k/100k × {gpu, gpu-grid, cpu-1 baseline}, FDEB, point cloud 100k/1M, native vs wasm. Numbers go into .nornir/facett-benchmarks.md with the box, the GPU and the load average.
  4. .nornir/wasm-threads-plan.md: record the GPU ruling. The threads bundle and the COOP/COEP front are PARKED unless a measurement shows a CPU-side stage that matters.

Lane B status (2026-09-29 00:25 UTC, branch lane-b/gpu-100k-bench, dwarf)

Blocker: loki is down. 192.168.1.102 answered at 22:20 UTC (idle, RTX 5080 44 °C) and has given No route to host (no ARP; the LAN router answers) since ~22:25 UTC. Nothing that needs a GPU or a browser has run. Everything is built and staged on dwarf in ~/runs/facett-0929/stage-laneB/ (layout_matrix, browser_bench, frame_cost, gv-test-baseline = graphview gpu lib test binary as of 2bab36c, dist/ = wasm bundle); the loki commands are at the end of .nornir/facett-benchmarks.md ("GPU lanes at 100k").

# state what, with shas
flake todo Not reproduced (needs loki). Static read of facett-graphview/src: the GPU tests that open a device WITHOUT gputurn::hold() are gpu_layout.rs gpu_front_door_lays_out_in_box_and_contracts_edges (two bring-ups), layout_job_matches_the_blocking_lane, the_host_device_seam_installs_and_clears, fdeb_gpu.rs cpu_and_gpu_bundle_agree, and the gpu.rs / lib.rs GpuRenderer::new render tests — the parallel-bring-up shape gputurn.rs's table records as SIGSEGV. First suspects; prove with the 20× loop before fixing.
1 todo 100k in headful Chrome not measured (loki). browser_bench --port added (2bab36c) so the run stays in 8701-8719. Radeon 680M: not measured, container has no /dev/dri.
2 written, unrun GpuLayout::new_grid + grid_all_pairs_and_cpu_agree_on_a_small_graph (gpu_layout.rs, 2bab36c): 400 nodes, 30 steps, all-pairs vs CPU ≤ 1e-2, grid vs CPU cos > 0.98 and ≤ 5 % of span, prints [parity-timing]. Compiles; tolerances not yet held against a GPU.
3 partial examples/layout_matrix.rs (2bab36c, --cpu-only 8b4be60). dwarf CPU rows in facett-benchmarks.md: cpu-1 100k 194.5 ms/step, cpu-all 111.4 ms/step, graphnav native first frame 8.35 s / steady 96.8 ms at 100k, load 22-25 on 12 threads. GPU, FDEB-gpu, cloud and wasm rows owed.
4 done GPU ruling recorded at the top of wasm-threads-plan.md (3ccd4f4); threads bundle + COOP/COEP front PARKED.
flake fix built, unproven d8b6dd6: the seven device-opening graphview lib tests take gputurn::hold() (no helper on those paths takes it, so no re-entry). dwarf 134/134 (GPU tests self-skip). Staged gv-test-baseline vs gv-test-fixed for the 20× loop.
CPU 100k done df3c7bd: cached facet_state() read at 100k 741/655 → 380/405 ms (stats sig, acyclic cache, schema in frame index); the native 8.35 s "first frame" is the CPU layout (GPU job's in a browser), the frame after it is 140-225 ms. graphnav 92/92, facet-wrapped 81/81.
staging done 6689f0e: browser_bench finds the session (wayland/X11, uid runtime dir), default port first free of 8701-8719. Binaries need glibc ≥ 2.43. Runbook in facett-benchmarks.md.
flake done, proven t14s Radeon 890M, 20 runs each: gv-test-baseline (2bab36c) parallel 8/20 SIGSEGV in libvulkan (threads of the 7 unturned GPU tests), --test-threads=1 0/20; gv-test-fixed (d8b6dd6) 0/20 and 0/20.
parity done 20dcd9a: grid held per step + by settled shape (30-step positions diverge by chaos: 10.3 of 28.7). Radeon: all-pairs vs CPU 1.84e-3, grid step cos 1.0000, gpu_layout:: 15/15, full gv lib 134/134.
graphnav GPU job done a436a0c: no size floor — gallery-sized graphnav/lineage now lay out on gpu-job in the browser (lane A saw cpu).
100k browser done (t14s) headless Radeon: first frame 228-229 ms, settled 1.36-1.38 s on gpu-job/grid, 60 fps under a synthetic drag, wasm 285 MB, JS heap 118 MB. loki (RTX 5080) rows still owed.
integration done integration/0929 @ 42c366c (lane A c9d9401 + lane B 51b727b): 3545 passed / 135 failed / 39 ignored over 552 test binaries on dwarf; 121 failures need a GPU adapter, 13 do not (list in the report). Staged ~/runs/facett-0929/stage-int/ + RUNBOOK.txt + STAGED_SHA; smoke on the t14s all green.
knut matrix done 39f3403: knut-pipelines dev-dep restored (commented out by accident in e565e0a, 2026-07-13); knut_facett_matrix 2/2, silenced_tests_guard green; gate of fe52fd7 reverted.
GPU-only on t14s done integration b9ad95e: 91 failing-on-dwarf test binaries run one at a time, --test-threads=1, VK_LOADER_DRIVERS_SELECT=*radeon* (llvmpipe invisible): 76 green on the Radeon; 7 are path-bound (compiled-in /home/rickard/runs/facett-0929/facett-int paths); 3 real GPU reds (geomap osm_paint_order, map3d gfx_v2_item6_parity, map3d postfx_bypass); 5 main debt. dwarf CPU run b9ad95e: 3553 passed / 129 failed / 39 ignored, every non-GPU red is main debt.

Where things run

Status at handover (2026-09-29 ~00:40, measured on loki, idle)

feat/wasm-threads-gatling merged to main after: facet-wrapped 81/81, facett-graphnav 92/92, facett-graphview (gpu) lib 133/133 three runs in a row, navgraph_demo 4/4, lane guard 5/5, wasm32 check of facet-wrapped clean. One flake to chase: in one of five runs, cargo test -p facett-graphview --features gpu --lib died with no test result line (the process ended mid-run, most likely a GPU test crashing under parallel tests). Run it in a loop with --test-threads=1 and without to find which test.