Skip to content

Add correlation id to frame header#280

Merged
leynos merged 4 commits intomainfrom
geg70w-codex/add-correlation_id-field-to-frame-header
Aug 7, 2025
Merged

Add correlation id to frame header#280
leynos merged 4 commits intomainfrom
geg70w-codex/add-correlation_id-field-to-frame-header

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Aug 6, 2025

Summary

  • extend Packet and default Envelope with a correlation_id
  • propagate the correlation_id through middleware and responses
  • document and test multi-frame correlation handling

Testing

  • make fmt
  • make lint
  • make test
  • make markdownlint
  • make nixie (fails: FileNotFound: failed copying files from cache to destination for package lodash-es)

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

Summary by Sourcery

Add support for request correlation IDs in frame headers and propagate them through packet APIs, middleware, service handlers, and response streams.

New Features:

  • Introduce a 64-bit correlation_id field in the frame header and update Packet and Envelope APIs to include the correlation ID

Enhancements:

  • Refactor Envelope to embed a PacketHeader struct and adapt middleware (ServiceRequest) and route services to handle correlation IDs
  • Update server handling logic to forward the correlation ID in multi-frame responses
  • Update examples to demonstrate correlation ID usage

Documentation:

  • Extend documentation, README, design docs, and roadmap to describe the new correlation_id feature and usage

Tests:

  • Add unit and integration tests (including Cucumber scenarios) to verify correlation ID propagation in single- and multi-frame streams

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Aug 6, 2025

Reviewer's Guide

Introduces a 64-bit correlation_id into every frame by extending the core Packet and Envelope types, propagates this identifier through middleware and service request/response flows, updates the connection handling logic, and refreshes tests, examples, and documentation to ensure consistent multi-frame correlation.

Sequence diagram for correlation_id propagation through request/response flow

sequenceDiagram
    participant Client
    participant ConnectionActor
    participant RouteService
    participant Handler
    Client->>ConnectionActor: Send Envelope (id, correlation_id, msg)
    ConnectionActor->>RouteService: ServiceRequest(msg, correlation_id)
    RouteService->>Handler: from_parts(id, correlation_id, msg)
    Handler-->>RouteService: Response
    RouteService->>ConnectionActor: Envelope.new(id, correlation_id, resp_msg)
    ConnectionActor->>Client: Send Envelope (id, correlation_id, resp_msg)
Loading

Class diagram for updated Packet, Envelope, and PacketHeader types

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

Class diagram for updated ServiceRequest and RouteService

classDiagram
    class ServiceRequest {
        +inner: FrameContainer<Vec<u8>>
        +correlation_id: u64
        +new(frame: Vec<u8>, correlation_id: u64)
        +frame() &[u8]
        +correlation_id() u64
        +frame_mut() &mut Vec<u8>
    }
    class RouteService {
        +call(req: ServiceRequest) -> Result<ServiceResponse, Self::Error>
    }
    ServiceRequest --> FrameContainer
    RouteService --> ServiceRequest
Loading

File-Level Changes

Change Details Files
Extend Packet trait and Envelope framing to include a correlation_id
  • Added Packet::correlation_id method and updated into_parts/from_parts signatures
  • Introduced PacketHeader to encapsulate id and correlation_id
  • Refactored Envelope struct, constructor, and Packet impl to use the new header
src/app.rs
Propagate correlation_id through middleware and service layer
  • Updated ServiceRequest to accept and expose correlation_id
  • Adjusted RouteService::call to forward correlation_id when constructing packets
  • Modified connection loop to pass correlation_id into ServiceRequest and response Envelope
src/middleware.rs
src/app.rs
Adapt test suite and examples for correlation_id support
  • Updated existing Packet implementations and Envelope::new calls in tests
  • Extended cucumber runner with CorrelationWorld and step definitions
  • Added feature spec and unit test to verify correlation_id on streamed frames
tests/world.rs
tests/cucumber.rs
tests/routes.rs
tests/lifecycle.rs
tests/metadata.rs
tests/middleware.rs
tests/middleware_order.rs
tests/steps/mod.rs
tests/correlation_id.rs
tests/steps/correlation_steps.rs
tests/features/correlation_id.feature
Update documentation and sample code to document correlation_id usage
  • Documented correlation_id field in README, design docs, and roadmap
  • Refreshed metadata_routing example to include the new field
README.md
docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
docs/roadmap.md
examples/metadata_routing.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 6, 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.

Warning

Rate limit exceeded

@leynos has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 10 minutes and 2 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 6f88430 and 524e68a.

📒 Files selected for processing (1)
  • tests/cucumber.rs (1 hunks)

Summary by CodeRabbit

  • New Features

    • Introduced a correlation ID field to packets, envelopes, and service requests, enabling tracking and propagation of request identifiers through multi-part responses.
    • Added new test scenarios and Cucumber steps to verify correlation ID behaviour in streaming and routing contexts.
  • Bug Fixes

    • Ensured correlation IDs are preserved across all response frames.
  • Documentation

    • Updated documentation and examples to describe correlation ID usage and propagation.
  • Tests

    • Expanded and updated tests to cover correlation ID propagation and validation in various scenarios.

Walkthrough

Extend the protocol, core logic, and test suite to introduce and propagate a correlation_id field of type u64 throughout the packet lifecycle. Update all relevant struct definitions, trait signatures, method implementations, and documentation. Add and adapt tests and Cucumber steps to verify correct handling and propagation of the correlation ID in both single and streaming scenarios.

Changes

Cohort / File(s) Change Summary
Core Protocol & Envelope Structures
src/app.rs, src/middleware.rs
Add correlation_id to Envelope, Packet, and ServiceRequest. Update trait and method signatures to handle the new field. Ensure correlation ID is propagated in request/response handling.
Documentation
README.md, docs/roadmap.md, docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
Update documentation and examples to describe and demonstrate the new correlation_id field in the protocol and envelope structures. Mark roadmap item as complete.
Example
examples/metadata_routing.rs
Update envelope construction to include correlation ID argument.
Test Envelope & Routing
tests/routes.rs, tests/lifecycle.rs
Add correlation_id to test envelope structs and update trait implementations and test assertions to verify propagation.
Test Middleware
tests/middleware.rs, tests/middleware_order.rs, tests/metadata.rs
Update test envelope/request construction and destructuring to include the correlation ID field. Adjust test logic accordingly.
Correlation ID Feature & Steps
tests/correlation_id.rs, tests/features/correlation_id.feature, tests/steps/correlation_steps.rs, tests/steps/mod.rs, tests/world.rs, tests/cucumber.rs
Add new test world, Cucumber feature, and step implementations to verify streamed frames reuse the request correlation ID. Integrate new steps and world into the test runner.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant App
    participant Handler
    participant ResponseStream

    Client->>App: Send Frame (id, correlation_id, msg)
    App->>Handler: Pass Envelope (id, correlation_id, msg)
    Handler-->>App: Return Envelope (id, correlation_id, response_msg)
    App-->>Client: Send Frame (id, correlation_id, response_msg)
    Note over App,Client: correlation_id remains unchanged throughout
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Poem

Correlation flows, a thread of gold,
Through every packet, brave and bold.
From tests to docs, the ID persists,
In streaming frames, it still exists.
Now every message knows its kin—
Let the tracing games begin!
📨🔗✨

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch geg70w-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 and they look great!

Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments

### Comment 1
<location> `src/app.rs:199` </location>
<code_context>
 /// message identifier and raw payload bytes.
-#[derive(bincode::Decode, bincode::Encode)]
+#[derive(bincode::Decode, bincode::Encode, Debug)]
 pub struct Envelope {
     pub(crate) id: u32,
+    pub(crate) correlation_id: u64,
</code_context>

<issue_to_address>
Consider grouping the identifier fields into a PacketHeader struct and delegating Envelope methods to reduce duplication.

```rust
// 1) Group the two `u32`/`u64` identifiers into a small struct:
#[derive(Copy, Clone, Debug)]
pub struct PacketHeader {
    pub id: u32,
    pub correlation_id: u64,
}

// 2) Change `Envelope` to own a `PacketHeader` + `msg`, and keep only one
//    `new`/`into_parts` implementation:
#[derive(bincode::Decode, bincode::Encode, Debug)]
pub struct Envelope {
    pub header: PacketHeader,
    pub msg: Vec<u8>,
}

impl Envelope {
    #[must_use]
    pub fn new(id: u32, correlation_id: u64, msg: Vec<u8>) -> Self {
        Self {
            header: PacketHeader { id, correlation_id },
            msg,
        }
    }

    #[must_use]
    pub fn into_parts(self) -> (PacketHeader, Vec<u8>) {
        (self.header, self.msg)
    }
}

// 3) Delegate `Packet`‐trait methods to those two helpers, eliminating boilerplate:
impl Packet for Envelope {
    fn id(&self) -> u32 {
        self.header.id
    }

    fn correlation_id(&self) -> u64 {
        self.header.correlation_id
    }

    fn into_parts(self) -> (u32, u64, Vec<u8>) {
        let (header, msg) = Envelope::into_parts(self);
        (header.id, header.correlation_id, msg)
    }

    fn from_parts(id: u32, correlation_id: u64, msg: Vec<u8>) -> Self {
        Envelope::new(id, correlation_id, msg)
    }
}
```

This:

- Collapses your two separate fields into one `PacketHeader`.
- Leaves you only one `new`/`into_parts` implementation in `Envelope`.
- Makes the `Packet` impl a thin wrapper that just *delegates* to those methods.
</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.

Comment thread src/app.rs Outdated
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Aug 7, 2025

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Aug 7, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 4

🔭 Outside diff range comments (1)
tests/cucumber.rs (1)

1-4: Update documentation to reflect dual test contexts.

The file now runs both panic and correlation ID tests, but the documentation only mentions panic resilience testing.

Apply this diff to update the documentation:

-//! Cucumber test runner for panic resilience integration tests.
+//! Cucumber test runner for integration tests.
 //!
-//! Runs behavioural tests defined in `tests/features/` using the
-//! `PanicWorld` test context to verify server panic handling.
+//! Runs behavioural tests defined in `tests/features/` using appropriate
+//! test contexts to verify server panic handling and correlation ID propagation.
♻️ Duplicate comments (1)
src/app.rs (1)

198-235: Refactor to reduce duplication between Envelope and Packet implementations

The current implementation duplicates the identifier handling logic. Extract the identifiers into a PacketHeader struct as previously suggested to improve maintainability and reduce code duplication.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between e890d53 and 338d53e.

📒 Files selected for processing (17)
  • README.md (2 hunks)
  • docs/roadmap.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/app.rs (4 hunks)
  • src/middleware.rs (2 hunks)
  • tests/correlation_id.rs (1 hunks)
  • tests/cucumber.rs (1 hunks)
  • tests/features/correlation_id.feature (1 hunks)
  • tests/lifecycle.rs (2 hunks)
  • tests/metadata.rs (2 hunks)
  • tests/middleware.rs (1 hunks)
  • tests/middleware_order.rs (2 hunks)
  • tests/routes.rs (5 hunks)
  • tests/steps/correlation_steps.rs (1 hunks)
  • tests/steps/mod.rs (1 hunks)
  • tests/world.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.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/steps/mod.rs
  • tests/cucumber.rs
  • tests/metadata.rs
  • tests/middleware_order.rs
  • tests/middleware.rs
  • tests/steps/correlation_steps.rs
  • examples/metadata_routing.rs
  • src/middleware.rs
  • tests/lifecycle.rs
  • tests/routes.rs
  • tests/world.rs
  • tests/correlation_id.rs
  • src/app.rs
**/*.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/roadmap.md
  • docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md
  • README.md
🧬 Code Graph Analysis (7)
tests/middleware_order.rs (1)
src/app.rs (2)
  • new (208-214)
  • new (309-309)
tests/middleware.rs (1)
src/middleware.rs (6)
  • new (20-20)
  • new (45-50)
  • new (78-82)
  • new (129-129)
  • new (180-180)
  • new (266-276)
tests/steps/correlation_steps.rs (1)
tests/world.rs (1)
  • cid (129-129)
src/middleware.rs (3)
src/app.rs (6)
  • new (208-214)
  • new (309-309)
  • correlation_id (185-185)
  • correlation_id (224-224)
  • from_parts (191-191)
  • from_parts (228-234)
tests/lifecycle.rs (2)
  • correlation_id (112-112)
  • from_parts (116-122)
tests/routes.rs (2)
  • correlation_id (31-31)
  • from_parts (35-41)
tests/lifecycle.rs (1)
src/app.rs (9)
  • id (182-182)
  • id (222-222)
  • correlation_id (185-185)
  • correlation_id (224-224)
  • into_parts (188-188)
  • into_parts (218-218)
  • into_parts (226-226)
  • from_parts (191-191)
  • from_parts (228-234)
tests/routes.rs (2)
tests/lifecycle.rs (4)
  • id (110-110)
  • correlation_id (112-112)
  • into_parts (114-114)
  • from_parts (116-122)
src/app.rs (10)
  • id (182-182)
  • id (222-222)
  • correlation_id (185-185)
  • correlation_id (224-224)
  • into_parts (188-188)
  • into_parts (218-218)
  • into_parts (226-226)
  • from_parts (191-191)
  • from_parts (228-234)
  • from (143-143)
tests/world.rs (3)
src/app.rs (4)
  • new (208-214)
  • new (309-309)
  • correlation_id (185-185)
  • correlation_id (224-224)
tests/connection_actor.rs (1)
  • queues (25-25)
src/push.rs (1)
  • bounded (297-300)
🪛 LanguageTool
docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md

[uncategorized] ~63-~63: Use a comma before ‘so’ if it connects two independent clauses (unless they are closely connected and short).
Context: ... each message in a multi-packet response so clients can tie fragments back to their...

(COMMA_COMPOUND_SENTENCE_2)

🔇 Additional comments (25)
tests/features/correlation_id.feature (1)

1-5: Well-structured BDD scenario for correlation ID testing.

The Gherkin syntax is correct and the scenario clearly tests the core requirement that streamed frames preserve the request correlation ID throughout processing.

tests/steps/mod.rs (1)

6-6: Proper integration of correlation steps module.

The addition follows the existing pattern and correctly exposes the new correlation step definitions for the Cucumber test framework.

docs/roadmap.md (1)

182-184: Roadmap item correctly marked as completed.

The correlation_id field implementation has been completed and this documentation update properly reflects that achievement.

tests/metadata.rs (2)

63-63: Constructor updated to match new Envelope signature.

The addition of the correlation_id parameter (0) correctly aligns the test with the updated Envelope::new signature whilst maintaining the test's focus on metadata parsing.


108-108: Constructor updated to match new Envelope signature.

The addition of the correlation_id parameter (0) correctly aligns the test with the updated Envelope::new signature whilst maintaining the test's focus on metadata parsing.

tests/cucumber.rs (1)

10-16: Test execution properly separated by context.

The separation of PanicWorld and CorrelationWorld test execution allows each context to handle its specific feature files appropriately.

tests/middleware_order.rs (2)

67-67: LGTM!

Correctly updated Envelope::new to include the correlation_id parameter, maintaining consistency with the new constructor signature.


91-91: LGTM!

Properly updated destructuring to handle the additional correlation_id field from into_parts().

tests/correlation_id.rs (1)

1-24: Excellent test coverage for correlation ID propagation.

This test effectively validates that correlation IDs are preserved through streaming responses, directly testing the core feature introduced in this PR.

tests/middleware.rs (1)

57-57: LGTM!

Correctly updated ServiceRequest::new to include the correlation_id parameter, maintaining test compatibility with the updated constructor.

examples/metadata_routing.rs (1)

55-55: LGTM!

Correctly updated Envelope::new to include the correlation_id parameter, maintaining example compatibility with the new constructor signature.

README.md (1)

101-110: LGTM! Documentation correctly reflects the correlation_id extension.

The custom envelope example properly demonstrates the new correlation_id field integration with the Packet trait. The method signatures and struct definition align with the broader codebase changes.

tests/steps/correlation_steps.rs (1)

1-16: LGTM! Clean and focused BDD step definitions.

The cucumber step implementations properly interact with the CorrelationWorld and provide clear, focused test scenarios for correlation_id propagation verification.

tests/lifecycle.rs (2)

105-123: LGTM! StateEnvelope correctly updated for correlation_id support.

The struct extension and Packet trait implementation properly integrate the correlation_id field, maintaining consistency with the codebase-wide changes.


137-137: LGTM! Test data updated correctly.

The test instance properly includes the correlation_id parameter with a sensible default value.

src/middleware.rs (3)

39-50: LGTM! ServiceRequest correctly extended with correlation_id.

The struct extension and constructor update properly integrate correlation_id propagation through the middleware layer.


56-58: LGTM! Appropriate accessor method for correlation_id.

The getter method provides clean access to the correlation_id field with proper documentation and attributes.


306-309: LGTM! RouteService correctly handles correlation_id propagation.

The service implementation properly passes the correlation_id to from_parts and correctly destructures the 3-tuple from into_parts, maintaining the correlation_id through the request lifecycle.

tests/routes.rs (4)

22-26: LGTM!

The correlation_id field addition to the test envelope struct is correct and properly typed.


28-42: LGTM!

The Packet trait implementation correctly includes the correlation ID in all required methods, maintaining consistency with the trait definition.


67-89: LGTM!

The test correctly verifies correlation ID propagation through the echo response flow.


102-146: LGTM!

The test appropriately verifies that correlation IDs are preserved for multiple frames processed in sequence.

src/app.rs (3)

151-192: LGTM!

The documentation example correctly demonstrates the Packet trait implementation with the new correlation ID field.


283-309: LGTM!

The example documentation correctly illustrates the custom envelope implementation with correlation ID support.


725-738: LGTM!

The handle_frame method correctly propagates the correlation ID from request to response, enabling proper request-response correlation.

Comment thread docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md Outdated
Comment thread tests/world.rs Outdated
Comment thread tests/world.rs Outdated
Comment thread tests/world.rs Outdated
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: 1

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 7cc9b11 and 6f88430.

📒 Files selected for processing (1)
  • tests/cucumber.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.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

⚙️ 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
🔍 MCP Research (1 server)

Deepwiki:

  • Document [docs/roadmap.md]: The checklist item for adding a correlation_id field to the Frame header in the protocol enhancement section of the roadmap was changed from incomplete ("[ ]") to completed ("[x]"). This indicates that the feature of including a unique request ID in the Frame header, which must be matched by each message in a multi-packet response, has been implemented.

  • Document [docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md]: The documentation was updated to specify that each frame header now includes a 64-bit correlation_id. This identifier is set by the request and repeated in every packet of a multi-part response, enabling clients to correlate response frames with their originating request.

  • Document [src/app.rs]: The Packet trait has been extended to include a correlation_id method returning a u64, and the signatures of into_parts and from_parts have been updated to include the correlation ID as an additional parameter and return value. The Envelope struct has been refactored to embed a new PacketHeader struct containing both id and correlation_id fields, replacing the previous flat structure. The handle_frame method now routes and constructs service requests including the correlation ID, and responses preserve this ID. Logging statements were updated accordingly.

  • Document [src/middleware.rs]: The ServiceRequest struct was extended with a new correlation_id field of type u64. Its constructor new was updated to accept this additional parameter and initialize the field. A new accessor method correlation_id() was added. The RouteService implementation was updated to call E::from_parts with the correlation ID and to destructure env.into_parts() into three components.

🔇 Additional comments (2)
tests/cucumber.rs (2)

11-11: LGTM!

The import correctly includes both test world contexts needed for the separated test suites.


14-17: LGTM!

The sequential execution of distinct test suites is well-structured and aligns with the separation of concerns between panic resilience and correlation ID testing. The approach ensures each test context operates independently with appropriate state management.

Comment thread tests/cucumber.rs Outdated
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Aug 7, 2025

@sourcery-ai review

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:

  • Consider switching correlation_id from a raw u64 to Option so you can distinguish frames that never had a correlation set from those explicitly using zero, avoiding ambiguous defaults.
  • The Packet trait’s into_parts/from_parts methods currently use a bare (u32, u64, Vec) tuple—refactor these to use the PacketHeader (or a dedicated PacketParts struct) for clarity and to reduce repeated tuple unpacking.
  • Update your tracing/logging calls (e.g. in handle_connection) to include correlation_id alongside the message id, which will make debugging multi‐frame flows much easier.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- Consider switching correlation_id from a raw u64 to Option<u64> so you can distinguish frames that never had a correlation set from those explicitly using zero, avoiding ambiguous defaults.
- The Packet trait’s into_parts/from_parts methods currently use a bare (u32, u64, Vec<u8>) tuple—refactor these to use the PacketHeader (or a dedicated PacketParts struct) for clarity and to reduce repeated tuple unpacking.
- Update your tracing/logging calls (e.g. in handle_connection) to include correlation_id alongside the message id, which will make debugging multi‐frame flows much easier.

## Individual Comments

### Comment 1
<location> `tests/middleware.rs:57` </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>
No test for non-zero correlation_id in middleware.

Add a test with a non-zero correlation_id to verify the middleware preserves its value.

Suggested implementation:

```rust
    let mw = ModifyMiddleware;
    let wrapped = mw.transform(service).await;

    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'?']);
}

#[tokio::test]
async fn test_modify_middleware_preserves_nonzero_correlation_id() {
    let service = TestService;
    let mw = ModifyMiddleware;
    let wrapped = mw.transform(service).await;

    let correlation_id = 42;
    let request = ServiceRequest::new(vec![4, 5, 6], correlation_id);
    let response = wrapped.call(request).await.expect("middleware call failed");
    assert_eq!(response.frame(), &[4, 5, 6, b'!', b'?']);
    assert_eq!(response.correlation_id(), correlation_id);
}

```

- This assumes that `ServiceResponse` (the type returned by `wrapped.call`) has a `correlation_id()` method. If not, you may need to adjust the assertion to match your actual API for checking the correlation ID.
- If you use a test framework other than `tokio::test`, adjust the test attribute accordingly.
</issue_to_address>

### Comment 2
<location> `src/app.rs:199` </location>
<code_context>
-#[derive(bincode::Decode, bincode::Encode)]
-pub struct Envelope {
+#[derive(bincode::Decode, bincode::Encode, Copy, Clone, Debug)]
+pub struct PacketHeader {
     pub(crate) id: u32,
+    pub(crate) correlation_id: u64,
</code_context>

<issue_to_address>
Consider removing the PacketHeader struct and flattening its fields directly into Envelope to simplify the data structure.

```suggestion
// You can remove the extra `PacketHeader` type and flatten `Envelope` to avoid
// one more level of nesting + unpack/repack. For example:
//
// 1. Drop `PacketHeader` entirely:
//
//    #[derive(bincode::Decode, bincode::Encode, Debug)]
//    pub struct Envelope {
//        pub(crate) id: u32,
//        pub(crate) correlation_id: u64,
//        pub(crate) msg: Vec<u8>,
//    }
//
// 2. Adjust `new` and `into_parts` on `Envelope`:
//
//    impl Envelope {
//        #[must_use]
//        pub fn new(id: u32, correlation_id: u64, msg: Vec<u8>) -> Self {
//            Self { id, correlation_id, msg }
//        }
//
//        #[must_use]
//        pub fn into_parts(self) -> (u32, u64, Vec<u8>) {
//            (self.id, self.correlation_id, self.msg)
//        }
//    }
//
// 3. Simplify the `Packet` impl:
//
//    impl Packet for Envelope {
//        fn id(&self) -> u32 { self.id }
//        fn correlation_id(&self) -> u64 { self.correlation_id }
//        fn into_parts(self) -> (u32, u64, Vec<u8>) {
//            (self.id, self.correlation_id, self.msg)
//        }
//        fn from_parts(id: u32, correlation_id: u64, msg: Vec<u8>) -> Self {
//            Envelope::new(id, correlation_id, msg)
//        }
//    }
//
// Finally, update all `.header.id` / `.header.correlation_id` uses to `.id` /
// `.correlation_id`. This removes the extra struct and one unpack/repack cycle
// without losing any functionality.
```
</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.

Comment thread tests/middleware.rs
Comment thread src/app.rs
@leynos leynos merged commit ce4bce5 into main Aug 7, 2025
5 checks passed
@leynos leynos deleted the geg70w-codex/add-correlation_id-field-to-frame-header branch August 7, 2025 23:55
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