Skip to content

feat(channel): drive a Channel through a recv/handle/send loop (#564)#672

Open
real-venus wants to merge 1 commit into
GeniePod:mainfrom
real-venus:feat/channel-serve-loop
Open

feat(channel): drive a Channel through a recv/handle/send loop (#564)#672
real-venus wants to merge 1 commit into
GeniePod:mainfrom
real-venus:feat/channel-serve-loop

Conversation

@real-venus

@real-venus real-venus commented Jul 9, 2026

Copy link
Copy Markdown

What changed

Adds genie_core::channel::serve_channel, the recv → handle → send driver loop over the Channel trait. A transport now only implements Channel and supplies a per-turn handler; serve_channel owns the loop. This is the primitive the module's own docs point to — ChannelRegistry explicitly does not drive channels, and ScriptedChannel exists to exercise wiring without
sockets, but nothing tied them together.

  • Handler (application) errors are per-turn: logged and skipped, so one bad turn does not close the channel.
  • send (transport) errors are fatal: the loop stops and returns the error.
  • Returns the count of responses successfully delivered.

Resolving #564 incrementally (channel-driver step for M2). No existing transport behavior changes — this only adds the shared loop the voice/HTTP/Telegram handlers will adopt when ported onto Channel.

Real Behavior Proof

  • cargo fmt --all -- --check — clean (Linux, rust 1.96)
  • cargo clippy --workspace --all-targets --locked -- -D warnings — clean
  • cargo clippy -p genie-core -p genie-ctl --no-default-features --all-targets --locked -- -D warnings — clean (chat-only axis)
  • cargo test --workspace --locked --all-targets — passing, incl. 4 new tests in channel::serve
  • cargo test --workspace --locked --docserve_channel doctest compiles

New tests in crates/genie-core/src/channel/serve.rs:

  • drives_every_queued_turn_and_records_responses — three queued turns delivered in order
  • closed_channel_delivers_nothing — empty inbox returns 0
  • handler_error_skips_the_turn_without_stopping_the_channel — a failing turn is skipped, others still delivered
  • send_error_is_fatal_and_stops_the_loop — a transport send failure ends the loop after one attempt

Verified on x86_64 Linux (rust 1.96) reproducing the CI job set. Not Jetson-tested: this is a transport-agnostic control-flow addition with no hardware surface.

…Pod#564)

Add `serve_channel`, the loop that owns a single Channel end to end: `recv`
a turn, route it through a per-turn handler, `send` the response, repeat
until the channel closes. `ChannelRegistry` deliberately does not drive
channels and `ScriptedChannel` exists to exercise wiring without sockets,
but nothing connected the two -- this is that missing primitive.

Error handling splits along the transport/application seam. A handler
(application) error is per-turn: it is logged and the turn skipped, so one
bad turn does not tear the channel down. A `send` (transport) error is
treated as a dead channel and ends the loop. Returns the number of
responses delivered.

Existing transport behavior is unchanged; this only adds the shared driver
they will adopt when ported onto Channel (GeniePod#564).

@matedev01 matedev01 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — adds serve_channel, the recv→handle→send driver the channel module's docs already pointed to (ChannelRegistry deliberately doesn't drive; ScriptedChannel exercises wiring). Error split is right: handler (application) errors are per-turn (logged, skipped), send (transport) errors are fatal and end the loop; returns the delivered count. Incremental step on #564, no transport behavior change. Verified: clippy -D warnings clean, channel unit tests (19) + serve_channel doctest pass, fmt clean.

@matedev01

Copy link
Copy Markdown
Contributor

Reviewed and the driver loop itself is good — approving in spirit. The only thing blocking merge is a CHANGELOG.md conflict from other PRs that landed since (the serve.rs/mod.rs code merges clean). Please rebase onto main and re-resolve the changelog entry; I'll merge as soon as it's green.

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.

2 participants