Skip to content

Conversation

leynos
Copy link
Owner

@leynos leynos commented Aug 27, 2025

Summary

  • add PushQueuesBuilder with configuration setters
  • deprecate bounded* constructors and expose PushQueues::builder
  • update tests to use the new builder

Testing

  • make fmt
  • make lint
  • make test

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

Summary by Sourcery

Introduce a builder pattern for PushQueues to configure capacities, rate limiting, and an optional dead-letter queue; deprecate existing bounded constructors in favor of the builder and update tests accordingly.

New Features:

  • Add PushQueuesBuilder with methods for high_capacity, low_capacity, rate, dlq, and build

Enhancements:

  • Add PushQueues::builder to initialize the builder using default settings
  • Deprecate bounded, bounded_no_rate_limit, bounded_with_rate, and bounded_with_rate_dlq constructors in favor of the builder API

Documentation:

  • Update documentation comments to reference PushQueuesBuilder and its methods

Tests:

  • Refactor existing tests to use the new builder API instead of deprecated constructors

Copy link
Contributor

coderabbitai bot commented Aug 27, 2025

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Summary by CodeRabbit

  • New Features

    • Introduced a builder-based API for prioritised push queues with configurable high/low capacities, optional rate limiting, and optional dead-letter queue.
    • Added a cloneable push handle and push policies for full-queue behaviour.
    • Exposed MAX_PUSH_RATE and clearer, actionable error types/messages for configuration and runtime.
  • Documentation

    • Updated guides and design docs to use the new builder workflow, with examples covering rate limits and DLQ configuration.
  • Tests

    • Migrated tests to the builder API, added validation for invalid rates, and improved error messaging.

Walkthrough

Introduce a prioritised push subsystem with high/low async queues, rate limiting and optional dead‑letter queue; add a builder-based construction API returning (PushQueues, PushHandle) with validation and error types; implement PushHandle push/try_push semantics and update tests/docs to use the builder.

Changes

Cohort / File(s) Summary
Push module & re-exports
src/push/mod.rs
Add push module entry; re-export selected queues items: MAX_PUSH_RATE, PushConfigError, PushError, PushHandle, PushPolicy, PushPriority, PushQueues, PushQueuesBuilder; expose crate-visible internals FrameLike, PushHandleInner.
Push queues core
src/push/queues/mod.rs, src/push/queues/builder.rs, src/push/queues/errors.rs, src/push/queues/handle.rs
Add prioritised non-blocking push queues with high/low mpsc channels, biased recv, FrameLike trait, MAX_PUSH_RATE, PushPriority/PushPolicy enums, PushQueues<F>, PushHandle/PushHandleInner, errors PushError/PushConfigError, and PushQueuesBuilder with chainable high_capacity, low_capacity, rate, dlq and build (validation returns Result).
Tests — builder migration
tests/... (multiple files, e.g., tests/push.rs, tests/advanced/*, tests/connection_actor.rs, tests/push_policies.rs, tests/session_registry.rs, tests/stream_end.rs, tests/wireframe_protocol.rs, tests/world.rs, tests/correlation_id.rs)
Replace PushQueues::bounded(...) and other direct constructors with PushQueues::<T>::builder().high_capacity(...).low_capacity(...).[rate(...)] .dlq(...).build().expect(...); add fixtures; adjust an error variant to PushError::QueueFull; change some unwrap() to expect(...); adjust lint attributes.
Tests — lint & minor adjustments
tests/push_policies.rs, tests/session_registry.rs, tests/server.rs
Replace some #[allow(...)] with #[expect(...)] and add #[allow(unfulfilled_lint_expectations)]; change unwrap() to expect(...) in one test for clearer panic messages.
Docs
docs/asynchronous-outbound-messaging-design.md, docs/hardening-wireframe-a-guide-to-production-resilience.md, docs/efficiency-report.md
Update design docs to describe builder-based construction, rate/DLQ options and diagrams; record micro-optimisation (freeze before to_vec) and formatting improvements.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Test as Test / Producer
  participant Builder as PushQueuesBuilder::<F>
  participant Creator as build_with_rate_dlq
  participant PQ as PushQueues::<F>
  participant PH as PushHandle::<F>

  Test->>Builder: PushQueues::builder()
  Builder-->>Test: PushQueuesBuilder
  Test->>Builder: high_capacity(...), low_capacity(...), rate(...), dlq(...)
  Test->>Builder: build()
  Builder->>Creator: validate capacities & rate, create channels, limiter, DLQ
  Creator-->>Builder: Result<(PushQueues, PushHandle), PushConfigError>
  Builder-->>Test: Result<(PQ, PH), PushConfigError>
  note right of Test: Tests unwrap via expect(...)
Loading
sequenceDiagram
  autonumber
  participant Producer as Producer
  participant PH as PushHandle
  participant RL as RateLimiter?
  participant HQ as High-prio mpsc
  participant LQ as Low-prio mpsc
  participant PQ as PushQueues
  participant Consumer as Connection/Consumer

  Producer->>PH: try_push(frame, priority, policy)
  alt rate limiter configured
    PH->>RL: consume token (async)
  end
  alt priority == High
    PH->>HQ: send(frame)
  else priority == Low
    PH->>LQ: send(frame)
  end
  par biased receive
    PQ->>HQ: recv() (biased)
    PQ->>LQ: recv()
  end
  PQ-->>Consumer: (priority, frame)
  note over PH,PQ: On full: return `QueueFull` or drop to DLQ per `PushPolicy`.<br/>On closed: return `Closed`.
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

Two lanes for frames, one high, one low,
A builder now whispers which way to go.
A leaky bucket ticks, “pace every beat,”
DLQ cradles what the queue could not keep.
Tests step in time, fluent, neat—push on, repeat.

Run these checks locally:
- Verify builder validation rejects zero capacities and out-of-range rates (test PushConfigError variants).
- Verify MAX_PUSH_RATE bound enforcement and error messages match tests.
- Verify DLQ routing on drop and that WarnAndDropIfFull logs as expected.
- Verify biased recv behaviour under contention and concurrency tests still pass.
- Run full test suite and fix any regressions.
✨ Finishing Touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/introduce-pushqueuesbuilder-with-deprecation

🪧 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.
    • 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.
  • 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 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/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit 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

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • 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.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Contributor

sourcery-ai bot commented Aug 27, 2025

Reviewer's Guide

This PR introduces a fluent builder pattern for configuring PushQueues, replaces legacy constructors with a shared build implementation, and updates all documentation and tests to use the new API.

Class diagram for PushQueuesBuilder and PushQueues changes

classDiagram
    class PushQueuesBuilder {
        +high_capacity: usize
        +low_capacity: usize
        +rate: Option<usize>
        +dlq: Option<mpsc::Sender<F>>
        +new() PushQueuesBuilder
        +high_capacity(capacity: usize) PushQueuesBuilder
        +low_capacity(capacity: usize) PushQueuesBuilder
        +rate(rate: Option<usize>) PushQueuesBuilder
        +dlq(dlq: Option<mpsc::Sender<F>>) PushQueuesBuilder
        +build() Result<(PushQueues<F>, PushHandle<F>), PushConfigError>
    }
    class PushQueues {
        +builder() PushQueuesBuilder
        +build_with_rate_dlq(...)
        +bounded(...) [deprecated]
        +bounded_no_rate_limit(...) [deprecated]
        +bounded_with_rate(...) [deprecated]
        +bounded_with_rate_dlq(...) [deprecated]
    }
    PushQueuesBuilder --> PushQueues : builds
Loading

Class diagram for deprecated PushQueues constructors

classDiagram
    class PushQueues {
        +bounded(high_capacity: usize, low_capacity: usize) (deprecated)
        +bounded_no_rate_limit(high_capacity: usize, low_capacity: usize) (deprecated)
        +bounded_with_rate(high_capacity: usize, low_capacity: usize, rate: Option<usize>) (deprecated)
        +bounded_with_rate_dlq(high_capacity: usize, low_capacity: usize, rate: Option<usize>, dlq: Option<mpsc::Sender<F>>) (deprecated)
    }
Loading

File-Level Changes

Change Details Files
Introduce PushQueuesBuilder with fluent configuration
  • Add PushQueuesBuilder struct with setters for high_capacity, low_capacity, rate, and dlq
  • Implement build() to delegate to PushQueues::build_with_rate_dlq
  • Expose PushQueues::builder() to start the builder
src/push/queues.rs
Deprecate old bounded constructors in favor of the builder
  • Mark bounded, bounded_no_rate_limit, bounded_with_rate, and bounded_with_rate_dlq as #[deprecated]
  • Redirect their implementations to the builder API
src/push/queues.rs
Unify queue construction logic into a private helper
  • Extract build_with_rate_dlq to handle rate validation, channel creation, and limiter setup
  • Reuse build_with_rate_dlq across builder.build() and deprecated methods
src/push/queues.rs
Update documentation and code examples to use the builder
  • Revise doc comments for MAX_PUSH_RATE reference and example snippets
  • Replace PushQueues::bounded* examples with builder calls
src/push/queues.rs
Refactor tests to exercise the builder API
  • Replace all PushQueues::bounded* and bounded_with_rate* calls with PushQueues::builder()
  • Adjust tests to unwrap builder.build() results
tests/push.rs
tests/connection_actor.rs
tests/push_policies.rs
tests/stream_end.rs
tests/wireframe_protocol.rs
tests/world.rs
tests/session_registry.rs
tests/advanced/interaction_fuzz.rs
tests/async_stream.rs
tests/correlation_id.rs
tests/advanced/concurrency_loom.rs
Add new module export for queues
  • Create src/push/mod.rs to re-export queues module
src/push/mod.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

Copy link
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 there - I've reviewed your changes and they look great!


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.

Copy link
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: 22

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
tests/push.rs (3)

31-35: Correct variant name in test docs.

Use PushError::QueueFull (not Full).

-/// return `PushError::Full` once the queue is at capacity.
+/// return `PushError::QueueFull` once the queue is at capacity.

44-46: Assert the precise error variant.

Tighten the assertion to validate policy behaviour.

-    assert!(result.is_err());
+    assert!(matches!(result, Err(PushError::QueueFull)));

79-113: Deduplicate queue construction with a rstest fixture.

Reduce repetition and centralise capacities/rate/DLQ wiring.

Example fixture to add in this module:

#[fixture]
fn queues() -> (PushQueues<u8>, wireframe::push::PushHandle<u8>) {
    PushQueues::builder()
        .high_capacity(2)
        .low_capacity(2)
        .rate(Some(1))
        .build()
        .expect("queue creation failed")
}

Then replace repeated builders with let (mut queues, handle) = queues();.

Also applies to: 115-161, 181-210

tests/push_policies.rs (1)

15-18: Replace forbidden #[allow] with narrowly scoped #[expect].

Fix compilation (reason is not valid in #[allow]) and follow lint policy.

-#[allow(
-    unused_braces,
-    reason = "rustc false positive for single line rstest fixtures"
-)]
+#[expect(unused_braces, reason = "rustc false positive for single line rstest fixtures")]
src/push/queues.rs (2)

489-495: Bias towards high priority is explicit.

Starvation is intentional; document this nuance in the enum or recv() docs.

 /// Receive the next frame, preferring high priority frames when available.
 ///
 /// Returns `None` when both queues are closed and empty.
 ///
 /// # Examples
+///
+/// Note: this method is biased towards high priority traffic and may starve
+/// low priority frames if producers saturate the high queue.

26-34: Make the compile‑time guard explicit (optional).

Assert the invariant directly for clarity.

-// Compile-time guard: DEFAULT_PUSH_RATE must not exceed MAX_PUSH_RATE.
-const _: usize = MAX_PUSH_RATE - DEFAULT_PUSH_RATE;
+// Compile-time guard: DEFAULT_PUSH_RATE must not exceed MAX_PUSH_RATE.
+const _: () = assert!(DEFAULT_PUSH_RATE <= MAX_PUSH_RATE);

Note: require a Rust toolchain where const panics are stable; otherwise keep existing guard.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 49b2adb and 35f4bf4.

📒 Files selected for processing (13)
  • src/push/mod.rs (1 hunks)
  • src/push/queues.rs (8 hunks)
  • tests/advanced/concurrency_loom.rs (1 hunks)
  • tests/advanced/interaction_fuzz.rs (1 hunks)
  • tests/async_stream.rs (1 hunks)
  • tests/connection_actor.rs (3 hunks)
  • tests/correlation_id.rs (1 hunks)
  • tests/push.rs (8 hunks)
  • tests/push_policies.rs (3 hunks)
  • tests/session_registry.rs (1 hunks)
  • tests/stream_end.rs (2 hunks)
  • tests/wireframe_protocol.rs (2 hunks)
  • tests/world.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless 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
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • src/push/mod.rs
  • tests/stream_end.rs
  • tests/session_registry.rs
  • tests/wireframe_protocol.rs
  • tests/advanced/concurrency_loom.rs
  • tests/async_stream.rs
  • tests/connection_actor.rs
  • tests/world.rs
  • tests/push.rs
  • tests/correlation_id.rs
  • tests/push_policies.rs
  • src/push/queues.rs
  • tests/advanced/interaction_fuzz.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.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • 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.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • src/push/mod.rs
  • tests/stream_end.rs
  • tests/session_registry.rs
  • tests/wireframe_protocol.rs
  • tests/advanced/concurrency_loom.rs
  • tests/async_stream.rs
  • tests/connection_actor.rs
  • tests/world.rs
  • tests/push.rs
  • tests/correlation_id.rs
  • tests/push_policies.rs
  • src/push/queues.rs
  • tests/advanced/interaction_fuzz.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • src/push/mod.rs
  • tests/stream_end.rs
  • tests/session_registry.rs
  • tests/wireframe_protocol.rs
  • tests/advanced/concurrency_loom.rs
  • tests/async_stream.rs
  • tests/connection_actor.rs
  • tests/world.rs
  • tests/push.rs
  • tests/correlation_id.rs
  • tests/push_policies.rs
  • src/push/queues.rs
  • tests/advanced/interaction_fuzz.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/stream_end.rs
  • tests/session_registry.rs
  • tests/wireframe_protocol.rs
  • tests/advanced/concurrency_loom.rs
  • tests/async_stream.rs
  • tests/connection_actor.rs
  • tests/world.rs
  • tests/push.rs
  • tests/correlation_id.rs
  • tests/push_policies.rs
  • tests/advanced/interaction_fuzz.rs
🧬 Code graph analysis (12)
src/push/mod.rs (1)
tests/connection_actor.rs (1)
  • queues (25-31)
tests/stream_end.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
tests/session_registry.rs (1)
src/push/queues.rs (1)
  • builder (359-359)
tests/wireframe_protocol.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
tests/advanced/concurrency_loom.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
tests/async_stream.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
tests/connection_actor.rs (1)
src/push/queues.rs (1)
  • builder (359-359)
tests/world.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
tests/push.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
tests/correlation_id.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
tests/push_policies.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
tests/advanced/interaction_fuzz.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
🔍 Remote MCP

Here are the key facts and concrete details to aid your review:

• A new fluent builder API was introduced in src/push/queues.rs:
– Added pub struct PushQueuesBuilder<F> with fields high_capacity, low_capacity, rate, and dlq.
– Chainable methods:
high_capacity(usize) -> Self
low_capacity(usize) -> Self
rate(Option<usize>) -> Self
dlq(Option<mpsc::Sender<F>>) -> Self
build(self) -> Result<(PushQueues<F>, PushHandle<F>), PushConfigError> which delegates to the new private helper PushQueues::build_with_rate_dlq(...). (github.com)

• Exposed the builder via

impl<F: FrameLike> PushQueues<F> {
    #[must_use]
    pub fn builder() -> PushQueuesBuilder<F> { PushQueuesBuilder::new() }
    // …
}

and consolidated all queue‐construction logic—capacity setup, optional rate limiting (with 1s refill intervals), and optional dead‐letter queue—into build_with_rate_dlq. (github.com)

• The four legacy constructors on PushQueues were deprecated and repointed to the builder:

#[deprecated(since = "0.1.0", note = "Use `PushQueues::builder` instead")]
pub fn bounded()(Self, PushHandle<F>) {}
#[deprecated()] pub fn bounded_no_rate_limit() {}
#[deprecated()] pub fn bounded_with_rate() {}
#[deprecated()] pub fn bounded_with_rate_dlq() {}

All now simply call through to the builder API. (github.com)

• A new module file src/push/mod.rs (5 additions) was added to re-export the queues API:

//! Prioritised queues used for asynchronously pushing frames to a connection.
mod queues;
pub use queues::*;
``` ([github.com](https://github.com/leynos/wireframe/commit/35f4bf4))All impacted tests (13 files across `tests/`) were updated to replace direct `PushQueues::bounded*` calls with  
```rust
let (queues, handle) = PushQueues::builder()
    .high_capacity()
    .low_capacity()
    //.rate(Some(n)) // where applicable
    //.dlq(Some(tx)) // where applicable
    .build()
    .unwrap(); // or `.expect("…")`

preserving existing test logic but surfacing build‐step errors via Result. (github.com)

• PR metadata:
– Single commit 35f4bf4
– +293/−147 lines over 13 files
– Created Aug 27, 2025 by leynos to merge codex/introduce-pushqueuesbuilder-with-deprecationmain
– Label: codex
– CI status: 4 checks (build/test workflow, CodeQL, pull_request jobs, CodeScene delta analysis)
– Test steps: make fmt, make lint, make test (github.com)

• Linked task for context:
https://chatgpt.com/codex/tasks/task_e_68aeba8d630c8322bcab55de80b2ef06

🔇 Additional comments (6)
tests/push_policies.rs (1)

83-89: LGTM on builder usage and error handling.

Builder configuration and .expect("queue creation failed") reads well.

Also applies to: 147-153

src/push/queues.rs (5)

1-8: Module docs read well and use en‑GB spelling.

Intro and scope are clear and accurate.


293-305: Builder structure and defaults look sound.

Defaults and fluent API are straightforward; docs explain behaviour clearly.

Also applies to: 307-354


397-466: Deprecations are correctly routed via the builder.

Shims preserve behaviour while nudging callers to the new API.


212-281: DLQ routing and logging are robust.

Error levels and payload visibility are appropriate; tests exercise both full and closed DLQ paths.


373-381: Confirm RateLimiter time source under tokio::time::pause()
Ensure tests that rely on virtual time remain deterministic.

  • Verify the exact crate and version providing RateLimiter
  • Inspect the crate’s docs or source to confirm RateLimiter::builder() uses Tokio’s clock (not std::thread::sleep or the system clock)
  • Ensure any tests that depend on refills explicitly call tokio::time::advance() under tokio::time::pause()
# Find which crate and version implements RateLimiter
rg -n "RateLimiter" Cargo.lock

# Locate the import in your code
rg -n "use .*RateLimiter" -C2 src/push/queues.rs

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/push.rs (1)

176-179: Clarify the “capacity” in the burst test comment.

The burst size equals the token‑bucket capacity (set to rate), not the queue length.

Apply this diff:

-/// A burst up to capacity succeeds and further pushes are blocked.
-/// The maximum burst size equals the configured `capacity` parameter.
+/// A burst up to the token‑bucket capacity succeeds and further pushes are blocked.
+/// The maximum burst size equals the configured `rate` (tokens per second).
♻️ Duplicate comments (5)
src/push/queues.rs (3)

367-371: Simplify rate validation; avoid .filter for control flow.

Use a straight branch for readability and to ease future extensions.

Apply this diff:

-        if let Some(r) = rate.filter(|r| *r == 0 || *r > MAX_PUSH_RATE) {
-            // Reject unsupported rates early to avoid building queues that cannot
-            // be used. The bounds prevent runaway resource consumption.
-            return Err(PushConfigError::InvalidRate(r));
-        }
+        if let Some(r) = rate {
+            if r == 0 || r > MAX_PUSH_RATE {
+                // Reject unsupported rates early to avoid building unusable queues and runaway limits.
+                return Err(PushConfigError::InvalidRate(r));
+            }
+        }

331-336: Model non‑zero rates at the type level via Option<NonZeroUsize>.

Add a primary rate_nz setter and keep the current rate as a shim for compatibility.

Apply this diff:

@@
-    /// Set the global push rate limit in pushes per second.
+    /// Set the global push rate limit in pushes per second.
     #[must_use]
     pub fn rate(mut self, rate: Option<usize>) -> Self {
-        self.rate = rate;
+        self.rate = rate;
         self
     }
+
+    /// Set the global push rate using a non‑zero type‑level guarantee.
+    #[must_use]
+    pub fn rate_nz(mut self, rate: Option<std::num::NonZeroUsize>) -> Self {
+        self.rate = rate.map(std::num::NonZeroUsize::get);
+        self
+    }

Add the import outside this hunk:

use std::num::NonZeroUsize; // at the top with other std imports

147-153: Replace unwrap() with expect(..) in all doc examples.

Align with repo guidelines and emit actionable failures in doctests.

Apply these diffs:

@@
-    ///         .build()
-    ///         .unwrap();
+    ///         .build()
+    ///         .expect("queue build failed");
-    ///     handle.push_high_priority(42u8).await.unwrap();
+    ///     handle.push_high_priority(42u8).await.expect("push high priority failed");
-    ///     let (priority, frame) = queues.recv().await.unwrap();
+    ///     let (priority, frame) = queues.recv().await.expect("recv failed");
@@
-    ///         .build()
-    ///         .unwrap();
+    ///         .build()
+    ///         .expect("queue build failed");
-    ///     handle.push_low_priority(10u8).await.unwrap();
+    ///     handle.push_low_priority(10u8).await.expect("push low priority failed");
-    ///     let (priority, frame) = queues.recv().await.unwrap();
+    ///     let (priority, frame) = queues.recv().await.expect("recv failed");
@@
-    ///         .build()
-    ///         .unwrap();
+    ///         .build()
+    ///         .expect("queue build failed");
@@
-    ///         .try_push(2u8, PushPriority::High, PushPolicy::DropIfFull)
-    ///         .unwrap();
+    ///         .try_push(2u8, PushPriority::High, PushPolicy::DropIfFull)
+    ///         .expect("try_push failed");
@@
-    ///         .build()
-    ///         .unwrap();
+    ///         .build()
+    ///         .expect("queue build failed");
-    ///     handle.push_high_priority(2u8).await.unwrap();
+    ///     handle.push_high_priority(2u8).await.expect("push high priority failed");
-    ///     let (priority, frame) = queues.recv().await.unwrap();
+    ///     let (priority, frame) = queues.recv().await.expect("recv failed");
@@
-    /// let (mut queues, _handle) = PushQueues::<u8>::builder().build().unwrap();
+    /// let (mut queues, _handle) = PushQueues::<u8>::builder().build().expect("queue build failed");

Also applies to: 178-184, 231-237, 481-485, 507-510

tests/push_policies.rs (1)

42-47: Replace .unwrap() with .expect(..) on build().

Emit clearer failures and align with test guidelines.

Apply this diff:

             .low_capacity(1)
-            .build()
-            .unwrap();
+            .build()
+            .expect("queue creation failed");
tests/push.rs (1)

23-28: Replace .unwrap() with .expect(..) on build().

Standardise failure messaging across tests.

Apply these diffs:

-        .build()
-        .unwrap();
+        .build()
+        .expect("queue creation failed");
-        .build()
-        .unwrap();
+        .build()
+        .expect("queue creation failed");
-        .build()
-        .unwrap();
+        .build()
+        .expect("queue creation failed");
-        .build()
-        .unwrap();
+        .build()
+        .expect("queue creation failed");

Also applies to: 47-52, 67-71, 161-167

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 35f4bf4 and b2d190c.

📒 Files selected for processing (3)
  • src/push/queues.rs (8 hunks)
  • tests/push.rs (8 hunks)
  • tests/push_policies.rs (4 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless 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
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • tests/push_policies.rs
  • tests/push.rs
  • src/push/queues.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.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • 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.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • tests/push_policies.rs
  • tests/push.rs
  • src/push/queues.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • tests/push_policies.rs
  • tests/push.rs
  • src/push/queues.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/push_policies.rs
  • tests/push.rs
🧬 Code graph analysis (2)
tests/push_policies.rs (3)
tests/push.rs (1)
  • queues (11-18)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (1)
  • builder (359-359)
tests/push.rs (2)
tests/connection_actor.rs (1)
  • queues (25-31)
src/push/queues.rs (2)
  • builder (359-359)
  • push_high_priority (159-161)
🔍 Remote MCP

Here are the key facts and concrete details to aid your review:

• A new fluent builder API was introduced in src/push/queues.rs:
– Added pub struct PushQueuesBuilder<F> with fields high_capacity, low_capacity, rate, and dlq.
– Chainable methods:
high_capacity(usize) -> Self
low_capacity(usize) -> Self
rate(Option<usize>) -> Self
dlq(Option<mpsc::Sender<F>>) -> Self
build(self) -> Result<(PushQueues<F>, PushHandle<F>), PushConfigError> which delegates to the new private helper PushQueues::build_with_rate_dlq(...). (github.com)

• Exposed the builder via

impl<F: FrameLike> PushQueues<F> {
    #[must_use]
    pub fn builder() -> PushQueuesBuilder<F> { PushQueuesBuilder::new() }
    // …
}

and consolidated all queue‐construction logic—capacity setup, optional rate limiting (with 1s refill intervals), and optional dead‐letter queue—into build_with_rate_dlq. (github.com)

• The four legacy constructors on PushQueues were deprecated and repointed to the builder:

#[deprecated(since = "0.1.0", note = "Use `PushQueues::builder` instead")]
pub fn bounded()(Self, PushHandle<F>) {}
#[deprecated()] pub fn bounded_no_rate_limit() {}
#[deprecated()] pub fn bounded_with_rate() {}
#[deprecated()] pub fn bounded_with_rate_dlq() {}

All now simply call through to the builder API. (github.com)

• A new module file src/push/mod.rs (5 additions) was added to re-export the queues API:

//! Prioritised queues used for asynchronously pushing frames to a connection.
mod queues;
pub use queues::*;
``` ([github.com](https://github.com/leynos/wireframe/commit/35f4bf4))All impacted tests (13 files across `tests/`) were updated to replace direct `PushQueues::bounded*` calls with  
```rust
let (queues, handle) = PushQueues::builder()
    .high_capacity()
    .low_capacity()
    //.rate(Some(n)) // where applicable
    //.dlq(Some(tx)) // where applicable
    .build()
    .unwrap(); // or `.expect("…")`

preserving existing test logic but surfacing build‐step errors via Result. (github.com)

• PR metadata:
– Single commit 35f4bf4
– +293/−147 lines over 13 files
– Created Aug 27, 2025 by leynos to merge codex/introduce-pushqueuesbuilder-with-deprecationmain
– Label: codex
– CI status: 4 checks (build/test workflow, CodeQL, pull_request jobs, CodeScene delta analysis)
– Test steps: make fmt, make lint, make test (github.com)

• Linked task for context:
https://chatgpt.com/codex/tasks/task_e_68aeba8d630c8322bcab55de80b2ef06

🔇 Additional comments (3)
src/push/queues.rs (2)

1-7: Solid module docs and en‑GB spelling.

Keep this level of clarity elsewhere in the module.


29-33: Keep the compile‑time guard; it prevents config drift.

Expose MAX_PUSH_RATE publicly and assert the default stays within bounds. Good.

tests/push.rs (1)

10-18: Good fixture: reuse queues with explicit rate for deterministic tests.

Leave as is.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
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: 8

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (6)
tests/push.rs (4)

67-75: Destructure queues as mutable at source

Avoid shadowing to make the binding mutable.

Apply:

-    let (queues, handle) = PushQueues::builder()
+    let (mut queues, handle) = PushQueues::builder()
@@
-    let mut queues = queues;
     queues.close();

89-118: Prefer start_paused attribute over manual pause

Use #[tokio::test(start_paused = true)] to remove explicit time::pause() and rely on deterministic auto‑advance in virtual time.

Apply:

-#[tokio::test]
+#[tokio::test(start_paused = true)]
 async fn rate_limiter_blocks_when_exceeded(#[case] priority: PushPriority) {
-    time::pause();
+    // virtual time provided by start_paused

Repeat similarly in other virtual‑time tests in this file.


176-186: Fix misleading comment about burst “capacity”

Refer to the configured rate/token‑bucket capacity rather than an undefined “capacity parameter”.

Apply:

-/// A burst up to capacity succeeds and further pushes are blocked.
-/// The maximum burst size equals the configured `capacity` parameter.
+/// A burst up to the token‑bucket capacity succeeds and further pushes are blocked.
+/// The maximum burst size equals the configured `rate` (token‑bucket capacity = rate).

1-206: Verify migration completeness and improve coverage for DLQ

Search for any remaining uses of deprecated constructors, stray .unwrap() on builder results, and absence of DLQ tests. Add at least one test exercising builder().dlq(Some(tx)) to validate dead‑letter routing on overflow/closure.

Run:

#!/usr/bin/env bash
set -euo pipefail

echo "Deprecated constructors still referenced?"
rg -nP --type=rust '\bPushQueues::bounded(_no_rate_limit|_with_rate(_dlq)?|)\s*\(' || echo "OK: no deprecated constructors"

echo "Builder results still unwrapped?"
rg -nP --type=rust '\.build\(\)\s*\.unwrap\(\)' || echo "OK: no unwrap on builder results"

echo "Old error variant lingering?"
rg -nP --type=rust '\bPushError::Full\b' || echo "OK: only QueueFull used"

echo "Any DLQ usage in tests?"
rg -nP --type=rust 'builder\(\)[\s\S]{0,200}\.dlq\s*\(' tests || echo "No DLQ coverage in tests"
tests/connection_actor.rs (1)

391-404: DRY the “small queues” setup behind a fixture.

Create a small_queues() rstest fixture to remove duplication and unify error messages.

+#[fixture]
+fn small_queues() -> (PushQueues<u8>, wireframe::push::PushHandle<u8>) {
+    PushQueues::<u8>::builder()
+        .high_capacity(1)
+        .low_capacity(1)
+        .build()
+        .expect("failed to build push queues")
+}
@@
-async fn push_queue_exhaustion_backpressure() {
-    let (mut queues, handle) = PushQueues::builder()
-        .high_capacity(1)
-        .low_capacity(1)
-        .build()
-        .expect("failed to build push queues");
+async fn push_queue_exhaustion_backpressure(mut queues: PushQueues<u8>, handle: wireframe::push::PushHandle<u8>) {

Repeat the same substitution inside the for-loop body in graceful_shutdown_waits_for_tasks.

Also applies to: 481-488

src/push/queues.rs (1)

73-88: Prevent panics: validate capacities and return a typed error.

mpsc::channel(0) panics. Reject zero capacities and surface a PushConfigError::InvalidCapacity.

@@
 pub enum PushConfigError {
     /// The provided rate was zero or exceeded [`MAX_PUSH_RATE`].
     InvalidRate(usize),
+    /// One or both queue capacities were zero, which would panic the runtime.
+    InvalidCapacity { high: usize, low: usize },
 }
@@
         match self {
             Self::InvalidRate(r) => {
                 write!(f, "invalid rate {r}; must be between 1 and {MAX_PUSH_RATE}")
             }
+            Self::InvalidCapacity { high, low } => {
+                write!(f, "invalid capacities (high={high}, low={low}); both must be ≥ 1")
+            }
         }
@@
-    /// Returns [`PushConfigError::InvalidRate`] if the rate is zero or above
-    /// [`MAX_PUSH_RATE`].
+    /// Returns:
+    /// - [`PushConfigError::InvalidCapacity`] if a capacity is zero.
+    /// - [`PushConfigError::InvalidRate`] if the rate is zero or above [`MAX_PUSH_RATE`].
     pub fn build(self) -> Result<(PushQueues<F>, PushHandle<F>), PushConfigError> {
         PushQueues::build_with_rate_dlq(self.high_capacity, self.low_capacity, self.rate, self.dlq)
     }
@@
-    ) -> Result<(Self, PushHandle<F>), PushConfigError> {
-        if let Some(r) = rate.filter(|r| *r == 0 || *r > MAX_PUSH_RATE) {
+    ) -> Result<(Self, PushHandle<F>), PushConfigError> {
+        if high_capacity == 0 || low_capacity == 0 {
+            return Err(PushConfigError::InvalidCapacity {
+                high: high_capacity,
+                low: low_capacity,
+            });
+        }
+        if let Some(r) = rate.filter(|r| *r == 0 || *r > MAX_PUSH_RATE) {
             // Reject unsupported rates early to avoid building queues that cannot
             // be used. The bounds prevent runaway resource consumption.
             return Err(PushConfigError::InvalidRate(r));
         }

Also applies to: 345-353, 361-372

♻️ Duplicate comments (9)
tests/wireframe_protocol.rs (2)

59-63: Builder migration + expect usage — LGTM

Adopt the builder and replace unwrap with expect; aligns with the guideline and prior review.


87-91: Builder migration + expect usage — LGTM

Use of expect with a clear message is correct; keep this pattern repo-wide.

tests/advanced/concurrency_loom.rs (1)

24-28: Replace unwrap with expect — resolved

The loom test now uses expect with a descriptive message; keep consistent across advanced tests.

tests/correlation_id.rs (1)

18-22: Builder migration + expect usage — LGTM

Adopt the builder path and preserve clear failure context.

src/push/mod.rs (2)

1-17: Module docs with runnable example — LGTM

Provide a concise no_run example using the builder and en‑GB spelling; meets docs guidance.


21-30: Explicit re-exports — LGTM

Avoid glob exports; the curated surface matches queues.rs.

tests/push_policies.rs (1)

15-20: Document the lint suppression reason.

Add the inline justification on the allow to match policy.

 #[expect(
     unused_braces,
     reason = "rustc false positive for single line rstest fixtures"
 )]
-#[allow(unfulfilled_lint_expectations)]
+// allow(unfulfilled_lint_expectations): rustc occasionally fails to emit the expected lint for single-line rstest fixtures on stable.
+#[allow(unfulfilled_lint_expectations)]
 #[fixture]
 fn rt() -> Runtime {
src/push/queues.rs (2)

331-336: Expose a NonZero rate setter to model invariants at the type level.

Add rate_nz(Option<NonZeroUsize>) and keep rate(Option<usize>) as a thin shim.

+use std::num::NonZeroUsize;
@@
-    pub fn rate(mut self, rate: Option<usize>) -> Self {
-        self.rate = rate;
+    pub fn rate(mut self, rate: Option<usize>) -> Self {
+        self.rate = rate;
+        self
+    }
+
+    /// Set the global push rate using a non-zero type.
+    #[must_use]
+    pub fn rate_nz(mut self, rate: Option<NonZeroUsize>) -> Self {
+        self.rate = rate.map(NonZeroUsize::get);
         self
     }

361-371: Clarify invalid-rate branching.

Expand the filter into straight-line logic for readability; behaviour unchanged.

-        if let Some(r) = rate.filter(|r| *r == 0 || *r > MAX_PUSH_RATE) {
-            // Reject unsupported rates early to avoid building queues that cannot
-            // be used. The bounds prevent runaway resource consumption.
-            return Err(PushConfigError::InvalidRate(r));
-        }
+        if let Some(r) = rate {
+            if r == 0 || r > MAX_PUSH_RATE {
+                // Reject unsupported rates early to avoid unusable queues and runaway resource use.
+                return Err(PushConfigError::InvalidRate(r));
+            }
+        }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b2d190c and 5fd7e53.

📒 Files selected for processing (13)
  • src/push/mod.rs (1 hunks)
  • src/push/queues.rs (8 hunks)
  • tests/advanced/concurrency_loom.rs (1 hunks)
  • tests/advanced/interaction_fuzz.rs (1 hunks)
  • tests/async_stream.rs (1 hunks)
  • tests/connection_actor.rs (3 hunks)
  • tests/correlation_id.rs (1 hunks)
  • tests/push.rs (8 hunks)
  • tests/push_policies.rs (4 hunks)
  • tests/session_registry.rs (1 hunks)
  • tests/stream_end.rs (2 hunks)
  • tests/wireframe_protocol.rs (2 hunks)
  • tests/world.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless 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
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • tests/async_stream.rs
  • tests/correlation_id.rs
  • tests/session_registry.rs
  • tests/wireframe_protocol.rs
  • tests/world.rs
  • tests/connection_actor.rs
  • tests/advanced/interaction_fuzz.rs
  • tests/push.rs
  • src/push/mod.rs
  • src/push/queues.rs
  • tests/stream_end.rs
  • tests/advanced/concurrency_loom.rs
  • tests/push_policies.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.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • 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.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • tests/async_stream.rs
  • tests/correlation_id.rs
  • tests/session_registry.rs
  • tests/wireframe_protocol.rs
  • tests/world.rs
  • tests/connection_actor.rs
  • tests/advanced/interaction_fuzz.rs
  • tests/push.rs
  • src/push/mod.rs
  • src/push/queues.rs
  • tests/stream_end.rs
  • tests/advanced/concurrency_loom.rs
  • tests/push_policies.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • tests/async_stream.rs
  • tests/correlation_id.rs
  • tests/session_registry.rs
  • tests/wireframe_protocol.rs
  • tests/world.rs
  • tests/connection_actor.rs
  • tests/advanced/interaction_fuzz.rs
  • tests/push.rs
  • src/push/mod.rs
  • src/push/queues.rs
  • tests/stream_end.rs
  • tests/advanced/concurrency_loom.rs
  • tests/push_policies.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/async_stream.rs
  • tests/correlation_id.rs
  • tests/session_registry.rs
  • tests/wireframe_protocol.rs
  • tests/world.rs
  • tests/connection_actor.rs
  • tests/advanced/interaction_fuzz.rs
  • tests/push.rs
  • tests/stream_end.rs
  • tests/advanced/concurrency_loom.rs
  • tests/push_policies.rs
🧬 Code graph analysis (12)
tests/async_stream.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (11-18)
src/push/queues.rs (1)
  • builder (359-359)
tests/correlation_id.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (11-18)
src/push/queues.rs (1)
  • builder (359-359)
tests/session_registry.rs (1)
src/push/queues.rs (1)
  • builder (359-359)
tests/wireframe_protocol.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (11-18)
src/push/queues.rs (1)
  • builder (359-359)
tests/world.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (11-18)
src/push/queues.rs (1)
  • builder (359-359)
tests/connection_actor.rs (3)
tests/push.rs (1)
  • queues (11-18)
src/push/queues.rs (2)
  • builder (359-359)
  • new (308-315)
src/connection.rs (3)
  • new (30-34)
  • new (138-151)
  • new (517-526)
tests/advanced/interaction_fuzz.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (11-18)
src/push/queues.rs (1)
  • builder (359-359)
tests/push.rs (2)
tests/connection_actor.rs (1)
  • queues (26-32)
src/push/queues.rs (2)
  • builder (359-359)
  • push_high_priority (159-161)
src/push/mod.rs (2)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (11-18)
tests/stream_end.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (11-18)
src/push/queues.rs (1)
  • builder (359-359)
tests/advanced/concurrency_loom.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (11-18)
src/push/queues.rs (1)
  • builder (359-359)
tests/push_policies.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (11-18)
src/push/queues.rs (1)
  • builder (359-359)
🔍 Remote MCP

Here are the key facts and concrete details to aid your review:

• A new fluent builder API was introduced in src/push/queues.rs:
– Added pub struct PushQueuesBuilder<F> with fields high_capacity, low_capacity, rate, and dlq.
– Chainable methods:
high_capacity(usize) -> Self
low_capacity(usize) -> Self
rate(Option<usize>) -> Self
dlq(Option<mpsc::Sender<F>>) -> Self
build(self) -> Result<(PushQueues<F>, PushHandle<F>), PushConfigError> which delegates to the new private helper PushQueues::build_with_rate_dlq(...). (github.com)

• Exposed the builder via

impl<F: FrameLike> PushQueues<F> {
    #[must_use]
    pub fn builder() -> PushQueuesBuilder<F> { PushQueuesBuilder::new() }
    // …
}

and consolidated all queue‐construction logic—capacity setup, optional rate limiting (with 1s refill intervals), and optional dead‐letter queue—into build_with_rate_dlq. (github.com)

• The four legacy constructors on PushQueues were deprecated and repointed to the builder:

#[deprecated(since = "0.1.0", note = "Use `PushQueues::builder` instead")]
pub fn bounded()(Self, PushHandle<F>) {}
#[deprecated()] pub fn bounded_no_rate_limit() {}
#[deprecated()] pub fn bounded_with_rate() {}
#[deprecated()] pub fn bounded_with_rate_dlq() {}

All now simply call through to the builder API. (github.com)

• A new module file src/push/mod.rs (5 additions) was added to re-export the queues API:

//! Prioritised queues used for asynchronously pushing frames to a connection.
mod queues;
pub use queues::*;
``` ([github.com](https://github.com/leynos/wireframe/commit/35f4bf4))All impacted tests (13 files across `tests/`) were updated to replace direct `PushQueues::bounded*` calls with  
```rust
let (queues, handle) = PushQueues::builder()
    .high_capacity()
    .low_capacity()
    //.rate(Some(n)) // where applicable
    //.dlq(Some(tx)) // where applicable
    .build()
    .unwrap(); // or `.expect("…")`

preserving existing test logic but surfacing build‐step errors via Result. (github.com)

• PR metadata:
– Single commit 35f4bf4
– +293/−147 lines over 13 files
– Created Aug 27, 2025 by leynos to merge codex/introduce-pushqueuesbuilder-with-deprecationmain
– Label: codex
– CI status: 4 checks (build/test workflow, CodeQL, pull_request jobs, CodeScene delta analysis)
– Test steps: make fmt, make lint, make test (github.com)

• Linked task for context:
https://chatgpt.com/codex/tasks/task_e_68aeba8d630c8322bcab55de80b2ef06

⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test
🔇 Additional comments (18)
tests/session_registry.rs (2)

9-13: Use targeted #[expect] on fixture — LGTM

Scope and justification are clear for the rstest false positive.


23-28: Builder migration + expect usage — LGTM

Construct via builder and fail with context; this matches the new API.

tests/push.rs (4)

10-18: Good fixture extraction for common queue config

Keep using this fixture to reduce duplication across rate‑limiter tests. The expect message is clear and aligns with guidelines.


23-28: Adopt builder API in routing test

Use of builder().high_capacity().low_capacity().build().expect(...) is correct and future‑proofs against deprecated constructors.


44-56: Align test with renamed error variant

Assertion against PushError::QueueFull is correct and the doc comment accurately describes behaviour.


161-166: Unlimited queues case is correct

rate(None) properly exercises the unlimited path; the timeout completes because the inner push is immediate under paused time.

tests/stream_end.rs (2)

26-31: Adopt builder API with clear failure context

Construction via builder with .expect("failed to build push queues") is compliant and readable.


58-63: Repeat builder usage consistently

Maintain this pattern across the file for consistency and clearer diagnostics.

tests/advanced/interaction_fuzz.rs (1)

26-31: Adopt builder API in fuzz harness

Initialisation via builder is correct; keep .expect(...) for actionable failures in property tests.

tests/world.rs (2)

145-150: Adopt builder API for correlation world

The change is correct and the error message is informative.


187-192: Adopt builder API for stream‑end world

Consistent with the rest of the suite and aligned with deprecations.

tests/connection_actor.rs (3)

27-31: Adopt the builder + expect path.

Good migration away from deprecated constructors and unwrap.


392-396: Adopt the builder + expect path.

Good usage with minimal capacities for back-pressure tests.


483-487: Adopt the builder + expect path.

Good usage in the loop; clear failure message.

tests/push_policies.rs (2)

42-47: Adopt the builder + expect path.

Good migration; message is clear.


84-90: Adopt the builder + expect path.

Good wiring of rate(None) and DLQ.

src/push/queues.rs (2)

1-7: Document the module.

Good high-level overview and en‑GB spelling.


33-33: Guard defaults at compile time.

Good invariant check.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
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: 12

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/server.rs (1)

61-66: Eliminate fixed sleep to reduce flakiness.

Probe readiness with a bounded retry loop rather than sleep(100ms).

Use this snippet to replace the fixed sleep:

// Poll for readiness with timeout to avoid flakes
let deadline = tokio::time::Instant::now() + Duration::from_secs(3);
loop {
    match TcpStream::connect(addr).await {
        Ok(stream) => { let _ = stream; break; }
        Err(e) if tokio::time::Instant::now() < deadline => tokio::time::sleep(Duration::from_millis(25)).await,
        Err(e) => panic!("connect failed after retries: {e}"),
    }
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 5fd7e53 and db60eaf.

📒 Files selected for processing (8)
  • src/push/queues/builder.rs (1 hunks)
  • src/push/queues/errors.rs (1 hunks)
  • src/push/queues/handle.rs (1 hunks)
  • src/push/queues/mod.rs (1 hunks)
  • tests/correlation_id.rs (1 hunks)
  • tests/server.rs (1 hunks)
  • tests/wireframe_protocol.rs (2 hunks)
  • tests/world.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless 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
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • src/push/queues/builder.rs
  • tests/server.rs
  • tests/world.rs
  • src/push/queues/errors.rs
  • tests/correlation_id.rs
  • src/push/queues/mod.rs
  • tests/wireframe_protocol.rs
  • src/push/queues/handle.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.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • 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.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • src/push/queues/builder.rs
  • tests/server.rs
  • tests/world.rs
  • src/push/queues/errors.rs
  • tests/correlation_id.rs
  • src/push/queues/mod.rs
  • tests/wireframe_protocol.rs
  • src/push/queues/handle.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • src/push/queues/builder.rs
  • tests/server.rs
  • tests/world.rs
  • src/push/queues/errors.rs
  • tests/correlation_id.rs
  • src/push/queues/mod.rs
  • tests/wireframe_protocol.rs
  • src/push/queues/handle.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/server.rs
  • tests/world.rs
  • tests/correlation_id.rs
  • tests/wireframe_protocol.rs
🧬 Code graph analysis (6)
src/push/queues/builder.rs (1)
src/push/queues/mod.rs (1)
  • build_with_rate_dlq (69-103)
tests/world.rs (3)
tests/push.rs (1)
  • queues (11-18)
tests/connection_actor.rs (1)
  • queues (26-32)
src/push/queues/mod.rs (1)
  • builder (67-67)
tests/correlation_id.rs (3)
tests/push.rs (1)
  • queues (11-18)
tests/connection_actor.rs (1)
  • queues (26-32)
src/push/queues/mod.rs (1)
  • builder (67-67)
src/push/queues/mod.rs (2)
src/push/queues/builder.rs (5)
  • new (22-29)
  • high_capacity (33-36)
  • low_capacity (40-43)
  • rate (47-50)
  • dlq (54-57)
src/push/queues/handle.rs (1)
  • from_arc (32-32)
tests/wireframe_protocol.rs (3)
tests/push.rs (1)
  • queues (11-18)
tests/connection_actor.rs (1)
  • queues (26-32)
src/push/queues/mod.rs (1)
  • builder (67-67)
src/push/queues/handle.rs (2)
src/push/queues/errors.rs (2)
  • fmt (15-20)
  • fmt (33-43)
src/push/queues/builder.rs (1)
  • dlq (54-57)
🔍 Remote MCP

Here are the key facts and concrete details to aid your review:

• A new fluent builder API was introduced in src/push/queues.rs:
– Added pub struct PushQueuesBuilder<F> with fields high_capacity, low_capacity, rate, and dlq.
– Chainable methods:
high_capacity(usize) -> Self
low_capacity(usize) -> Self
rate(Option<usize>) -> Self
dlq(Option<mpsc::Sender<F>>) -> Self
build(self) -> Result<(PushQueues<F>, PushHandle<F>), PushConfigError> which delegates to the new private helper PushQueues::build_with_rate_dlq(...). (github.com)

• Exposed the builder via

impl<F: FrameLike> PushQueues<F> {
    #[must_use]
    pub fn builder() -> PushQueuesBuilder<F> { PushQueuesBuilder::new() }
    // …
}

and consolidated all queue‐construction logic—capacity setup, optional rate limiting (with 1s refill intervals), and optional dead‐letter queue—into build_with_rate_dlq. (github.com)

• The four legacy constructors on PushQueues were deprecated and repointed to the builder:

#[deprecated(since = "0.1.0", note = "Use `PushQueues::builder` instead")]
pub fn bounded()(Self, PushHandle<F>) {}
#[deprecated()] pub fn bounded_no_rate_limit() {}
#[deprecated()] pub fn bounded_with_rate() {}
#[deprecated()] pub fn bounded_with_rate_dlq() {}

All now simply call through to the builder API. (github.com)

• A new module file src/push/mod.rs (5 additions) was added to re-export the queues API:

//! Prioritised queues used for asynchronously pushing frames to a connection.
mod queues;
pub use queues::*;
``` ([github.com](https://github.com/leynos/wireframe/commit/35f4bf4))All impacted tests (13 files across `tests/`) were updated to replace direct `PushQueues::bounded*` calls with  
```rust
let (queues, handle) = PushQueues::builder()
    .high_capacity()
    .low_capacity()
    //.rate(Some(n)) // where applicable
    //.dlq(Some(tx)) // where applicable
    .build()
    .unwrap(); // or `.expect("…")`

preserving existing test logic but surfacing build‐step errors via Result. (github.com)

• PR metadata:
– Single commit 35f4bf4
– +293/−147 lines over 13 files
– Created Aug 27, 2025 by leynos to merge codex/introduce-pushqueuesbuilder-with-deprecationmain
– Label: codex
– CI status: 4 checks (build/test workflow, CodeQL, pull_request jobs, CodeScene delta analysis)
– Test steps: make fmt, make lint, make test (github.com)

• Linked task for context:
https://chatgpt.com/codex/tasks/task_e_68aeba8d630c8322bcab55de80b2ef06

⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test
🔇 Additional comments (7)
tests/server.rs (1)

46-46: Swap unwrap with expect.

Good change. Preserve failure context per lint policy.

tests/correlation_id.rs (1)

18-22: Adopt builder API with explicit expect.

Good migration to the builder and improved failure diagnostics.

tests/wireframe_protocol.rs (2)

59-63: Adopt builder API in protocol hooks test.

Good update; complies with new construction path and lint policy.


87-91: Adopt builder API in connection actor test.

Good update; message clarifies context on failure.

tests/world.rs (2)

145-149: Adopt builder with .expect(...) — compliant and clear. LGTM.

The switch to the builder API with a descriptive .expect(...) message matches the lint policy and keeps the test intent obvious.


187-191: Same here — correct builder usage with .expect(...).

This aligns with the updated public API and avoids Clippy warnings from .unwrap().

src/push/queues/mod.rs (1)

37-39: Use a const block for the compile-time assertion and verify MSRV.

Adopt the idiomatic const-assert form and ensure it compiles on the project’s MSRV.

Apply:

-// Compile-time guard: DEFAULT_PUSH_RATE must not exceed MAX_PUSH_RATE.
-const _: () = assert!(DEFAULT_PUSH_RATE <= MAX_PUSH_RATE);
+// Compile-time guard: DEFAULT_PUSH_RATE must not exceed MAX_PUSH_RATE.
+const _: () = { assert!(DEFAULT_PUSH_RATE <= MAX_PUSH_RATE); };

Run:

#!/bin/bash
# Verify MSRV compatibility of const-assert and that no panics arise from capacities.
rg -nP 'channel\(\s*0\s*\)' --type=rs -C2
cargo check -q

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
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

♻️ Duplicate comments (9)
tests/session_registry.rs (3)

9-14: Attach a reason to the lint suppression or switch to #[expect].

Align with the guideline “Prefer #[expect(..)] over #[allow(..)]” and require a reason. Keep the scope tight.

Apply:

-#[allow(unfulfilled_lint_expectations)]
+#[allow(unfulfilled_lint_expectations, reason = "rstest fixtures use #[expect]; rustc may not emit the targeted lint on single-line fixtures")]

17-22: Repeat the lint-suppression rationale for consistency.

Mirror the rationale on this fixture too.

Apply:

-#[allow(unfulfilled_lint_expectations)]
+#[allow(unfulfilled_lint_expectations, reason = "rstest fixtures use #[expect]; rustc may not emit the targeted lint on single-line fixtures")]

23-28: Standardise the failure message casing in .expect(...).

Use the type name “PushQueues” for consistency across tests and docs.

Apply:

-        .expect("failed to build push queues")
+        .expect("failed to build PushQueues")
src/push/queues/errors.rs (1)

7-16: Mark public error enums non-exhaustive to allow forward-compatible additions.

Future-proof the API without semver breakage.

Apply:

-#[derive(Debug, Error)]
+#[non_exhaustive]
+#[derive(Debug, Error)]
 pub enum PushError {
src/push/queues/builder.rs (2)

7-14: Add a Rustdoc usage example.

Document an end-to-end builder flow to satisfy the public-API docs requirement.

Apply:

 /// Builder for [`PushQueues`].
 ///
 /// Allows configuration of queue capacities, rate limiting and an optional
 /// dead-letter queue before constructing [`PushQueues`] and its paired
 /// [`PushHandle`]. Defaults mirror the previous constructors: both queues have
 /// a capacity of one and pushes are limited to [`DEFAULT_PUSH_RATE`] per second
 /// unless overridden.
+///
+/// # Examples
+/// ```rust,no_run
+/// use tokio::sync::mpsc;
+/// use wireframe::push::PushQueues;
+///
+/// # async fn demo() {
+/// let (dlq_tx, _dlq_rx) = mpsc::channel(8);
+/// let (_queues, _handle) = PushQueues::<u8>::builder()
+///     .high_capacity(8)
+///     .low_capacity(8)
+///     .rate(Some(100))
+///     .dlq(Some(dlq_tx))
+///     .build()
+///     .expect("failed to build PushQueues");
+/// # }
+/// ```

45-50: Clarify rate(None) semantics in docs.

State explicitly that None disables rate limiting.

Apply:

-    /// Set the global push rate limit in pushes per second.
+    /// Set the global push rate limit in pushes per second. Pass `None` to disable rate limiting.
src/push/queues/mod.rs (3)

166-173: Standardise hyphenation: “dead‑letter queue”.

Keep terminology consistent across docs.

Apply:

-    /// Create queues with a custom rate limit and optional dead letter queue.
+    /// Create queues with a custom rate limit and optional dead‑letter queue.

208-214: Fix recv() early termination when the high-priority channel closes.

The biased select returns None as soon as one channel closes, dropping remaining frames in the other channel.

Apply:

-    pub async fn recv(&mut self) -> Option<(PushPriority, F)> {
-        tokio::select! {
-            biased;
-            res = self.high_priority_rx.recv() => res.map(|f| (PushPriority::High, f)),
-            res = self.low_priority_rx.recv() => res.map(|f| (PushPriority::Low, f)),
-        }
-    }
+    pub async fn recv(&mut self) -> Option<(PushPriority, F)> {
+        let mut high_closed = false;
+        let mut low_closed = false;
+        loop {
+            tokio::select! {
+                biased;
+                res = self.high_priority_rx.recv(), if !high_closed => match res {
+                    Some(f) => return Some((PushPriority::High, f)),
+                    None => high_closed = true,
+                },
+                res = self.low_priority_rx.recv(), if !low_closed => match res {
+                    Some(f) => return Some((PushPriority::Low, f)),
+                    None => low_closed = true,
+                },
+                else => return None,
+            }
+        }
+    }

31-39: Expose DEFAULT_PUSH_RATE or avoid linking to a private item.

Make the default discoverable and keep intra-doc links valid.

Apply:

-// Default maximum pushes per second when no custom rate is specified.
-// This is an internal implementation detail and may change.
-const DEFAULT_PUSH_RATE: usize = 100;
+/// Default per‑second push rate used by [`PushQueuesBuilder`] when no custom rate is configured.
+pub const DEFAULT_PUSH_RATE: usize = 100;
 // Highest supported rate for [`PushQueuesBuilder::rate`].
 pub const MAX_PUSH_RATE: usize = 10_000;
 
-// Compile-time guard: DEFAULT_PUSH_RATE must not exceed MAX_PUSH_RATE.
-const _: () = assert!(DEFAULT_PUSH_RATE <= MAX_PUSH_RATE);
+// Compile-time guard: DEFAULT_PUSH_RATE must not exceed MAX_PUSH_RATE.
+const _: () = assert!(DEFAULT_PUSH_RATE <= MAX_PUSH_RATE);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between db60eaf and 1e3b3c8.

📒 Files selected for processing (4)
  • src/push/queues/builder.rs (1 hunks)
  • src/push/queues/errors.rs (1 hunks)
  • src/push/queues/mod.rs (1 hunks)
  • tests/session_registry.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless 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
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • tests/session_registry.rs
  • src/push/queues/errors.rs
  • src/push/queues/builder.rs
  • src/push/queues/mod.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.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • 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.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • tests/session_registry.rs
  • src/push/queues/errors.rs
  • src/push/queues/builder.rs
  • src/push/queues/mod.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • tests/session_registry.rs
  • src/push/queues/errors.rs
  • src/push/queues/builder.rs
  • src/push/queues/mod.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/session_registry.rs
🧬 Code graph analysis (3)
tests/session_registry.rs (1)
src/push/queues/mod.rs (1)
  • builder (67-67)
src/push/queues/builder.rs (1)
src/push/queues/mod.rs (1)
  • build_with_rate_dlq (69-109)
src/push/queues/mod.rs (2)
src/push/queues/builder.rs (5)
  • new (22-29)
  • high_capacity (33-36)
  • low_capacity (40-43)
  • rate (47-50)
  • dlq (54-57)
src/push/queues/handle.rs (1)
  • from_arc (32-32)
🔍 Remote MCP

Here are the key facts and concrete details to aid your review:

• A new fluent builder API was introduced in src/push/queues.rs:
– Added pub struct PushQueuesBuilder<F> with fields high_capacity, low_capacity, rate, and dlq.
– Chainable methods:
high_capacity(usize) -> Self
low_capacity(usize) -> Self
rate(Option<usize>) -> Self
dlq(Option<mpsc::Sender<F>>) -> Self
build(self) -> Result<(PushQueues<F>, PushHandle<F>), PushConfigError> which delegates to the new private helper PushQueues::build_with_rate_dlq(...). (github.com)

• Exposed the builder via

impl<F: FrameLike> PushQueues<F> {
    #[must_use]
    pub fn builder() -> PushQueuesBuilder<F> { PushQueuesBuilder::new() }
    // …
}

and consolidated all queue‐construction logic—capacity setup, optional rate limiting (with 1s refill intervals), and optional dead‐letter queue—into build_with_rate_dlq. (github.com)

• The four legacy constructors on PushQueues were deprecated and repointed to the builder:

#[deprecated(since = "0.1.0", note = "Use `PushQueues::builder` instead")]
pub fn bounded()(Self, PushHandle<F>) {}
#[deprecated()] pub fn bounded_no_rate_limit() {}
#[deprecated()] pub fn bounded_with_rate() {}
#[deprecated()] pub fn bounded_with_rate_dlq() {}

All now simply call through to the builder API. (github.com)

• A new module file src/push/mod.rs (5 additions) was added to re-export the queues API:

//! Prioritised queues used for asynchronously pushing frames to a connection.
mod queues;
pub use queues::*;
``` ([github.com](https://github.com/leynos/wireframe/commit/35f4bf4))All impacted tests (13 files across `tests/`) were updated to replace direct `PushQueues::bounded*` calls with  
```rust
let (queues, handle) = PushQueues::builder()
    .high_capacity()
    .low_capacity()
    //.rate(Some(n)) // where applicable
    //.dlq(Some(tx)) // where applicable
    .build()
    .unwrap(); // or `.expect("…")`

preserving existing test logic but surfacing build‐step errors via Result. (github.com)

• PR metadata:
– Single commit 35f4bf4
– +293/−147 lines over 13 files
– Created Aug 27, 2025 by leynos to merge codex/introduce-pushqueuesbuilder-with-deprecationmain
– Label: codex
– CI status: 4 checks (build/test workflow, CodeQL, pull_request jobs, CodeScene delta analysis)
– Test steps: make fmt, make lint, make test (github.com)

• Linked task for context:
https://chatgpt.com/codex/tasks/task_e_68aeba8d630c8322bcab55de80b2ef06

🔇 Additional comments (1)
src/push/queues/mod.rs (1)

69-85: LGTM: validate capacities and rates before creating channels.

Reject zero capacities and out-of-range rates to avoid panics and runaway resource use.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
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: 2

♻️ Duplicate comments (2)
tests/session_registry.rs (2)

9-14: Add a reason to the lint suppression (repeat).

Annotate #[allow(unfulfilled_lint_expectations)] with an explicit reason per lint policy.

-#[allow(unfulfilled_lint_expectations)]
+#[allow(unfulfilled_lint_expectations, reason = "rstest fixtures use #[expect]; rustc may not emit the targeted lint on single-line fixtures")]

17-22: Add a reason to the second lint suppression (repeat).

Apply the same reasoning annotation here.

-#[allow(unfulfilled_lint_expectations)]
+#[allow(unfulfilled_lint_expectations, reason = "rstest fixtures use #[expect]; rustc may not emit the targeted lint on single-line fixtures")]
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1e3b3c8 and c356c31.

📒 Files selected for processing (2)
  • tests/session_registry.rs (1 hunks)
  • tests/stream_end.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless 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
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • tests/stream_end.rs
  • tests/session_registry.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.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • 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.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • tests/stream_end.rs
  • tests/session_registry.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • tests/stream_end.rs
  • tests/session_registry.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/stream_end.rs
  • tests/session_registry.rs
🧬 Code graph analysis (2)
tests/stream_end.rs (3)
tests/push.rs (1)
  • queues (11-18)
tests/connection_actor.rs (1)
  • queues (26-32)
src/push/queues/mod.rs (1)
  • builder (67-67)
tests/session_registry.rs (1)
src/push/queues/mod.rs (1)
  • builder (67-67)
🔍 Remote MCP Ref

Summary of additional, review-relevant facts (sourced from the PR context and files in the change):

  • New public builder API:
    • PushQueues::builder() -> PushQueuesBuilder
    • PushQueuesBuilder methods: high_capacity(usize), low_capacity(usize), rate(Option), dlq(Option<mpsc::Sender)), build(self) -> Result<(PushQueues, PushHandle), PushConfigError>
    • Builder defaults: high_capacity = 1, low_capacity = 1, rate = Some(DEFAULT_PUSH_RATE), dlq = None
  • Legacy constructors deprecated:
    • bounded, bounded_no_rate_limit, bounded_with_rate, bounded_with_rate_dlq now deprecated and forward to the builder
  • Configuration validation:
    • build validates rate (must be between 1 and MAX_PUSH_RATE) and capacity (must be ≥ 1); invalid values return PushConfigError::{InvalidRate, InvalidCapacity}
  • Error types and messages:
    • PushError: QueueFull ("push queue full"), Closed ("push queue closed")
    • PushConfigError: InvalidRate(usize) -> "invalid rate {0}; must be between 1 and {MAX_PUSH_RATE}", InvalidCapacity { high, low } -> "invalid capacities; high={high}, low={low}; each must be ≥ 1"
  • Runtime behaviour preserved:
    • PushQueues still uses two tokio::mpsc channels (high/low) with recv() biasing high priority and optional leaky_bucket::RateLimiter for per-second rate limiting
    • PushHandle implements push_high_priority, push_low_priority, try_push, and downgrade; DLQ routing on drop-if-full behaviours present
  • Test impact:
    • ~13 test files updated to replace PushQueues::bounded* calls with the builder; build() now returns Result and tests use expect()/unwrap(), surfacing construction errors as panics
    • New rstest fixture added in tests/push.rs to centralize builder usage
  • API surface additions (public):
    • PushQueuesBuilder, PushQueues::builder, PushPriority, PushPolicy, PushQueues, PushHandle, PushError, PushConfigError, MAX_PUSH_RATE, FrameLike trait (blanket impl for T: Send + 'static)
  • Miscellaneous PR metadata:
    • Single commit 35f4bf4, +293/−147 across 13 files; PR #334 by leynos; CI configured (build/test, CodeQL, etc.); recommended test steps: make fmt, make lint, make test

Tool attempts for further external documentation (failed with HTTP 402):

  • Attempted searches/reads via documentation tool(s) but requests returned 402 Payment Required; external doc fetches unavailable:,

Sources:

  • PR contents and diffs provided in the review context (files under src/push/* and tests/*) — summarized above.
  • Tool attempts noted:,
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test
🔇 Additional comments (3)
tests/stream_end.rs (2)

26-30: Adopt builder API correctly — LGTM.

Use of PushQueues::<u8>::builder() with .expect(...) matches the new API and testing guideline.


58-62: Adopt builder API correctly — LGTM.

Pattern mirrors the first test and is sound.

tests/session_registry.rs (1)

23-28: Builder-based setup — LGTM.

Fixture returns (PushQueues<u8>, PushHandle<u8>) via builder with .expect(...); this aligns with the new API and test style.

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
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: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
docs/hardening-wireframe-a-guide-to-production-resilience.md (1)

350-371: Use the new PushQueuesBuilder::dlq API in documentation.

Replace references to a “WireframeApp builder” DLQ with the canonical PushQueuesBuilder::dlq(...).

-The WireframeApp builder will allow the user to provide a mpsc::Sender for a
-DLQ. The PushHandle's internal logic for handling a full queue will be modified:
+Configure a Dead Letter Queue via the per-connection `PushQueuesBuilder`:
+call `.dlq(Some(mpsc::Sender<F>))` when building queues. The `PushHandle`
+routes frames that cannot be enqueued (e.g., queue full) to the DLQ:
tests/push_policies.rs (2)

59-62: Deflake the timeout.

Bump the timeout to reduce CI flakiness under load.

-            timeout(Duration::from_millis(20), queues.recv())
+            timeout(Duration::from_millis(100), queues.recv())

79-81: Standardise hyphenation: “dead‑letter queue”.

Align docs with preferred terminology.

-/// Dropped frames are forwarded to the dead letter queue.
+/// Dropped frames are forwarded to the dead‑letter queue.
♻️ Duplicate comments (13)
tests/connection_actor.rs (3)

21-26: Document the lint suppression reason (repeat).

Annotate the allow(unfulfilled_lint_expectations) with an inline justification, per lint policy.

 #[expect(
     unused_braces,
     reason = "rustc false positive for single line rstest fixtures"
 )]
-#[allow(unfulfilled_lint_expectations)]
+// allow(unfulfilled_lint_expectations): rustc occasionally fails to emit the expected lint for single-line rstest fixtures on stable.
+#[allow(unfulfilled_lint_expectations)]
 fn queues() -> (PushQueues<u8>, wireframe::push::PushHandle<u8>) {

35-40: Document the lint suppression reason (repeat).

Add the inline justification for the allow(...) to comply with project policy.

 #[expect(
     unused_braces,
     reason = "rustc false positive for single line rstest fixtures"
 )]
-#[allow(unfulfilled_lint_expectations)]
+// allow(unfulfilled_lint_expectations): rustc occasionally fails to emit the expected lint for single-line rstest fixtures on stable.
+#[allow(unfulfilled_lint_expectations)]
 fn shutdown_token() -> CancellationToken { CancellationToken::new() }

43-48: Document the lint suppression reason (repeat).

Justify the allow(unfulfilled_lint_expectations) in-line.

 #[expect(
     unused_braces,
     reason = "rustc false positive for single line rstest fixtures"
 )]
-#[allow(unfulfilled_lint_expectations)]
+// allow(unfulfilled_lint_expectations): rustc occasionally fails to emit the expected lint for single-line rstest fixtures on stable.
+#[allow(unfulfilled_lint_expectations)]
 fn empty_stream() -> Option<FrameStream<u8, ()>> { None }
src/push/queues/builder.rs (2)

16-25: Expand the Rustdoc example to cover capacities, rate, and DLQ.

Show end-to-end usage including .dlq(...) and a non-default .rate(...).

-/// # Examples
-///
-/// ```
-/// use wireframe::push::PushQueues;
-///
-/// let (_queues, _handle) = PushQueues::<u8>::builder()
-///     .build()
-///     .expect("failed to build push queues");
-/// # drop((_queues, _handle));
-/// ```
+/// # Examples
+///
+/// ```rust,no_run
+/// use tokio::sync::mpsc;
+/// use wireframe::push::PushQueues;
+///
+/// # async fn demo() {
+/// let (dlq_tx, _dlq_rx) = mpsc::channel(8);
+/// let (_queues, _handle) = PushQueues::<u8>::builder()
+///     .high_capacity(8)
+///     .low_capacity(8)
+///     .rate(Some(100))
+///     .dlq(Some(dlq_tx))
+///     .build()
+///     .expect("failed to build push queues");
+/// # }
+/// ```

60-66: Clarify rate(None) semantics.

State explicitly that None disables rate limiting.

-    /// Set the global push rate limit in pushes per second.
+    /// Set the global push rate limit in pushes per second. Pass `None` to disable rate limiting.
     #[must_use]
     pub fn rate(mut self, rate: Option<usize>) -> Self {
tests/push_policies.rs (2)

15-20: Scope and justify the lint suppression; keep #[allow] narrowly scoped.

Add an inline justification for the scoped allow per our learnings (PR #153), and keep it attached to this fixture only.

 #[expect(
     unused_braces,
     reason = "rustc false positive for single line rstest fixtures"
 )]
-#[allow(unfulfilled_lint_expectations)]
+// allow(unfulfilled_lint_expectations): work around rustc occasionally missing the expected lint in this rstest fixture (see PR #153 learning).
+#[allow(unfulfilled_lint_expectations)]
 #[fixture]
 fn rt() -> Runtime {

90-91: Unify .expect(...) failure messages.

Standardise on one message across this file (e.g., "failed to build push queues").

-            .expect("queue creation failed");
+            .expect("failed to build push queues");
@@
-            .expect("queue creation failed");
+            .expect("failed to build push queues");

Also applies to: 154-155

src/push/queues/handle.rs (3)

7-7: Demote noisy success log to trace.

Avoid debug‑level log spam on hot paths.

-use tracing::{debug, error, warn};
+use tracing::{error, warn, trace};
@@
-        debug!(?priority, "frame pushed");
+        trace!(?priority, "frame pushed");

Also applies to: 47-47


39-41: Plumb cancellation into rate‑limit waits to avoid shutdown hangs.

Do not await the limiter indefinitely; allow producers to abort on shutdown.

-        if let Some(ref limiter) = self.0.limiter {
-            limiter.acquire(1).await;
-        }
+        if let Some(ref limiter) = self.0.limiter {
+            // TODO: thread a CancellationToken through public push_* APIs and select on it here.
+            // use tokio_util::sync::CancellationToken;
+            // tokio::select! {
+            //     _ = limiter.acquire(1) => {},
+            //     _ = token.cancelled() => return Err(PushError::Closed),
+            // }
+            limiter.acquire(1).await;
+        }
Check latest Tokio guidance on cancellation patterns for rate-limited producers using leaky_bucket::RateLimiter.

132-141: Document and decouple try_push from frame Debug; clarify rate‑limit bypass.

State explicitly that try_push is non‑blocking and does not consume rate‑limiter tokens. Drop the F: Debug bound now that DLQ logging avoids payload dumps.

     /// Attempt to push a frame with the given priority and policy.
     ///
+    /// This method is non‑blocking and does not consume rate‑limiter tokens.
+    /// It never waits on capacity or rate and may drop frames according to `policy`.
     /// # Errors
@@
-    ) -> Result<(), PushError>
-    where
-        F: std::fmt::Debug,
-    {
+    ) -> Result<(), PushError> {

Also applies to: 168-176

src/push/queues/mod.rs (3)

31-39: Expose the default rate or document it for discoverability.

Make the default public and documented, or document it on the builder. Prefer the constant for clarity.

-// Default maximum pushes per second when no custom rate is specified.
-// This is an internal implementation detail and may change.
-const DEFAULT_PUSH_RATE: usize = 100;
+/// Default pushes per second when no custom rate is specified.
+pub const DEFAULT_PUSH_RATE: usize = 100;
@@
-// Compile-time guard: DEFAULT_PUSH_RATE must not exceed MAX_PUSH_RATE.
+// Compile‑time guard: DEFAULT_PUSH_RATE must not exceed MAX_PUSH_RATE.
 const _: () = assert!(DEFAULT_PUSH_RATE <= MAX_PUSH_RATE);

166-174: Standardise hyphenation: “dead‑letter queue”.

Align docs with consistent terminology.

-    /// Create queues with a custom rate limit and optional dead letter queue.
+    /// Create queues with a custom rate limit and optional dead‑letter queue.

208-214: Fix recv() early termination when the high‑priority queue closes.

Do not return None while the low queue may still yield items.

-    pub async fn recv(&mut self) -> Option<(PushPriority, F)> {
-        tokio::select! {
-            biased;
-            res = self.high_priority_rx.recv() => res.map(|f| (PushPriority::High, f)),
-            res = self.low_priority_rx.recv() => res.map(|f| (PushPriority::Low, f)),
-        }
-    }
+    pub async fn recv(&mut self) -> Option<(PushPriority, F)> {
+        let mut high_closed = false;
+        let mut low_closed = false;
+        loop {
+            tokio::select! {
+                biased;
+                res = self.high_priority_rx.recv(), if !high_closed => match res {
+                    Some(f) => return Some((PushPriority::High, f)),
+                    None => high_closed = true,
+                },
+                res = self.low_priority_rx.recv(), if !low_closed => match res {
+                    Some(f) => return Some((PushPriority::Low, f)),
+                    None => low_closed = true,
+                },
+                else => return None,
+            }
+        }
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between c356c31 and 6fbddd5.

📒 Files selected for processing (13)
  • docs/asynchronous-outbound-messaging-design.md (1 hunks)
  • docs/efficiency-report.md (4 hunks)
  • docs/hardening-wireframe-a-guide-to-production-resilience.md (1 hunks)
  • src/push/mod.rs (1 hunks)
  • src/push/queues/builder.rs (1 hunks)
  • src/push/queues/handle.rs (1 hunks)
  • src/push/queues/mod.rs (1 hunks)
  • tests/advanced/concurrency_loom.rs (1 hunks)
  • tests/advanced/interaction_fuzz.rs (1 hunks)
  • tests/connection_actor.rs (3 hunks)
  • tests/push.rs (8 hunks)
  • tests/push_policies.rs (4 hunks)
  • tests/wireframe_protocol.rs (2 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless 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
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • src/push/queues/builder.rs
  • tests/wireframe_protocol.rs
  • tests/advanced/interaction_fuzz.rs
  • src/push/mod.rs
  • src/push/queues/handle.rs
  • tests/connection_actor.rs
  • tests/push_policies.rs
  • tests/advanced/concurrency_loom.rs
  • tests/push.rs
  • src/push/queues/mod.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.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • 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.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • src/push/queues/builder.rs
  • tests/wireframe_protocol.rs
  • tests/advanced/interaction_fuzz.rs
  • src/push/mod.rs
  • src/push/queues/handle.rs
  • tests/connection_actor.rs
  • tests/push_policies.rs
  • tests/advanced/concurrency_loom.rs
  • tests/push.rs
  • src/push/queues/mod.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • src/push/queues/builder.rs
  • tests/wireframe_protocol.rs
  • tests/advanced/interaction_fuzz.rs
  • src/push/mod.rs
  • src/push/queues/handle.rs
  • tests/connection_actor.rs
  • tests/push_policies.rs
  • tests/advanced/concurrency_loom.rs
  • tests/push.rs
  • src/push/queues/mod.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/wireframe_protocol.rs
  • tests/advanced/interaction_fuzz.rs
  • tests/connection_actor.rs
  • tests/push_policies.rs
  • tests/advanced/concurrency_loom.rs
  • tests/push.rs
docs/**/*.md

📄 CodeRabbit inference engine (docs/documentation-style-guide.md)

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 runnable examples and explain the relevant concepts and APIs.

docs/**/*.md: Use docs/ markdown ...

Files:

  • docs/efficiency-report.md
  • docs/asynchronous-outbound-messaging-design.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/efficiency-report.md
  • docs/asynchronous-outbound-messaging-design.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md
**/*.md

📄 CodeRabbit inference engine (AGENTS.md)

**/*.md: Markdown paragraphs and bullet points must be wrapped at 80 columns
Markdown code blocks must be wrapped at 120 columns
Do not wrap tables and headings in Markdown
Use dashes (-) for list bullets in Markdown
Use GitHub-flavoured Markdown footnotes ([^1])

Files:

  • docs/efficiency-report.md
  • docs/asynchronous-outbound-messaging-design.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
  • 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/efficiency-report.md
  • docs/asynchronous-outbound-messaging-design.md
  • docs/hardening-wireframe-a-guide-to-production-resilience.md
🧠 Learnings (1)
📚 Learning: 2025-06-29T01:29:15.184Z
Learnt from: leynos
PR: leynos/wireframe#153
File: tests/session_registry.rs:9-9
Timestamp: 2025-06-29T01:29:15.184Z
Learning: In Rust test files using rstest fixtures, `#[allow(unused_braces)]` may be necessary due to a rustc bug that incorrectly flags braces as unnecessary in fixture functions. This is a legitimate use case for lint suppression to work around compiler issues, with active GitHub issues tracking the problem.

Applied to files:

  • tests/push_policies.rs
🧬 Code graph analysis (10)
src/push/queues/builder.rs (1)
src/push/queues/mod.rs (1)
  • build_with_rate_dlq (69-109)
tests/wireframe_protocol.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (18-25)
src/push/queues/mod.rs (1)
  • builder (67-67)
tests/advanced/interaction_fuzz.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (18-25)
src/push/queues/mod.rs (1)
  • builder (67-67)
src/push/mod.rs (2)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (18-25)
src/push/queues/handle.rs (1)
src/push/queues/builder.rs (1)
  • dlq (69-72)
tests/connection_actor.rs (2)
tests/push.rs (1)
  • queues (18-25)
src/push/queues/mod.rs (1)
  • builder (67-67)
tests/push_policies.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (18-25)
src/push/queues/mod.rs (1)
  • builder (67-67)
tests/advanced/concurrency_loom.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
tests/push.rs (1)
  • queues (18-25)
src/push/queues/mod.rs (1)
  • builder (67-67)
tests/push.rs (3)
tests/connection_actor.rs (1)
  • queues (26-32)
src/push/queues/mod.rs (1)
  • builder (67-67)
src/push/queues/handle.rs (1)
  • push_high_priority (79-81)
src/push/queues/mod.rs (2)
src/push/queues/builder.rs (5)
  • default (35-42)
  • high_capacity (48-51)
  • low_capacity (55-58)
  • rate (62-65)
  • dlq (69-72)
src/push/queues/handle.rs (1)
  • from_arc (32-32)
🪛 LanguageTool
docs/efficiency-report.md

[typographical] ~29-~29: To join two clauses or introduce examples, consider using an em dash.
Context: ...onversion entirely. Status: ✅ FIXED - Optimized to use freeze().to_vec() whi...

(DASH_RULE)


[typographical] ~42-~42: To join two clauses or introduce examples, consider using an em dash.
Context: ...ent::Shutdown, ``` Impact: Moderate - these clones are necessary for the async...

(DASH_RULE)


[typographical] ~72-~72: To join two clauses or introduce examples, consider using an em dash.
Context: ...0.len()); ``` Impact: Low to medium - depends on registry size and pruning fre...

(DASH_RULE)

🔍 Remote MCP

Summary of additional, review-relevant facts (sourced from the PR context and files in the change):

  • New public builder API:
    • PushQueues::builder() -> PushQueuesBuilder
    • PushQueuesBuilder methods: high_capacity(usize), low_capacity(usize), rate(Option), dlq(Option<mpsc::Sender)), build(self) -> Result<(PushQueues, PushHandle), PushConfigError>
    • Builder defaults: high_capacity = 1, low_capacity = 1, rate = Some(DEFAULT_PUSH_RATE), dlq = None
  • Legacy constructors deprecated:
    • bounded, bounded_no_rate_limit, bounded_with_rate, bounded_with_rate_dlq now deprecated and forward to the builder
  • Configuration validation:
    • build validates rate (must be between 1 and MAX_PUSH_RATE) and capacity (must be ≥ 1); invalid values return PushConfigError::{InvalidRate, InvalidCapacity}
  • Error types and messages:
    • PushError: QueueFull ("push queue full"), Closed ("push queue closed")
    • PushConfigError: InvalidRate(usize) -> "invalid rate {0}; must be between 1 and {MAX_PUSH_RATE}", InvalidCapacity { high, low } -> "invalid capacities; high={high}, low={low}; each must be ≥ 1"
  • Runtime behaviour preserved:
    • PushQueues still uses two tokio::mpsc channels (high/low) with recv() biasing high priority and optional leaky_bucket::RateLimiter for per-second rate limiting
    • PushHandle implements push_high_priority, push_low_priority, try_push, and downgrade; DLQ routing on drop-if-full behaviours present
  • Test impact:
    • ~13 test files updated to replace PushQueues::bounded* calls with the builder; build() now returns Result and tests use expect()/unwrap(), surfacing construction errors as panics
    • New rstest fixture added in tests/push.rs to centralize builder usage
  • API surface additions (public):
    • PushQueuesBuilder, PushQueues::builder, PushPriority, PushPolicy, PushQueues, PushHandle, PushError, PushConfigError, MAX_PUSH_RATE, FrameLike trait (blanket impl for T: Send + 'static)
  • Miscellaneous PR metadata:
    • Single commit 35f4bf4, +293/−147 across 13 files; PR #334 by leynos; CI configured (build/test, CodeQL, etc.); recommended test steps: make fmt, make lint, make test

Tool attempts for further external documentation (failed with HTTP 402):

  • Attempted searches/reads via documentation tool(s) but requests returned 402 Payment Required; external doc fetches unavailable:,

Sources:

  • PR contents and diffs provided in the review context (files under src/push/* and tests/*) — summarized above.
  • Tool attempts noted:,
🔇 Additional comments (13)
docs/efficiency-report.md (1)

26-31: One .to_vec() call remains at src/frame/processor.rs:75; decode uses split_to(len).freeze().to_vec() and still returns Vec<u8> as Frame. No other .to_vec() sites found.

tests/advanced/concurrency_loom.rs (1)

24-28: Disable rate limiting in loom to avoid time-coupled flakiness.

The builder defaults a non‑zero rate. Under loom, time does not advance normally, which can stall pushes. Disable the limiter for determinism.

-            let (queues, handle) = PushQueues::<u8>::builder()
-                .high_capacity(1)
-                .low_capacity(1)
-                .build()
+            let (queues, handle) = PushQueues::<u8>::builder()
+                .high_capacity(1)
+                .low_capacity(1)
+                .rate(None)
+                .build()
                 .expect("failed to build push queues");

Run:

tests/connection_actor.rs (3)

27-32: LGTM: builder-based fixture with expect()

Builder usage and .expect("failed to build push queues") align with guidelines.


392-396: LGTM: back-pressure test uses builder and expect()

Good use of small capacities and a timeout to assert blocking.


483-488: LGTM: graceful shutdown test uses builder and expect()

Pattern matches the shared approach across tests and adheres to lint policy.

tests/push.rs (6)

17-25: LGTM: shared queues fixture with expect()

Fixture centralises a sane default (capacities + rate) and uses .expect().


37-42: LGTM: routing test targets minimal capacities

Correctly verifies priority order using recv() pairs.


61-66: LGTM: try_push policy exercised

Validates ReturnErrorIfFullQueueFull.


81-86: LGTM: closed-queue error paths

Covers both high and low paths after queues.close().


175-180: LGTM: unlimited rate path

.rate(None) test confirms absence of rate-induced blocking.


195-201: LGTM: burst semantics

Confirms limiter burst equals configured rate and blocks excess.

src/push/queues/builder.rs (1)

81-84: LGTM: build() validates and delegates

Return type and error documentation match the constructor contract.

src/push/queues/mod.rs (1)

80-85: Good: reject zero capacities to avoid panic on mpsc::channel(0).

This closes the hole flagged earlier and routes misconfiguration to a typed error.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
tests/push.rs (1)

106-135: Deflake the real-time timeout.

Increase the 10 ms real-time timeout to 50 ms to absorb scheduler jitter on CI while time is paused.

-            time::timeout(Duration::from_millis(10), handle.push_high_priority(2u8)).await
+            time::timeout(Duration::from_millis(50), handle.push_high_priority(2u8)).await
@@
-            time::timeout(Duration::from_millis(10), handle.push_low_priority(2u8)).await
+            time::timeout(Duration::from_millis(50), handle.push_low_priority(2u8)).await
♻️ Duplicate comments (4)
src/push/queues/builder.rs (3)

16-36: Add a full end-to-end example (capacities, rate, DLQ).

Provide a runnable docs example that demonstrates all knobs as required by the guidelines.

 ///
 /// # Examples
 ///
-/// ```
-/// use wireframe::push::PushQueues;
-///
-/// let (_queues, _handle) = PushQueues::<u8>::builder()
-///     .build()
-///     .expect("failed to build push queues");
-/// # drop((_queues, _handle));
-/// ```
+/// ```rust,no_run
+/// use tokio::sync::mpsc;
+/// use wireframe::push::PushQueues;
+///
+/// # async fn demo() {
+/// let (dlq_tx, _dlq_rx) = mpsc::channel(8);
+/// let (queues, handle) = PushQueues::<u8>::builder()
+///     .high_capacity(8)
+///     .low_capacity(8)
+///     .rate(Some(100)) // set pushes-per-second; use `None` to disable
+///     .dlq(Some(dlq_tx)) // send dropped frames to DLQ
+///     .build()
+///     .expect("failed to build push queues");
+/// # let _ = (queues, handle);
+/// # }
+/// ```

71-76: Clarify rate(None) semantics.

State explicitly that None disables rate limiting.

-    /// Set the global push rate limit in pushes per second.
+    /// Set the global push rate limit in pushes per second. Pass `None` to disable rate limiting.

78-83: Clarify DLQ behaviour when absent or full.

Document drop behaviour when DLQ is None or saturated.

-    /// Provide a dead-letter queue for discarded frames.
+    /// Provide a dead-letter queue for frames that cannot be enqueued (e.g., queue full).
+    /// If the DLQ is `None` or the DLQ is full, the frame is dropped.
tests/push.rs (1)

28-35: Add capacity validation coverage.

Test InvalidCapacity for zero high/low capacities to cover all builder validations.

 fn builder_rejects_invalid_rate(#[case] rate: usize) {
     let result = PushQueues::<u8>::builder().rate(Some(rate)).build();
     assert!(matches!(result, Err(PushConfigError::InvalidRate(r)) if r == rate));
 }
+
+/// Builder rejects zero capacities.
+#[test]
+fn builder_rejects_zero_capacity() {
+    let hi = PushQueues::<u8>::builder().high_capacity(0).build();
+    assert!(matches!(hi, Err(PushConfigError::InvalidCapacity { high: 0, low: 1 })));
+    let lo = PushQueues::<u8>::builder().low_capacity(0).build();
+    assert!(matches!(lo, Err(PushConfigError::InvalidCapacity { high: 1, low: 0 })));
+}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

💡 Knowledge Base configuration:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 6fbddd5 and 983550e.

📒 Files selected for processing (2)
  • src/push/queues/builder.rs (1 hunks)
  • tests/push.rs (8 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use precise names; boolean names should start with is/has/should
Use en-GB-oxendict spelling and grammar in comments
Function documentation must include clear examples; test documentation should omit redundant examples
Keep code files ≤ 400 lines; split long switch/dispatch logic by feature; move large test data to external files
Disallow Clippy warnings
Fix warnings emitted during tests in code rather than silencing them
Extract helper functions for long functions; adhere to separation of concerns and CQRS
Group related parameters into meaningful structs when functions have many parameters
Consider using Arc for large error returns to reduce data size
Each Rust module must begin with a module-level //! comment describing purpose and utility
Document public APIs with Rustdoc /// comments to enable cargo doc generation
Prefer immutable data; avoid unnecessary mut
Handle errors with Result instead of panicking where feasible
Avoid unsafe code unless 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
Do not silence lints except as a last resort
Lint suppressions must be tightly scoped and include a clear reason
Prefer #[expect(..)] over #[allow(..)] for lints
Prefer .expect() over .unwrap()
Use concat!() to combine long string literals rather than escaping newlines
Prefer single-line function bodies where appropriate (e.g., pub fn new(id: u64) -> Self { Self(id) })
Prefer semantic error enums deriving std::error::Error via thiserror for inspectable conditions

Files:

  • tests/push.rs
  • src/push/queues/builder.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.
  • Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.

  • 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.
  • Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such

    • For testing of functionality depending upon environment variables, dependency injection and the mockable crate are the preferred option.
    • If mockable cannot be used, env mutations in tests ...

Files:

  • tests/push.rs
  • src/push/queues/builder.rs
{src,tests}/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

Write unit and behavioural tests for new functionality

Files:

  • tests/push.rs
  • src/push/queues/builder.rs
tests/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

tests/**/*.rs: Use rstest fixtures for shared setup
Replace duplicated tests with #[rstest(...)] parameterised cases
Prefer mockall for mocks/stubs

Files:

  • tests/push.rs
🧬 Code graph analysis (2)
tests/push.rs (4)
tests/connection_actor.rs (1)
  • queues (26-32)
src/push/queues/mod.rs (1)
  • builder (67-67)
src/push/queues/builder.rs (1)
  • rate (73-76)
src/push/queues/handle.rs (1)
  • push_high_priority (79-81)
src/push/queues/builder.rs (1)
src/push/queues/mod.rs (1)
  • build_with_rate_dlq (69-109)
🔍 Remote MCP

Relevant facts to aid review (concise):

  • New builder API:
    • PushQueues::::builder() -> PushQueuesBuilder
    • PushQueuesBuilder methods: high_capacity(usize), low_capacity(usize), rate(Option), dlq(Option<mpsc::Sender>), build() -> Result<(PushQueues, PushHandle), PushConfigError>
    • Builder defaults: high=1, low=1, rate=Some(DEFAULT_PUSH_RATE), dlq=None
  • Deprecated/removed direct constructors:
    • bounded, bounded_no_rate_limit, bounded_with_rate, bounded_with_rate_dlq are deprecated and forward to the builder
  • Validation and errors:
    • build() validates capacities (≥1) and rate (1..=MAX_PUSH_RATE); errors return PushConfigError::InvalidCapacity or PushConfigError::InvalidRate(rate)
    • Error types: PushError::{QueueFull, Closed} (with messages), PushConfigError::{InvalidRate(usize), InvalidCapacity{high,low}}
    • Public constant MAX_PUSH_RATE = 10_000 (default internal rate = 100)
  • Runtime behavior preserved:
    • Two tokio::mpsc channels (high/low), recv() biases high priority; optional leaky_bucket::RateLimiter; optional DLQ with try_send on drop
    • PushHandle provides push_high_priority, push_low_priority (async), try_push with PushPolicy handling, and downgrade() to Weak
  • Test and docs impact:
    • ~13 tests updated to use builder; build() now returns Result and tests call expect()/unwrap() (may panic if builder validation fails)
    • New test added: builder_rejects_invalid_rate asserting InvalidRate for 0 and MAX_PUSH_RATE+1
    • Docs updated to reflect builder usage and deprecations
  • API surface changes to review:
    • Added public: PushQueuesBuilder, PushConfigError, PushError, PushHandle (re-exported), PushPriority, PushPolicy, MAX_PUSH_RATE, FrameLike trait (blanket impl for T: Send + 'static)
    • Ensure deprecated constructors are properly annotated and forwarded to builder, and public docs/examples updated accordingly
  • Review focal points:
    • Correctness of validation logic and error messages (boundary values for rate and capacity)
    • Deprecation hygiene (attributes, forwarding implementations, docs)
    • No behavioural regressions: DLQ routing, rate-limiting integration, recv() prioritisation, and PushHandle semantics
    • Tests: ensure expect() usage is intentional (will panic on invalid config) and builder_rejects_invalid_rate covers edge cases

Sources: PR contents and diffs provided in the review context.

🔇 Additional comments (8)
tests/push.rs (8)

5-5: Imports and public API usage look good.

Keep the imports explicit and local to the tests module.

Also applies to: 7-15


18-26: Good use of an rstest fixture.

Centralise common configuration; default to a low rate to exercise the limiter.


40-56: Priority routing test reads well.

Assert high-priority bias first; capacities of 1/1 keep the scenario tight.


64-79: Policy handling is correct.

Verify QueueFull, drain, then accept; this exercises the fast path.


84-97: Closed-queue error paths are validated.

Close, then assert Closed on both priorities; solid.


151-172: Shared limiter behaviour is asserted correctly.

Block across priorities, advance, then succeed; ordering checks are apt.


176-191: Unlimited queues test is crisp.

rate(None) path is covered and non-blocking behaviour is asserted.


196-222: Burst and window semantics are well exercised.

Push at rate capacity, assert block, advance, and drain in order.

@leynos
Copy link
Owner Author

leynos commented Aug 30, 2025

@coderabbitai pause

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Contributor

coderabbitai bot commented Aug 30, 2025

✅ Actions performed

Reviews paused.

Repository owner deleted a comment from coderabbitai bot Aug 30, 2025
Repository owner deleted a comment from chatgpt-codex-connector bot Aug 30, 2025
Repository owner deleted a comment from coderabbitai bot Aug 30, 2025
Repository owner deleted a comment from chatgpt-codex-connector bot Aug 30, 2025
Repository owner deleted a comment from coderabbitai bot Aug 30, 2025
Repository owner deleted a comment from chatgpt-codex-connector bot Aug 30, 2025
Repository owner deleted a comment from coderabbitai bot Aug 30, 2025
Repository owner deleted a comment from chatgpt-codex-connector bot Aug 30, 2025
codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link

@codescene-delta-analysis codescene-delta-analysis bot left a comment

Choose a reason for hiding this comment

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

Gates Failed
Enforce advisory code health rules (1 file with Code Duplication, Complex Conditional)

Gates Passed
5 Quality Gates Passed

See analysis details in CodeScene

Reason for failure
Enforce advisory code health rules Violations Code Health Impact
mod.rs 2 advisory rules 10.00 → 9.10 Suppress

Quality Gate Profile: Pay Down Tech Debt
Want more control? Customize Code Health rules or catch issues early with our IDE extension and CLI tool.

@leynos
Copy link
Owner Author

leynos commented Aug 30, 2025

@coderabbitai resolve

Copy link
Contributor

coderabbitai bot commented Aug 30, 2025

✅ Actions performed

Comments resolved and changes approved.

@leynos
Copy link
Owner Author

leynos commented Aug 30, 2025

@coderabbitai resolve

Copy link
Contributor

coderabbitai bot commented Aug 30, 2025

✅ Actions performed

Comments resolved and changes approved.

@leynos
Copy link
Owner Author

leynos commented Aug 30, 2025

Superseded by #338

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