Skip to main content

BehaviorSpec

Struct BehaviorSpec 

Source
pub struct BehaviorSpec {
    pub on_init: Option<PathBuf>,
    pub on_call: Option<PathBuf>,
    pub on_cast: Option<PathBuf>,
    pub on_info: Option<PathBuf>,
    pub on_state_change: Option<PathBuf>,
    pub on_terminate: Option<PathBuf>,
}
Expand description

Path-to-callback bindings for an OTP-shaped Servico.

All fields optional. The wasm-engine looks up the callback by kind at instance start; if absent, the runtime default is used.

Fields§

§on_init: Option<PathBuf>

Called once before the instance accepts traffic. Analog of gen_server:init/1. Runs to completion or the instance fails to start.

§on_call: Option<PathBuf>

Synchronous request/response handler. Analog of gen_server:handle_call/3 — reply is awaited by the caller. For HTTP servicos this is the wasi:http/incoming-handler.

§on_cast: Option<PathBuf>

Asynchronous fire-and-forget handler. Analog of gen_server:handle_cast/2 — caller does not wait. For HTTP servicos this maps onto Accepted: 202 shapes.

§on_info: Option<PathBuf>

System / out-of-band message handler. Analog of gen_server:handle_info/2 — timeouts, downstream nodedown, monitor signals, scheduler ticks.

§on_state_change: Option<PathBuf>

State migration callback for hot-upgrades. Analog of gen_server:code_change/3 — receives old state + version, returns new state. Composes with the :upgrade-from slot declared at the Caixa root.

§on_terminate: Option<PathBuf>

Cleanup callback before the instance shuts down. Analog of gen_server:terminate/2. Best-effort — runs only when the instance terminates gracefully (not on hard kill).

Implementations§

Source§

impl BehaviorSpec

Source

pub fn declared_slots(&self) -> impl Iterator<Item = (&'static str, &Path)>

Iterate over every declared callback path tagged with the kebab-case :on-* slot it came from. Used by the layout checker (existence) and by BehaviorSpec::validate (value-shape) so diagnostics can name the offending slot.

Each per-arm kebab-case label is routed through the peer [crate::M2_BEHAVIOR_AUTHOR_KEY_ON_*] consts declared next to the [crate::M2_BEHAVIOR_KEY_ON_*] renderer-side wire-key peers, so both halves of the M2 :behavior sub-slot’s dual axis (author-facing kebab-case label + renderer-side camelCase wire key) route through one canonical declaration per arm.

Each per-arm Option<&Path> path-value is routed through the sibling lifted BehaviorSpec::on_init / BehaviorSpec::on_call / BehaviorSpec::on_cast / BehaviorSpec::on_info / BehaviorSpec::on_state_change / BehaviorSpec::on_terminate per-slot accessors, so the iterator’s per-arm typed dispatch composes with every future accessor-side extension (a per-prior-:versao state-migration callback the operator pins through a future :behavior :on-state-change-overrides slot the theory/ABSORPTION-ROADMAP.md M2.5 wasm-engine callback-dispatch wire acknowledges, a per-tenant callback alias table the M4 CR materializer resolves per-CR, a per-cluster callback overlay the operator pins through a future placement-scoped slot) as a unit: the layout checker’s existence sweep + the sibling BehaviorSpec::validate value-shape gate consume whichever accept-set the accessor exposes, so both halves of the diagnostic surface migrate together. Prior to this converge the six per-arm self.on_*.as_ref() raw-field-access sites bypassed the accessor dispatch — the accessors owned the accept-set on the read side but the iterator that both production consumers actually read projected through the raw Option<PathBuf> field, silently disagreeing with every accessor extension until the two-site rewrite reached both halves in lockstep.

Source

pub fn declared_paths(&self) -> impl Iterator<Item = &Path>

Iterate over every declared callback path. Used by the layout checker.

Source

pub fn is_empty(&self) -> bool

True when no callback is declared.

Source

pub fn on_state_change(&self) -> Option<&Path>

Substrate-canonical per-:behavior :on-state-change OTP-gen_server:code_change/3-shaped state-migration callback path scalar accessor every consumer of the Servico’s hot-upgrade dispatch keys off — returns the author-declared :behavior :on-state-change typed callback path verbatim as an Option<&Path>, borrowed from the typed slot’s own Option<PathBuf> storage. None when the slot is absent (the canonical “no state-migration callback declared — the caixa exposes no hot-upgrade state-fold path, so any :upgrade-from entry carrying a (:state-change …) instruction is structurally half a composition” arm the peer crate::validate_upgrade_from_against_behavior cross-slot gate keys off through this accessor).

The :behavior :on-state-change slot carries the OTP gen_server:code_change/3 callback contract (the module-level BehaviorSpec::on_state_change docstring pins the analog verbatim: “State migration callback for hot-upgrades. Analog of gen_server:code_change/3 — receives old state + version, returns new state. Composes with the :upgrade-from slot declared at the Caixa root.”). The composition it half-forms is realized in OTP by release_handler:install_release/1, which invokes the running gen_server’s code_change/3 during the appup’s code_change / update, m, soft step — the appup’s instruction triggers the callback, the callback folds the prior-version state shape into the current-version shape, and the operator advances to the next instruction only after the callback returns successfully (theory/INSPIRATIONS.md §II.3 — OTP gen_server + release_handler state-migration wire, translated onto pleme-io’s typed :behavior + :upgrade-from slot pair). caixa decomposes the same composition into two typed slots: the per-version migration logic lives in the (:state-change "lib/migrations/…lisp") instruction’s :script (the :upgrade-from author surface, resolved through crate::UpgradeInstruction::StateChange), and the runtime hook the operator dispatches the migration through lives in the :behavior :on-state-change callback (the :behavior author surface, resolved through this accessor). The crate::validate_upgrade_from_against_behavior cross-slot gate closes the composition at validate time by refusing a Caixa that carries a :state-change instruction without declaring :on-state-change — the sole caixa-core consumer that reads the callback’s Option<&Path> presence rather than the callback path itself.

Prior to this lift the .on_state_change field was accessed inline at two sites — BehaviorSpec::declared_slots’s :on-state-change arm’s self.on_state_change.as_ref() map into the six-tuple iterator, and the sibling crate::validate_upgrade_from_against_behavior cross-slot gate’s behavior.and_then(|b| b.on_state_change.as_ref()).is_some() short-circuit — two open-coded field-accesses that expressed no compile-time link back to the typed slot. A future extension of the :behavior :on-state-change axis to a richer author surface — a per-prior-:versao state-migration callback the operator pins through a future :behavior :on-state-change-overrides slot the theory/ABSORPTION-ROADMAP.md M2.5 wasm-engine callback-dispatch wire acknowledges, a per-tenant migration alias table the M4 CR materializer resolves per-CR, a per-Aplicacao dynamic state-change derivation the future adaptive hot-upgrade engine computes from the sibling :upgrade-from instruction chain — would have had to be threaded through both open-coded copies in lockstep or the declared_slots iterator (the tag surface every per-slot diagnostic reads) and the validate_upgrade_from_against_behavior gate (the composition closure every hot-upgrade admission reads) would silently disagree on which callback a given BehaviorSpec resolves to. Lifting the resolution to a typed method on the substrate primitive means every downstream consumer of the Servico’s per-:behavior state-migration callback surface reaches for exactly one typed dispatch — the resolver’s accept-set migrates as a unit on any future axis addition.

First Option<&Path>-return accessor on the M2 :behavior slot family (peer of the sibling per-:placement crate::Placement::shard_key 7cd2a28 / crate::Placement::affinity 74ec2d3 Option<&str> accessors on the M3 mesh-slot family — same “one typed dispatch on the substrate primitive, thin projections at each consumer” discipline extended onto the peer per-:behavior Option<PathBuf> optional-scalar axis; opens the “optional per-slot Option<&Path> scalar” projection pattern the sibling per-:behavior :on-init / :on-call / :on-cast / :on-info / :on-terminate future lifts fold on). Named on_state_change() to match the storage field’s name; the accessor’s identity name maps onto the canonical theory/INSPIRATIONS.md §II.3 vocabulary the slot’s docstring already carries.

Source

pub fn on_init(&self) -> Option<&Path>

Substrate-canonical per-:behavior :on-init OTP-gen_server:init/1- shaped once-per-instance-start callback-path scalar accessor every consumer of the Servico’s instance-start dispatch keys off — returns the author-declared :behavior :on-init typed callback path verbatim as an Option<&Path>, borrowed from the typed slot’s own Option<PathBuf> storage. None when the slot is absent (the canonical “no init callback declared — the runtime falls back to the wasm-engine’s no-op instance-start default” arm the runtime’s callback-lookup consults at instance-start time; peer of the sibling BehaviorSpec::on_state_change None-arm’s “no state-migration callback” semantic on the sibling axis).

The :behavior :on-init slot carries the OTP gen_server:init/1 callback contract (the module-level BehaviorSpec::on_init docstring pins the analog verbatim: “Called once before the instance accepts traffic. Analog of gen_server:init/1. Runs to completion or the instance fails to start.”). Its position in the OTP lifecycle is first — the runtime instantiates the wasm process, dispatches the init callback, and only then flips the instance’s readiness state so downstream traffic (:on-call / :on-cast) is accepted (theory/INSPIRATIONS.md §II.3 — OTP gen_server behavior’s six-callback lifecycle, translated onto pleme-io’s typed :behavior slot family; theory/CAIXA-SDLC.md §I — the author-surface pins :on-init as the first arm of the :behavior overlay every Servico may declare).

Prior to this lift the .on_init field was accessed inline at one production site — BehaviorSpec::declared_slots’s :on-init arm’s self.on_init.as_ref() map into the six-tuple iterator that both the layout checker (existence sweep at layout.rs:900) and the sibling BehaviorSpec::validate value-shape gate consume — an open-coded field-access that expressed no compile-time link back to the typed slot. A future extension of the :behavior :on-init axis to a richer author surface — a per-tenant init-callback override the M4 CR materializer resolves per-CR, a per-cluster instance-start callback overlay the theory/ABSORPTION-ROADMAP.md M2.5 wasm-engine callback-dispatch wire acknowledges, a per-Aplicacao dynamic init-callback derivation the future adaptive hot-instantiation engine computes from the sibling :limits wasm-engine sandbox — would have had to be threaded through the open-coded field-access in declared_slots (the tag surface every per-slot diagnostic reads) or the declared_slots iterator would silently disagree on which callback a given BehaviorSpec resolves to. Lifting the resolution to a typed method on the substrate primitive means every downstream consumer of the Servico’s per-:behavior init-callback surface reaches for exactly one typed dispatch — the resolver’s accept-set migrates as a unit on any future axis addition.

Second Option<&Path>-return accessor on the M2 :behavior slot family (sibling of the prior BehaviorSpec::on_state_change 9b4ecde Option<&Path> accessor on the peer per-:behavior :on-state-change axis — same “one typed dispatch on the substrate primitive, thin projections at each consumer” discipline extended onto the peer per-:behavior Option<PathBuf> optional-scalar axis; continues the “optional per-slot Option<&Path> scalar” projection pattern the sibling per-:behavior :on-call / :on-cast / :on-info / :on-terminate future lifts fold on). Named on_init() to match the storage field’s name; the accessor’s identity name maps onto the canonical theory/INSPIRATIONS.md §II.3 vocabulary the slot’s docstring already carries.

Source

pub fn on_call(&self) -> Option<&Path>

Substrate-canonical per-:behavior :on-call OTP-gen_server:handle_call/3-shaped synchronous request/response callback-path scalar accessor every consumer of the Servico’s synchronous-dispatch callback path keys off — returns the author-declared :behavior :on-call typed callback path verbatim as an Option<&Path>, borrowed from the typed slot’s own Option<PathBuf> storage. None when the slot is absent (the canonical “no synchronous-call callback declared — the runtime falls back to the wasm-engine’s raw wasi:http/incoming-handler default that surfaces the request to the underlying HTTP proxy world verbatim without any author-supplied reply-shape interposed” arm the M2.5 wasm-engine callback-dispatch wire consults at every synchronous incoming call; peer of the sibling BehaviorSpec::on_init / BehaviorSpec::on_state_change None-arm’s “no instance-start / state-migration callback” semantic on the sibling axes).

The :behavior :on-call slot carries the OTP gen_server:handle_call/3 callback contract (the module-level BehaviorSpec::on_call docstring pins the analog verbatim: “Synchronous request/response handler. Analog of gen_server:handle_call/3 — reply is awaited by the caller. For HTTP servicos this is the wasi:http/incoming-handler.”). Its position in the OTP dispatch triad is the request/response half: the runtime routes every synchronous incoming message (every wasi:http/incoming-handler invocation whose caller awaits a reply, every synchronous WIT-typed peer edge whose contract carries a reply payload) through the callback; the callback runs to completion, computes the reply, and the runtime hands the reply back to the awaiting caller before flipping the process back to the mailbox-drain state (theory/INSPIRATIONS.md §II.3 — OTP gen_server behavior’s six-callback lifecycle, translated onto pleme-io’s typed :behavior slot family; theory/CAIXA-SDLC.md §I — the author-surface pins :on-call as the second arm of the :behavior overlay every Servico may declare, sibling to :on-cast / :on-info on the peer asynchronous-dispatch axes; theory/RUNTIME-PATTERNS.md §II — the synchronous-request-response pattern the runtime realizes through this callback).

Prior to this lift the .on_call field was accessed inline at one production site — BehaviorSpec::declared_slots’s :on-call arm’s self.on_call.as_ref() map into the six-tuple iterator that both the layout checker (existence sweep at layout.rs:900) and the sibling BehaviorSpec::validate value-shape gate consume — an open-coded field-access that expressed no compile-time link back to the typed slot. A future extension of the :behavior :on-call axis to a richer author surface — a per-tenant call-callback override the M4 CR materializer resolves per-CR, a per-cluster synchronous-dispatch callback overlay the theory/ABSORPTION-ROADMAP.md M2.5 wasm-engine callback-dispatch wire acknowledges, a per-contrato per-:wit-world call-callback derivation the future adaptive dispatch engine computes from the sibling :contratos M3 mesh-slot edges — would have had to be threaded through the open-coded field-access in declared_slots (the tag surface every per-slot diagnostic reads) or the declared_slots iterator would silently disagree on which callback a given BehaviorSpec resolves to. Lifting the resolution to a typed method on the substrate primitive means every downstream consumer of the Servico’s per-:behavior synchronous-call callback surface reaches for exactly one typed dispatch — the resolver’s accept-set migrates as a unit on any future axis addition.

Third Option<&Path>-return accessor on the M2 :behavior slot family (sibling of the prior BehaviorSpec::on_state_change 9b4ecde and BehaviorSpec::on_init d66c702 Option<&Path> accessors on the peer per-:behavior :on-state-change / :on-init axes — same “one typed dispatch on the substrate primitive, thin projections at each consumer” discipline extended onto the peer per-:behavior Option<PathBuf> optional-scalar axis; continues the “optional per-slot Option<&Path> scalar” projection pattern the sibling per-:behavior :on-cast / :on-info / :on-terminate future lifts fold on). Named on_call() to match the storage field’s name; the accessor’s identity name maps onto the canonical theory/INSPIRATIONS.md §II.3 vocabulary the slot’s docstring already carries.

Source

pub fn on_cast(&self) -> Option<&Path>

Substrate-canonical per-:behavior :on-cast OTP-gen_server:handle_cast/2-shaped asynchronous fire-and-forget callback-path scalar accessor every consumer of the Servico’s asynchronous-dispatch callback path keys off — returns the author-declared :behavior :on-cast typed callback path verbatim as an Option<&Path>, borrowed from the typed slot’s own Option<PathBuf> storage. None when the slot is absent (the canonical “no asynchronous-cast callback declared — the runtime falls back to the wasm-engine’s default Accepted: 202 fire-and-forget response shape that surfaces the request to the underlying HTTP proxy world verbatim without any author-supplied post-accept-side-effect interposed” arm the M2.5 wasm-engine callback-dispatch wire consults at every asynchronous incoming call; peer of the sibling BehaviorSpec::on_init / BehaviorSpec::on_call / BehaviorSpec::on_state_change None-arm’s “no instance-start / synchronous-call / state-migration callback” semantic on the sibling axes).

The :behavior :on-cast slot carries the OTP gen_server:handle_cast/2 callback contract (the module-level BehaviorSpec::on_cast docstring pins the analog verbatim: “Asynchronous fire-and-forget handler. Analog of gen_server:handle_cast/2 — caller does not wait. For HTTP servicos this maps onto Accepted: 202 shapes.”). Its position in the OTP dispatch triad is the fire-and-forget half sibling to the synchronous request/response :on-call half: the runtime routes every asynchronous incoming message (every wasi:http/incoming-handler invocation whose caller does not await a reply and whose runtime response the wasm-engine short-circuits into an Accepted: 202 shape at accept time, every asynchronous WIT-typed peer edge whose contract carries no reply payload, every NATS nats:pub-sub subscriber the future M3 mesh-slot NATS bridge dispatches through the :on-cast callback the way the sibling wasi:http/proxy HTTP bridge dispatches through :on-call) through the callback; the callback runs to completion on the actor’s own mailbox turn without any reply-shape awaiting caller, and the runtime returns to the mailbox-drain state as soon as the callback returns (theory/INSPIRATIONS.md §II.3 — OTP gen_server behavior’s six-callback lifecycle, translated onto pleme-io’s typed :behavior slot family; theory/CAIXA-SDLC.md §I — the author-surface pins :on-cast as the third arm of the :behavior overlay every Servico may declare, sibling to :on-call on the peer synchronous-dispatch axis and :on-info on the peer out-of-band-dispatch axis; theory/RUNTIME-PATTERNS.md §II — the asynchronous-fire-and-forget pattern the runtime realizes through this callback).

Prior to this lift the .on_cast field was accessed inline at one production site — BehaviorSpec::declared_slots’s :on-cast arm’s self.on_cast.as_ref() map into the six-tuple iterator that both the layout checker (existence sweep at layout.rs:900) and the sibling BehaviorSpec::validate value-shape gate consume — an open-coded field-access that expressed no compile-time link back to the typed slot. A future extension of the :behavior :on-cast axis to a richer author surface — a per-tenant cast-callback override the M4 CR materializer resolves per-CR, a per-cluster asynchronous-dispatch callback overlay the theory/ABSORPTION-ROADMAP.md M2.5 wasm-engine callback-dispatch wire acknowledges, a per-nats:pub-sub-subject cast-callback derivation the future M3 mesh-slot NATS bridge computes from the sibling :contratos M3 mesh-slot edges’ :subject axis — would have had to be threaded through the open-coded field-access in declared_slots (the tag surface every per-slot diagnostic reads) or the declared_slots iterator would silently disagree on which callback a given BehaviorSpec resolves to. Lifting the resolution to a typed method on the substrate primitive means every downstream consumer of the Servico’s per-:behavior asynchronous-cast callback surface reaches for exactly one typed dispatch — the resolver’s accept-set migrates as a unit on any future axis addition.

Fourth Option<&Path>-return accessor on the M2 :behavior slot family (sibling of the prior BehaviorSpec::on_state_change 9b4ecde, BehaviorSpec::on_init d66c702, and BehaviorSpec::on_call 156ddbe Option<&Path> accessors on the peer per-:behavior :on-state-change / :on-init / :on-call axes — same “one typed dispatch on the substrate primitive, thin projections at each consumer” discipline extended onto the peer per-:behavior Option<PathBuf> optional-scalar axis; continues the “optional per-slot Option<&Path> scalar” projection pattern the sibling per-:behavior :on-info / :on-terminate future lifts fold on). Named on_cast() to match the storage field’s name; the accessor’s identity name maps onto the canonical theory/INSPIRATIONS.md §II.3 vocabulary the slot’s docstring already carries.

Source

pub fn on_info(&self) -> Option<&Path>

Substrate-canonical per-:behavior :on-info OTP-gen_server:handle_info/2-shaped system / out-of-band message-handler callback-path scalar accessor every consumer of the Servico’s out-of-band-dispatch callback path keys off — returns the author-declared :behavior :on-info typed callback path verbatim as an Option<&Path>, borrowed from the typed slot’s own Option<PathBuf> storage. None when the slot is absent (the canonical “no out-of-band-info callback declared — the runtime silently drops every non-:on-call / non-:on-cast mailbox message the wasm-engine’s gen_server-shaped dispatcher classifies as system / out-of-band (timeouts, downstream nodedown, monitor DOWN signals, scheduler ticks, wasm-engine wasi:clocks timer fires, adaptive-dispatch backpressure notifications the M2.5 wasm-engine callback-dispatch wire emits on peer-Servico circuit-open transitions) without any author-supplied side-effect interposed” arm the M2.5 wasm-engine callback-dispatch wire consults at every out-of-band mailbox turn; peer of the sibling BehaviorSpec::on_init / BehaviorSpec::on_call / BehaviorSpec::on_cast / BehaviorSpec::on_state_change None-arm’s “no instance-start / synchronous-call / asynchronous-cast / state-migration callback” semantic on the sibling axes).

The :behavior :on-info slot carries the OTP gen_server:handle_info/2 callback contract (the module-level BehaviorSpec::on_info docstring pins the analog verbatim: “System / out-of-band message handler. Analog of gen_server:handle_info/2 — timeouts, downstream nodedown, monitor signals, scheduler ticks.”). Its position in the OTP dispatch triad is the out-of-band half sibling to the synchronous request/response :on-call and asynchronous fire-and-forget :on-cast halves: the runtime routes every mailbox message the gen_server-shaped dispatcher classifies as neither a :on-call synchronous request (no reply-awaiting caller) nor a :on-cast asynchronous WIT-typed edge (no peer Servico originated the message via a declared :contratos entry) through the callback; the callback runs to completion on the actor’s own mailbox turn with no reply-shape awaiting caller and no peer-Servico dispatch semantics, and the runtime returns to the mailbox-drain state as soon as the callback returns (theory/INSPIRATIONS.md §II.3 — OTP gen_server behavior’s six-callback lifecycle, translated onto pleme-io’s typed :behavior slot family; theory/CAIXA-SDLC.md §I — the author-surface pins :on-info as the fourth arm of the :behavior overlay every Servico may declare, sibling to :on-cast on the peer asynchronous-dispatch axis and :on-terminate on the peer lifecycle-tail axis; theory/RUNTIME-PATTERNS.md §II — the out-of-band-info pattern the runtime realizes through this callback).

Prior to this lift the .on_info field was accessed inline at one production site — BehaviorSpec::declared_slots’s :on-info arm’s self.on_info.as_ref() map into the six-tuple iterator that both the layout checker (existence sweep at layout.rs:900) and the sibling BehaviorSpec::validate value-shape gate consume — an open-coded field-access that expressed no compile-time link back to the typed slot. A future extension of the :behavior :on-info axis to a richer author surface — a per-tenant info-callback override the M4 CR materializer resolves per-CR, a per-cluster out-of-band-dispatch callback overlay the theory/ABSORPTION-ROADMAP.md M2.5 wasm-engine callback-dispatch wire acknowledges, a per-monitor-signal callback derivation the future adaptive-dispatch engine computes from the sibling :politicas :circuit-breaker axis (routing peer-Servico circuit-open notifications through the info-callback the way Erlang routes DOWN messages through handle_info/2) — would have had to be threaded through the open-coded field-access in declared_slots (the tag surface every per-slot diagnostic reads) or the declared_slots iterator would silently disagree on which callback a given BehaviorSpec resolves to. Lifting the resolution to a typed method on the substrate primitive means every downstream consumer of the Servico’s per-:behavior out-of-band-info callback surface reaches for exactly one typed dispatch — the resolver’s accept-set migrates as a unit on any future axis addition.

Fifth Option<&Path>-return accessor on the M2 :behavior slot family (sibling of the prior BehaviorSpec::on_state_change 9b4ecde, BehaviorSpec::on_init d66c702, BehaviorSpec::on_call 156ddbe, and BehaviorSpec::on_cast 99616ac Option<&Path> accessors on the peer per-:behavior :on-state-change / :on-init / :on-call / :on-cast axes — same “one typed dispatch on the substrate primitive, thin projections at each consumer” discipline extended onto the peer per-:behavior Option<PathBuf> optional-scalar axis; continues the “optional per-slot Option<&Path> scalar” projection pattern the last-remaining sibling per-:behavior :on-terminate future lift folds on). Named on_info() to match the storage field’s name; the accessor’s identity name maps onto the canonical theory/INSPIRATIONS.md §II.3 vocabulary the slot’s docstring already carries.

Source

pub fn on_terminate(&self) -> Option<&Path>

Substrate-canonical per-:behavior :on-terminate OTP-gen_server:terminate/2-shaped graceful-shutdown cleanup callback-path scalar accessor every consumer of the Servico’s lifecycle-tail dispatch keys off — returns the author-declared :behavior :on-terminate typed callback path verbatim as an Option<&Path>, borrowed from the typed slot’s own Option<PathBuf> storage. None when the slot is absent (the canonical “no terminate callback declared — the runtime tears down the wasm instance without dispatching any author-supplied cleanup side-effect, the Lunatic-per-process sandbox reclaims every wasm32 linear-memory page + fuel budget the sibling :limits axes accept-set caps, and every outstanding wasi:http/incoming-handler / wasi:keyvalue/store / NATS nats:pub-sub open handle the WIT-component-model closes the wasm process’s export-side at process-tear-down time is dropped on the floor without any author-visible flush” arm the M2.5 wasm-engine callback-dispatch wire consults at every graceful tear-down turn; peer of the sibling BehaviorSpec::on_init / BehaviorSpec::on_call / BehaviorSpec::on_cast / BehaviorSpec::on_info / BehaviorSpec::on_state_change None-arm’s “no instance-start / synchronous-call / asynchronous-cast / out-of-band-info / state-migration callback” semantic on the sibling axes).

The :behavior :on-terminate slot carries the OTP gen_server:terminate/2 callback contract (the module-level BehaviorSpec::on_terminate docstring pins the analog verbatim: “Cleanup callback before the instance shuts down. Analog of gen_server:terminate/2. Best-effort — runs only when the instance terminates gracefully (not on hard kill).”). Its position in the OTP lifecycle is the lifecycle-tail complement of the :on-init head — the runtime instantiates the wasm process, dispatches :on-init, dispatches every :on-call / :on-cast / :on-info mailbox turn the instance accepts across its lifetime, and only at graceful tear-down time (a supervisor’s RestForOne restart pass, a rolling wasm-engine hot-upgrade the sibling :upgrade-from axis’s appup instructions describe, an operator-driven Aplicacao teardown the M4 CR materializer emits as a Kubernetes deletion event, a per-tenant per-:placement evict the future adaptive-placement engine computes on per-cluster capacity pressure) dispatches the terminate callback (theory/INSPIRATIONS.md §II.3 — OTP gen_server behavior’s six-callback lifecycle, translated onto pleme-io’s typed :behavior slot family; theory/CAIXA-SDLC.md §I — the author-surface pins :on-terminate as the sixth and final arm of the :behavior overlay every Servico may declare, sibling to :on-init on the peer lifecycle-head axis and :on-state-change on the peer hot-upgrade-composition axis; theory/RUNTIME-PATTERNS.md §II — the graceful-tear-down cleanup pattern the runtime realizes through this callback). The callback runs to completion on the actor’s own mailbox turn before the runtime returns the wasm process’s resources to the wasm-engine pool; the Lunatic-per-process sandbox guarantees the callback cannot exceed the sibling :limits :wall-clock axis’s per-call cap, so a runaway cleanup path cannot wedge the tear-down (the caller receives the same LimitsError::WallClockExceeded-shaped runtime diagnostic the sibling :on-* dispatch arms surface on the peer cap-exceed path). The “best-effort — runs only when the instance terminates gracefully (not on hard kill)” clause of the module-level docstring is the OTP terminate/2 clause verbatim: the runtime dispatches the callback on every controlled tear-down but never on EXIT-kill / SIGKILL / wasm-engine OOM eviction / fuel starvation cap-exceed.

Prior to this lift the .on_terminate field was accessed inline at one production site — BehaviorSpec::declared_slots’s :on-terminate arm’s self.on_terminate.as_ref() map into the six-tuple iterator that both the layout checker (existence sweep at layout.rs:900) and the sibling BehaviorSpec::validate value-shape gate consume — an open-coded field-access that expressed no compile-time link back to the typed slot. A future extension of the :behavior :on-terminate axis to a richer author surface — a per-tenant terminate-callback override the M4 CR materializer resolves per-CR, a per-cluster graceful-tear-down callback overlay the theory/ABSORPTION-ROADMAP.md M2.5 wasm-engine callback-dispatch wire acknowledges, a per-supervisor terminate-callback derivation the future adaptive-supervision engine computes from the sibling :estrategia restart-strategy axis (routing a RestForOne cascade’s per-child terminate through the callback the way Erlang routes terminate/2 before each restart_child/2 retry), a per-:upgrade-from version migration terminate-callback the future rolling hot-upgrade engine computes from the sibling :upgrade-from instruction chain (dispatching the terminate callback with the outgoing version’s state before the sibling :on-state-change callback folds it into the incoming version’s shape) — would have had to be threaded through the open-coded field-access in declared_slots (the tag surface every per-slot diagnostic reads) or the declared_slots iterator would silently disagree on which callback a given BehaviorSpec resolves to. Lifting the resolution to a typed method on the substrate primitive means every downstream consumer of the Servico’s per-:behavior graceful-tear-down callback surface reaches for exactly one typed dispatch — the resolver’s accept-set migrates as a unit on any future axis addition.

Sixth and final Option<&Path>-return accessor on the M2 :behavior slot family (sibling of the prior BehaviorSpec::on_state_change 9b4ecde, BehaviorSpec::on_init d66c702, BehaviorSpec::on_call 156ddbe, BehaviorSpec::on_cast 99616ac, and BehaviorSpec::on_info 4846cef Option<&Path> accessors on the peer per-:behavior :on-state-change / :on-init / :on-call / :on-cast / :on-info axes — same “one typed dispatch on the substrate primitive, thin projections at each consumer” discipline extended onto the peer per-:behavior Option<PathBuf> optional-scalar axis; closes the last unlifted per-:behavior Option<&Path> scalar-value axis, so every arm of the six-callback OTP gen_server lifecycle the slot family models now routes through one typed dispatch on the substrate primitive). Named on_terminate() to match the storage field’s name; the accessor’s identity name maps onto the canonical theory/INSPIRATIONS.md §II.3 vocabulary the slot’s docstring already carries.

Source

pub fn validate(&self) -> Result<(), BehaviorError>

Reject operationally-meaningless callback path values on every declared slot. Each slot remains optional — omitting a field expresses “fall back to the runtime default callback”; the bug being closed is carrying a foot-shaped path value, which the layout checker’s root.join(p) would either silently treat as the project root (PathBuf::new()), escape the project root (absolute path replaces root per Path::join semantics), or traverse out of the root via .. components.

Four invariants per slot, evaluated in declaration order (:on-init:on-call:on-cast:on-info:on-state-change:on-terminate) so the diagnostic for multi-malformed manifests is deterministic:

  • non-empty path string,
  • relative path (Lunatic-style sandbox: callbacks live under the caixa root, never in /etc/...),
  • no .. components (relative paths must not escape the caixa root via parent-directory traversal),
  • terminating .lisp extension (the wasm-engine reads every callback path as tatara-lisp source — a .txt / .rs / .lisp.bak / no-extension shape is structurally a parser error at instance-start time, far from the source caixa.lisp).

Mirrors the discipline applied to :limits axes (LimitsSpec::validate) and to the M3 mesh :entrada :paths invariants (AplicacaoSpec::validate) — every typed value carried by a slot is either absent or value-shape valid.

Trait Implementations§

Source§

impl Clone for BehaviorSpec

Source§

fn clone(&self) -> BehaviorSpec

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for BehaviorSpec

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for BehaviorSpec

Source§

fn default() -> BehaviorSpec

Returns the “default value” for a type. Read more
Source§

impl<'de> Deserialize<'de> for BehaviorSpec

Source§

fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>
where __D: Deserializer<'de>,

Deserialize this value from the given Serde deserializer. Read more
Source§

impl Eq for BehaviorSpec

Source§

impl PartialEq for BehaviorSpec

Source§

fn eq(&self, other: &BehaviorSpec) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl Serialize for BehaviorSpec

Source§

fn serialize<__S>(&self, __serializer: __S) -> Result<__S::Ok, __S::Error>
where __S: Serializer,

Serialize this value into the given Serde serializer. Read more
Source§

impl StructuralPartialEq for BehaviorSpec

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DeserializeOwned for T
where T: for<'de> Deserialize<'de>,

Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
Source§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

Source§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.