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
impl BehaviorSpec
Sourcepub fn declared_slots(&self) -> impl Iterator<Item = (&'static str, &Path)>
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.
Sourcepub fn declared_paths(&self) -> impl Iterator<Item = &Path>
pub fn declared_paths(&self) -> impl Iterator<Item = &Path>
Iterate over every declared callback path. Used by the layout checker.
Sourcepub fn on_state_change(&self) -> Option<&Path>
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.
Sourcepub fn on_init(&self) -> Option<&Path>
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.
Sourcepub fn on_call(&self) -> Option<&Path>
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.
Sourcepub fn on_cast(&self) -> Option<&Path>
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.
Sourcepub fn on_info(&self) -> Option<&Path>
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.
Sourcepub fn on_terminate(&self) -> Option<&Path>
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.
Sourcepub fn validate(&self) -> Result<(), BehaviorError>
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
.lispextension (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
impl Clone for BehaviorSpec
Source§fn clone(&self) -> BehaviorSpec
fn clone(&self) -> BehaviorSpec
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for BehaviorSpec
impl Debug for BehaviorSpec
Source§impl Default for BehaviorSpec
impl Default for BehaviorSpec
Source§fn default() -> BehaviorSpec
fn default() -> BehaviorSpec
Source§impl<'de> Deserialize<'de> for BehaviorSpec
impl<'de> Deserialize<'de> for BehaviorSpec
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for BehaviorSpec
Source§impl PartialEq for BehaviorSpec
impl PartialEq for BehaviorSpec
Source§impl Serialize for BehaviorSpec
impl Serialize for BehaviorSpec
impl StructuralPartialEq for BehaviorSpec
Auto Trait Implementations§
impl Freeze for BehaviorSpec
impl RefUnwindSafe for BehaviorSpec
impl Send for BehaviorSpec
impl Sync for BehaviorSpec
impl Unpin for BehaviorSpec
impl UnsafeUnpin for BehaviorSpec
impl UnwindSafe for BehaviorSpec
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.