diff --git a/.changeset/petrinaut-hir-compiler.md b/.changeset/petrinaut-hir-compiler.md new file mode 100644 index 00000000000..e05f5e338d3 --- /dev/null +++ b/.changeset/petrinaut-hir-compiler.md @@ -0,0 +1,10 @@ +--- +"@hashintel/petrinaut": patch +"@hashintel/petrinaut-core": minor +--- + +Compile all user code (dynamics, rates, kernels, metrics) through a new HIR +to programs reading the packed frame buffers directly, replacing Babel. + +Compatibility: code outside the supported TypeScript subset no longer runs — +it is rejected with an error diagnostic pointing at the offending syntax. diff --git a/libs/@hashintel/petrinaut-core/dependency-cruiser.tsconfig.json b/libs/@hashintel/petrinaut-core/dependency-cruiser.tsconfig.json new file mode 100644 index 00000000000..cbff533fc46 --- /dev/null +++ b/libs/@hashintel/petrinaut-core/dependency-cruiser.tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "baseUrl": "../../../..", + "paths": { + "@hashintel/petrinaut-core": [ + "libs/@hashintel/petrinaut-core/src/index.ts" + ], + "@hashintel/petrinaut-core/examples": [ + "libs/@hashintel/petrinaut-core/src/examples/index.ts" + ], + "@hashintel/petrinaut-core/hir": [ + "libs/@hashintel/petrinaut-core/src/hir.ts" + ], + "@hashintel/petrinaut-core/hir-runtime": [ + "libs/@hashintel/petrinaut-core/src/hir-runtime.ts" + ], + "@hashintel/petrinaut-core/workers/lsp": [ + "libs/@hashintel/petrinaut-core/src/workers/lsp.ts" + ], + "@hashintel/petrinaut-core/workers/monte-carlo": [ + "libs/@hashintel/petrinaut-core/src/workers/monte-carlo.ts" + ], + "@hashintel/petrinaut-core/workers/simulation": [ + "libs/@hashintel/petrinaut-core/src/workers/simulation.ts" + ] + } + }, + "include": ["src", "../petrinaut/src"] +} diff --git a/libs/@hashintel/petrinaut-core/docs/architecture/authoring.html b/libs/@hashintel/petrinaut-core/docs/architecture/authoring.html index 5d6d9d47e06..ae048fa3b0a 100644 --- a/libs/@hashintel/petrinaut-core/docs/architecture/authoring.html +++ b/libs/@hashintel/petrinaut-core/docs/architecture/authoring.html @@ -17,10 +17,9 @@
- authoring/ — turns user-authored strings (TypeScript modules,
- expressions, function bodies) into plain JS functions the engine can call.
- Nothing here is a real security boundary: user code runs in the same
- realm, hardened against accidents, not attackers.
+ The HIR pipeline turns user-authored TypeScript into checked,
+ source-spanned buffer programs. Scenario code retains a separate
+ same-realm compiler hardened against accidents, not attackers.
InitialMarking for
- scenarios, fn(state) for metrics)
+ Versioned HIR artifacts for runtime code; InitialMarking
+ for scenarios
init) · Main thread
- (scenario, quick-sim metrics) · MC worker (experiment metrics)
+ LSP worker (HIR compilation) · simulation workers (buffer programs) ·
+ main thread (scenarios and timeline metric evaluation)
- user-code/compile-user-code.ts handles the three engine
- surfaces that are authored as modules (export default Wrapper(fn)):
+ Dynamics, lambdas, kernels, and metrics all compile through the HIR. The
+ first three are authored as export default Wrapper(fn)
+ modules; metrics are authored as function bodies.
new Function(...)()
- Same-realm plain JS closure, handed to the engine
+ Instantiate in runtime
+ Validate v4 fingerprint, then bind parameters, pool, and ABI
+ views
Color_*,
Parameters, Dynamics,
TransitionKernel… declarations that Monaco checks against, so
- editor diagnostics and runtime behaviour must be kept in sync by hand.
+ editor diagnostics and runtime artifacts are produced from the same HIR
+ checks and emitters.
Lambda(fn)buildSimulation → compileUserCodecompileHirArtifacts in the LSP worker(input: {PlaceName: TokenRecord[]}, params) → boolean |
- rate
+ (f64, u64, u8, placeBases, indices) → boolean | rate
TransitionKernel(fn)buildSimulationcompileHirArtifacts in the LSP worker(input, params) → {OutputPlace: token[]} — values may
- be Distribution objects, sampled later by the engine
+ (views, placeBases, indices, outputViews, sink) → void
Dynamics(fn)buildSimulation (only for colours with a real element)
+ compileHirArtifacts (colours with a real element)
(tokens: TokenRecord[], params) → derivative[] (real
- elements only; others zeroed)
+ (placeBytes, tokenCount) → Float64Array
authoring/metric/compile-metric.tscompileHirArtifacts in the LSP worker(state: {places: {[name]: {count, tokens}}}) → finite
- number(f64, u64, u8, placeCounts, placeOffsets) → finite number
— NaN/∞ throw
SimulationFrameReader into
- state.places[name] = {count, tokens} (keyed by place
- name, tokens decoded).Bind referenced place ordinals and the per-run string pool.
authoring/sandbox.ts)authoring/sandbox.ts)var window, document, globalThis, self, fetch, XMLHttpRequest,
importScripts, Function, setTimeout, setInterval, queueMicrotaskSandboxing (authoring/sandbox.ts)
- user-code/distribution.ts injects a tiny runtime providing
- Distribution.Gaussian / Uniform / Lognormal. Kernels don’t
- sample — they return distribution objects; the engine samples
- each one once per token with the seeded RNG
- (sample-distribution.ts), so chained
- .map(fn) transforms share a single draw and runs stay
+ HIR-emitted kernels construct small runtime values for
+ Distribution.Gaussian / Uniform / Lognormal. Kernels defer
+ sampling through the ABI sink; the engine samples each value once per
+ token with the seeded RNG (sample-distribution.ts), so
+ chained .map(fn) transforms share a single draw and runs stay
reproducible. When stochasticity is disabled, the runtime isn’t injected
and plain values are required.
export default Wrapper(…)) —
- an AST check via the already-present Babel pass would be stricter. (2)
- Compiled functions receive decoded TokenRecord objects;
- compiling to buffer-level accessors (the “IR” idea in the Monte Carlo
- README) would remove per-firing object churn. (3) The runtime/LSP contract
- (shapes, availability rules) is duplicated between
- generate-virtual-files.ts, ai.ts prose, and the
- compilers — a single source of truth would prevent drift.
+ Compatibility seam. HIR artifacts contain a version and
+ fingerprint of their sanitized compilation input. Any schema, code, or
+ extension change requires recompilation before the engine will run them.