wireframe 0.3.0

Simplify building servers and clients for custom binary protocols.
Documentation
# Client Message API with Correlation Identifiers

This Execution Plan (ExecPlan) is a living document. The sections `Progress`,
`Surprises & Discoveries`, `Decision Log`, and `Outcomes & Retrospective` must
be kept up to date as work proceeds.

## Purpose / Big Picture

Wireframe's client library needs async `send`, `receive`, and `call` APIs that
encode `Message` implementers, forward correlation identifiers, and deserialize
typed responses using the configured serializer. This work extends the existing
client runtime to support envelope-aware messaging with automatic correlation
ID generation and validation.

Success is observable when:

- The client provides `send_envelope`, `receive_envelope`, and `call_correlated`
  methods that work with the `Packet` trait.
- Correlation IDs are auto-generated when not present on outbound envelopes.
- Response correlation IDs are validated against request IDs in
  `call_correlated`.
- A `CorrelationMismatch` error variant exists for mismatched correlation IDs.
- Unit tests cover correlation ID generation, stamping, and mismatch detection.
- Cucumber behavioural tests validate the messaging flow.
- `docs/users-guide.md` documents the new client APIs.
- `docs/roadmap.md` marks 10.2.1 as done.

## Progress

- [x] 2026-01-09 Draft ExecPlan for 10.2.1.
- [x] 2026-01-09 Add `correlation_counter: AtomicU64` field to
      `WireframeClient`.
- [x] 2026-01-09 Add `CorrelationMismatch` error variant to `ClientError`.
- [x] 2026-01-09 Implement `next_correlation_id()` method.
- [x] 2026-01-09 Implement `send_envelope<P: Packet>()` with auto-correlation.
- [x] 2026-01-09 Implement `receive_envelope<P: Packet>()` method.
- [x] 2026-01-09 Implement `call_correlated<P: Packet>()` with validation.
- [x] 2026-01-09 Add unit tests in `src/client/tests/messaging.rs`.
- [x] 2026-01-09 Add Cucumber feature and steps for client messaging.
- [x] 2026-01-09 Update `docs/users-guide.md` with client messaging API
      documentation.
- [x] 2026-01-09 Mark roadmap 10.2.1 as done.
- [ ] Run full validation (fmt, lint, test).

## Surprises & Discoveries

- The existing `send`, `receive`, and `call` methods work with raw `Message`
  types and do not use correlation IDs. The new envelope-aware APIs are
  additive and do not modify existing behaviour, preserving backwards
  compatibility.

- The `Packet` trait already provides `correlation_id()`, `into_parts()`, and
  `from_parts()` methods that enable generic envelope manipulation without
  knowing the concrete type.

- The `Envelope` struct's `payload()` method consumes `self`, requiring use of
  `into_parts()` to extract the payload while preserving other fields.

## Decision Log

- Decision: Add envelope-aware APIs (`send_envelope`, `receive_envelope`,
  `call_correlated`) alongside existing raw message APIs rather than modifying
  them. Rationale: Preserves backwards compatibility for existing client code
  that doesn't need correlation. Date/Author: 2026-01-09 (Codex).

- Decision: Use per-client `AtomicU64` counter starting from 1 for correlation
  ID generation, using `Ordering::Relaxed` for atomic increments. Rationale:
  Avoids global contention and ensures uniqueness within a connection. The
  counter starts at 1 so that 0 can be distinguished from auto-generated IDs if
  needed. `Ordering::Relaxed` is sufficient because correlation IDs only
  require per-connection uniqueness, not cross-thread ordering or
  synchronization with other memory operations. Date/Author: 2026-01-09 (Codex).

- Decision: Validate correlation ID match in `call_correlated` and return
  `CorrelationMismatch` error on failure. Rationale: Mismatched correlation IDs
  indicate protocol violations or interleaved responses. Explicit error variant
  enables callers to handle the case appropriately. Date/Author: 2026-01-09
  (Codex).

- Decision: `send_envelope` returns the correlation ID that was used (auto-
  generated or explicit). Rationale: Allows callers to track correlation
  without inspecting the envelope after mutation. Date/Author: 2026-01-09
  (Codex).

## Outcomes & Retrospective

Not started yet.

## Context and Orientation

The wireframe client runtime (`src/client/runtime.rs`) already provides basic
`send`, `receive`, and `call` methods that work with raw `Message` types. These
methods use the configured `Serializer` for encoding/decoding but do not handle
correlation identifiers.

The server-side uses the `Envelope` struct (`src/app/envelope.rs`) and `Packet`
trait for routing and correlation. The `Envelope` contains:

- `id: u32` - Message type ID for routing
- `correlation_id: Option<u64>` - Optional correlation ID for request/response
  matching
- `payload: Vec<u8>` - Serialized message payload

The `CorrelatableFrame` trait (`src/correlation.rs`) provides generic access to
correlation IDs on frames.

Key references:

- `src/client/runtime.rs` - Client runtime implementation
- `src/client/error.rs` - Client error types
- `src/app/envelope.rs` - Envelope and Packet trait definitions
- `src/correlation.rs` - CorrelatableFrame trait
- `docs/multi-packet-and-streaming-responses-design.md` - Correlation ID
  requirements
- Testing guidance: `docs/rust-testing-with-rstest-fixtures.md`,
  `docs/behavioural-testing-in-rust-with-cucumber.md`

## Plan of Work

Start by adding the correlation ID counter field to `WireframeClient` and
initializing it in the builder. Add the `CorrelationMismatch` error variant to
`ClientError`. Then implement the three new methods: `send_envelope` (with
auto-correlation), `receive_envelope`, and `call_correlated` (with validation).
Add unit tests covering the new functionality. Add Cucumber behavioural tests.
Finally, update documentation and mark the roadmap item as done.

## Concrete Steps

1. Add `correlation_counter: AtomicU64` field to `WireframeClient` struct in
   `src/client/runtime.rs`.

2. Initialize the counter to 1 in the builder's `connect` method in
   `src/client/builder.rs`.

3. Add `CorrelationMismatch { expected: Option<u64>, received: Option<u64> }`
   variant to `ClientError` in `src/client/error.rs`.

4. Implement `next_correlation_id(&self) -> u64` method that atomically
   increments and returns the counter.

5. Implement `send_envelope<P: Packet>(&mut self, envelope: P) -> Result<u64,
   ClientError>`:
   - Auto-generate correlation ID if not present
   - Serialize and send the envelope
   - Return the correlation ID used

6. Implement `receive_envelope<P: Packet>(&mut self) -> Result<P, ClientError>`:
   - Receive and deserialize the frame as the packet type
   - Invoke error hook on failures

7. Implement `call_correlated<P: Packet>(&mut self, request: P) -> Result<P,
   ClientError>`:
   - Send request with auto-correlation
   - Receive response
   - Validate correlation ID matches
   - Return `CorrelationMismatch` error on mismatch

8. Add unit tests in `src/client/tests/messaging.rs`:
   - Test correlation ID generation (sequential, unique)
   - Test auto-stamping on outbound envelopes
   - Test explicit correlation ID preservation
   - Test correlation mismatch detection
   - Test error hook invocation on mismatch
   - Test round-trip with various payload sizes

9. Add behavioural tests using existing test infrastructure:
   - Create `tests/features/client_messaging.feature`
   - Create `tests/worlds/client_messaging.rs`
   - Create `tests/steps/client_messaging_steps.rs`
   - Register world in `tests/cucumber.rs` and `tests/world.rs`
   - Note: Uses current Cucumber infrastructure pending rstest-bdd migration
     per ADR-003.

10. Update `docs/users-guide.md` with client messaging API documentation:
    - Add section on correlation ID support
    - Document `send_envelope`, `receive_envelope`, `call_correlated` methods
    - Provide usage examples

11. Update `docs/roadmap.md` to mark 10.2.1 as done.

## Validation and Acceptance

Acceptance requires all of the following:

- New public methods compile and are documented with examples.
- Unit tests cover correlation ID generation, stamping, and validation.
- Behavioural tests for client messaging pass.
- Documentation updated in users guide.
- Roadmap item 10.2.1 marked as done.

Run validation from the repository root (use `tee` to capture full output):

    set -o pipefail
    timeout 300 make fmt 2>&1 | tee /tmp/wireframe-fmt.log
    echo "fmt exit: $?"

    set -o pipefail
    timeout 300 make markdownlint 2>&1 | tee /tmp/wireframe-markdownlint.log
    echo "markdownlint exit: $?"

    set -o pipefail
    timeout 300 make check-fmt 2>&1 | tee /tmp/wireframe-check-fmt.log
    echo "check-fmt exit: $?"

    set -o pipefail
    timeout 300 make lint 2>&1 | tee /tmp/wireframe-lint.log
    echo "lint exit: $?"

    set -o pipefail
    timeout 300 make test 2>&1 | tee /tmp/wireframe-test.log
    echo "test exit: $?"

## Idempotence and Recovery

All steps are additive and can be re-run safely. If a step fails, fix the
underlying issue and re-run only the affected command(s). Use the `tee` outputs
to locate the failure before retrying. Avoid destructive commands; if a local
change needs to be backed out, revert only the specific files edited for this
feature.

## Artifacts and Notes

Expected artifacts after completion:

- Modified `src/client/runtime.rs` with new methods and correlation counter.
- Modified `src/client/error.rs` with `CorrelationMismatch` variant.
- Modified `src/client/builder.rs` to initialize correlation counter.
- New `src/client/tests/messaging.rs` with unit tests.
- New `tests/features/client_messaging.feature` with behaviour-driven
  development (BDD) scenarios.
- New `tests/worlds/client_messaging.rs` with test world.
- New `tests/steps/client_messaging_steps.rs` with step definitions.
- Updated `docs/users-guide.md` with API documentation.
- Updated `docs/roadmap.md` with completion status.

## Interfaces and Dependencies

At the end of this work, the following public interfaces exist:

- `WireframeClient::next_correlation_id(&self) -> u64` - Generate unique ID
- `WireframeClient::send_envelope<P: Packet>(&mut self, envelope: P) ->
  Result<u64, ClientError>` - Send with auto-correlation
- `WireframeClient::receive_envelope<P: Packet>(&mut self) -> Result<P,
  ClientError>` - Receive typed envelope
- `WireframeClient::call_correlated<P: Packet>(&mut self, request: P) ->
  Result<P, ClientError>` - Request-response with validation
- `ClientError::CorrelationMismatch { expected: Option<u64>, received:
  Option<u64> }` - Error variant for mismatched IDs

The methods depend on the `Packet` trait which is implemented by `Envelope`.