Skip to content

Add correlation IDs to frame headers#260

Closed
leynos wants to merge 2 commits intomainfrom
codex/add-correlation_id-field-to-frame-header
Closed

Add correlation IDs to frame headers#260
leynos wants to merge 2 commits intomainfrom
codex/add-correlation_id-field-to-frame-header

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Aug 4, 2025

Summary

  • include correlation IDs in packet headers so multi-packet responses can be matched to requests
  • validate correlation IDs via unit and behavioural tests
  • record correlation ID design and resilience guidance in docs and roadmap

Testing

  • make fmt
  • make lint
  • make test
  • make markdownlint
  • make nixie (fails: Cannot find module '../../third_party/mitt/mitt.js')

https://chatgpt.com/codex/tasks/task_e_688ff43688fc8322aaa82f424c41a9bd

Summary by Sourcery

Introduce a correlation_id header field across the wireframe protocol and propagate it through Packet, Envelope, service routing, and connection actor to enable matching multi-packet responses to their requests, accompanied by tests and documentation updates.

New Features:

  • Add correlation_id field to Packet trait signatures and Envelope type, updating into_parts and from_parts to include correlation support
  • Propagate correlation IDs through ServiceRequest, ServiceResponse, handler routing, WireframeApp, and ConnectionActor for multi-packet response association
  • Add unit, integration, and cucumber behavioural tests to validate correct correlation ID propagation and error handling

Enhancements:

  • Update existing examples, middleware, routing, and metadata tests to pass and echo correlation_id parameters

Documentation:

  • Document correlation ID design, validation guidance, and feature status in README, resilience guide, roadmap, and related documentation

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Aug 4, 2025

Reviewer's Guide

This PR extends the Packet trait and Envelope structures to include a request-level correlation_id, updates framing, service routing, and handler logic to propagate and validate these identifiers, adjusts existing tests and adds new behavioural tests for correlation ID handling, and revises documentation and the roadmap to reflect the new design.

Sequence diagram for request/response with correlation_id propagation

sequenceDiagram
    actor Client
    participant Server
    participant Handler
    Client->>Server: Send Envelope (id, correlation_id, msg)
    Server->>Handler: ServiceRequest::new(msg, correlation_id)
    Handler-->>Server: Response (msg')
    Server->>Client: Envelope (id, correlation_id, msg')
Loading

Class diagram for updated Packet trait and Envelope struct

classDiagram
    class Packet {
        +id() u32
        +correlation_id() u32
        +into_parts() (u32, u32, Vec<u8>)
        +from_parts(id: u32, correlation_id: u32, msg: Vec<u8>) Self
    }
    class Envelope {
        +id: u32
        +correlation_id: u32
        +msg: Vec<u8>
        +new(id: u32, correlation_id: u32, msg: Vec<u8>) Self
        +into_parts() (u32, u32, Vec<u8>)
    }
    Packet <|.. Envelope
Loading

Class diagram for ServiceRequest and ServiceResponse with correlation_id

classDiagram
    class FrameContainer~F~ {
        +frame: F
        +new(frame: F) Self
        +frame() &F
        +frame_mut() &mut F
        +into_inner() F
    }
    class ServiceRequest {
        -inner: FrameContainer<Vec<u8>>
        -correlation_id: u32
        +new(frame: Vec<u8>, correlation_id: u32) Self
        +frame() &[u8]
        +frame_mut() &mut Vec<u8>
        +into_inner() Vec<u8>
        +correlation_id() u32
    }
    class ServiceResponse {
        -inner: FrameContainer<Vec<u8>>
        +new(frame: Vec<u8>) Self
        +frame() &[u8]
        +frame_mut() &mut Vec<u8>
        +into_inner() Vec<u8>
    }
Loading

File-Level Changes

Change Details Files
Extend Packet trait and Envelope to support correlation_id
  • Add correlation_id() method to Packet trait and update into_parts()/from_parts() signatures
  • Introduce correlation_id field in Envelope and adjust its constructor and decomposition methods
  • Update example CustomEnvelope in comments to illustrate new API
src/app.rs
Propagate correlation_id through requests, routing, and responses
  • Store correlation_id in ServiceRequest and expose via accessor
  • Pass correlation_id into Envelope when calling services
  • Unpack and repack correlation_id in routing handlers and ServiceResponse
src/middleware.rs
src/app.rs
Update and add tests to cover correlation_id behavior
  • Modify existing unit tests to supply and assert correlation_id on TestEnvelope/StateEnvelope
  • Add new correlation_id Cucumber scenarios and world implementations
  • Adjust middleware and metadata tests to include correlation_id in Envelope.new calls
tests/routes.rs
tests/lifecycle.rs
tests/middleware.rs
tests/metadata.rs
tests/middleware_order.rs
tests/correlation_world.rs
tests/correlation_id.rs
tests/steps/correlation_steps.rs
tests/correlation_cucumber.rs
tests/features/correlation/multi_packet.feature
Revise documentation and roadmap for correlation_id guidance
  • Document correlation_id validation in production resilience guide
  • Describe correlation identifiers in feature set philosophy docs
  • Enable roadmap checkboxes and update README example for new API
  • Extend message versioning doc with correlation_id field
README.md
docs/hardening-wireframe-a-guide-to-production-resilience.md
docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
docs/roadmap.md
docs/message-versioning.md
Apply minor formatting and consistency fixes
  • Expand single-line function definitions into blocks with braces
  • Wrap main functions in tests with braces for readability
src/app.rs
src/middleware.rs
tests/cucumber.rs

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Aug 4, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Summary by CodeRabbit

New Features

  • Added support for correlation IDs in packet envelopes and request/response processing, enabling tracking of requests and responses across the protocol.
  • Introduced correlation ID validation to prevent protocol errors and enhance security.
  • Updated documentation to describe correlation ID behaviour and requirements.
  • Added comprehensive tests for correlation ID propagation and validation, including Cucumber feature tests.

Bug Fixes

  • Ensured all frames in multi-packet responses consistently carry the correct correlation ID.

Refactor

  • Refactored code to propagate correlation IDs throughout the middleware and packet abstractions.
  • Streamlined frame access methods using macros for improved maintainability.

Documentation

  • Updated guides, examples, and roadmap to reflect correlation ID changes and protocol enhancements.

Tests

  • Added new unit and integration tests for correlation ID handling and error scenarios.

Walkthrough

Expand the envelope, packet, and middleware abstractions throughout the codebase to include a correlation_id field and propagate it across all relevant trait signatures, struct constructors, and request/response flows. Update documentation, examples, and tests to reflect and validate this new identifier, ensuring end-to-end correlation ID handling and validation.

Changes

Cohort / File(s) Change Summary
Core Envelope & Packet Abstractions
src/app.rs, src/middleware.rs
Add correlation_id to Envelope, Packet trait, and ServiceRequest. Update all related method signatures, struct fields, and request/response flows to handle and propagate correlation IDs. Refactor function bodies to block style where previously single-line.
Examples & Demonstrations
README.md, examples/metadata_routing.rs
Update custom envelope example and metadata routing example to include and initialise the correlation_id field. Adjust trait implementations and constructor calls accordingly.
Documentation
docs/hardening-wireframe-a-guide-to-production-resilience.md, docs/message-versioning.md, docs/roadmap.md, docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
Add and describe correlation_id in protocol, DoS mitigation, versioning, and roadmap documentation. Mark relevant roadmap tasks as complete.
Test Infrastructure
tests/correlation_id.rs, tests/correlation_cucumber.rs, tests/correlation_world.rs, tests/features/correlation/multi_packet.feature, tests/steps/correlation_steps.rs
Introduce new tests and Cucumber scenarios for correlation ID propagation and validation. Add test world, step definitions, and feature files to verify multi-packet correlation ID consistency.
Test Envelope & Packet Implementations
tests/lifecycle.rs, tests/routes.rs
Extend test envelope structs to include correlation_id. Update trait implementations and test logic to initialise and assert on the new field.
Test & Middleware Adjustments
tests/middleware.rs, tests/middleware_order.rs, tests/metadata.rs, tests/cucumber.rs
Update test and middleware code to match new envelope and request signatures. Add or adjust correlation ID parameters and destructuring as required.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant App
    participant Middleware
    participant Handler

    Client->>App: Send Envelope(id, correlation_id, payload)
    App->>Middleware: Create ServiceRequest(frame, correlation_id)
    Middleware->>Handler: Call Handler with Envelope(id, correlation_id, payload)
    Handler-->>Middleware: Return Response Envelope(id, correlation_id, payload)
    Middleware-->>App: Return Response Envelope(id, correlation_id, payload)
    App-->>Client: Send Envelope(id, correlation_id, payload)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

Correlation IDs now march in line,
Through packets, requests, and every design.
Docs and tests all echo the call,
No frame left behind, none shall fall.
With every response, the link is clear—
Protocol’s future is finally here!
📨🔗

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/add-correlation_id-field-to-frame-header

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey @leynos - I've reviewed your changes - here's some feedback:

  • Add a negative test case for mismatched correlation IDs to verify the error path when a peer sends an incorrect identifier.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider isolating logic changes from formatting-only updates (e.g. expanding one-line functions) into a separate commit to make the diff easier to review.
- The new Packet trait signature is a breaking change—consider providing a default adapter or deprecation path to ease downstream migration.
- Add a negative test case for mismatched correlation IDs to verify the error path when a peer sends an incorrect identifier.

## Individual Comments

### Comment 1
<location> `examples/metadata_routing.rs:55` </location>
<code_context>
         // `parse` receives the complete frame because `LengthPrefixedProcessor`
         // ensures `src` contains exactly one message. Returning `src.len()` is
         // therefore correct for this demo.
-        Ok((Envelope::new(id, payload), src.len()))
+        Ok((Envelope::new(id, 0, payload), src.len()))
     }
 }
</code_context>

<issue_to_address>
Envelope::new now requires a correlation_id; using 0 as a default may not always be appropriate.

If correlation_id has specific meaning, consider using a more representative value or adding a comment to clarify its use in this context.
</issue_to_address>

<suggested_fix>
<<<<<<< SEARCH
        Ok((Envelope::new(id, 0, payload), src.len()))
=======
        // Using 0 as the correlation_id here because there is no correlation tracking in this demo.
        // If correlation_id semantics change, update this value accordingly.
        Ok((Envelope::new(id, 0, payload), src.len()))
>>>>>>> REPLACE

</suggested_fix>

### Comment 2
<location> `tests/middleware.rs:59` </location>
<code_context>
     let wrapped = mw.transform(service).await;

-    let request = ServiceRequest::new(vec![1, 2, 3]);
+    let request = ServiceRequest::new(vec![1, 2, 3], 0);
     let response = wrapped.call(request).await.expect("middleware call failed");
     assert_eq!(response.frame(), &[1, 2, 3, b'!', b'?']);
 }
</code_context>

<issue_to_address>
Consider asserting correlation ID preservation through middleware.

Please add an assertion to verify that the correlation ID remains unchanged after passing through the middleware.
</issue_to_address>

### Comment 3
<location> `src/middleware.rs:20` </location>
<code_context>
     /// Create a new container holding `frame` bytes.
     #[must_use]
-    pub fn new(frame: F) -> Self { Self { frame } }
+    pub fn new(frame: F) -> Self {
+        Self { frame }
+    }
</code_context>

<issue_to_address>
Consider using a macro or helper crates to eliminate repeated trivial forwarding methods and constructors.

You’ve added a lot of identical, trivial forwarding methods and `new`‐ctors. You can collapse almost all of that boilerplate with either a tiny `macro_rules!` or by pulling in a small helper crate like `derive-new` + `delegate`. Here are two options:

Option 1: a single `macro_rules!` to forward all three methods for both request/response:

```rust
// at top of file
macro_rules! forward_frame_bytes {
    ($t:ident) => {
        impl $t {
            #[must_use] pub fn frame(&self)     -> &[u8]       { self.inner.frame().as_slice() }
            #[must_use] pub fn frame_mut(&mut self) -> &mut Vec<u8> { self.inner.frame_mut() }
            #[must_use] pub fn into_inner(self) -> Vec<u8>       { self.inner.into_inner() }
        }
    };
}

// then, instead of repeating impl ServiceRequest/ServiceResponse ...
forward_frame_bytes!(ServiceRequest);
forward_frame_bytes!(ServiceResponse);
```

You’d keep only the one‐line `new` and `correlation_id` methods in `ServiceRequest`, dropping the 6+ repeated lines.

Option 2: pull in two 0.1–0.5 MB crates to auto-derive everything.

Cargo.toml:
```toml
derive-new = "0.5"
delegate   = "0.1"
```

```rust
use derive_new::New;
use delegate::delegate;

// your container
#[derive(Debug, Default, New)]
pub struct FrameContainer<F> { frame: F }

// request / response
#[derive(Debug, New)]
pub struct ServiceRequest {
    inner: FrameContainer<Vec<u8>>,
    correlation_id: u32,
}
impl ServiceRequest {
    // still need this one by hand
    #[must_use] pub fn correlation_id(&self) -> u32 { self.correlation_id }
    // auto-forward all three
    delegate! {
        to self.inner {
            #[must_use] pub fn frame(&self)     -> &[u8];
            #[must_use] pub fn frame_mut(&mut self) -> &mut Vec<u8>;
            #[must_use] pub fn into_inner(self) -> Vec<u8>;
        }
    }
}

#[derive(Debug, Default, New)]
pub struct ServiceResponse {
    inner: FrameContainer<Vec<u8>>,
}
impl ServiceResponse {
    delegate! {
        to self.inner {
            #[must_use] pub fn frame(&self)     -> &[u8];
            #[must_use] pub fn frame_mut(&mut self) -> &mut Vec<u8>;
            #[must_use] pub fn into_inner(self) -> Vec<u8>;
        }
    }
}

// and similarly for Next, FromFn, FnService, HandlerService, etc.
```

Pick whichever fits your dependency-budget. Both solutions preserve 100% of the API while collapsing dozens of lines of trivial boilerplate into a couple of macros.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

// `parse` receives the complete frame because `LengthPrefixedProcessor`
// ensures `src` contains exactly one message. Returning `src.len()` is
// therefore correct for this demo.
Ok((Envelope::new(id, payload), src.len()))
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.

suggestion: Envelope::new now requires a correlation_id; using 0 as a default may not always be appropriate.

If correlation_id has specific meaning, consider using a more representative value or adding a comment to clarify its use in this context.

Suggested change
Ok((Envelope::new(id, payload), src.len()))
// Using 0 as the correlation_id here because there is no correlation tracking in this demo.
// If correlation_id semantics change, update this value accordingly.
Ok((Envelope::new(id, 0, payload), src.len()))

Comment thread tests/middleware.rs Outdated
Comment on lines 59 to 61
let request = ServiceRequest::new(vec![1, 2, 3], 0);
let response = wrapped.call(request).await.expect("middleware call failed");
assert_eq!(response.frame(), &[1, 2, 3, b'!', b'?']);
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.

suggestion (testing): Consider asserting correlation ID preservation through middleware.

Please add an assertion to verify that the correlation ID remains unchanged after passing through the middleware.

Comment thread src/middleware.rs
pub fn new(frame: F) -> Self {
Self { frame }
}

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.

issue (complexity): Consider using a macro or helper crates to eliminate repeated trivial forwarding methods and constructors.

You’ve added a lot of identical, trivial forwarding methods and new‐ctors. You can collapse almost all of that boilerplate with either a tiny macro_rules! or by pulling in a small helper crate like derive-new + delegate. Here are two options:

Option 1: a single macro_rules! to forward all three methods for both request/response:

// at top of file
macro_rules! forward_frame_bytes {
    ($t:ident) => {
        impl $t {
            #[must_use] pub fn frame(&self)     -> &[u8]       { self.inner.frame().as_slice() }
            #[must_use] pub fn frame_mut(&mut self) -> &mut Vec<u8> { self.inner.frame_mut() }
            #[must_use] pub fn into_inner(self) -> Vec<u8>       { self.inner.into_inner() }
        }
    };
}

// then, instead of repeating impl ServiceRequest/ServiceResponse ...
forward_frame_bytes!(ServiceRequest);
forward_frame_bytes!(ServiceResponse);

You’d keep only the one‐line new and correlation_id methods in ServiceRequest, dropping the 6+ repeated lines.

Option 2: pull in two 0.1–0.5 MB crates to auto-derive everything.

Cargo.toml:

derive-new = "0.5"
delegate   = "0.1"
use derive_new::New;
use delegate::delegate;

// your container
#[derive(Debug, Default, New)]
pub struct FrameContainer<F> { frame: F }

// request / response
#[derive(Debug, New)]
pub struct ServiceRequest {
    inner: FrameContainer<Vec<u8>>,
    correlation_id: u32,
}
impl ServiceRequest {
    // still need this one by hand
    #[must_use] pub fn correlation_id(&self) -> u32 { self.correlation_id }
    // auto-forward all three
    delegate! {
        to self.inner {
            #[must_use] pub fn frame(&self)     -> &[u8];
            #[must_use] pub fn frame_mut(&mut self) -> &mut Vec<u8>;
            #[must_use] pub fn into_inner(self) -> Vec<u8>;
        }
    }
}

#[derive(Debug, Default, New)]
pub struct ServiceResponse {
    inner: FrameContainer<Vec<u8>>,
}
impl ServiceResponse {
    delegate! {
        to self.inner {
            #[must_use] pub fn frame(&self)     -> &[u8];
            #[must_use] pub fn frame_mut(&mut self) -> &mut Vec<u8>;
            #[must_use] pub fn into_inner(self) -> Vec<u8>;
        }
    }
}

// and similarly for Next, FromFn, FnService, HandlerService, etc.

Pick whichever fits your dependency-budget. Both solutions preserve 100% of the API while collapsing dozens of lines of trivial boilerplate into a couple of macros.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🔭 Outside diff range comments (1)
docs/message-versioning.md (1)

41-52: Synchronise prose with updated struct

Update the section heading to reflect both fields and explain the new correlation_id:

  • Change heading from:

    “Extend Envelope with an optional version field”

    to:

    “Extend Envelope with a correlation_id and an optional version field”

  • After the snippet, add:

    “The new correlation_id field links related messages for end-to-end tracing, ensuring that request–response pairs can be correlated across services.”

File to update:

  • docs/message-versioning.md (around lines 41–52)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51b6d6a and 6ec569c.

📒 Files selected for processing (19)
  • README.md (1 hunks)
  • docs/hardening-wireframe-a-guide-to-production-resilience.md (1 hunks)
  • docs/message-versioning.md (1 hunks)
  • docs/roadmap.md (2 hunks)
  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md (1 hunks)
  • examples/metadata_routing.rs (1 hunks)
  • src/app.rs (6 hunks)
  • src/middleware.rs (7 hunks)
  • tests/correlation_cucumber.rs (1 hunks)
  • tests/correlation_id.rs (1 hunks)
  • tests/correlation_world.rs (1 hunks)
  • tests/cucumber.rs (1 hunks)
  • tests/features/correlation/multi_packet.feature (1 hunks)
  • tests/lifecycle.rs (2 hunks)
  • tests/metadata.rs (2 hunks)
  • tests/middleware.rs (2 hunks)
  • tests/middleware_order.rs (2 hunks)
  • tests/routes.rs (3 hunks)
  • tests/steps/correlation_steps.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
docs/**/*.md

📄 CodeRabbit Inference Engine (docs/contents.md)

Conventions for writing project documentation as described in the documentation style guide

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-oxendict) for documentation text.
The word "outwith" is acceptable in documentation.
Keep US spelling when used in an API, for example color.
Use the Oxford comma in documentation text.
Treat company names as collective nouns in documentation (e.g., "Lille Industries are expanding").
Write headings in sentence case in documentation.
Use Markdown headings (#, ##, ###, etc.) in order without skipping levels.
Follow markdownlint recommendations for Markdown files.
Provide code blocks and lists using standard Markdown syntax.
Always provide a language identifier for fenced code blocks; use plaintext for non-code text.
Use - as the first level bullet and renumber lists when items change.
Prefer inline links using [text](url) or angle brackets around the URL; avoid reference-style links like [foo][bar].
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown.
Ensure tables have a delimiter line below the header row in Markdown.
Expand any uncommon acronym on first use, for example, Continuous Integration (CI).
Wrap paragraphs at 80 columns in documentation.
Wrap code at 120 columns in documentation.
Do not wrap tables in documentation.
Use sequentially numbered footnotes referenced with [^1] and place definitions at the end of the file.
Where it adds clarity, include Mermaid diagrams in documentation.
When embedding figures, use ![alt text](path/to/image) and provide concise alt text describing the content.
Add a brief description before each Mermaid diagram in documentation for screen readers.

Document examples showing how to deprecate old message versions gracefully

Write the official documentation for the new features. Create separate guides for "Duplex Messaging & Pushes", "Streaming Responses", and "Message Fragmentation". Each guide must include runna...

Files:

  • docs/message-versioning.md
  • docs/roadmap.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md
  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
docs/**/*.{md,rs}

📄 CodeRabbit Inference Engine (docs/multi-packet-and-streaming-responses-design.md)

docs/**/*.{md,rs}: The official documentation and examples must exclusively use the declarative Response model for handler responses.
The async-stream pattern must be documented as the canonical approach for dynamic stream generation.

Files:

  • docs/message-versioning.md
  • docs/roadmap.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md
  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
**/*.md

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.md: Documentation must use en-GB-oxendict spelling and grammar. (EXCEPTION: the naming of the LICENSE file, which is to be left unchanged for community consistency.)
Markdown paragraphs and bullet points must be wrapped at 80 columns.
Code blocks in Markdown files must be wrapped at 120 columns.
Tables and headings in Markdown files must not be wrapped.
Use dashes (-) for list bullets in Markdown files.
Use GitHub-flavoured Markdown footnotes ([^1]) for references and footnotes.

Files:

  • docs/message-versioning.md
  • docs/roadmap.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md
  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
  • README.md

⚙️ CodeRabbit Configuration File

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -our) spelling and grammar
  • Paragraphs and bullets must be wrapped to 80 columns, except where a long URL would prevent this (in which case, silence MD013 for that line)
  • Code blocks should be wrapped to 120 columns.
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/message-versioning.md
  • docs/roadmap.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md
  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
  • README.md
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • tests/cucumber.rs
  • tests/metadata.rs
  • tests/correlation_world.rs
  • tests/correlation_id.rs
  • tests/correlation_cucumber.rs
  • tests/middleware_order.rs
  • tests/steps/correlation_steps.rs
  • tests/middleware.rs
  • tests/routes.rs
  • examples/metadata_routing.rs
  • src/middleware.rs
  • tests/lifecycle.rs
  • src/app.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • tests/cucumber.rs
  • tests/metadata.rs
  • tests/correlation_world.rs
  • tests/correlation_id.rs
  • tests/correlation_cucumber.rs
  • tests/middleware_order.rs
  • tests/steps/correlation_steps.rs
  • tests/middleware.rs
  • tests/routes.rs
  • examples/metadata_routing.rs
  • src/middleware.rs
  • tests/lifecycle.rs
  • src/app.rs
🧠 Learnings (4)
📚 Learning: applies to docs/src/frame/mod.rs : add a `correlation_id` field to the `frame` header and ensure eac...
Learnt from: CR
PR: leynos/wireframe#0
File: docs/roadmap.md:0-0
Timestamp: 2025-08-03T14:16:03.267Z
Learning: Applies to docs/src/frame/mod.rs : Add a `correlation_id` field to the `Frame` header and ensure each message in a multi-packet response carries the correct `correlation_id`.

Applied to files:

  • docs/roadmap.md
📚 Learning: applies to docs/src/connection.rs : modify the `connection` actor: upon receiving `response::multipa...
Learnt from: CR
PR: leynos/wireframe#0
File: docs/roadmap.md:0-0
Timestamp: 2025-08-03T14:16:03.267Z
Learning: Applies to docs/src/connection.rs : Modify the `Connection` actor: upon receiving `Response::MultiPacket`, it should consume messages from the receiver and send each one as a `Frame`.

Applied to files:

  • docs/roadmap.md
📚 Learning: applies to docs/tests/cucumber.rs : the main cucumber test runner must be implemented as a rust file...
Learnt from: CR
PR: leynos/ortho-config#0
File: docs/behavioural-testing-in-rust-with-cucumber.md:0-0
Timestamp: 2025-08-03T16:45:14.708Z
Learning: Applies to docs/tests/cucumber.rs : The main Cucumber test runner must be implemented as a Rust file in the `tests/` directory (e.g., `tests/cucumber.rs`) and must provide a custom `main` function with `#[tokio::main]` and call `World::run("tests/features")`.

Applied to files:

  • tests/correlation_cucumber.rs
📚 Learning: applies to docs/tests/cucumber.rs : the main cucumber test runner must be implemented as a rust file...
Learnt from: CR
PR: leynos/netsuke#0
File: docs/behavioural-testing-in-rust-with-cucumber.md:0-0
Timestamp: 2025-07-27T17:58:24.453Z
Learning: Applies to docs/tests/cucumber.rs : The main Cucumber test runner must be implemented as a Rust file in the `tests/` directory (e.g., `tests/cucumber.rs`) and must provide a custom `main` function with `#[tokio::main]`.

Applied to files:

  • tests/correlation_cucumber.rs
🧬 Code Graph Analysis (7)
tests/metadata.rs (1)
src/app.rs (2)
  • new (207-213)
  • new (285-287)
tests/correlation_world.rs (5)
src/app.rs (7)
  • id (181-181)
  • id (223-225)
  • new (207-213)
  • new (285-287)
  • correlation_id (184-184)
  • correlation_id (227-229)
  • from (143-145)
tests/steps/correlation_steps.rs (1)
  • set_id (8-10)
src/middleware.rs (8)
  • id (318-320)
  • new (20-22)
  • new (53-58)
  • new (94-98)
  • new (151-153)
  • new (204-206)
  • new (294-304)
  • correlation_id (80-82)
tests/connection_actor.rs (1)
  • queues (25-25)
src/push.rs (1)
  • bounded (297-300)
tests/middleware_order.rs (1)
src/app.rs (2)
  • new (207-213)
  • new (285-287)
tests/steps/correlation_steps.rs (1)
tests/correlation_world.rs (1)
  • set_id (29-31)
tests/middleware.rs (2)
src/middleware.rs (8)
  • transform (190-190)
  • transform (273-278)
  • new (20-22)
  • new (53-58)
  • new (94-98)
  • new (151-153)
  • new (204-206)
  • new (294-304)
tests/middleware_order.rs (1)
  • transform (41-50)
src/middleware.rs (3)
src/app.rs (8)
  • new (207-213)
  • new (285-287)
  • correlation_id (184-184)
  • correlation_id (227-229)
  • id (181-181)
  • id (223-225)
  • from_parts (190-190)
  • from_parts (235-241)
tests/lifecycle.rs (3)
  • correlation_id (113-115)
  • id (110-112)
  • from_parts (121-127)
tests/routes.rs (3)
  • correlation_id (32-34)
  • id (29-31)
  • from_parts (40-46)
tests/lifecycle.rs (3)
src/middleware.rs (2)
  • id (318-320)
  • correlation_id (80-82)
src/app.rs (9)
  • id (181-181)
  • id (223-225)
  • correlation_id (184-184)
  • correlation_id (227-229)
  • into_parts (187-187)
  • into_parts (217-219)
  • into_parts (231-233)
  • from_parts (190-190)
  • from_parts (235-241)
tests/routes.rs (4)
  • id (29-31)
  • correlation_id (32-34)
  • into_parts (36-38)
  • from_parts (40-46)
🪛 LanguageTool
docs/hardening-wireframe-a-guide-to-production-resilience.md

[style] ~293-~293: Consider replacing this word to strengthen your wording.
Context: ...request. A mismatch is a protocol error and should terminate the stream. This check...

(AND_THAT)

docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md

[misspelling] ~119-~119: This word is normally spelled as one.
Context: .... This mechanism allows out-of-order or multi-part replies to be reassembled reliably with...

(EN_COMPOUNDS_MULTI_PART)

🔇 Additional comments (28)
tests/cucumber.rs (1)

13-15: Ignore global runner suggestion

PanicWorld tests live in tests/cucumber.rs and are designed to run only the panic scenario in tests/features/connection_panic.feature. Correlation scenarios under tests/features/correlation are already covered by tests/correlation_cucumber.rs with CorrelationWorld. Leaving the explicit path prevents running feature files under the wrong world context.

Likely an incorrect or invalid review comment.

docs/roadmap.md (2)

180-184: Good update – task correctly marked complete

The protocol enhancement bullet now reflects the implemented correlation-ID field.


197-198: Confirm downstream coverage

Ensure every outbound frame (including error and push frames) sets the correlation_id. Add a regression test if one is missing.

tests/correlation_cucumber.rs (1)

1-13: LGTM! Follows established Cucumber patterns.

The implementation correctly follows the documented pattern for Cucumber test runners with the required #[tokio::main] function and proper feature path.

tests/features/correlation/multi_packet.feature (1)

1-5: LGTM! Clear test scenario for correlation ID consistency.

The feature properly tests that correlation IDs are preserved across multi-packet response streams, which is essential for the correlation functionality.

tests/metadata.rs (2)

63-63: LGTM! Constructor updated for correlation ID support.

The Envelope constructor call correctly includes the new correlation_id parameter, maintaining consistency with the updated signature.


108-108: LGTM! Constructor updated for correlation ID support.

The Envelope constructor call correctly includes the new correlation_id parameter, maintaining consistency with the updated signature.

examples/metadata_routing.rs (1)

55-55: LGTM! Constructor updated for correlation ID support.

The Envelope constructor call correctly includes the new correlation_id parameter whilst maintaining the example's focus on metadata-based routing.

tests/middleware.rs (1)

59-59: Correctly updated for new API.

The constructor call properly includes the correlation_id parameter as required by the updated ServiceRequest::new signature.

tests/correlation_id.rs (2)

1-2: Module documentation follows conventions.

Clear and concise module-level documentation explaining the purpose.


12-35: Comprehensive correlation ID roundtrip test.

The test effectively validates that correlation IDs are preserved through the request-response cycle. The use of a specific correlation ID value (7) makes assertions clear and verifiable.

tests/steps/correlation_steps.rs (4)

1-2: Module documentation follows conventions.

Clear documentation explaining the module's purpose for behavioral testing.


7-10: Correct step definition implementation.

The given step properly extracts the correlation ID from the regex pattern and delegates to the world state.


12-15: Proper async step handling.

The when step correctly handles the asynchronous actor execution.


17-21: Thorough verification step.

The then step performs both direct correlation ID comparison and delegates to the world's assertion method for comprehensive validation.

README.md (2)

102-102: Correctly updated struct definition.

The addition of the correlation_id field properly extends the envelope structure to support the new correlation ID requirement.


106-110: Proper Packet trait implementation.

The trait implementation correctly includes the new correlation_id() method and updates the into_parts and from_parts methods to handle the three-parameter format.

tests/routes.rs (3)

22-26: Correct struct extension.

The addition of the correlation_id field properly extends the test envelope structure.


29-47: Complete Packet trait implementation.

The trait implementation correctly includes all required methods with proper signatures for correlation ID support.


74-74: Appropriate test data initialisation.

Using correlation_id: 0 in test scenarios is appropriate for basic functionality testing.

Also applies to: 111-111

tests/correlation_world.rs (2)

19-26: Well-implemented Debug trait

The custom Debug implementation correctly shows only the length of frames rather than the full vector, which prevents overwhelming debug output.


52-61: Clean assertion implementation

Good use of iterator methods for checking all frames. The panic documentation clearly indicates the failure condition.

tests/lifecycle.rs (1)

103-128: Correct Packet trait implementation with correlation ID

The StateEnvelope struct and Packet trait implementation correctly incorporate the correlation_id field, maintaining consistency with the protocol changes.

src/middleware.rs (2)

44-83: Proper correlation ID integration in ServiceRequest

The ServiceRequest struct correctly incorporates the correlation_id field with appropriate constructor changes and accessor method. The #[must_use] attribute on the accessor is good practice.


333-341: Correct correlation ID propagation in RouteService

The RouteService correctly extracts and propagates the correlation_id through the request handling chain.

src/app.rs (3)

148-191: Well-documented Packet trait extension

The Packet trait correctly adds correlation_id support with clear documentation and a helpful example showing the implementation.


193-242: Consistent Envelope implementation with correlation ID

The Envelope struct and its Packet trait implementation correctly incorporate the correlation_id field, maintaining consistency with the existing id field pattern.


706-714: Proper correlation ID propagation in request handling

The handle_frame method correctly propagates the correlation_id from request to response, ensuring multi-packet responses can be matched to their originating requests.

Comment thread docs/hardening-wireframe-a-guide-to-production-resilience.md
Comment on lines +114 to +121
#### Correlation Identifiers

Every frame header now carries a `correlation_id` that ties it to the
originating request. Clients set a unique identifier on each request and the
server mirrors this value on every frame in the response stream. This mechanism
allows out-of-order or multi-part replies to be reassembled reliably without
relying on transport sequencing.

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.

🧹 Nitpick (assertive)

Fix compound adjective spelling

Use “multipart” (one word) in line with en-GB spelling rules flagged by LanguageTool.

-    out-of-order or multi-part replies
+    out-of-order or multipart replies
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
#### Correlation Identifiers
Every frame header now carries a `correlation_id` that ties it to the
originating request. Clients set a unique identifier on each request and the
server mirrors this value on every frame in the response stream. This mechanism
allows out-of-order or multi-part replies to be reassembled reliably without
relying on transport sequencing.
#### Correlation Identifiers
Every frame header now carries a `correlation_id` that ties it to the
originating request. Clients set a unique identifier on each request and the
server mirrors this value on every frame in the response stream. This mechanism
allows out-of-order or multipart replies to be reassembled reliably without
relying on transport sequencing.
🧰 Tools
🪛 LanguageTool

[misspelling] ~119-~119: This word is normally spelled as one.
Context: .... This mechanism allows out-of-order or multi-part replies to be reassembled reliably with...

(EN_COMPOUNDS_MULTI_PART)

🤖 Prompt for AI Agents
In
docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
around lines 114 to 121, the term "multi-part" should be corrected to the single
word "multipart" to comply with en-GB spelling conventions. Replace "multi-part"
with "multipart" in the sentence describing replies to ensure proper compound
adjective usage.

Comment thread tests/correlation_world.rs Outdated
Comment thread tests/middleware_order.rs Outdated
Comment thread tests/middleware_order.rs Outdated
Comment thread tests/middleware.rs
Comment on lines +32 to +34
async fn transform(&self, service: S) -> Self::Output {
ModifyService { inner: service }
}
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.

🧹 Nitpick (assertive)

Unnecessary formatting change.

The conversion from single-line to multi-line format provides no functional benefit. Revert to the more concise single-line format unless required by automated formatting tools.

-    async fn transform(&self, service: S) -> Self::Output {
-        ModifyService { inner: service }
-    }
+    async fn transform(&self, service: S) -> Self::Output { ModifyService { inner: service } }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async fn transform(&self, service: S) -> Self::Output {
ModifyService { inner: service }
}
async fn transform(&self, service: S) -> Self::Output { ModifyService { inner: service } }
🤖 Prompt for AI Agents
In tests/middleware.rs around lines 32 to 34, the transform function was changed
from a single-line to a multi-line format unnecessarily. Revert the function
back to the original single-line format to keep the code concise, unless your
automated formatter enforces multi-line style.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

♻️ Duplicate comments (2)
docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md (1)

119-119: Fix compound adjective spelling

Use "multipart" (one word) in line with en-GB spelling rules flagged by LanguageTool.

-    out-of-order or multi-part replies
+    out-of-order or multipart replies
tests/middleware.rs (1)

33-35: Fix the formatting to comply with cargo fmt.

The multi-line format violates the project's formatting standards. Revert to single-line format.

Apply this diff:

-    async fn transform(&self, service: S) -> Self::Output {
-        ModifyService { inner: service }
-    }
+    async fn transform(&self, service: S) -> Self::Output { ModifyService { inner: service } }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6ec569c and 151309a.

📒 Files selected for processing (8)
  • docs/hardening-wireframe-a-guide-to-production-resilience.md (1 hunks)
  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md (1 hunks)
  • examples/metadata_routing.rs (1 hunks)
  • src/middleware.rs (7 hunks)
  • tests/correlation_id.rs (1 hunks)
  • tests/correlation_world.rs (1 hunks)
  • tests/middleware.rs (3 hunks)
  • tests/middleware_order.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (4)
**/*.rs

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.rs: Function documentation must include clear examples demonstrating the usage and outcome of the function. Test documentation should omit examples where the example serves only to reiterate the test logic.
No single code file may be longer than 400 lines. Long switch statements or dispatch tables should be broken up by feature and constituents colocated with targets. Large blocks of test data should be moved to external data files.
Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider using Arc to reduce the amount of data returned.
Write unit and behavioural tests for new functionality. Run both before and after making any change.
Every module must begin with a module level (//! ) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessary mut bindings.
Handle errors with the Result type instead of panicking where feasible.
Avoid unsafe code unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not use return in single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Prefer expect over allow.
Prefer .expect() over .unwrap().
Use concat!() to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums. Derive std::error::Error (via the thiserror crate) for any condition the caller might inspect, retry, or map to an HTTP status....

Files:

  • tests/correlation_id.rs
  • tests/correlation_world.rs
  • tests/middleware.rs
  • tests/middleware_order.rs
  • examples/metadata_routing.rs
  • src/middleware.rs

⚙️ CodeRabbit Configuration File

**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.

  • Adhere to single responsibility and CQRS

  • Place function attributes after doc comments.

  • Do not use return in single-line functions.

  • Move conditionals with >2 branches into a predicate function.

  • Avoid unsafe unless absolutely necessary.

  • Every module must begin with a //! doc comment that explains the module's purpose and utility.

  • Comments and docs must follow en-GB-oxendict (-ize / -our) spelling and grammar

  • Lints must not be silenced except as a last resort.

    • #[allow] is forbidden.
    • Only narrowly scoped #[expect(lint, reason = "...")] is allowed.
    • No lint groups, no blanket or file-wide suppression.
    • Include FIXME: with link if a fix is expected.
  • Use rstest fixtures for shared setup and to avoid repetition between tests.

  • Replace duplicated tests with #[rstest(...)] parameterised cases.

  • Prefer mockall for mocks/stubs.

  • Prefer .expect() over .unwrap()

  • Ensure that any API or behavioural changes are reflected in the documentation in docs/

  • Ensure that any completed roadmap steps are recorded in the appropriate roadmap in docs/

  • Files must not exceed 400 lines in length

    • Large modules must be decomposed
    • Long match statements or dispatch tables should be decomposed by domain and collocated with targets
    • Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.

Files:

  • tests/correlation_id.rs
  • tests/correlation_world.rs
  • tests/middleware.rs
  • tests/middleware_order.rs
  • examples/metadata_routing.rs
  • src/middleware.rs
docs/**/*.md

📄 CodeRabbit Inference Engine (docs/contents.md)

Conventions for writing project documentation as described in the documentation style guide

docs/**/*.md: Use British English based on the Oxford English Dictionary (en-oxendict) for documentation text.
The word "outwith" is acceptable in documentation.
Keep US spelling when used in an API, for example color.
Use the Oxford comma in documentation text.
Treat company names as collective nouns in documentation (e.g., "Lille Industries are expanding").
Write headings in sentence case in documentation.
Use Markdown headings (#, ##, ###, etc.) in order without skipping levels.
Follow markdownlint recommendations for Markdown files.
Provide code blocks and lists using standard Markdown syntax.
Always provide a language identifier for fenced code blocks; use plaintext for non-code text.
Use - as the first level bullet and renumber lists when items change.
Prefer inline links using [text](url) or angle brackets around the URL; avoid reference-style links like [foo][bar].
Ensure blank lines before and after bulleted lists and fenced blocks in Markdown.
Ensure tables have a delimiter line below the header row in Markdown.
Expand any uncommon acronym on first use, for example, Continuous Integration (CI).
Wrap paragraphs at 80 columns in documentation.
Wrap code at 120 columns in documentation.
Do not wrap tables in documentation.
Use sequentially numbered footnotes referenced with [^1] and place definitions at the end of the file.
Where it adds clarity, include Mermaid diagrams in documentation.
When embedding figures, use ![alt text](path/to/image) and provide concise alt text describing the content.
Add a brief description before each Mermaid diagram in documentation for screen readers.

Document examples showing how to deprecate old message versions gracefully

Write the official documentation for the new features. Create separate guides for "Duplex Messaging & Pushes", "Streaming Responses", and "Message Fragmentation". Each guide must include runna...

Files:

  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md
docs/**/*.{md,rs}

📄 CodeRabbit Inference Engine (docs/multi-packet-and-streaming-responses-design.md)

docs/**/*.{md,rs}: The official documentation and examples must exclusively use the declarative Response model for handler responses.
The async-stream pattern must be documented as the canonical approach for dynamic stream generation.

Files:

  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md
**/*.md

📄 CodeRabbit Inference Engine (AGENTS.md)

**/*.md: Documentation must use en-GB-oxendict spelling and grammar. (EXCEPTION: the naming of the LICENSE file, which is to be left unchanged for community consistency.)
Markdown paragraphs and bullet points must be wrapped at 80 columns.
Code blocks in Markdown files must be wrapped at 120 columns.
Tables and headings in Markdown files must not be wrapped.
Use dashes (-) for list bullets in Markdown files.
Use GitHub-flavoured Markdown footnotes ([^1]) for references and footnotes.

Files:

  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md

⚙️ CodeRabbit Configuration File

**/*.md: * Avoid 2nd person or 1st person pronouns ("I", "you", "we")

  • Use en-GB-oxendict (-ize / -our) spelling and grammar
  • Paragraphs and bullets must be wrapped to 80 columns, except where a long URL would prevent this (in which case, silence MD013 for that line)
  • Code blocks should be wrapped to 120 columns.
  • Headings must not be wrapped.
  • Documents must start with a level 1 heading
  • Headings must correctly increase or decrease by no more than one level at a time
  • Use GitHub-flavoured Markdown style for footnotes and endnotes.
  • Numbered footnotes must be numbered by order of appearance in the document.

Files:

  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md
🧬 Code Graph Analysis (3)
tests/correlation_world.rs (4)
src/app.rs (7)
  • id (181-181)
  • id (223-225)
  • new (207-213)
  • new (285-287)
  • correlation_id (184-184)
  • correlation_id (227-229)
  • from (143-145)
tests/steps/correlation_steps.rs (1)
  • set_id (8-10)
tests/connection_actor.rs (1)
  • queues (25-25)
src/push.rs (1)
  • bounded (297-300)
tests/middleware.rs (1)
src/middleware.rs (14)
  • call (164-166)
  • call (176-176)
  • call (258-261)
  • call (333-341)
  • call (348-350)
  • new (20-22)
  • new (53-58)
  • new (94-98)
  • new (151-153)
  • new (204-206)
  • new (294-304)
  • frame (26-28)
  • frame (62-64)
  • frame (102-104)
src/middleware.rs (3)
src/app.rs (6)
  • new (207-213)
  • new (285-287)
  • correlation_id (184-184)
  • correlation_id (227-229)
  • id (181-181)
  • id (223-225)
tests/lifecycle.rs (2)
  • correlation_id (113-115)
  • id (110-112)
tests/routes.rs (2)
  • correlation_id (32-34)
  • id (29-31)
🪛 LanguageTool
docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md

[uncategorized] ~117-~117: Possible missing comma found.
Context: ...Clients set a unique identifier on each request and the server mirrors this value on ev...

(AI_HYDRA_LEO_MISSING_COMMA)


[misspelling] ~119-~119: This word is normally spelled as one.
Context: .... This mechanism allows out-of-order or multi-part replies to be reassembled reliably with...

(EN_COMPOUNDS_MULTI_PART)

docs/hardening-wireframe-a-guide-to-production-resilience.md

[style] ~293-~293: Consider replacing this word to strengthen your wording.
Context: ...request. A mismatch is a protocol error and must terminate the stream. The server o...

(AND_THAT)

🪛 GitHub Actions: CI
tests/correlation_world.rs

[error] 26-26: cargo fmt formatting check failed. Line 26 does not conform to the expected formatting style. Run 'cargo fmt --all' to fix code style issues.

tests/middleware.rs

[error] 30-34: cargo fmt formatting check failed. Lines 30-34 do not conform to the expected formatting style. Run 'cargo fmt --all' to fix code style issues.

src/middleware.rs

[error] 17-306: cargo fmt formatting check failed. Multiple lines in src/middleware.rs do not conform to the expected formatting style. Run 'cargo fmt --all' to fix code style issues.

🪛 GitHub Check: build-test
src/middleware.rs

[warning] 38-38:
Diff in /home/runner/work/wireframe/wireframe/src/middleware.rs


[warning] 32-32:
Diff in /home/runner/work/wireframe/wireframe/src/middleware.rs


[warning] 26-26:
Diff in /home/runner/work/wireframe/wireframe/src/middleware.rs

🔇 Additional comments (12)
docs/hardening-wireframe-a-guide-to-production-resilience.md (1)

289-298: Excellent addition of correlation ID validation as a DoS mitigation measure.

The new subsection clearly establishes correlation ID validation as a mandatory protocol requirement. The language appropriately uses "must" for protocol obligations, and the section effectively explains both the security benefits and implementation requirements for correlation ID consistency checking.

tests/middleware_order.rs (2)

67-68: Proper correlation ID implementation with clear documentation.

The change correctly mirrors the request ID as the correlation ID and includes a clear comment explaining the choice. This addresses the previous concern about hard-coding correlation IDs and ensures proper correlation tracking.


92-92: Excellent explicit destructuring implementation.

The named variable _corr_id clearly indicates the correlation ID field and addresses the previous feedback about making destructuring explicit. This improves code readability and prevents accidental misuse.

examples/metadata_routing.rs (1)

55-57: Proper correlation ID implementation with clear documentation.

The change correctly adds the correlation_id parameter with an appropriate default value of 0 for this example. The comment clearly explains the rationale and provides guidance for future updates, addressing the previous review feedback about clarifying correlation_id usage.

tests/correlation_id.rs (3)

15-38: Comprehensive test for correlation ID echoing behaviour.

The test properly validates that responses maintain the same correlation ID as the originating request. The setup with WireframeApp, serialization, and verification is thorough and follows good testing practices. The use of drive_with_bincode helper and proper error handling makes this a robust test case.


40-52: Effective negative test for correlation ID mismatch detection.

The test properly validates that the system detects and fails on correlation ID mismatches. The use of should_panic with specific expected message and the CorrelationWorld test harness creates a robust test scenario. Testing both matching (ID 7) and mismatching (ID 9) correlation IDs ensures proper error detection.


1-14: Well-structured test module with appropriate dependencies.

The module documentation clearly states its purpose, and the imports are well-organised. The use of rstest for parameterised testing, wireframe_testing utilities, and the dedicated correlation_world test support module demonstrates good testing architecture and separation of concerns.

tests/middleware.rs (1)

8-17: LGTM! Correlation ID tracking properly implemented.

The changes correctly implement correlation ID validation in the middleware test. The EchoService now stores and validates the expected correlation ID, ensuring it's preserved through the middleware chain.

Also applies to: 56-61

tests/correlation_world.rs (1)

33-47: Well-designed configurable test helper.

The method properly addresses configurability concerns by accepting frames and queue capacity as parameters, enabling flexible test scenarios.

src/middleware.rs (3)

43-65: Excellent use of macro to reduce boilerplate.

The forward_frame_methods! macro effectively eliminates code duplication for frame access methods, addressing previous feedback about repeated forwarding methods.

Also applies to: 107-108


71-88: Correlation ID properly integrated into ServiceRequest.

The implementation correctly adds correlation ID tracking with appropriate constructor updates and accessor method.


324-332: Correct propagation of correlation ID through the routing layer.

The implementation properly extracts the correlation ID from the request and includes it when constructing the packet envelope, ensuring end-to-end correlation tracking.

#### Correlation Identifiers

Every frame header now carries a `correlation_id` that ties it to the
originating request. Clients set a unique identifier on each request and the
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.

🧹 Nitpick (assertive)

Add comma for improved sentence clarity

Insert a comma after "request" to properly separate the two independent clauses describing client and server actions.

-Clients set a unique identifier on each request and the server mirrors this value
+Clients set a unique identifier on each request, and the server mirrors this value
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
originating request. Clients set a unique identifier on each request and the
originating request. Clients set a unique identifier on each request, and the
server mirrors this value
🧰 Tools
🪛 LanguageTool

[uncategorized] ~117-~117: Possible missing comma found.
Context: ...Clients set a unique identifier on each request and the server mirrors this value on ev...

(AI_HYDRA_LEO_MISSING_COMMA)

🤖 Prompt for AI Agents
In
docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
at line 117, add a comma after the word "request" to separate the two
independent clauses clearly, improving sentence clarity.

Comment thread src/middleware.rs
Comment on lines 20 to +40

/// Borrow the inner frame data.
#[must_use]
pub fn frame(&self) -> &F { &self.frame }
pub fn frame(&self) -> &F {
&self.frame
}

/// Mutable access to the frame data.
#[must_use]
pub fn frame_mut(&mut self) -> &mut F { &mut self.frame }
pub fn frame_mut(&mut self) -> &mut F {
&mut self.frame
}

/// Consume the container, returning the frame.
#[must_use]
pub fn into_inner(self) -> F { self.frame }
pub fn into_inner(self) -> F {
self.frame
}
}

macro_rules! forward_frame_methods {
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.

⚠️ Potential issue

Fix formatting for all FrameContainer methods.

These simple methods should remain single-line format per cargo fmt standards.

Apply this diff:

-    pub fn new(frame: F) -> Self {
-        Self { frame }
-    }
+    pub fn new(frame: F) -> Self { Self { frame } }

-    pub fn frame(&self) -> &F {
-        &self.frame
-    }
+    pub fn frame(&self) -> &F { &self.frame }

-    pub fn frame_mut(&mut self) -> &mut F {
-        &mut self.frame
-    }
+    pub fn frame_mut(&mut self) -> &mut F { &mut self.frame }

-    pub fn into_inner(self) -> F {
-        self.frame
-    }
+    pub fn into_inner(self) -> F { self.frame }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
pub fn new(frame: F) -> Self {
Self { frame }
}
/// Borrow the inner frame data.
#[must_use]
pub fn frame(&self) -> &F { &self.frame }
pub fn frame(&self) -> &F {
&self.frame
}
/// Mutable access to the frame data.
#[must_use]
pub fn frame_mut(&mut self) -> &mut F { &mut self.frame }
pub fn frame_mut(&mut self) -> &mut F {
&mut self.frame
}
/// Consume the container, returning the frame.
#[must_use]
pub fn into_inner(self) -> F { self.frame }
pub fn into_inner(self) -> F {
self.frame
}
pub fn new(frame: F) -> Self { Self { frame } }
/// Borrow the inner frame data.
#[must_use]
pub fn frame(&self) -> &F { &self.frame }
/// Mutable access to the frame data.
#[must_use]
pub fn frame_mut(&mut self) -> &mut F { &mut self.frame }
/// Consume the container, returning the frame.
#[must_use]
pub fn into_inner(self) -> F { self.frame }
🧰 Tools
🪛 GitHub Check: build-test

[warning] 38-38:
Diff in /home/runner/work/wireframe/wireframe/src/middleware.rs


[warning] 32-32:
Diff in /home/runner/work/wireframe/wireframe/src/middleware.rs


[warning] 26-26:
Diff in /home/runner/work/wireframe/wireframe/src/middleware.rs

🤖 Prompt for AI Agents
In src/middleware.rs between lines 20 and 40, the methods of FrameContainer are
currently formatted with multiple lines. To comply with cargo fmt standards and
improve readability, refactor all these simple methods to single-line format,
keeping the entire method definition on one line each.

Comment thread src/middleware.rs
Comment on lines 142 to 144

/// Call the next service with the provided request.
///
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.

⚠️ Potential issue

Fix remaining formatting issues for single-expression methods.

These simple methods should use single-line format.

Apply this diff:

-    pub fn new(service: &'a S) -> Self {
-        Self { service }
-    }
+    pub fn new(service: &'a S) -> Self { Self { service } }

-    pub fn new(f: F) -> Self {
-        Self { f }
-    }
+    pub fn new(f: F) -> Self { Self { f } }

-pub fn from_fn<F>(f: F) -> FromFn<F> {
-    FromFn::new(f)
-}
+pub fn from_fn<F>(f: F) -> FromFn<F> { FromFn::new(f) }

-    pub const fn id(&self) -> u32 {
-        self.id
-    }
+    pub const fn id(&self) -> u32 { self.id }

Also applies to: 195-197, 226-228, 309-311

🤖 Prompt for AI Agents
In src/middleware.rs at lines 142-144, 195-197, 226-228, and 309-311, the
single-expression methods are currently using multi-line formatting. Refactor
these methods to use a single-line format by placing the entire method
definition on one line to improve code consistency and readability.

.field("frames_len", &self.frames.len())
.finish()
}
}
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.

⚠️ Potential issue

Fix the formatting issue.

Line 26 does not conform to cargo fmt standards.

Run cargo fmt --all to fix the formatting.

🧰 Tools
🪛 GitHub Actions: CI

[error] 26-26: cargo fmt formatting check failed. Line 26 does not conform to the expected formatting style. Run 'cargo fmt --all' to fix code style issues.

🤖 Prompt for AI Agents
In tests/correlation_world.rs at line 26, the closing brace does not conform to
cargo fmt standards. Run `cargo fmt --all` in the project root to automatically
fix the formatting issues and ensure the code matches the standard Rust style
guidelines.

Comment on lines +51 to +61
#[allow(dead_code)]
pub async fn run_actor(&mut self) {
self.run_actor_with_frames(
vec![
Envelope::new(1, self.correlation_id, vec![1]),
Envelope::new(1, self.correlation_id, vec![2]),
],
1,
)
.await;
}
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.

⚠️ Potential issue

Remove the dead code or document its purpose.

The #[allow(dead_code)] suppression violates coding guidelines. Either remove this unused method or replace the suppression with #[expect(dead_code, reason = "...")] explaining why it's kept.

🤖 Prompt for AI Agents
In tests/correlation_world.rs around lines 51 to 61, the run_actor method is
marked with #[allow(dead_code)], which violates coding guidelines. Either remove
this unused method entirely if it is not needed, or replace the
#[allow(dead_code)] attribute with #[expect(dead_code, reason = "explain why
this method is kept, e.g., used in future tests or for debugging purposes")] to
document its purpose clearly.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Aug 4, 2025

Stale

@leynos leynos closed this Aug 4, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant