Skip to content

FE-1685: Draw every sweep study's objective by step under the Parameters sliders - #9660

Merged
kube merged 21 commits into
mainfrom
claude/opt-proto-sweep-objective-chart
Sep 13, 2026
Merged

FE-1685: Draw every sweep study's objective by step under the Parameters sliders#9660
kube merged 21 commits into
mainfrom
claude/opt-proto-sweep-objective-chart

Conversation

@kube

@kube kube commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

Important

Experimental
Behind the Parameter sweeps and In-browser optimization feature flags.

Summary

Before this PR, a study started from a sweep's Parameters card showed its progress as one line under the sliders: the step count while it ran, the outcome once it settled. The objective's path over the steps, the chart the Optimizations tab draws for every study, was nowhere in the sweep drawer.

This PR draws it at the bottom of the Parameters card. From the first Optimize on, a full-width purple strip sits under the sliders: a disclosure row naming the metric, the steps run and the best value so far, and beneath it a compact chart of the objective per step with the best-so-far line, the x axis pinned to the steps to come so dots fill left to right while the study streams. The strip stays after the study settles and folds from its row in both states. A second Optimize appends its steps after a dashed divider, the numbering continuing. Before any study the card is unchanged.

9660.mp4

Links

Changes

Shared chart

  • ObjectiveHistoryChart moves to SimulateView/shared

    Takes points, an ObjectiveHistoryStyle, an optional pinned xMax and dividers drawn dashed. The default style keeps the study drawer's look; ObjectiveHistoryCard renders it unchanged.

  • ObjectiveHistoryCard moves to study-results/objective-history-card.tsx

    The card around the shared chart in the study results, its look unchanged.

  • objective-history-data.ts is shared too

    One buildObjectiveHistory for the study card and the strip; the infeasible colour lives in shared/infeasible-color.ts.

  • Fold exported through drawer-frame.tsx

    The strip folds behind the frame kit's Fold; FoldProps stays private to the folder.

Sweep drawer

  • useSweepOptimizer exposes every study of the sweep

    studies in creation order; study is the last of them.

  • ResultsBand.below slot

    Rendered after a band's content; the Parameters band fills it once a study exists, null before.

  • SweepObjectiveStrip

    A full-row disclosure button with a rotating chevron, a dot that breathes while a study drives, the title Objective by step and a tabular summary.
    The summary reads like Infected · 47 steps in 2 optimizations · best 650.500.
    Under it a Fold holds the 120 px chart in the purple ramp.
    Canvas colours ignore the dark theme, as the study chart's do.

  • Studies concatenate

    buildSweepObjectiveHistory offsets each study's steps by the ones before, restarts the best-so-far line per study, draws a divider at each later study's first step, and pins the axis to the last study's requested steps only while it is active.
    Studies of different metrics share one y axis; the row summarises the last study that drew a point.

  • Zero layout shift within a state

    Collapsed and open heights are constants; the chart instance stays alive while folded, so reopening shows the current picture.
    The open state resets when the drawer reopens.

Review fixes

  • Best-so-far line breaks at each divider

    uPlot drew the stepped line as one series, so the earlier study's best held across the divider into the next.
    toObjectiveHistoryData takes the dividers and lays a null gap sample half a step before each, which the dots skip and the axis never labels.

  • Sweep whose only study failed at start gets the empty summary

    buildSweepObjectiveHistory fell back to the last study for the metric name and best, so the row read Metric · 0 steps against its own contract.
    Summary now comes from the last counted study only and the row omits the metric segment when there is none, reading 0 steps.

  • Strip reads "No steps run" when its every study failed at start

    The shared chart said "Waiting for the first step" for any empty points, so a sweep whose only study failed before a step showed a wait that never ends under a row reading 0 steps.
    ObjectiveHistoryChart takes an emptyLabel, the strip sets it from history.studyCount, and view-experiment-drawer.test.tsx asserts both labels.

Next steps

  • Push a changed xMax through setScale if recreating the plot on settle ever flickers

Test coverage

  • sweep-objective-history.test.ts:

    Global step numbering across studies, dividers, best-so-far restarting per study, the pinned axis only while active, an empty running study keeping its divider, a study that failed at start left out of the count and the summary, a sole failed study giving the empty summary.

  • objective-history-data.test.ts:

    Aligned data with a null gap sample before each divider, no gap without dividers or for a divider no step has reached.

  • experiment-results.test.tsx, view-experiment-drawer.test.tsx:

    The band's below slot null before a study and the strip after; the disclosure's aria-expanded and aria-controls; the row summary.
    The row reading 0 steps with no metric when the sweep's only study failed at start.

  • sweep-optimizer coverage through view-experiment-drawer.test.tsx:

    Two sweep studies passed newest-first sort into creation order.
    The row reads 7 steps in 2 optimizations with the later study's best, the divider and the axis edge follow it, and Stop cancels its id.

  • drawer-frame.test.tsx:

    Gains a jsdom ResizeObserver stub for the computing list's popover; nothing in the suite depends on a measurement.

  • Storybook:

    Simulate / ViewExperimentDrawer gains Sweep, optimized twice and Sweep, optimization stopped; the optimizable and optimizing stories show the strip.

How to test

  • Open Petrinaut preview on Vercel
  • Viewport controls > Settings > Simulation > Parameter sweeps, In-browser optimization
  • Menu > Load example > SIR Model
  • Simulate > Experiments > Create
  • Max runs per selection 100, Scenario Seasonal Flu, Sweep on population and infected_ratio
  • Add metric > Place tokens, Place Infected
  • Create sweep

    Expect no strip under the sliders

  • Parameters > Optimize > Minimize, Steps 12 > Start

    Expect a purple Objective by step row under the sliders with a breathing dot, a chart filling left to right as steps land, the axis spanning 12 steps

  • Click the row

    Expect the chart to fold away, the row to stay, the cards below to move as one block

  • Click the row again, wait for the last step

    Expect the chart back, the dot still, the row reading Infected · 12 steps · best …

  • Parameters > Optimize > Steps 6 > Start

    Expect a dashed divider after step 12 and the new steps numbered 13 onward, the row reading 18 steps in 2 optimizations

@kube kube self-assigned this Sep 11, 2026
@vercel

vercel Bot commented Sep 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hash Ready Ready Preview Sep 13, 2026 2:53pm UTC
petrinaut Ready Ready Preview Sep 13, 2026 2:53pm UTC
petrinaut-docs Ready Ready Preview Sep 13, 2026 2:53pm UTC
1 Skipped Deployment
Project Deployment Actions Updated
hashdotdesign-tokens Ignored Ignored Preview Sep 13, 2026 2:53pm UTC

Request Review

@kube
kube added this pull request to stack #9549 September 11, 2026 02:39
@github-actions github-actions Bot added area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > frontend Owned by the @frontend team type/eng > backend Owned by the @backend team area/apps > hash.design Affects the `hash.design` design site (app) labels Sep 11, 2026
@kube
kube force-pushed the claude/opt-proto-sweep-objective-chart branch from e20bd4b to e767790 Compare September 11, 2026 13:03
@kube
kube force-pushed the claude/opt-proto-sweep-objective-chart branch from e767790 to b385ea6 Compare September 11, 2026 13:07
@kube kube changed the title Draw every sweep study's objective by step under the Parameters sliders FE-1685: Draw every sweep study's objective by step under the Parameters sliders Sep 11, 2026
@kube
kube force-pushed the claude/opt-proto-sweep-objective-chart branch from b385ea6 to fd1cfc7 Compare September 11, 2026 18:29
@kube
kube marked this pull request as ready for review September 11, 2026 22:11
Copilot AI balanced review requested due to automatic review settings September 11, 2026 22:11
@cursor

cursor Bot commented Sep 11, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Simulate UI and chart refactor only; sweep optimization behavior is unchanged aside from surfacing study history in the drawer.

Overview
Adds an Objective by step strip to the sweep experiment drawer: after the first Optimize, a foldable purple row under the Parameters sliders shows the same objective-over-steps chart as the Optimizations tab, streaming while the study runs and staying after it settles. Further optimizations append on one axis with dashed study dividers and a per-study best-so-far line.

Shared chart refactor: ObjectiveHistoryChart and objective history data move to SimulateView/shared, with optional xMax, dividers, styling, and gap samples so the best-so-far line does not carry across studies. The study drawer keeps ObjectiveHistoryCard as a thin wrapper.

Sweep wiring: useSweepOptimizer exposes all sweep-origin studies (creation order); ResultsBand.below renders SweepObjectiveStrip, backed by buildSweepObjectiveHistory. Docs and Storybook/tests cover multi-study ordering, empty/failed studies, and fold behavior.

Reviewed by Cursor Bugbot for commit 76d4a9e. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The chart incorrectly connects studies, drops infeasible-point rendering, mishandles failed-only summaries, and lacks the required changeset.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Adds a persistent objective-history chart beneath sweep parameter sliders, reusing the optimization history chart infrastructure.

Changes:

  • Extracts reusable objective-history data and chart components.
  • Adds concatenated sweep-study histories, dividers, summaries, and folding UI.
  • Updates tests, stories, architecture docs, and user documentation.
File summaries
File Description
libs/@local/petrinaut-arch-docs/content/ui/optimizations-tab.mdx Documents shared chart and sweep strip architecture.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/shared/results-view.tsx Renders content below result-band controls.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/shared/results-model.ts Adds the result-band below slot.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/shared/objective-history-data.ts Provides shared objective-history transformation.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/shared/objective-history-data.test.ts Tests objective-history generation.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/shared/objective-history-chart.tsx Generalizes chart styling, axis pinning, and dividers.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/shared/infeasible-color.ts Shares the infeasible-step color.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/shared/drawer-frame.tsx Exports the shared fold component.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/shared/drawer-frame.test.tsx Adds a ResizeObserver test stub.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/optimizations/view-optimization-drawer.test.tsx Updates the objective-card mock path.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/optimizations/study-results/steps-table.tsx Uses the shared infeasible color.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/optimizations/study-results/objective-history-card.tsx Wraps the shared chart for study results.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/optimizations/study-results.tsx Uses the extracted card and initializes below.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/optimizations/optimization-full-view.test.tsx Updates the objective-card mock path.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/view-experiment-drawer.test.tsx Tests sweep-strip behavior and multiple studies.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/view-experiment-drawer.stories.tsx Adds optimized and stopped sweep stories.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/sweep-optimizer.ts Exposes all sweep studies in chronological order.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/sweep-objective-strip/sweep-objective-history.ts Builds concatenated sweep histories and summaries.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/sweep-objective-strip/sweep-objective-history.test.ts Tests history concatenation and axis behavior.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/sweep-objective-strip.tsx Implements the folding objective strip.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/experiment-results.tsx Places the strip beneath sweep sliders.
libs/@hashintel/petrinaut/src/ui/views/Editor/panels/SimulateView/experiments/experiment-results.test.tsx Tests result-model strip integration.
libs/@hashintel/petrinaut/docs/optimization.md References the sweep objective chart.
libs/@hashintel/petrinaut/docs/experiments.md Documents the new sweep-strip workflow.
Review details
  • Files reviewed: 21/24 changed files
  • Comments generated: 3
  • Review effort level: Balanced

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue because a pull request earlier in the stack was removed Sep 12, 2026
@kube
kube dismissed drdma’s stale review September 12, 2026 16:23

The merge-base changed after approval.

@kube
kube force-pushed the claude/opt-proto-sweep-objective-chart branch from 3fb1fae to 8df70ef Compare September 12, 2026 16:23
vilkinsons
vilkinsons previously approved these changes Sep 12, 2026
kube added 21 commits September 13, 2026 14:45
…es through the drawer and drop the unused FoldProps export
…hose only study failed at start the empty summary
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/apps > hash.design Affects the `hash.design` design site (app) area/infra Relates to version control, CI, CD or IaC (area) area/libs Relates to first-party libraries/crates/packages (area) type/eng > backend Owned by the @backend team type/eng > frontend Owned by the @frontend team

Development

Successfully merging this pull request may close these issues.

4 participants