Skip to content

core(reply): typed single-shot reply port — deletes Box<dyn Any> erasure (#115)#140

Merged
joeldsouzax merged 14 commits into
mainfrom
core-reply-115
Jul 5, 2026
Merged

core(reply): typed single-shot reply port — deletes Box<dyn Any> erasure (#115)#140
joeldsouzax merged 14 commits into
mainfrom
core-reply-115

Conversation

@joeldsouzax

Copy link
Copy Markdown
Contributor

What

Rebuilds reply (#115) as the typed, single-shot reply-channel primitive in bombay-core, following the epic #122 rigor contract. Kameo's Box<dyn Any> Reply-trait erasure (~1,048 LOC, ~40 std impls + a derive) is deleted — a typed per-variant reply port erases nothing, so any R: Send + 'static is a reply.

Depends on #113 (error model), now on main.

Design (spec: docs/superpowers/specs/2026-07-05-reply-channel-primitive-design.md, ADR-0002)

  • ReplySender<R, E = Infallible> / ReplyReceiver<R, E> / reply_channel() over tokio::sync::oneshot<Result<R, E>> — the oneshot kept an impl detail behind the wrappers (mailbox channel-seam philosophy, ADR-0001).
  • send / send_err consume self → a double-reply is a compile error (proved by a compile_fail doctest), strictly stronger than kameo's runtime "second send is a no-op".
  • A gone asker is reported as AskerGone (unit signal) — a reply to a vanished asker is un-actionable, and handing the payload back would force a mutation-dead match arm.
  • recv maps the oneshot outcome into core(error): rebuild from kameo reference — typed error domains #113's AskError: Ok(Ok r)→Ok(r) · Ok(Err e)→Handler(e) · sender-dropped→Interrupted. Generic over the never-produced M, so core(request): rebuild from kameo reference — ask/tell builders #118 gets a ready-to-return AskError<M, E>.

Re-scope (recorded on #115)

DelegatedReply / ForwardedReply are deferred to #116/#118 — in the reference they are produced only by Context::reply_sender/forward, which need ActorRef + Message; shipping them now would be dead-until-later types testable only for construction (YAGNI, CLAUDE rule 4). They land wired + tested with their machinery.

Tests (TDD, 4 cross-cutting categories first)

8 tests: @bug typed-handler-error probe, Ok-reply sequence, recv-parks-then-send-wakes (reverse ordering — the oneshot waker path the buffered-value tests skip), drop→Interrupted lifecycle (never hangs), send-to-gone-asker defensive, Infallible (tell) roundtrip, 2-thread barrier'd linearizability, and a proptest over all three handler actions; plus the compile_fail doctest.

Mutation: 0 missed (cargo-mutants on reply.rs). No bombay-owned atomics → loom N/A (delegated to tokio oneshot), same as #113.

Benched (benches/reply.rs)

The typed port is ≈1.5× faster than kameo's Box<dyn Any> erasure mechanism — 21.4 µs vs 32.8 µs per 1k reply roundtrips (the box-on-send + downcast-on-recv the redesign removes). Measured, recorded in ADR-0002 — the redesign's justification, substantiated rather than asserted.

Gate

nix flake check green. No README change — the rebuilt spine is not behind the public umbrella yet (same as #113/#114/#133); coverage recorded in docs/testing/coverage-baseline.md.

Typed single-shot reply port over tokio::sync::oneshot<Result<R, E>> —
deletes kameo's Box<dyn Any> Reply-trait erasure; recv maps into #113's
AskError. Delegated/Forwarded deferred to #116/#118 (recorded on #115).
@joeldsouzax joeldsouzax merged commit 1d49ce4 into main Jul 5, 2026
6 checks passed
@joeldsouzax joeldsouzax deleted the core-reply-115 branch July 5, 2026 19:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant