Skip to content

v0.21.0+ciris.1 — the request/response contract (#55), IFAC size defaults, h2

Choose a tag to compare

@emooreatx emooreatx released this 19 Aug 00:55
· 854 commits to main since this release

The request/response contract (leviculum#55)

#55 asked for send_response to be forwarded onto the std driver. It already is — ReticulumNode::send_response, beside send_response_resource and send_file_response, public on the same impl as register_request_handler, present at the tag the issue cites; an external crate holding an Arc<ReticulumNode> compiles a call to it. Nothing was blocked.

What the issue got right is that a careful consumer searched for the verb, missed it, and had no stated contract to build a serve path against. Both are fixed here.

Findability. NodeEvent::RequestReceived said "call send_response()" without saying where it lives. It now names NodeCore::send_response and the async ReticulumNode::send_response, plus send_response_resource for bodies past the link MDU.

Contract, measured rather than asserted, on the method's own doc and pinned by leviculum-std/tests/request_response_contract.rs:

  • Ok(()) means handed to the link, not delivered. If the peer has vanished but this node has not yet processed the link's death, the reply is accepted and goes nowhere. A responder must not read Ok as proof the requester got the bytes.
  • Once the link is known dead (closed here, or a LinkClosed processed) a reply is refused with RequestError::LinkNotFound — a typed signal as soon as one is available.
  • Replying twice for one request_id is accepted, so a retrying responder needs no bookkeeping; the requester may then see the response more than once.

Catch-up to upstream master @ 352c6a62 (+3)

Per-interface IFAC size defaults (upstream Codeberg #293). Two peers that disagree on the access-code length reject each other's frames in both directions, with nothing in either log naming the cause — an IFAC-protected link that looks like it never came up. Upstream replaced a medium-inferred grouping with per-interface-type defaults checked against the reference. The fork's scoped-transit paths pass an explicit ifac_size, so the conformance harness is unaffected (6/6); deployments relying on the default should re-read it after this bump. Also: the 32-bit usize gate now covers the core suite and no longer compiles out the compression module.

Security

h2 0.4.15 → 0.4.16 for RUSTSEC-2026-0258, re-applied — a rebase takes upstream's lockfile, which reverts it. Lockfile only; h2 enters solely via lblogd → axum → hyper, not leviculum-core/leviculum-std. Now a standing per-sync check until upstream's own tree carries the bump.

Gate: core 1,644 / std 585 / request-response contract 3/3 (10× stress) / destination-lifecycle 3/3 / scoped-transit 6/6; clippy -D warnings; fmt; thumbv6m; full CI green on all platforms.