Status: proposal (2026-10-15). It continues step 6 of unified-worlds.md, which deferred "experiments as scopes" until an algorithm runs over Attempts. Speculation and inference are such algorithms.
An agent should be able to try alternatives before committing to one, simulate what an action would do without doing it, and reason under uncertainty by inference, and it should be able to do each of these inside the others: a simulation inside a particle of an inference, an inference inside a speculative Run. dvergr and its libraries already provide most of the parts. This document names the one operation they share, the laws that keep it composable, the gaps that break those laws today, and an order in which to close them.
| Part | Where | Guarantee |
|---|---|---|
| Forking and settlement | the fork contract in worlds-and-forks.md | a world forks; a child is merged, discarded or transferred exactly once by an affine token; a nested merge targets the immediate parent |
| Conserved budgets | dvergr.resource wallets on one ledger; dvergr.resource.authority/authority as spindel's PResourceAuthority | a fork moves authority (grant), a discard returns it, a resume grants the remainder; transfer ids make retries idempotent |
| Model spend | dvergr.resource/charge-spend! against the bound dvergr.resource/*spend-wallet* | every model call is charged once, to the wallet of its charge scope (a Run's model step, a protocol Run, an Attempt's observation) |
| Inference in forked worlds | foerster's :world-policy :fork with :authority and :grant | the root draws the grant, particles split it, copies split their ancestor's remainder at resampling, discards refund |
| Search over agent steps | org.replikativ.foerster.steer/model; best-of-n over Runs with :review settlement | SMC over scored steps; Runs side by side, each in its own fork |
| Inference in rooms | the :foerster/inference sandbox extension (dvergr.sandbox.ns.data/install-foerster!) | infer/ and dist/ in the agent's interpreter, results as plain data, fresh worlds by default |
Speculative execution, simulation and inference are one operation: fork worlds with moved authority, run a program in each, and join. They differ in how many worlds they fork and in the join.
| Use | Worlds | Join | What reaches the parent |
|---|---|---|---|
| speculation: try alternatives | k | select one and merge it, discard the rest | one settled world |
| simulation: what would happen | 1 to k | discard all | the result values |
| inference: what is likely | N particles, copied and dropped | a weighted mixture | a posterior and its evidence |
| nesting | any of the above inside a world of another | the inner join's result is a value in the outer world | for inference, the inner evidence multiplies the outer weight |
A Run is then a weighted world: its result is a value, its verifier's or judge's score is a log weight (factor), and its settlement is the join of the world that was selected. Best-of-n is inference over Runs with a selection join, and steer is the same with resampling between steps.
Each law is a test, run at one level and at two nested levels.
How many worlds to fork, how to split a budget among them, and when to stop are decisions of an allocation policy, separate from the mechanism above: SMC's resampling, racing with a deadline, best-of-n with early stopping when the evidence decides, or a person raising a budget through :directive/raise-budget. The mechanism guarantees the laws whatever the policy decides, so a policy can be changed or learned without re-checking them.
Verified by reading the code on main (2026-10-15):
dvergr.resource/*spend-wallet*, the Run's. A grant from a world authority goes to the world's own wallet (dvergr.resource.authority/wallet-of), which model calls never charge. So a particle funded with a share would refund its share untouched while its model calls draw on the Run's wallet. Law 4 fails, and Law 2 holds only because both wallets are on the same ledger.infer/ in the sandbox passes :world-policy :fresh and no :authority, so foerster's particle scope has none and particle worlds have no wallet. With :fork, the particles are copies of the Run's world and spend, through G1, from the Run's wallet without a per-particle bound.steer over steps implement the same search separately; a Run is not yet a world a scope can copy, weight and select (step 6's "scope whose fork and discard the embedder supplies").foerster.core's re-exported effects (foerster#79), and the newer distributions.Found by tests (2026-10-16):
dvergr.resource.authority/authority did not implement PResourceAuthority/balance, which world-scope/copy! asks to split a world's remainder between its copies, so SMC under :world-policy :fork with the ledger authority failed at the first resampling.dvergr.resource/*spend-wallet* binding is absent, so a charge made inside a particle finds no spend wallet and is not recorded. Charging it needs the world, not the thread, to carry the charge scope: a world with a wallet of its own charges it under a scope named by its fork id, with a per-world debit counter in its state, so a retried step still debits once. Spindel stays unaware of the ledger: the world records its Room's id, and dvergr finds the Room through a process-local registry.Each step lands with the tests of the laws it makes true.
[:dvergr/wallet]), model calls made in it charge that wallet, falling back to the Run's. Pass the room's ledger authority to the sandbox's infer/ together with a :grant the agent names, and test conservation: N particles that make model calls, resampled, then the ledger's totals.dist/ to the current constructors, add :enumerate and :pmmh to foerster.sandbox, and register foerster.core's effect names in the sandbox's breakpoints.steer over Runs then use one implementation.infer/conditional (foerster's nested inference) inside a particle, with the conjugate test, and the rule for observations shared between levels.Steps 1 and 2 are independent and small; 3 needs 1; 4 is independent; 5 needs 1 and 2.
The fork contract, the ledger and its transfer ids, Run resume, and settlement by :automatic, :review and :discard stay as they are. This proposal adds the rule that spend follows the world, a classification of effects, and one search over worlds; everything else is how the existing parts compose.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |