Builds the capability callbacks handed to a sandboxed evaluation.
Every callback here is copied into the sandbox process, and that copy is
flat — spawn does not preserve sharing. A callback must therefore close
over only what it reads. Dispatcher.dispatch/8 resolves one name, so each
capability callback carries one capability via
PtcRunner.Kernel.Environment.capability_view/2; only the runtime discovery
routes carry the whole map, via capability_view/1.
The cost of getting this wrong is not linear. A term every callback captures
is copied once per callback, so capturing anything environment-sized makes
the hand-over O(capabilities²) — enough for a tool-rich MCP environment to
blow the sandbox setup ceiling before the program runs, and enough for a
modest environment to eat the program's whole heap budget through the
measured baseline. PtcRunner.Sandbox documents how that baseline is billed.
Size a grant with :erts_debug.flat_size (plus referenced binaries for byte
units); that is what the sandbox's own baseline measurement bills.
Summary
Functions
Returns the capability dispatch callbacks plus reserved runtime routes for one environment.
Functions
@spec capability_callbacks( term(), :workflow | :mission, map(), %{ mission_name: binary() | nil, timeout_ms: non_neg_integer(), validation_heap_words: pos_integer(), evaluation_lease: reference() | nil, validation_deadline_ms: integer() | nil }, term(), term() ) :: %{required(binary()) => (map() -> map())}
Returns the capability dispatch callbacks plus reserved runtime routes for one environment.
Callers add their own environment-specific routes (kernel-eval, the
workflow inventory routes, TrustedTool wrapping) to the result. Those
extra routes are not capability callbacks and are not refusal-counted;
wrapping happens inside this grant, after RuntimeTools.tools/5 is merged.