Skip to content

fix(session): AimX over serial — every reconnect gets its events (#328) - #350

Merged
lxsaah merged 6 commits into
mainfrom
feat/328-serial-session-reset
Oct 24, 2026
Merged

lxsaah merged 6 commits into
mainfrom
feat/328-serial-session-reset

Conversation

@lxsaah

@lxsaah lxsaah commented Oct 24, 2026 •

Copy link
Copy Markdown
Member

Description

Fixes #328: over a serial line (UART, e.g. the ST-LINK virtual COM port of a NUCLEO board), every other client that reconnected without a board reset got no events. Its subscription was acknowledged, but nothing arrived.

This merges the feature branch feat/328-serial-session-reset. Each fix was reviewed as its own PR into that branch.

PR What
#345 An ended pump only removes its own subscription (generation guard); a sub whose ID is still live is refused with Denied
#346 A second handshake on a live connection starts a new session (Session::starts_session, AimX: hello)
#347 A subscription whose stream ends on its own is reported to the client (Internal under the subscribe ID)
#348 embassy-mqtt-connector-demo: the sensor records get a subscriber slot for remote access
#349 aimdb-client: a subscription the server ended no longer reads as "engine/transport failure"
docs Changelogs (aimdb-core, aimdb-serial-connector, aimdb-client, root) and the "Sessions on a line that never closes" section in the serial connector docs

Causes

  1. No session boundary. A UART never closes, so the serial server serves one session for the firmware's lifetime. A departed client's subscriptions kept streaming and held their buffer subscriber slots.
  2. IDs collide. cancels was keyed by the client's subscription ID, and every client starts at 1. The new subscribe replaced the old entry, and the old pump's cleanup then removed the new one.
  3. A refused subscriber is silent. Buffer::subscribe() can't fail. Without a free SPMC slot, the stream ended at once, and the client was never told.

On the board, all three combined. The analysis is in #328.

Behaviour changes

  • A hello on a connection that already had one ends that connection's previous session: its subscriptions stop and their queued events are dropped. This applies to every transport. On UDS/TCP it doesn't happen with a well-behaved client.
  • A sub whose ID is still live gets Denied instead of silently replacing the live subscription.
  • A subscription whose source ends gets a terminal Internal error instead of just stopping.
  • aimdb-client: a subscription's terminal Internal reads "the server ended the subscription (its source closed or could not be opened)". Calls keep "engine/transport failure".
  • New trait method Session::starts_session(method), with a default (false), so not breaking.

Tests

  • aimdb-core/tests/session_engine.rs: six new tests (live ID refused, ID reused after unsub, second handshake, first handshake, ended subscription reported, dropped subscription not reported).
  • aimdb-serial-connector/tests/reconnect.rs (new): three clients one after another on a pipe that stays open like a UART, each with exactly its values from its own subscription.
  • aimdb-client: unit tests for the subscription and call error texts.
  • Each fix's new tests fail on the code before it.

Live on a NUCLEO-H563ZI

Four aimdb watch command.temp.indoor clients over the ST-LINK UART, one after another without a board reset, three commands published over MQTT per client:

Client main This branch
A 3/3 3/3
B 0/3 3/3
C 3/3 3/3
D 0/3 3/3

Known gap (documented, not fixed)

A client that leaves without another one connecting stays invisible: its subscriptions keep streaming into the UART until the next hello. Detecting that would need a timeout, and the session engine is deliberately timer-free.

Verified locally

  • All Makefile tests for aimdb-core, aimdb-client, aimdb-uds-connector, aimdb-tcp-connector, aimdb-serial-connector, aimdb-websocket-connector, aimdb-cli and aimdb-mcp.
  • Clippy (-D warnings) for aimdb-core and aimdb-serial-connector, including thumbv7em.
  • cargo doc -D warnings for aimdb-core (including --all-features) and aimdb-serial-connector.
  • This is the first full CI run over all of "[BUG] AimX over serial: every other reconnect gets no events until the board is reset" #328: the PRs into the feature branch don't trigger CI.

Related Issue

Checklist

  • I have read the CONTRIBUTING.md document.
  • My code follows the project's coding standards.
  • I have added tests to cover my changes.
  • All new and existing tests passed (make check). The affected crates pass locally; the full run is left to CI.
  • I have updated the documentation accordingly.

🤖 Generated with Claude Code

https://claude.ai/code/session_01YPDjQ947yKjLLAq3Xzgu3e

@lxsaah lxsaah changed the title fix(session): a pump's cleanup only removes its own subscription; refuse a live id (#345) fix(session): AimX over serial — every reconnect gets its events (#328) Oct 24, 2026
- Changelogs: `aimdb-core` (session engine fixes, `Session::starts_session`),
  `aimdb-serial-connector`, `aimdb-client`, and the root changelog.
- `aimdb-serial-connector`: "Sessions on a line that never closes" in the
  crate docs: a client's `hello` starts a new session; a client that leaves
  without another connecting keeps its subscriptions until the next `hello`;
  size subscriber slots for remote access on top of a record's taps and links.
- `aimdb-core`: drop a redundant explicit doc link target on
  `Session::starts_session`, which failed `make doc` (`-D warnings`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YPDjQ947yKjLLAq3Xzgu3e
@lxsaah
lxsaah merged commit b9d64a8 into main Oct 24, 2026
10 checks passed
@lxsaah
lxsaah deleted the feat/328-serial-session-reset branch October 24, 2026 16:29
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.

"[BUG] AimX over serial: every other reconnect gets no events until the board is reset"

1 participant