Hibana
Hibana lets Rust programs execute a finite multiparty protocol from one global choreography. The choreography is projected into a compact program for each role, and every send, receive, or route step must match that program before progress commits.
Hibana is a choreography-derived runtime enforcement kernel. It is
unconditionally no_std, needs no allocator, and uses caller-provided storage.
Protocol state is kept in compact descriptors instead of a distinct Rust
continuation type for every state, so protocol growth does not become endpoint
type growth.
- one choreography for up to 256 roles using the complete one-byte role domain;
- asynchronous
send,seq,par, binaryroute, and guardedroll; - affine endpoints that may be dropped but cannot publish progress twice;
- transport-neutral integration through one
Transporttrait; - the same public API on hosted and embedded targets.
Role IDs cover 0..=255. Projection, route participation, and attachment
accounting derive storage from actual events and local participants; the runtime
does not reserve a 256-entry role table. Splitting a protocol across several
sessions still changes the guarantee boundary: Hibana checks each session, not
the original choreography as one global protocol.
Hibana does not implement a network stack or a distributed algorithm. It enforces the protocol at each attached endpoint and states the carrier, deployment, codec, and scheduling conditions needed to lift that local result to a distributed guarantee.
This README is arranged by responsibility:
| Reader | Start here | You will find |
|---|---|---|
| Evaluating Hibana | Model | What it enforces, what remains external, and why endpoint types stay small |
| Writing a choreography | Protocol Language | Projection, messages, routes, parallel flows, and repetition |
| Implementing a role | Endpoint Operations | send, recv, offer, branch handling, and failure behavior |
| Integrating a protocol | Runtime Boundary | Storage, attach, sessions, resolvers, and observation |
| Implementing a carrier | Transport | The complete five-operation contract and delivery premises |
| Auditing a deployment | Guarantees | Local guarantees, conditional distributed guarantees, resource use, and verification |
Quick Start
Add the crate:
The crate uses Rust 2024 and requires stable Rust 1.95 or newer. It has no
normal dependencies and no feature-selected hosted variant.
Run the complete two-role example from a repository checkout:
ping=7, pong=8
The example is self-checking, ships in the published package, and is executed
by the release gate. Read the complete source in
examples/ping_pong.rs. Its protocol is small enough
to see in one place:
use ;
The executable example adds caller-owned runtime storage and an in-memory host
transport, attaches both role programs to one SessionId, and drives the two
endpoints with send() and recv(). An embedded deployment supplies its own
transport, storage budget, and executor; the choreography and endpoint
operations stay the same.
Model
global choreography
-> project(&choreography) once per role
-> compact RoleProgram descriptors
-> attach each role to one SessionId
-> drive Endpoint::send / recv / offer
-> commit exactly one permitted step or fail the session generation
Multiparty means peer, direction, and order come from one choreography projected for every role. Asynchronous means a successful send transfers a frame to the carrier; it does not wait for the remote receive. Affine means one live endpoint owner can advance a projected step at most once. The endpoint may be dropped, but it cannot be cloned or used to publish duplicate progress.
Hibana has two public surfaces:
| Audience | Surface | Responsibility |
|---|---|---|
| Role implementation | hibana::g, Endpoint, RouteBranch, EndpointError |
Describe messages and drive one attached role |
| Protocol integration | hibana::runtime |
Project roles, provide storage and transport, attach sessions, and install explicit resolvers |
Application code normally stays on hibana::g and Endpoint. Protocol
integration code uses hibana::runtime; it does not expose carrier state or
descriptor machinery to role code. docs.rs is the
signature reference for the same surface described here.
The temporary choreography value carries its structure in Rust while
project(&choreography) builds a compact RoleProgram<ROLE>. Endpoint futures
do not carry the choreography tree or every future payload type. Reusing one
projected artifact for many isolated sessions therefore does not multiply
endpoint types. Projection lowers the existing public DSL in one internal pass;
its flat event rows, scope markers, resolver markers, and allocation scratch do
not enter the endpoint, descriptor header, or Pico runtime state.
Protocol Language
| Form | Meaning |
|---|---|
g::send::<FROM, TO, g::Msg<LABEL, PAYLOAD>>() |
One visible asynchronous message |
g::seq(left, right) |
left precedes right |
g::par(left, right) |
Independent arms may progress concurrently |
g::route(left, right) |
One of two protocol arms |
route.resolve::<ID>() |
An explicit resolver owns a non-message choice |
body.roll() |
A guarded structural region may re-enter |
Projection rejects unsupported route shapes, ambiguous simultaneous endpoint
operations, conflicting parallel lanes, empty parallel arms, and unguarded
re-entry. Logical message labels identify choreography messages; they need not
be globally unique. A same-role send is a zero-byte local effect and must use
(). It does not hide payload data in a private queue.
Repeated regions add no iteration field to endpoint types, descriptor rows, or the eight-byte core frame header. Freshness comes from the projected execution rules plus carrier FIFO, replay exclusion, and generation isolation, not from growing every frame or endpoint.
The compact descriptor domains impose these explicit limits:
| Domain | Limit | Meaning |
|---|---|---|
| Roles | 256 | The complete u8 role domain, 0..=255 |
| Event identities | 65,535 | Dense identity domain; u16::MAX remains the absent sentinel |
| Program image | 65,535 B | Compact u16 byte-offset domain for one immutable global image |
| Atom-only program | 5,957 events | 65,535 / 11; control columns reduce this shape-dependent ceiling |
| Role image | 65,535 B per role | Compact u16 byte-offset domain for one projected role image |
| Structured scopes | Image-derived | Every scope contributes at least two five-byte markers, so the byte ceiling binds before the compact scope-id domain |
| Route commit chain | Image-derived | A u16 descriptor range; no separate u8 chain ceiling |
| Resolver identities | 65,536 | The complete u16 domain; intrinsic/dynamic authority is tagged separately in the route row |
| Physical lanes | 256 | Storage follows the exact projected lane span; lanes are reused when endpoint-role sets do not conflict and no hidden binding lanes are reserved |
| Offer frontier | Descriptor-derived | Active-key storage follows active lanes; restart-spanning visited identities follow the finite local-step domain |
| Inbound frame colors | 256 | Maximum simultaneously competing receive candidates for one source/receiver/lane key |
Frame colors are not cumulative message numbers. More than 256 ordered
messages may reuse a color; distinct sources may also reuse a color because the
runtime compares source, lane, and frame color together. Inside .roll, equal
route paths reuse one color while distinct paths of the same inbound key receive
distinct colors for elastic re-entry. Projection rejects only a frontier that
genuinely requires a 257th color for one complete inbound key. Routes remain
binary by design.
The event-identity domain is not a promise that every 65,535-event source fits
one image. A protocol is accepted only when both its global image and every
projected role image fit their byte domains; the exact event ceiling therefore
depends on its messages, scopes, dependencies, route evidence, and role views.
The internal scope-id domain contains 8,192 identities, but this is not an
additional acceptance limit: even the smallest structured scope consumes ten
program-image bytes, so a fitting image contains at most 6,553 scopes. Route
commit-chain lengths use the same compact u16 count domain and are therefore
bounded by descriptor structure rather than by an unrelated 255-entry runtime
field. Runtime route history is a packed sparse table sized by emitted
(lane, route) relations, not by active lanes × maximum route depth.
The temporary source is still a Rust type tree, but lowering stores events,
normalized closed scope markers, and resolver markers in one exact-count tagged
arena. Scope publication is atomic, and primary markers carry the proof-only arm
boundaries needed by later passes; that metadata is erased from the descriptor.
Production const capacity validation ties source counts to the exact final
column counts and byte length, Kani checks the packed count domain, and Lean
proves generally that the exact descriptor bytes dominate the source-row count.
Row contents remain the separate responsibility of translation validation. The
temporary arena therefore has no smaller independent acceptance ceiling. Its
lane matching scratch is bounded by the 256-value wire lane domain rather than
by event count.
A const fixture constructs and emits the full 5,957-event
atom-only image. Public typed fixtures separately track 289 messages and 258
parallel events under rustc's default recursion limit. A Pico-target compile
gate projects 256 linear cyclic sender handoffs, 64 handoffs per route arm, and
a 64-event rolled cycle while bounding compiler time and memory for each causal
validation path. Large generated type trees should compose balanced subtrees;
genuinely nested source semantics deeper than that compiler limit may require a
crate-level recursion_limit. The dedicated >128 scope test keeps this source
constraint separate from runtime, descriptor, stack, and SRAM measurements.
Messages And Payloads
g::Msg<L, P> names logical label L and wire payload P. Built-in exact
codecs cover (), bool, signed and unsigned integers, byte slices, and fixed
byte arrays. Fixed-width decoders reject trailing bytes. Received slices may
borrow from the carrier-owned frame for the endpoint borrow.
Custom payloads implement both contracts:
WireEncode::encode_intowrites deterministic bytes and reports their length;WirePayload::validate_payloadaccepts the exact canonical byte shape before endpoint progress commits;WirePayload::decode_validated_payloaddecodes bytes already validated;WirePayload::SCHEMA_IDnames that canonical wire contract in the descriptor.
The schema id is not a cross-binary Rust nominal type id and is not sent in the
core frame header. Incompatible encodings or validation rules require distinct
ids. Different Rust wrappers may share an id only when they deliberately
implement the same canonical bytes and validation. Schema 0 belongs to the
exact zero-byte unit schema.
This complete custom fixed-width codec illustrates the contract:
use ;
;
Codec correctness remains the codec implementor's responsibility. Hibana checks that each operation uses the schema id projected for that event and that the decoder accepts the received bytes before committing progress.
Endpoint Operations
The role API is deliberately small:
| Operation | Result and commit rule |
|---|---|
Endpoint::send::<M>(&payload) |
Commits after the descriptor accepts M and the carrier accepts the frame |
Endpoint::recv::<M>() |
Returns M::Payload::Decoded after carrier evidence, M, and its payload all match |
Endpoint::offer() |
Returns a RouteBranch preview without committing by itself |
RouteBranch::label() |
Reports the selected arm's first logical message label |
RouteBranch::send / recv |
Consumes the preview and commits the selected arm's first visible step |
Inside an async role function, ordinary message flow is direct:
use ;
async
Endpoint progress happens when send(), recv(), or a route branch first-step
operation succeeds. Dropping an unpolled send publishes no progress. A dropped
route preview, rejected operation, or successful requeue(...) consumes no
protocol step.
Route Choice
Prefer in-band choice: make the message that selects a branch its first visible
action. RouteBranch::label() then reports that selected arm's first logical
message label, and the first send or receive is performed through the branch.
Payload contents, queue position, and carrier observations are never branch
authority.
For example, this route is selected by the first message visible to role 1:
use g;
let accepted = ;
let rejected = ;
let routed = route;
The receiving role previews, inspects, and consumes that selected first step:
use ;
async
When a timer, readiness signal, budget, or another non-message signal owns the
choice, mark the route with .resolve::<ID>() and install a typed
ResolverRef::<ID>::decision_state(...). Resolver failure rejects the step; it
does not select another arm. Resolver state is local input, so roles that act
before receiving in-band branch evidence need deployment-level agreement on
the decision.
Parallel And Repeated Regions
g::par(left, right) combines independent flows. Projection assigns logical
lanes and rejects simultaneous local operations that cannot be selected
exactly. The arms are not threads and do not choose an executor; they describe
protocol independence that the attached roles may drive concurrently.
use g;
let left = ;
let right = ;
let independent = par;
.roll() marks a guarded structural region that may re-enter. For an explicit
route resolver, resolve the route first and roll the surrounding region second:
use g;
const ROUTE_DECISION: u16 = 7;
let repeated = route
.
.roll;
The reverse call order is unavailable because resolve::<ID>() belongs to a
route value, not to the rolled result. Nested repeated regions follow the same
rule. An intentional infinite repeated region is valid protocol behavior, so
Hibana does not claim that every session terminates.
Runtime Boundary
The runtime borrows one caller-provided byte region and derives its internal
layout from the projected descriptors. SessionKitStorage::uninit().init() is
the single construction path. SessionKit::rendezvous(...) binds the storage
region and one transport. RendezvousKit::enter(...) attaches a projected role
to a session.
SessionKit and its endpoints belong to one local runtime owner; they are not
shared concurrent handles. Interrupts, worker threads, and device callbacks
communicate through transport-owned state and wake the executor through stored
wakers. The executor itself is integration-owned.
The runnable example uses this complete construction sequence after projection:
use ;
let mut slab = ;
let mut storage = uninit;
let kit = storage.init;
let rendezvous = kit
.rendezvous
.expect;
let session = new;
let client = rendezvous
.enter
.expect;
let server = rendezvous
.enter
.expect;
InMemoryTransport, client_program, and server_program are defined by the
runnable example. A deployment replaces only the transport and measured slab
budget. SessionKitStorage, the choreography, projection, attach sequence, and
endpoint API are unchanged. An undersized slab produces AttachError; Hibana
does not substitute a smaller layout or hidden allocation.
The first local attach binds a session generation to one exact compiled
program image. A byte-different image or a second live attach for the same
(rendezvous, SessionId, role) is rejected. Dropping an endpoint releases its
lease. Resolver-dependent local roles must be attached before first resolver
execution seals local membership.
| Boundary | Hibana owns | Integration owns |
|---|---|---|
| Choreography | Projection and exact local descriptor admission | Distributing the accepted role images |
| Endpoint | Affine, fail-closed progress | Driving enabled operations fairly |
| Payload | Schema identity and validation at the endpoint | Correct canonical codec implementations |
| Carrier | Framed header checks; unique lane/label/schema interpretation for headerless ingress; exact descriptor event admission in both cases | Peer binding, FIFO delivery, replay exclusion, generation isolation, and closure notification |
| Security | No hidden security claim | Authentication, cryptography, admission control, and failure detection |
Transport
Transport owns byte buffers, framing, readiness, ingress demultiplexing, and
wakeups. Hibana owns choreography meaning and route authority. Transport
implementations provide two associated handle types and five operations:
| Operation | Required behavior |
|---|---|
open(PortOpen) |
Create Tx/Rx handles bound to the descriptor-derived local role, SessionId, and lane |
poll_send(tx, Outgoing, cx) |
Progress one frame; Ready(Ok(())) transfers it to carrier ownership, while Pending retains no payload pointer |
cancel_send(tx) |
Remove transport-owned state for a dropped pending send, or retire the logical direction if bytes are already irrevocable |
poll_recv(rx, cx) |
Return one borrowed ReceivedFrame and store the current waker whenever the operation parks |
requeue(rx) |
Make the most recently returned frame observable again on the same handle after a zero-commit rejection |
PortOpen exposes local_role(), session_id(), and lane(). Outgoing
exposes frame_label(), target_role(), lane(), and payload(). The handles
returned by open may borrow buffers, device state, DMA records, and wakers
from the transport owner, so no allocation or transport-specific future type
enters Hibana's endpoint API.
After poll_send returns Pending, a later poll supplies the same encoded
content again, but its scratch address may differ. The transport may retain its
own progress in Tx; it must not retain the prior Payload pointer.
Receive evidence has two explicit construction paths:
use ;
let direct = deterministic;
let framed = framed;
ReceivedFrame::deterministic(...) is valid only when direct recv() has one
live descriptor, or after RouteBranch::recv() already owns one materialized
receive descriptor. Route offer and unresolved route demultiplexing require
ReceivedFrame::framed(...) evidence. The core header is exactly eight
carrier-owned bytes:
session id (4 bytes, big endian) | lane | source role | target role | frame label
The transport stores the PortOpen facts needed to build or validate that
framing. A framed receive is checked against the endpoint's exact session, lane,
source, target, frame label, descriptor event, logical label, and schema before
progress commits. A deterministic receive does not claim to observe source,
target, or frame label: its lane-bound Rx handle plus the requested logical label
and schema must identify exactly one enabled descriptor receive. Zero or multiple
matches fail closed. Peer authenticity and affine delivery remain carrier-profile
premises in both cases; reordering, repetition, and mismatch are not repaired
into ordinary progress.
A successful poll_send proves carrier acceptance, not remote receipt. To lift
local enforcement to global fidelity and progress, a concrete carrier must
also provide:
- expected peer and direction binding;
- FIFO delivery within each mapped logical direction;
- no unsolicited replay and no frame leakage across carrier generations;
- exactly one observation for each delivered frame;
- eventual delivery of accepted frames or observable terminal closure;
- receiver wakeup after accepted frames drain or are quarantined on closure.
Fresh transport-instance state is a sufficient carrier generation. Address or
path changes may remain inside one generation. Reusing a SessionId after
retirement requires carrier state that cannot expose a frame from the retired
generation. A multiplexed carrier may retire one logical direction while
unrelated sessions remain live.
Protocol-invisible liveness detection belongs to the transport. A wait that
cannot progress returns TransportError from poll_send or poll_recv; it
does not create a hidden timeout branch. Returning Pending forever after
known peer closure does not satisfy the closing contract.
Hibana does not require an in-band protocol-image handshake. A deployment may establish exact role-image agreement through its build artifact, authenticated manifest, or an application protocol. This keeps bootstrap policy out of the core and permits carriers with different framing requirements.
The Unix datagram carrier is an executable conformance example for peer binding, FIFO delivery, replay exclusion, closure wakeup, and generation isolation. It demonstrates that the contract is realizable; it is not a mandatory dependency or universal proof of third-party transports.
External Route Resolvers
An explicit resolver connects a non-message decision owner to a route marked
with .resolve::<ID>(). The id is checked against the projected role program,
and the state reference lives for the runtime configuration lifetime.
use ;
const ROUTE_RESOLVER: u16 = 7;
let state = RouteState ;
let resolver = decision_state;
rendezvous.set_resolver?;
Register against the exact RoleProgram that contains the resolver site.
ResolverRef::decide() permits typed resolver owners to compose other typed
resolver owners without exposing erased storage. Resolver rejection is
terminal evidence for that attempted endpoint step and never grants alternate
route authority.
A resolver registered in one rendezvous does not establish agreement with a remote device. If several roles act before receiving an in-band indication, the deployment or application protocol must supply the same decision to those resolver owners.
Sessions, Reconfiguration, And Observation
A projected descriptor is a finite session template, not a singleton runtime
instance. Distinct SessionId values have independent cursors, queues, leases,
and failure domains. Resolver registrations belong to the exact role program
within one rendezvous and may deliberately read application state shared across
sessions. Retrying an interaction or changing the finite participant set
creates a fresh session; changing the choreography also creates a fresh
projected artifact.
Persistent application data, membership policy, scheduling, restart policy, and algorithm invariants remain application-owned. Larger systems may compose explicit families of finite sessions, but each session keeps its own protocol guarantee. This is an application architecture, not an equivalent encoding of one global choreography across those sessions.
RendezvousKit::tap() returns a read-only iterator over the latest 21 public
16-byte evidence values. The ring stores 12-byte records and rebuilds their
monotonic timestamps while reading, so its 252-byte storage stays within the
256-byte budget. Events cover endpoint operations, carrier observations,
faults, lanes, route selection, and resolver decisions. Public code may read
records but cannot construct or push them. Tap is diagnostic evidence; it
cannot select a route or authorize progress.
Failure Semantics
Each public boundary reports its own error instead of widening all failures into one catch-all type:
| Boundary | Error | Meaning |
|---|---|---|
rendezvous / enter |
AttachError |
Storage, descriptor image, role lease, or attach admission failed; no endpoint is returned |
set_resolver / resolver callback |
ResolverError |
Registration failed or the decision owner rejected the route step |
poll_send / poll_recv / requeue |
TransportError |
The carrier reports offline, deadline, capacity, or fatal I/O evidence |
send / recv / offer / branch operation |
EndpointError |
The current session generation cannot continue through that endpoint |
EndpointError is terminal diagnostic evidence for the current session
generation. A codec mismatch, descriptor mismatch, or carrier failure poisons
that generation and wakes local waiters. Remote cancellation termination also
requires the carrier to make peer closure observable after accepted frames are
drained or quarantined.
There is no public same-generation retry, reselection, timeout, or cancellation operation. Errors are not route arms. A fresh attempt uses a fresh session generation; a protocol-visible timeout or cancellation is expressed as an ordinary choreography message or explicit route decision.
Guarantees
For every attached endpoint, Hibana enforces:
- exactly one permitted descriptor transition for each successful operation;
- zero transitions for previews, rejection, drop before commit, and requeue;
- fail-closed checks of peer, direction, lane, event, label, schema, and payload;
- no duplicate publication by one endpoint owner;
- first-fault preservation and terminal local waiter wakeup;
- isolation between live
SessionIdgenerations in one runtime.
project(&choreography) rejects unsupported or ambiguous choreographies. The
machine-checked global theorems apply to exact role images accepted by the
independent protocol artifact checker.
These guarantees do not silently absorb external responsibilities:
| Claim | Additional requirement |
|---|---|
| Exact local protocol enforcement | All endpoint operations go through Hibana |
| Cross-role fidelity | Every role uses the exact accepted image and matching canonical schemas |
| Distributed cancellation completion | The carrier drains or quarantines accepted frames and makes closure observable |
| Session progress | The carrier remains live and the executor fairly polls enabled operations |
| Deployment security | The integration authenticates peers and protects its medium as required |
When Deadlock Freedom Holds
Successful projection alone is not a distributed deadlock-freedom guarantee. Hibana provides per-session protocol deadlock freedom when all of the following hold:
- every role executes the exact accepted image of the same projectable choreography;
- peers agree on each canonical wire schema and use conforming codecs;
- the carrier binds the expected peers and directions, preserves FIFO order, excludes replay across session generations, and eventually delivers each accepted frame or reports terminal closure;
- the executor eventually polls operations that remain enabled.
Under those conditions, every reachable live, unfinished protocol state has an
enabled transition. An intentional infinite .roll may continue forever, and
application cycles spanning separate sessions remain application scheduling
concerns.
Measured Footprint
The repository compiles the public choreography and projection API for
thumbv6m-none-eabi without an allocator, SDK, host transport, or target-only
Hibana API. With Rust 1.95.0, the tracked release measurements are:
| Hibana-owned quantity | Current | Release ceiling |
|---|---|---|
SessionKitStorage |
24 B | 32 B |
| Fixed per-rendezvous storage, including the 252 B tap records | 412 B | 952 B |
| Peak live runtime slab across tracked heavy shapes | 2,311 B | 4,323 B |
| Runtime operation stack high-water | 2,847 B | 3,663 B |
| Modeled runtime SRAM envelope | 5,530 B | 8,954 B |
| Minimal linked protocol artifact | 352 B | 2,048 B |
| Largest linked artifact in the tracked protocol matrix | 1,824 B | 16,384 B |
Complete no-default libhibana.rlib sections |
98,936 B | 169,965 B |
Library .data + .bss |
0 B | 0 B |
The linked-artifact and library rows are thumbv6m-none-eabi release
measurements. The complete rlib is not the flash cost paid by one linked
protocol. Stack high-water is measured around runtime operations on the pinned
aarch64-unknown-linux-gnu measurement host used by the release gate.
The modeled SRAM envelope combines the target's Hibana .data/.bss, storage
owners, one measured live slab shape, and runtime operation stack. Component
maxima may come from different shapes and must not be added as one observed
run. Application state, concrete transport buffers, executor state, interrupt
stacks, codec scratch, and platform startup are outside this Hibana-owned
envelope.
examples/pico/src/lib.rs is the tracked no_std
projection sample. The release gate regenerates these measurements and rejects
any value above its ceiling.
Verification
Hibana uses complementary tools rather than attributing every guarantee to one checker:
| Tool | Responsibility |
|---|---|
| Lean | Global and role-local semantics, projection artifacts, fidelity, progress, cancellation, and repeated-region freshness |
| Kani/CBMC | Bounded exhaustive checks of compact prepare/commit kernels and ownership state |
| Miri | Strict provenance, borrowing, drop, cancellation, waiter, and callback re-entry behavior |
| Rust tests and release gates | Executable examples, compile-time rejection, carrier conformance, package contents, and resource regressions |
The Lean verification guide summarizes the checked boundary, assumptions, generated artifacts, and machine-checked claim inventories. Each tool is evidence only for the part it checks. Kani and Miri strengthen the Rust implementation evidence; neither is presented as a Lean proof of arbitrary Rust source.
The static Lean theorem package and exact descriptor/kernel certificates are kernel-checked. Finite executable regressions and concrete finite-closure witnesses that use the pinned native evaluator are isolated and audited rather than presented as kernel-only proofs.
Release gates discover the Lean, Kani, and Miri inventories from their canonical sources, pin Lean claim types and axiom closures, and reject missing or changed obligations. Current inventory counts are emitted by the gates instead of being duplicated in documentation.
Build And Release
The crate has no normal dependencies and no feature-selected host API. Useful checks from a repository checkout are:
Compile the tracked embedded projection with the same public API:
Run the complete non-Kani release gate with the pinned toolchains:
It executes the runnable example, Rust tests, no_std target checks, rustdoc,
package checks, Miri, Lean, the Unix carrier conformance suite, and resource
measurements. Kani/CBMC is a separate required CI job and can be run locally
after installing the version recorded in .github/kani-version:
Scope
Hibana covers finite-role sessions executed through its endpoint API. It does not claim correctness for code that bypasses the endpoint, arbitrary transport implementations, application algorithms, carrier authentication or cryptography, failure-detector accuracy, unbounded role sets, or channel delegation. Cross-binary agreement is defined over canonical wire schemas, not Rust nominal type identity.
The exact public position is therefore: a compact choreography-derived runtime enforcement kernel for finite-role affine asynchronous multiparty protocols, with distributed fidelity, progress, and cancellation conclusions stated under explicit carrier, deployment, codec, and scheduling requirements.
Hibana is licensed under either Apache-2.0 or MIT, at your option.