FE-1219: Define and enforce a Scenario HIR for server-side Petrinaut optimization - #9060
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
PR SummaryMedium Risk Overview The CLI calls HIR lowering adds scenario-specific rules (e.g. no Reviewed by Cursor Bugbot for commit 718ddcd. Bugbot is set up for automated code reviews on this repo. Configure here. |
47f2fea to
a38af6e
Compare
718ddcd to
f0e2672
Compare
a38af6e to
e48cebd
Compare
f0e2672 to
e69446c
Compare
…optimization Server-side scenario materialization now goes through the existing restricted HIR pipeline instead of executing manifest-authored strings via sandboxed `new Function`, closing the last unrestricted raw-code path on the optimizer's server path. The in-editor sandbox path is unchanged. - petrinaut-core: new `scenarioExpression` and `scenarioInit` HIR surfaces, lowered, typechecked, and instantiated over compiler-emitted source only. - Scenario orchestration extracted to `compile-scenario-core.ts`, shared by the unchanged sandboxed `compileScenario` (editor) and the new Node-only `compileScenarioProgram` (compile once per study, evaluate per trial). - petrinaut-cli: the scenario program is compiled once at bootstrap, so a manifest outside the supported subset fails startup with the offending path; per-trial evaluation runs pre-instantiated evaluators. - `Math.random()` is a compile error on scenario surfaces (determinism), and redeclaring the `scenario`/`parameters` inputs is rejected to match the sandbox. - Docs: the threat model's raw-execution path is removed, scenarios.md and hir/README.md document the subset and that server-compiled equality is strict.
e48cebd to
a72b3b5
Compare
e69446c to
33a0607
Compare
🌟 What is the purpose of this PR?
Makes server-side Petrinaut scenario materialization go through the existing restricted HIR pipeline instead of executing manifest-authored strings via sandboxed
new Function, closing the last unrestricted raw-code execution path on the optimizer's server path. The in-editor sandbox path is unchanged.🔗 Related links
🚫 Blocked by
#9066 → #9058 → this); needs FE-1220: Harden and document Petrinaut optimization execution isolation #9058'sthreat-model.mdandOPTIMIZATION_INTEGRATION.md🔍 What does this change?
petrinaut-core: two new HIR surface kinds —scenarioExpression(a single expression over(parameters, scenario)→ scalar) andscenarioInit(a statement body → record of place-name → count | token records) — lowered, typechecked, and instantiated over compiler-emitted source only.compile-scenario-core.ts, shared by the unchanged sandboxedcompileScenario(editor) and a new Node-onlycompileScenarioProgram(compile once per study, evaluate per trial). Exported only via the Node-only./compiled-modelsubpath, so the main entry gains no TypeScript-compiler dependency.Math.random()is a compile error on scenario surfaces (determinism).petrinaut-cli:createOptimizationProtocolcompiles the scenario program once at bootstrap; per-trialoptimization.evaluateruns the pre-instantiated evaluators. No sandboxedcompileScenarioreferences remain in CLI source.const/callback parameter shadowing thescenario/parametersinputs (hir:redeclared-parameter), matching the sandbox; documents that server-compiled scenario equality is strict (==→===) and can differ from the editor for mixed-type comparisons.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:
🛡 What tests cover this?
New
petrinaut-coretests: a parity suite (HIR program vs sandbox for representative scenarios incl. code-mode colored tokens and the unknown-place-skip quirk), a rejection matrix (dynamic import,process,globalThis,fetch,Function, template substitution, loops,Math.random, wrapper-name shadowing), and a security test proving zero dynamic evaluation per trial. Newpetrinaut-clitests: bootstrap rejection listing offending paths, compile-once-evaluate-many, and aFunction-proxy test proving no per-trial dynamic evaluation.❓ How to test this?
turbo run test:unit --filter '@hashintel/petrinaut-core' --filter '@hashintel/petrinaut-cli'examples/supply-chain-profit-optimization.jsonand confirm it evaluates; confirm an out-of-subset scenario manifest fails at bootstrap with the offending path in the message.