Skip to content

FE-1408: Run a trial as multiple seeded simulations aggregated by mean - #9223

Merged
kube merged 1 commit into
mainfrom
cf/fe-1408-petrinaut-cli-run-a-trials-seeded-simulations-in-parallel
Aug 19, 2026
Merged

FE-1408: Run a trial as multiple seeded simulations aggregated by mean#9223
kube merged 1 commit into
mainfrom
cf/fe-1408-petrinaut-cli-run-a-trials-seeded-simulations-in-parallel

Conversation

@kube

@kube kube commented Aug 16, 2026

Copy link
Copy Markdown
Collaborator

🌟 What is the purpose of this PR?

The CLI scores an optimization trial on one simulation, so a stochastic net is judged on a single sample. This PR runs each trial as execution.seedsPerTrial seeded simulations and returns their mean.

  • Runs execute sequentially. Parallel execution comes later through the shared experiment-backend interface (FE-1341), tracked as FE-1429, so the CLI and the editor share one worker implementation.
  • The response keeps the { objective } shape, so the Python optimizer service needs no changes.
  • Out of scope: aggregation-method selection (FE-1277) and Optuna-side per-seed handling (FE-1281).

Stack #9226: FE-1410 (contract) → FE-1411 (async protocol) → this PRFE-1413 (arch-docs manual) → FE-1270 (Python bindings) → FE-1412 (Python timeout).

🔗 Related links

  • FE-1408 (internal): this PR
  • FE-1273 (internal): parent, M seeded runs per Optuna step
  • FE-1341 (internal): the shared experiment-backend interface
  • FE-1429 (internal): follow-up, run these replicates through that backend
  • FE-1277 (internal): follow-up, user-selectable aggregation

🔍 What does this change?

@hashintel/petrinaut-cli only:

  • optimization.evaluate runs the trial's seeds one after another and returns:
    • objective: the mean of the per-seed objectives;
    • replicates: [{ seed, objective }], present when seedsPerTrial > 1.
  • optimization.describe reports study.seedsPerTrial.
  • Seeds derive once per study and are identical for every trial (common random numbers):
    • replicate 0 uses execution.seed, so one seed per trial behaves bit-identically to today and one editor run still reproduces a replicate;
    • replicate i uses the Monte Carlo deriveRunSeed(seed, i) exported by FE-1410.
  • Wall-clock time of a trial grows linearly with seedsPerTrial.
  • New smoke test spawns the bundled dist/cli.js and checks a full describe/evaluate exchange, including a two-seed trial.

🧪 Example

The manifest's execution block asks for three seeds per trial:

// optimization.json (excerpt)
"execution": { "seed": 42, "dt": 1, "maxTime": 100, "seedsPerTrial": 3 }

Serve it and send one trial over stdio:

node libs/@hashintel/petrinaut-cli/dist/cli.js serve --optimization optimization.json --stdio
{ "id": 1, "method": "optimization.evaluate", "params": { "parameterValues": { "infected_ratio": 0.1 } } }

The trial runs seeds 42, 1013904268 and 1520856381 in that order and answers with their mean:

{
  "id": 1,
  "result": {
    "objective": 0.31,
    "replicates": [
      { "seed": 42, "objective": 0.28 },
      { "seed": 1013904268, "objective": 0.33 },
      { "seed": 1520856381, "objective": 0.32 }
    ]
  }
}

Every trial reuses those three seeds, so repeating the request returns identical values. With seedsPerTrial: 1 (or the field omitted) the response is { "objective": ... } alone, unchanged from today.

Pre-Merge Checklist 🚀

🚢 Has this modified a publishable library?

This PR:

  • modifies a workspace but not a publishable library (@hashintel/petrinaut-cli is private; the @hashintel/petrinaut-core changeset landed with FE-1410)

📜 Does this require a change to the docs?

The changes in this PR:

  • require changes to docs which are made as part of this PR
    • OPTIMIZATION_INTEGRATION.md and the CLI README document the field, the seed derivation, and the response shape. The in-app user guide is untouched: the UI never sets seedsPerTrial, so in-app behaviour is unchanged until FE-1273's UI half lands.

🕸️ Does this require a change to the Turbo Graph?

The changes in this PR:

  • affected the execution graph, and the turbo.json's have been updated to reflect this
    • petrinaut-cli's test:unit now depends on its own build, so the smoke test always runs against a fresh bundle in CI.

🐾 Next steps

  • FE-1412 (top of stack): the Python client scales its per-response timeout by seedsPerTrial.
  • FE-1429: run the seeded replicates through the shared experiment backend once FE-1341 lands.
  • FE-1277 / FE-1281: aggregation selection and Optuna-side per-seed handling.

🛡 What tests cover this?

  • optimization.test.ts: mean aggregation, per-seed replicates, identical seed list across trials, fail-fast on a non-finite replicate, extreme-value aggregation, deriveTrialSeeds range and stability.
  • transports.test.ts: multi-seed evaluate over stdio, seedsPerTrial in describe.
  • built-cli.test.ts: spawns the real bundled CLI for the full exchange with two seeds.

❓ How to test this?

  1. turbo run test:unit --filter @hashintel/petrinaut-cli
  2. Manual: add "seedsPerTrial": 4 to execution in libs/@hashintel/petrinaut-cli/examples/supply-chain-profit-optimization.json, run yarn workspace @hashintel/petrinaut-cli build, then node libs/@hashintel/petrinaut-cli/dist/cli.js serve --optimization <manifest> --stdio and send an optimization.evaluate request.
  3. The response carries the mean objective plus four replicates; repeating the request returns identical values.

🤖 Generated with Claude Code

@kube kube self-assigned this Aug 16, 2026
@vercel

vercel Bot commented Aug 16, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
hash Ready Ready Preview Aug 19, 2026 10:46am
petrinaut Ready Ready Preview Aug 19, 2026 10:46am
petrinaut-docs Ready Ready Preview Aug 19, 2026 10:46am
1 Skipped Deployment
Project Deployment Actions Updated (UTC)
hashdotdesign-tokens Ignored Ignored Preview Aug 19, 2026 10:46am

@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 area/tests New or updated tests area/apps labels Aug 16, 2026
@kube
kube force-pushed the cf/fe-1408-petrinaut-cli-run-a-trials-seeded-simulations-in-parallel branch from 797689e to ec38102 Compare August 16, 2026 17:10
@github-actions github-actions Bot removed area/tests New or updated tests area/apps labels Aug 16, 2026
@kube
kube changed the base branch from main to cf/fe-1411-petrinaut-cli-make-the-protocol-handler-async-safe August 16, 2026 17:12
@kube
kube force-pushed the cf/fe-1408-petrinaut-cli-run-a-trials-seeded-simulations-in-parallel branch from ec38102 to 8b4144f Compare August 17, 2026 23:51
@vercel
vercel Bot temporarily deployed to Preview – petrinaut August 17, 2026 23:51 Inactive
@kube kube changed the title FE-1408: Run a trial's seeded simulations in parallel in the Petrinaut CLI, aggregated by mean FE-1408: Run a trial as multiple seeded simulations aggregated by mean Aug 17, 2026
@kube
kube marked this pull request as ready for review August 17, 2026 23:52
Copilot AI balanced review requested due to automatic review settings August 17, 2026 23:52
@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes how optimization objectives are computed for stochastic models and multiplies per-trial runtime linearly with seedsPerTrial; backward compatible when seedsPerTrial is omitted or 1.

Overview
Each optimization trial can run execution.seedsPerTrial (default 1) simulations instead of a single run. optimization.evaluate runs those seeds sequentially, returns objective as the mean of per-seed results, and when seedsPerTrial > 1 adds replicates: [{ seed, objective }]. With one seed, the response stays { objective } only.

Seeds are fixed for the whole study via deriveTrialSeeds (first replicate uses execution.seed; later ones use core’s deriveRunSeed) so every trial shares the same sequence (common random numbers). optimization.describe now includes study.seedsPerTrial. Evaluation fails fast on non-finite replicate objectives and uses an online mean to avoid overflow.

Docs (OPTIMIZATION_INTEGRATION.md, README) describe the field, seed rule, and response shape. Tests cover aggregation, CRN, stdio transport, and a bundled dist/cli.js smoke test; turbo.json makes test:unit depend on build.

Reviewed by Cursor Bugbot for commit c44a97d. 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.

Pull request overview

Adds deterministic multi-seed optimization trials to the Petrinaut CLI, aggregating replicate objectives by mean.

Changes:

  • Runs sequential simulations using reusable derived seeds.
  • Returns mean objectives and per-seed replicate results.
  • Adds protocol, bundle, and unit coverage plus documentation.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
turbo.json Builds CLI before unit tests.
optimization.ts Implements seeded trial evaluation and aggregation.
optimization.test.ts Tests seeds, aggregation, and validation.
transports.test.ts Tests multi-seed stdio responses.
built-cli.test.ts Adds bundled CLI smoke test.
README.md Documents multi-seed evaluation.
OPTIMIZATION_INTEGRATION.md Documents protocol and seed derivation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread libs/@hashintel/petrinaut-cli/src/runtime/optimization.ts Outdated
Comment thread libs/@hashintel/petrinaut-cli/src/runtime/optimization.ts Outdated
Copilot AI review requested due to automatic review settings August 18, 2026 00:33
@kube
kube force-pushed the cf/fe-1408-petrinaut-cli-run-a-trials-seeded-simulations-in-parallel branch from 8b4144f to cbb5fca Compare August 18, 2026 00:33

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Comment thread libs/@hashintel/petrinaut-cli/src/runtime/optimization.ts
Copilot AI review requested due to automatic review settings August 18, 2026 22:38
@kube
kube force-pushed the cf/fe-1408-petrinaut-cli-run-a-trials-seeded-simulations-in-parallel branch from 47d6052 to 60028b5 Compare August 18, 2026 22:38

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.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 18, 2026 22:48
@kube
kube force-pushed the cf/fe-1408-petrinaut-cli-run-a-trials-seeded-simulations-in-parallel branch from 60028b5 to 8b25fed Compare August 18, 2026 22:48

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.

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.

Pull request overview

Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.

Optimization trials run execution.seedsPerTrial seeded simulations
sequentially within one evaluate and aggregate the per-seed objectives
by mean. Seeds derive deterministically from execution.seed - replicate
0 keeps the base seed, later replicates reuse the Monte Carlo
derivation - and every trial reuses the same list, so Optuna compares
configurations under common random numbers. The evaluate response stays
{objective}-compatible and reports per-seed replicates; describe
reports seedsPerTrial. Parallelising the seeded runs is deferred to the
shared experiment-backend interface (FE-1341) so the CLI and the editor
share one worker story instead of a CLI-specific pool.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Development

Successfully merging this pull request may close these issues.

3 participants