Skip to content

UI redesign - #2

Merged
hashtagRR merged 2 commits into
mainfrom
ui-redesign
Oct 4, 2026
Merged

hashtagRR merged 2 commits into
mainfrom
ui-redesign

Conversation

@hashtagRR

Copy link
Copy Markdown
Owner

No description provided.

Replaces the single-page form in anontestlab/dashboard/static/index.html
with a full client-side app (app.js router plus core.js, builder.js,
charts.js, analyses.js, views.js) covering the experiment builder, live
run tracking, results, and the research tools (compare, sweep, paired,
predict, fidelity) as their own pages instead of CLI-only commands.
Charts (ROC, score distributions, latency CDF, paired slope and interval
plots, a force-directed relay graph) are hand-rolled inline SVG with no
new JS dependency.

server.py gained a proper job model: a stop endpoint that signals a
job's real relay subprocess PIDs (SIGTERM, escalating to SIGKILL),
scoped to the specific job that requested it so a late-arriving retry
can't kill a later, unrelated job's relays; sweep and paired jobs check
a cooperative stop flag between points/seeds so a stop doesn't throw
away already-finished work; a custom output directory per job
(the dashboard's equivalent of the CLI's --out), with correct handling
when that path is itself nested under results/; and a job type that
runs two fresh, possibly never-executed configs and diffs them in one
action, persisting both component runs as well as the diff.

Added anontestlab/dashboard/store.py (a read-only view of the results
directory, shared by the JSON API and the new PDF reports) and
anontestlab/dashboard/spec.py (round-trips the flat ExperimentConfig
dict the dashboard edits against the nested YAML spec ExperimentConfig.
from_yaml reads, verified against every example config).

anontestlab/dashboard/report.py adds PDF reports (matplotlib's PdfPages,
no new dependency) for a single run, a stored comparison, and a paired
analysis.

Small additions to the core library in support of the above: session_
complete and session_failed events now carry the session's actual
chosen relay ids (anontestlab/emulator/orchestrator.py), relays_ready
carries their PIDs, and MetricsCollector/ExperimentResult/write_results
persist every delivered packet's one-way delay to oneway_delays.npz
(anontestlab/metrics/collector.py, anontestlab/experiment/runner.py) so
a real empirical latency CDF can be charted instead of just p50/p95/p99.
None of this touches the packet forwarding hot path.

tests/test_dashboard.py is rewritten for the new API shape: the full
run/sweep/paired/fidelity/compare job lifecycle, stop behavior
(including the relay-process-kill race and the cross-job watcher bug
found while testing it), path traversal guards, and static asset
serving.
and clear a UI/UX pass over the dashboard

PDF reports needed matplotlib but the dashboard extra never installed
it; a fresh install hit a bare 500 and the browser saved that error
page as a broken report.pdf. matplotlib is now part of the dashboard
extra, the route returns a clear 503 naming the install command when
it's still missing, and PDF links are fetched before saving so a
failure shows a message instead of a corrupt file.

Live run view: the single "most recent session" circuit diagram is
replaced with a sender-to-receiver rendering of every leg of a
multipath session, relay by relay, with a shared exit (common_exit)
drawn once where legs converge and animated dots along each leg sized
by its measured share of real packets (a new leg_real_sent field on
session_complete, from a count the emulator already kept). The relay
connectivity graph gets the same sender/receiver anchors, pulling each
relay toward its average hop position so the layout reads left to
right. Fixed a double-counted event bug in the job poller that showed
twice the real session count on a fresh page load.

The rest is a UI/UX pass, each item checked against a real run in a
headless browser, not just read in the source:

- Dashboard tests no longer write into the real results/ directory
  (they pointed at results/ directly before, so running them could
  list, and a same-named rerun could overwrite, an actual experiment).
- Compare's outcome table showed a raw-seconds delta next to
  millisecond A/B values; it now converts through the same formatter,
  with "-0.0 ms"-style noise cleaned off deltas that round to zero.
- Sweep and Paired charts: a flat or near-ceiling series on a
  probability metric padded its axis past 1.0 (or below 0); the pad is
  now clamped to a metric's own [0, 1] once its real values sit
  inside it. Auto-generated axis ticks no longer repeat an identical
  rounded label.
- Paired analysis wrote its per-seed CSV with the configs' own names as
  column headers; reference and treatment with the same name collided
  into one CSV column, silently losing the reference values to the
  treatment ones. Fixed at the source (fixed "reference"/"treatment"
  column names) with matching fixes in the PDF report and the
  dashboard, which still show the real names, disambiguated when equal.
- The global observer's TPR card now visibly flags (amber, not quiet
  grey text) when its threshold was chosen on the same pairs it's
  scored against; this also fixed the card reading the wrong run's
  calibration flag (the correlation suite's, instead of global
  observer's own), so a properly calibrated run was shown as
  optimistic.
- Experiments' "Open builder" and "New experiment" buttons went to the
  same place; replaced with one button, plus a resume-draft option
  only when an unfinished draft actually exists. Experiments, Runs and
  Artifacts list pages now cross-link and describe what's different
  about each.
- The Adversaries tab is only offered when a run actually used the
  correlation suite, instead of always being present and empty.
- A long run name overflowed the stored-run picker on Sweep and Paired
  (native <select> sizes to its longest option) and pushed the action
  buttons beside it onto their own line; the picker is now capped and
  truncates instead.
- Mobile nav wrapped into an overflowing single row that ran off
  screen; it now wraps onto as many rows as it needs. KPI tiles sit two
  per row instead of one per row, which was most of what made a
  phone-width Results page so long to scroll.
- Chart SVGs scaled with whatever container they landed in, so the
  same chart's text could run oversized in a wide desktop card and
  shrink unreadable in a narrow mobile one; width is now bounded to a
  comfortable range, with horizontal scroll as the fallback below that.
- The Paths card appeared twice on a multipath run, once embedded in
  Summary and again as the whole Paths tab; Summary now shows a
  compact version (just the measured per-leg traffic share) linking to
  the full diagram.
- Compare's configuration diff was a flat, alphabetized list of raw
  YAML keys, with object/list values cut off at the edge of a <pre>
  block; it's now grouped into the same sections the experiment
  builder itself uses, labeled the same way, with long values wrapping
  inside their cell instead of overflowing.
- The Predict page was a bare dropdown and button with no sign of what
  running it does; it now explains what the model predicts, what
  picking a stored run adds, and where to find the comparison.

Left open, by design: a run doesn't store which relays a session
actually used (only the configured design), so Results can't yet show
the same sender-to-receiver diagram the live view now draws from real
per-session events. That needs new data persisted per run, not a UI
change.
@hashtagRR
hashtagRR merged commit a2d2841 into main Oct 4, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant