feat: pulseplot v1 — native live pulse rendering replaces PNG display (Closes #66) - #69
Closed
kateebonner wants to merge 3 commits into
Closed
feat: pulseplot v1 — native live pulse rendering replaces PNG display (Closes #66)#69kateebonner wants to merge 3 commits into
kateebonner wants to merge 3 commits into
Conversation
…m raw data, replacing PNG display The solve emits pulse telemetry as additive run.log lines and the inspector renders it natively — theme-aware SVG, updating every iteration (5 Hz cap) instead of every 6th via PNG. iter_<N>.png stays a run-dir/archival artifact (plot_pulse remains canonical for publication-grade output) but the inspector no longer reads it, which also structurally removes the mid-write PNG read race. Wire format (prototype-grade, additive to the stdout tee — unknown lines are ignored by all existing consumers, β contract freeze untouched): AMICODE_PULSE_META drives=2 knots=50 labels="a_1","a_2" bounds=-0.2:0.2,-0.2:0.2 AMICODE_PULSE iter=6 dt=0.204082 a=<values ,-sep; drives ;-sep> (~1KB/iter) - run_dir_reader: pinned grammar (NUM domain shared with AMICODE_ITER, incl. Inf/NaN) + PulseStream cross-line policy: records before meta dropped; last meta wins and its shape governs; count-mismatched records and inconsistent metas ignored (duplicate metas are expected — the tailer re-reads from offset 0 on truncation). - Delivery: replay ingest forwards meta + the NEWEST record only (no history burst); the live tailer forwards meta and each record in order (on a live run the tailer is the only meta carrier); replay-seeded meta arms the live stream across mid-flight run switches; LogTailer.poke() self-attaches when run.log appears early. - Host: postPulse with pre-materialization buffering (meta + newest record, replayed before any buffered completion) and a 5 Hz trailing-edge throttle. New webview messages: pulsemeta, pulse. - Component: media/ui/components/pulseplot.ts — stacked per-drive panels matching plot_pulse (zero-order-hold stairs, bounds band + dashed limits, per-drive labels, shared time axis); fixed-order categorical series tokens riding VS Code's theme chart colors (dev fallbacks validated light + dark); >512 knots stride-decimated; owns idle / warming / no-pulse-data states. - Template: PulseEmitCallback on the same solver-agnostic (primal, iter) hook as LivePulsePlotCallback, delegating to it and printing the lines. (update! qualified — Makie exports the same name; drive component is :u with :a fallback.) - Demo re-recorded from a converged solve (F=0.9998): run.log carries META + 61 records (round-trip verified, 0 dropped); PNGs + pulse.jld2 NOT bundled — the demo ships only what replay exercises. - Dead code from the PNG display path removed: preview component, frame delivery/buffering/dedup, ITER_PNG_RE, img-src CSP grant, runs-root/workspace resource roots. - Dev harness (pnpm run dev:pulseplot) for visual iteration + render bench; excluded from the VSIX. Implements #66 (closed; design record and scope amendment there). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… docstring Review should-fix: AGENTS.md (the agent-facing prompt) still described iter_<N>.png as "the live plot the Inspector shows" and never mentioned the pulse lines — a hand-authored script per that contract would get a dead live plot (stuck on warming, then the no-data hint). The contract section now leads with AMICODE_PULSE_META/AMICODE_PULSE (prototype-grade shapes shown), points at the template's PulseEmitCallback idiom (incl. the DTO-0.9.6 fallback path), and re-labels PNGs as archival. Review nit: the poll-backstop docstring in file_watcher.ts still cited iter_*.png frame creations; it now describes what the tick actually backstops (latest swings, FINISHED, tailer poke/self-attach). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…l-signal comment - Template: drive-component selection now uses a names-membership check instead of something(traj.u, traj.a) — the fallback no longer leans on property access returning `nothing` for missing components (eager `something` evaluates both anyway). Verified on a real saved trajectory (picks :u, 2×50) and a full solve (converged F=0.9998, 61 pulse records). - run_inspector: the drop-iter-records-pre-materialization comment cited the removed "image stream is canonical" rationale; it now states the actual one (next record refreshes the row; replay re-ingests on switch; pulse events are buffered because the log line is their only delivery). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements #66 (design-of-record; closed — full context mirrored here). Successor to #67 (auto-closed when its base branch #65 merged and was deleted); review history and Raghav's approval-in-substance live there. All review findings addressed (AGENTS.md contract, poll docstring, :a-fallback reachability, canonical-signal comment).
What this does
The inspector's live pulse now renders natively from raw solve data — fully replacing PNG display. The solve emits the pulse's knot values per iteration as additive
run.loglines; the extension parses, routes, and renders them as a theme-aware SVG component.iter_<N>.pngfiles are still written by every solve (archival/publication artifacts —plot_pulseremains canonical there) but the inspector no longer reads them.Originally scoped as a side-by-side compare with the PNG preview; amended mid-implementation by the design-lane owner to full replacement (see the scope-amendment comment on #66). Net effect: −231/+61 on the display path, and the mid-write PNG race class is structurally gone from the inspector — it can't mis-render a file it never reads.
Wire format (prototype-grade, candidate GA)
Additive lines in the
run.logstdout tee — consumers that don't know them ignore them (anchored-regex no-match), so the β contract freeze is untouched:Numeric domain shared with
AMICODE_ITER(incl.Inf/NaN). Cross-line policy: records before meta dropped; last meta wins and its shape governs; count-mismatched records and internally inconsistent metas ignored (duplicate metas are expected — the tailer re-reads from offset 0 on truncation).The pieces
PulseStreampolicy — pure, in the vscode-free reader; unit-tested against the pinned grammar incl. all edge cases.LogTailer.poke()now self-attaches whenrun.logappears before its retry timer fires.postPulsewith pre-materialization buffering (meta + newest record, replayed before any buffered completion) and the same 5 Hz trailing-edge throttle the PNG path used. New webview messages:pulsemeta,pulse.media/ui/components/pulseplot.ts: stacked per-drive panels matchingplot_pulse(zero-order-hold stairs, bounds band + dashed limits, per-drive labels, shared time axis). Fixed-order categorical series tokens inbrand.cssride VS Code's theme chart colors; dev fallbacks validated (dataviz six checks) light + dark. >512 knots stride-decimated. Owns idle / warming / no-pulse-data states.PulseEmitCallbackin the solve template, on the same solver-agnostic(primal, iter)hook asLivePulsePlotCallback, delegating to it and printing the lines. (Two real-solve-discovered fixes:update!must be qualified — Makie exports the same name — and the drive component is:u, not:a.)run.logcarries META + 61 records (round-trip verified, 0 dropped). "Replay demo run" exercises the whole pipeline.pnpm run dev:pulseplot(visual iteration + AC8 render bench); excluded from the VSIX.Not in scope (follow-ups)
Hover/scrub interactivity · convergence trace (objective + rollout fidelity, needs an
AMICODE_FIDline) · populations/leakage panel · GA contract-docs pass for the pulse lines · upstream atomic-save fix in Piccolo's live-plot callback.Verification
94 unit tests green (grammar, policy, both delivery paths, buffering, throttle, seam), typecheck + build clean, two real solves through amico-run (converged, F ≥ 0.9998), parser round-trip on the real log: 1 meta + 61 records, 0 dropped.
🤖 Generated with Claude Code