feat/web-buttons-phase-aware-stage-api #149

Closed
vxfemboy wants to merge 0 commits from feat/web-buttons-phase-aware-stage-api into main
Owner
No description provided.
The single-run dashboard rebuilds the metric card list on every 10 Hz
WebSocket snapshot (`renderCards` does `els.cards.innerHTML = ""`), so each
card <div> is destroyed and recreated every 100ms. A per-card `onclick` is
therefore torn down between a user's mousedown and mouseup: the browser fires
`click` on the nearest common ancestor of the two (the #cards container, not
either card), so the card handler never runs. The cards look live and show
`cursor: pointer`, but clicks do nothing — "buttons aren't pressable".

Fix: attach one delegated `click` listener to the stable #cards container and
read the target metric from a `data-label` attribute. The listener survives
the per-frame rebuilds, so clicks register regardless of snapshot cadence.

Verified in a real browser against the web_demo server: with per-card
handlers, a click spanning a rebuild logged mousedown+mouseup but zero click
events; after the fix, clicking a card mid-churn switches the selected metric
and chart title. Only index.html is affected — project.html fetches once and
never rebuilds on a timer.
Brings the web dashboard to parity with the terminal chart for
curriculum/multi-phase runs. Previously the web chart plotted the whole
window on one y-scale, so phases with very different loss scales looked like
the run diverged at each transition (the same problem the TUI fixed in
d2d2b4f / EMRY phase-aware work).

Changes:
- state.rs: checkpoints now carry a derived label (WebCheckpoint{step,label}),
  not just a bare step. `checkpoint_label` mirrors emry_tui::ui::checkpoint_label
  (parent dir, phaseN- prefix stripped, else file stem); a paired test asserts
  the same cases so the two copies can't silently drift. The /ws JSON
  `checkpoints` field changes from [step] to [{step,label}].
- index.html: drawChart now EMA-smooths the series (adaptive span, ported from
  the TUI) and, when checkpoints split the visible window, draws one connected
  polyline per segment each y-scaled to its own range, with dashed dividers and
  a per-segment label; the title shows the label chain (`math │ polish │
  current`). Single-scale mode keeps the dashed baseline overlay; segment mode
  omits it (can't share per-segment scales) and the title no longer advertises
  a baseline it isn't drawing.
- web_demo.rs: synthetic checkpoints now use curriculum-style paths
  (phaseN-<stage>/…) so the label chain is exercised.

Verified in a real browser against web_demo: three autoscaled segments render
with correct labels ("math │ polish │ current"), no console errors, and the
delegated metric-card clicks still switch the selected metric.
Adds an explicit API to demarcate curriculum stages, the phase-aware-chart
follow-up: `run.stage("reasoning")` names the current stage so the dashboards
split and label the loss chart at stage boundaries, instead of only inferring
labels from checkpoint paths.

New core event `Event::StageChange{name,step}` threaded end-to-end:
- emry-core: the variant + adjacently-tagged STAGE_CHANGE tag (roundtrip and
  tag-stability tests extended).
- emry-engine: RunHandle::stage_change pushes it to the event ring; emry-py
  exposes it as PyRunHandle.stage_change (embedded mode).
- Python SDK: Run.stage(name, *, step=None) + current_stage property; wired
  through every backend — JsonlBackend (events.jsonl), SocketBackend (msgpack
  wire), NativeBackend (native handle). Backend protocol + NullBackend updated.
- Reducers: UiState (TUI) and WebState (web) record stage marks; the chart uses
  stages as segment boundaries, taking precedence over checkpoint-derived labels
  when both are present. build_segments now takes generic (step,label) marks.

Verified: Rust workspace tests + clippy clean; Python suite green (added stage
tests for Run, JSONL events log, wire shape, socket frame, and native handle);
browser check confirms the web chart segments+labels by stage and falls back to
checkpoints when no stages are present.
Exercises the Event::StageChange match arm in both reducers and the
stages-take-precedence-over-checkpoints branch, keeping the >=90% line
coverage gate satisfied for the new stage handling.
test: verify file-mode read-back of StageChange (EventLogTailer)
All checks were successful
CI / python (3.10) (pull_request) Successful in 12m8s
CI / python (3.11) (pull_request) Successful in 12m7s
CI / python (3.12) (pull_request) Successful in 11m54s
CI / helm (pull_request) Successful in 50s
CI / torch (pull_request) Successful in 15m47s
CI / wheels (pull_request) Successful in 6m35s
CI / rust (pull_request) Successful in 11m29s
CI / pre-commit (pull_request) Successful in 12m39s
1942dddbf0
Locks the contract that a STAGE_CHANGE row in events.jsonl deserializes to
Event::StageChange, the path 'emry watch --run-dir' hits on a JSONL run.
Author
Owner

Integrated into main via merge commit 45079bf (all 8 CI jobs green on run #35). The branch is already an ancestor of main, so there is nothing left to merge through the PR UI — closing as merged-in-main.

Integrated into `main` via merge commit 45079bf (all 8 CI jobs green on run #35). The branch is already an ancestor of main, so there is nothing left to merge through the PR UI — closing as merged-in-main.
vxfemboy closed this pull request 2026-08-01 05:48:31 +00:00
All checks were successful
CI / python (3.10) (pull_request) Successful in 12m8s
CI / python (3.11) (pull_request) Successful in 12m7s
CI / python (3.12) (pull_request) Successful in 11m54s
CI / helm (pull_request) Successful in 50s
CI / torch (pull_request) Successful in 15m47s
CI / wheels (pull_request) Successful in 6m35s
CI / rust (pull_request) Successful in 11m29s
CI / pre-commit (pull_request) Successful in 12m39s

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
femboy/emry!149
No description provided.