FE-1341: Give experiment compute backends one interface - #9178
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
976a2dd to
afff6ce
Compare
afff6ce to
8ad93e6
Compare
8ad93e6 to
1456a69
Compare
914345d to
c46fb0a
Compare
c46fb0a to
6e22a1b
Compare
e442d01 to
ae86805
Compare
ae86805 to
c2ff943
Compare
c2ff943 to
02de988
Compare
02de988 to
5b45419
Compare
PR SummaryMedium Risk Overview
The worker-pool path is the first implementation ( Reviewed by Cursor Bugbot for commit 8f6a8f6. Bugbot is set up for automated code reviews on this repo. Configure here. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit b75157f. Configure here.
| selection.declined | ||
| .map((entry) => `${entry.backendId}: ${entry.reason}`) | ||
| .join("; ") || "No compute backend could run this experiment.", | ||
| ); |
There was a problem hiding this comment.
Prefixed setup failure messages
Low Severity
When the only registered backend refuses during instantiate, setup failures are rethrown as `${backendId}: ${reason}`. That reaches experiment status and error notifications, so users now see a cpu: prefix that was not present when createMonteCarloExperiment failed directly. The PR claims no behaviour change.
Reviewed by Cursor Bugbot for commit b75157f. Configure here.
Choosing a backend was hardcoded in ExperimentsProvider. The runtime half of swappability already worked — a backend produces a MonteCarloExperiment and consumers drive one with no branching — so this adds only the missing part: asking a backend whether it can run a net, and choosing between backends when one declines. A request is plain serializable data; anything describing how to compute belongs to the backend's construction or to per-call options. Refusal is a value carrying structured blockers with a code, an item id and an origin, so a UI can attribute a problem to the item that caused it. Assessment settles the net without acquiring a device or worker pool and hands back an instantiate() closure. Pure refactor: no user-visible behaviour changes. Registrations carry a deferred load so a heavy backend need not enter the bundle.
Replaces em dashes and drops 'deliberately' in backend-selection.mdx. No content change.
Rewrites the module docstrings in src/experiments to state what each file is before why it is that way, and replaces em dashes. No code change.


🌟 What is the purpose of this PR?
Adds
@hashintel/petrinaut-core/experiments: one interface both compute backends satisfy, and a registry that picks between them.ExperimentsProviderhardcodes the backend choice today; #9179 registers a backend against this interface instead of rewiring the provider. App behaviour is unchanged.This PR sits above #9177 in stack #9280, and #9179 builds on it.
🔗 Related links
🚫 Blocked by
🔍 What does this change?
Both paths already produce a
MonteCarloExperiment, and consumers drive one without branching. That half is untouched. This PR adds four types:ExperimentRequestdescribes what to compute, as serializable data. Worker factories, the ODE method, signals, and callbacks describe how to compute it, and belong to backend construction or per-call options.ExperimentAssessmentis a backend's answer to "can you run this?", as a value. Each blocker carries acode, an optionalitemId, and anorigin.ExperimentBackend.assesschecks the net without acquiring a device or worker pool, then returns aninstantiate()closure that reuses that work.selectExperimentBackendwalks registrations in preference order and records each refusal.A blocker's
origintells a UI what to do:modelmeans edit the net,configurationmeans edit the experiment,environmentmeans hide the option, andcapacitymeans retry or use fewer runs. Each registration'sloadis deferred, so a heavy backend stays out of a bundle that never uses it.Adds
content/experiments/backend-selection.mdxand thecore.experimentsarchitecture layer.Review fixes
selectExperimentBackendtreats a thrownassess()orinstantiate()as that backend's refusal and moves to the next candidate instead of abandoning the walk. Abort errors are re-thrown, and the walk stops before assessing a candidate when the signal is already aborted, so a cancelled experiment cannot fall through and start on the fallback backend.AbortErrorinstead of reporting the cancellation as a configuration blocker.WORKER_POOL_BACKEND_IDinstead of duplicating the literal.load()doc no longer claims a promise cache that does not exist.@hashintel/petrinaut-core/experimentsentry point.Pre-Merge Checklist 🚀
🚢 Has this modified a publishable library?
This PR:
📜 Does this require a change to the docs?
The changes in this PR:
🕸️ Does this require a change to the Turbo Graph?
The changes in this PR:
assessnever refuses and the blocker types stay unexercised until FE-1340: Add an experimental WebGPU compute backend for experiments #9179.GPUDeviceare still acquired per experiment. Reuse depends on the worker resetting frame and metric state; a worker that kept state would produce plausible-looking wrong results.🐾 Next steps
Supply backends through a React context, so an embedder can register its own.
🛡 What tests cover this?
select-experiment-backend.test.tsruns 9 cases covering preference order, deferred loading, refusal recording, instantiation failure, blocker ordering, unavailable backends, module load failure, and per-requirement request building.❓ How to test this?
Run an experiment. Behaviour is unchanged.
🤖 Generated with Claude Code