Skip to content

Add CodecError Regression Tests with wireframe_testing and ExecPlan#497

Merged
leynos merged 7 commits intomainfrom
add-codecerror-regression-tests-qmk3tf
Mar 14, 2026
Merged

Add CodecError Regression Tests with wireframe_testing and ExecPlan#497
leynos merged 7 commits intomainfrom
add-codecerror-regression-tests-qmk3tf

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Mar 6, 2026

Summary

  • Adds a comprehensive CodecError regression testing surface backed by wireframe_testing, including unit tests, BDD-style scenarios, and a dedicated regression world.
  • Introduces an ExecPlan document for roadmap item 9.7.4 and updates the roadmap accordingly after validation gates.
  • This PR includes code changes to the codec (EOF classification/context handling via a new EofContext), new test scaffolding (shared helpers), tests, and documentation; no breaking public API changes.

Changes

  • Added docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md describing the regression plan, constraints, tolerances, risks, and plan of work.
  • src/codec.rs: introduce EofContext and context-based EOF error building used at EOF synthesis
  • tests/common/codec_error_regression_support.rs: Shared helpers for codec-error regression tests
  • tests/test_codec_error_regressions.rs: rstest-based regression tests for taxonomy-to-policy mappings
  • tests/features/codec_error_regressions.feature, tests/fixtures/codec_error_regressions.rs, tests/scenarios/codec_error_regressions_scenarios.rs, tests/scenarios/mod.rs, tests/steps/codec_error_regressions_steps.rs, tests/steps/mod.rs, tests/fixtures/mod.rs (updates)
  • Added a BDD world and helpers in tests/fixtures/codec_error_regressions.rs
  • Added test wiring for wireframe_testing usage: ObservabilityHandle, encode_frame, new_test_codec, etc.
  • Updated docs/roadmap.md to mark 9.7.4 as complete.
  • Updated docs/wireframe-testing-crate.md with notes on the regression pattern and how to drive taxonomy assertions from wireframe_testing
  • Updated tests/fixtures/mod.rs to export codec_error_regressions
  • Added tests/scenarios/codec_error_regressions_scenarios.rs and tests/scenarios/mod.rs entries to wire in the new scenarios

Rationale

  • Provides a living, well-scoped regression surface for CodecError taxonomy, recovery policy labels, and EOF handling, backed by the reusable testing surface in wireframe_testing.
  • Aligns with roadmap item 9.7.4 by outlining executable regression coverage and acceptance criteria prior to implementation, and now with code and tests that exercise that surface.
  • Builds on existing 9.1.2 concepts and existing tests to harden regression coverage without changing public API semantics.

Plan of work (high level)

Stage A: create failing regression coverage first

  • Add a rstest-based integration test set tests/test_codec_error_regressions.rs focused on 9.1.2 semantics.

Stage B: add only the minimum missing test-support API

  • If needed, extend wireframe_testing with minimal helpers to support new regressions (kept narrowly scoped).

Stage C: add behavioural coverage through rstest-bdd

  • Introduce a dedicated world and BDD scenarios under tests/features/codec_error_regressions.feature and corresponding fixtures/scenarios/steps.

Stage D: update documentation and roadmap

  • Update docs/wireframe-testing-crate.md and docs/roadmap.md to reflect new testing approach and 9.7.4 completion.

Stage E: validate red, green, and full gates

  • Run full formatting, linting, and test gates; ensure all tests pass and documentation is coherent with the implemented surface.

Testing plan

  • The regression suite is wired as executable tests, with both unit (rstest) and behavioural (rstest-bdd) components.
  • Local validation steps (example):
    • cargo test --all --tests
    • cargo test --test test_codec_error_regressions
    • cargo test --test codec_error_regressions_scenarios
    • make fmt; make lint; make check-fmt
  • The ExecPlan document will guide future work and acceptance criteria once the red/green gates are satisfied.

Documentation impact

  • Adds an ExecPlan for 9.7.4 detailing the codec-error regression strategy and testing surface.
  • Updates to docs/wireframe-testing-crate.md to reflect regression testing patterns and observability assertions.
  • Updates to docs/roadmap.md to reflect 9.7.4 status as completed once gates are green.

Approval notes

  • This is a combined coding/testing/documentation update that implements the regression surface, adds tests and scenarios, and updates planning documentation. Please review for clarity, completeness, and consistency with existing planning and governance. Once green, mark 9.7.4 done.

◳ Generated by DevBoxer

Summary by Sourcery

Add codec EOF error classification context and a regression suite validating codec error taxonomy, recovery policy labels, and observability labels via wireframe_testing, and mark the related roadmap item complete.

New Features:

  • Introduce a codec EOF context structure to carry header and payload information into structured EOF error construction.
  • Add rstest-based and BDD-style codec error regression tests that exercise codec error taxonomy, EOF classification, and recovery policy labelling through wireframe_testing.

Bug Fixes:

  • Correct EOF error synthesis in the length-delimited codec to base MidHeader vs MidFrame classification on explicit buffer-derived context rather than ad hoc state.

Enhancements:

  • Document the codec error regression testing pattern and wireframe_testing usage, and add an execution plan capturing constraints, risks, and validation for roadmap item 9.7.4.
  • Update the roadmap to reflect completion of codec error taxonomy regression tests.

📎 Task: https://www.devboxer.com/task/9ccbe999-9e5b-4d0e-9fc4-19617abe61d6

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Mar 6, 2026

Reviewer's Guide

Implements context-aware EOF error construction in the length-delimited codec and adds a comprehensive CodecError regression suite (rstest + BDD via wireframe_testing), along with an ExecPlan document and roadmap/docs updates describing and wiring the new testing pattern.

Sequence diagram for EOF handling in LengthDelimitedDecoder.decode_eof

sequenceDiagram
    participant Upstream as UpstreamDecoderUser
    participant Decoder as LengthDelimitedDecoder
    participant Inner as InnerDecoder
    participant Buf as BytesMut
    participant Ctx as EofContext
    participant Builder as build_eof_error

    Upstream->>Decoder: decode_eof(Buf)
    Decoder->>Buf: inspect buffer
    Decoder->>Ctx: from_buffer(Buf)
    Ctx-->>Decoder: EofContext

    Decoder->>Inner: decode_eof(Buf)
    alt Inner returns frame at EOF
        Inner-->>Decoder: Ok(Some(frame))
        Decoder-->>Upstream: Ok(Some(BytesMut::freeze(frame)))
    else Inner reports incomplete data at EOF
        Inner-->>Decoder: Ok(None)
        Decoder->>Builder: build_eof_error(EofContext)
        Builder-->>Decoder: io::Error(CodecError::Eof(...))
        Decoder-->>Upstream: Err(io::Error)
    else Inner returns error
        Inner-->>Decoder: Err(io::Error)
        Decoder->>Decoder: classify_error(io::Error)
        alt InvalidData framing error
            Decoder-->>Upstream: Err(io::Error)
        else other error
            Decoder->>Builder: build_eof_error(EofContext)
            Builder-->>Decoder: io::Error(CodecError::Eof(...))
            Decoder-->>Upstream: Err(io::Error)
        end
    end
Loading

Class diagram for EofContext and EOF error construction

classDiagram
    class LengthDelimitedDecoder {
        +decode_eof(src: BytesMut) Result~Option~BytesMut~~
    }

    class EofContext {
        +bytes_received: usize
        +expected: Option~usize~
        +from_buffer(src: BytesMut) EofContext
    }

    class CodecError {
        +Eof(EofError)
    }

    class EofError {
    }

    class EofErrorMidHeader {
        +bytes_received: usize
        +header_size: usize
    }

    class EofErrorMidFrame {
        +bytes_received: usize
        +expected: usize
    }

    class IoError {
    }

    class build_eof_error {
        +build_eof_error(context: EofContext) IoError
    }

    LengthDelimitedDecoder --> EofContext : uses
    LengthDelimitedDecoder --> build_eof_error : calls
    build_eof_error --> EofContext : reads
    build_eof_error --> CodecError : constructs
    CodecError --> EofError : wraps
    EofError <|-- EofErrorMidHeader
    EofError <|-- EofErrorMidFrame
    CodecError --> IoError : converts
Loading

Flow diagram for CodecError regression tests using wireframe_testing

flowchart TD
    Dev[Developer] --> CT[cargo test]
    CT --> IT[test_codec_error_regressions]
    CT --> BDD[codec_error_regressions_scenarios]

    subgraph IntegrationTests
        IT --> WFHelpers[wireframe_testing helpers\nencode_frame, new_test_codec]
        WFHelpers --> Codec[LengthDelimitedFrameCodec]
        Codec --> ObsHandle[ObservabilityHandle]
        ObsHandle --> Labels[Assert error_type and recovery_policy]
    end

    subgraph BDDScenarios
        BDD --> World[codec_error_regressions world]
        World --> Steps[codec_error_regressions_steps]
        Steps --> Fixtures[codec_error_regressions fixtures]
        Fixtures --> CodecBDD[LengthDelimitedFrameCodec]
        CodecBDD --> ObsHandleBDD[ObservabilityHandle]
        ObsHandleBDD --> TaxonomyAsserts[Taxonomy and EOF behaviour assertions]
    end

    Labels --> Outcome[CodecError taxonomy regression coverage]
    TaxonomyAsserts --> Outcome
Loading

File-Level Changes

Change Details Files
Refactor EOF error construction in the length-delimited codec to use an explicit EofContext, preserving taxonomy semantics while improving context handling at EOF.
  • Introduce EofContext struct capturing bytes_received and optional expected frame length from the buffer
  • Change LengthDelimitedDecoder::decode_eof to compute an EofContext once per call and pass it into EOF error construction
  • Update build_eof_error to accept EofContext instead of a raw buffer and use it to distinguish mid-header vs mid-frame EOF cases
src/codec.rs
Add rstest-based codec error regression tests that pin CodecError taxonomy, recovery policies, EOF classification, recovery hooks, and hotline fixtures via wireframe_testing helpers.
  • Define helper functions to classify EOFs using LengthDelimitedFrameCodec and to construct partial wires (mid-header, mid-frame) for testing
  • Add TaxonomyCase and DefaultEofCase test matrices covering framing/protocol/io/eof variants and default recovery policy behaviour
  • Verify ObservabilityHandle metrics labelling for codec errors and that existing hotline wire fixtures surface expected io::Error messages
tests/test_codec_error_regressions.rs
Introduce a BDD world and scenarios for codec error regressions, exercising EOF classification and observability through rstest-bdd and wireframe_testing.
  • Create CodecErrorRegressionsWorld fixture encapsulating ObservabilityHandle, EOF tracking, and helper methods to drive clean and partial EOF cases
  • Implement step definitions that map feature file steps onto world methods, including strict recovery hook override behaviour
  • Register four codec_error_regressions scenarios that run against the new feature file using rstest-bdd
tests/fixtures/codec_error_regressions.rs
tests/steps/codec_error_regressions_steps.rs
tests/scenarios/codec_error_regressions_scenarios.rs
tests/features/codec_error_regressions.feature
Wire new codec error regression fixtures, steps, and scenarios into the existing test harness modules.
  • Export codec_error_regressions fixture module from the tests fixtures mod
  • Register codec_error_regressions_scenarios and codec_error_regressions_steps modules in their respective mod.rs files so they are discovered by the test runner
tests/fixtures/mod.rs
tests/scenarios/mod.rs
tests/steps/mod.rs
Document the codec error regression plan, testing approach, and roadmap status for item 9.7.4.
  • Add an ExecPlan for 9.7.4 detailing constraints, tolerances, risks, plan of work, and outcomes for codec-error regression tests
  • Update wireframe-testing-crate documentation to describe recommended patterns for codec error taxonomy assertions using wireframe_testing and ObservabilityHandle
  • Mark roadmap item 9.7.4 as complete and apply minor copy/formatting tweaks in an existing ExecPlan document
docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md
docs/wireframe-testing-crate.md
docs/roadmap.md
docs/execplans/11-1-2-structured-logging-and-tracing-spans.md

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

codescene-delta-analysis[bot]

This comment was marked as outdated.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 6, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6593e27e-5248-4865-819b-9556e04e5928

📥 Commits

Reviewing files that changed from the base of the PR and between 8f21855 and 73c9fd5.

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

Summary by CodeRabbit

  • Bug Fixes

    • Improved EOF context and diagnostics for unexpected frame closures; error→IO mapping now preserves original error variants and kinds; decoder path preserves underlying decoder errors and flags trailing-bytes/truncation.
  • Tests

    • Added comprehensive regression suite validating codec error taxonomy, recovery-policy behaviours, EOF variants and observability.
  • Documentation

    • New exec plan, expanded testing guidance and clarified roadmap entry.
  • Notes

    • No public API or runtime behaviour changes introduced.

Walkthrough

Summarise the change: add an ExecPlan and wireframe_testing guidance; capture EOF context in src/codec.rs to construct structured EOF errors; adjust CodecError -> io::Error mapping and error test traversal; simplify helper decode paths; and add a BDD-style regression test suite (features, scenarios, steps, fixtures, helpers, and tests).

Changes

Cohort / File(s) Summary
Documentation & Planning
docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md, docs/roadmap.md, docs/wireframe-testing-crate.md
Add a standalone ExecPlan and expand wireframe_testing guidance; editorial update to roadmap phrasing; specify test placement, observability assertions and test governance.
Codec EOF Handling
src/codec.rs, src/codec/error.rs, src/codec/error_tests.rs
Introduce EofContext to capture bytes_received/expected_length and refactor EOF error construction to consume that context; change mapping of CodecErrorio::Error to wrap variants; update tests to traverse error chains to locate EofError.
wireframe_testing helpers
wireframe_testing/src/helpers/codec_ext.rs
Simplify decode error propagation (use ?), add trailing-data detection yielding InvalidData, and document preserved error source chain.
BDD Feature & Scenario Infrastructure
tests/features/codec_error_regressions.feature, tests/scenarios/codec_error_regressions_scenarios.rs, tests/scenarios/mod.rs
Add four feature scenarios for codec-error regressions and scaffold scenario functions; register new scenarios module for test discovery.
BDD Step Definitions
tests/steps/codec_error_regressions_steps.rs, tests/steps/mod.rs
Add Given/When/Then step implementations that exercise CodecErrorRegressionsWorld; register steps module.
Test Fixtures & World
tests/fixtures/codec_error_regressions.rs, tests/fixtures/mod.rs
Add CodecErrorRegressionsWorld fixture, helpers to record/inspect observability metrics and classify EOFs, and export the fixtures module.
Regression Tests & Utilities
tests/test_codec_error_regressions.rs, tests/common/codec_error_regression_support.rs
Add extensive parametrised regression tests, EOF-classification helpers, StrictRecoveryHook, frame encoders and truncated-wire builders, and assertion helpers for metrics and EOF kinds.

Sequence Diagram(s)

sequenceDiagram
  participant Client as Client
  participant Decoder as LengthDelimitedDecoder
  participant Inner as InnerDecoder
  participant Builder as EOF\ Builder
  participant Observ as Observability

  Client->>Decoder: send bytes / EOF
  Decoder->>Decoder: EofContext::from_buffer(src)
  Decoder->>Inner: inner.decode_eof()
  alt Inner returns Ok(None)
    Decoder->>Builder: build_eof_error(EofContext)
    Builder->>Observ: record EOF classification (MidHeader / MidFrame)
    Builder-->>Decoder: Err(EofError)
  else Inner returns Err(e) and e != InvalidData
    Decoder->>Decoder: debug log
    Decoder->>Builder: build_eof_error(EofContext)
    Builder->>Observ: record EOF classification
    Builder-->>Decoder: Err(EofError)
  else Inner returns Err(InvalidData)
    Inner-->>Decoder: propagate original error
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🧪 Frames close soft, contexts keep,
EOFs revealed where bytes fall deep,
Tests march in BDD array,
Labels set and rules betray,
Metrics hum as errors sleep.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title directly summarises the main change: adding CodecError regression tests with wireframe_testing and an ExecPlan document, which aligns with the core work across test files, documentation, and codec modifications.
Description check ✅ Passed The description comprehensively explains the changeset, detailing the CodecError regression testing surface, EofContext implementation, test scaffolding, BDD scenarios, documentation updates, and the staged plan of work, all of which match the actual file modifications.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-codecerror-regression-tests-qmk3tf
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos leynos changed the title Add CodecError Regression Tests ExecPlan Add CodecError Regression Tests with wireframe_testing and ExecPlan Mar 9, 2026
@leynos leynos marked this pull request as ready for review March 10, 2026 11:12
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

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

Hey - I've found 2 issues, and left some high level feedback:

  • There’s quite a bit of duplicated helper logic between tests/test_codec_error_regressions.rs and tests/fixtures/codec_error_regressions.rs (e.g. encoded_default_frame, classify_eof, extract_eof_error, partial header/payload builders); consider extracting these into a shared test helper module to keep the regression logic in one place.
  • In partial_payload_wire you hard-code 4 for the header size when allocating capacity; using LENGTH_HEADER_SIZE instead would keep the helper consistent with the production codec constants.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- There’s quite a bit of duplicated helper logic between `tests/test_codec_error_regressions.rs` and `tests/fixtures/codec_error_regressions.rs` (e.g. `encoded_default_frame`, `classify_eof`, `extract_eof_error`, partial header/payload builders); consider extracting these into a shared test helper module to keep the regression logic in one place.
- In `partial_payload_wire` you hard-code `4` for the header size when allocating capacity; using `LENGTH_HEADER_SIZE` instead would keep the helper consistent with the production codec constants.

## Individual Comments

### Comment 1
<location path="tests/test_codec_error_regressions.rs" line_range="184" />
<code_context>
+        expected_clean_close: true,
+    }
+)]
+fn taxonomy_cases_emit_expected_recovery_labels(#[case] case: TaxonomyCase) {
+    assert_eq!(case.error.error_type(), case.expected_type);
+    assert_eq!(case.error.default_recovery_policy(), case.expected_policy);
</code_context>
<issue_to_address>
**suggestion (testing):** Add taxonomy cases for MidHeader and MidFrame EOF variants to fully lock in EOF policies and flags

The `taxonomy_cases_emit_expected_recovery_labels` test currently only covers `CodecError::Eof(EofError::CleanClose)` and misses the `MidHeader` and `MidFrame` variants. Please add `TaxonomyCase` entries for `EofError::MidHeader { .. }` and `EofError::MidFrame { .. }` to assert their `error_type()`, `default_recovery_policy()`, `should_disconnect()`, and `is_clean_close()` so EOF taxonomy is fully regression-tested for all variants, independent of the EOF classification helper tests.

Suggested implementation:

```rust
)]
#[case::clean_close(
    TaxonomyCase {
        error: CodecError::Eof(EofError::CleanClose),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: true,
    }
)]
#[case::mid_header(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidHeader {
            // TODO: fill in struct fields according to the EofError::MidHeader
            // definition, for example:
            // header_len: 10,
            // received_len: 5,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]
#[case::mid_frame(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidFrame {
            // TODO: fill in struct fields according to the EofError::MidFrame
            // definition, for example:
            // frame_len: 1024,
            // received_len: 512,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]
fn taxonomy_cases_emit_expected_recovery_labels(#[case] case: TaxonomyCase) {

```

1. Replace the `// TODO` field initializations in `EofError::MidHeader { .. }` and `EofError::MidFrame { .. }` with the actual field names and values from your `EofError` enum definition so the code compiles.
2. If `MidHeader` or `MidFrame` carry additional context that should affect taxonomy (e.g., different policies for certain sizes), adjust the `expected_policy`, `expected_disconnect`, and `expected_clean_close` values to match the real semantics. Currently these are set to `Disconnect`, `true`, and `false` respectively, assuming mid-stream EOFs are treated as non-clean disconnect-worthy errors.
</issue_to_address>

### Comment 2
<location path="tests/fixtures/codec_error_regressions.rs" line_range="191" />
<code_context>
+    Ok(wire)
+}
+
+fn classify_eof(bytes: &[u8], consume_frame_before_eof: bool) -> TestResult<EofError> {
+    let codec = LengthDelimitedFrameCodec::new(1024);
+    let mut decoder = codec.decoder();
</code_context>
<issue_to_address>
**suggestion:** Consider a regression test around EOF with zero-length payloads or header-only frames

Current tests exercise clean close, partial header, and partial payload, but always with a non‑empty payload. Please add a case with a zero‑length frame (header present, no payload) that goes through `classify_eof` and asserts the resulting `EofError` and metrics, either here or in `tests/test_codec_error_regressions.rs`, to confirm the new EOF context logic handles empty payloads correctly.

Suggested implementation:

```rust
    wire.extend_from_slice(
        payload
            .get(..partial_len)
            .ok_or("partial payload slice should be available")?,
    );
    Ok(wire)
}

#[test]
fn eof_with_zero_length_payload_frame_is_classified() -> TestResult<()> {
    // Construct a single frame with a valid header indicating a zero-length payload
    // (header present, no payload bytes).
    let mut wire = Vec::with_capacity(4);
    wire.extend_from_slice(&write_network_u32(0));

    // Do not consume any frame before EOF; we want EOF immediately after the header-only frame.
    let eof_error = classify_eof(&wire, false)?;

    // Basic sanity assertion that we got some EOF classification back.
    // The exact variant/metrics should be asserted in line with the other tests.
    let _ = eof_error;

    Ok(())
}

fn classify_eof(bytes: &[u8], consume_frame_before_eof: bool) -> TestResult<EofError> {

```

To fully implement the intent of your review comment:

1. Strengthen the assertion in `eof_with_zero_length_payload_frame_is_classified` to match the expected `EofError` variant and associated fields, following the pattern used by the other EOF regression tests in this file (e.g., `assert_eq!(eof_error, EofError::... )` or `assert!(matches!(eof_error, EofError::...))`).
2. If you are tracking metrics (counters/gauges) in other tests, also add assertions here to verify the metric values for the zero-length frame EOF case (e.g., frame count, bytes, EOF classification labels).
3. If tests are organized in `tests/test_codec_error_regressions.rs` as well, you may want to add a higher-level integration test there that uses this fixture and asserts the observable metrics exported by the codec layer for the zero-length payload EOF scenario.
</issue_to_address>

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

Comment thread tests/test_codec_error_regressions.rs
Comment thread tests/fixtures/codec_error_regressions.rs Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 5

Caution

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

⚠️ Outside diff range comments (1)
src/codec.rs (1)

158-165: ⚠️ Potential issue | 🔴 Critical

Track pending frame state before classifying EOF.

Line 160 only checks the external buffer. After an earlier decode() call,
LengthDelimitedCodec can already have consumed the length prefix and be
waiting for payload bytes while src is empty, so this path returns Ok(None)
instead of EofError::MidFrame. The same missing state means
EofContext::from_buffer() can reinterpret payload bytes as a new header on
later EOFs. Persist the pending payload length in LengthDelimitedDecoder,
clear it once a frame is emitted, and build EOF errors from that stored state
rather than the current buffer snapshot. Verify this against the
tokio_util::codec::LengthDelimitedCodec partial-read state machine.

Also applies to: 195-237

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/codec.rs` around lines 158 - 165, The EOF handling currently checks only
the external buffer in decode_eof and calls EofContext::from_buffer, which
misses the case where a previous decode() consumed the length prefix and the
decoder is waiting for payload bytes; modify LengthDelimitedDecoder to store
pending_payload_len (Option<usize>) when a length header is parsed, consult that
stored state at the start of decode_eof (and in the EOF-paths around lines
referenced) to return EofError::MidFrame when pending_payload_len.is_some(),
clear pending_payload_len when a full frame is emitted in decode() (or when a
frame is otherwise completed), and build EOF errors from this stored
pending_payload_len instead of relying solely on EofContext::from_buffer so
partial-read state matches tokio_util::codec::LengthDelimitedCodec behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md`:
- Around line 339-343: Remove the hard-coded MDLINT environment override in the
recipe line that currently sets "MDLINT=/root/.bun/bin/markdownlint-cli2" and
instead invoke the documented project target "make markdownlint" so the step
runs in a normal checkout; update the line that references the MDLINT variable
to call only "make markdownlint" while keeping the surrounding set -o pipefail
and tee redirection unchanged.

In `@docs/roadmap.md`:
- Around line 440-441: Update the roadmap entry text that currently reads
"9.7.4. Add regression tests in `wireframe_testing`..." so it does not point
readers to the wrong location; change the wording to indicate the tests are
"backed by `wireframe_testing`" (or similar), e.g. replace the phrase "in
`wireframe_testing`" with "backed by `wireframe_testing`" in the line starting
with "9.7.4. Add regression tests" so the item correctly reflects that the
executable regressions live under the repository-root tests/ directory while
using wireframe_testing as a dev-dependency.

In `@tests/fixtures/codec_error_regressions.rs`:
- Around line 20-21: The public fixture surface (symbols like TestResult,
CodecErrorRegressionsWorld, the fixture constructor and its public world
methods) is undocumented and likely should not be broadly exported; either add
concise rustdoc comments (///) to each exported item explaining purpose and
usage or restrict visibility to pub(crate) for TestResult,
CodecErrorRegressionsWorld, the fixture constructor and any public methods on
the world struct; update the declarations accordingly so only intended items
remain public or are documented with /// lines describing the API.

In `@tests/test_codec_error_regressions.rs`:
- Around line 257-273: The test should not rely only on Display text—downcast
the decoding failure returned by decode_frames_with_codec in
wireframe_testing_fixture_cases_continue_to_surface_expected_errors to the
concrete wireframe::codec::CodecError and assert the expected enum variant and
its recovery policy; specifically, after expecting an error from
decode_frames_with_codec(&codec, wire), get the underlying source (e.g.,
error.source() or error.get_ref()),
downcast_ref::<wireframe::codec::CodecError>(), then match or assert that it is
the exact variant (e.g., the oversize variant vs the truncated-header variant)
and that its recovery/policy field has the expected value.
- Around line 32-95: Move the duplicated test helpers (extract_eof_error,
classify_eof, encoded_default_frame, truncated_payload_wire, record_codec_error
and the StrictRecoveryHook) into a single shared test module and replace the
local copies in both tests with imports; create rstest fixtures in that shared
module for common setup (e.g., a codec/decoder fixture used by classify_eof) and
export the helper functions so both the BDD tests and integration tests use
them, then remove the duplicated definitions from
tests/test_codec_error_regressions.rs and
tests/fixtures/codec_error_regressions.rs and update their uses to call the
shared helpers.

---

Outside diff comments:
In `@src/codec.rs`:
- Around line 158-165: The EOF handling currently checks only the external
buffer in decode_eof and calls EofContext::from_buffer, which misses the case
where a previous decode() consumed the length prefix and the decoder is waiting
for payload bytes; modify LengthDelimitedDecoder to store pending_payload_len
(Option<usize>) when a length header is parsed, consult that stored state at the
start of decode_eof (and in the EOF-paths around lines referenced) to return
EofError::MidFrame when pending_payload_len.is_some(), clear pending_payload_len
when a full frame is emitted in decode() (or when a frame is otherwise
completed), and build EOF errors from this stored pending_payload_len instead of
relying solely on EofContext::from_buffer so partial-read state matches
tokio_util::codec::LengthDelimitedCodec behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 39e0fa32-6c37-4bff-a98a-20083011fff4

📥 Commits

Reviewing files that changed from the base of the PR and between 926468d and c5552f7.

📒 Files selected for processing (13)
  • docs/execplans/11-1-2-structured-logging-and-tracing-spans.md
  • docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md
  • docs/roadmap.md
  • docs/wireframe-testing-crate.md
  • src/codec.rs
  • tests/features/codec_error_regressions.feature
  • tests/fixtures/codec_error_regressions.rs
  • tests/fixtures/mod.rs
  • tests/scenarios/codec_error_regressions_scenarios.rs
  • tests/scenarios/mod.rs
  • tests/steps/codec_error_regressions_steps.rs
  • tests/steps/mod.rs
  • tests/test_codec_error_regressions.rs

Comment thread docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md
Comment thread docs/roadmap.md Outdated
Comment thread tests/fixtures/codec_error_regressions.rs Outdated
Comment thread tests/test_codec_error_regressions.rs
Comment thread tests/test_codec_error_regressions.rs
leynos and others added 2 commits March 10, 2026 19:06
Add a comprehensive execution plan document 9-7-4-codec-error-taxonomy-regression-tests.md detailing the purpose, constraints, testing strategy, risks, progress checkpoints, decision log, and expected outcomes for the 9.7.4 roadmap item. This plan establishes the approach to hardening codec-error taxonomy regression tests using the wireframe_testing crate, including staged work for regression coverage, helper improvements, BDD scenarios, documentation updates, and validation steps.

This document will guide the subsequent implementation and test additions to ensure robust, reusable, and observable codec-error regression testing aligned with roadmap 9.7.4 requirements.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
…codec error taxonomy and recovery

- Added extensive regression tests under tests/test_codec_error_regressions.rs using rstest
- Introduced BDD feature file tests/features/codec_error_regressions.feature with multiple scenarios
- Implemented a new test fixture world in tests/fixtures/codec_error_regressions.rs supporting detailed EOF and recovery policy classification
- Added scenario definitions in tests/scenarios/codec_error_regressions_scenarios.rs
- Added step definitions in tests/steps/codec_error_regressions_steps.rs for BDD scenarios
- Updated tests/fixtures/mod.rs, tests/scenarios/mod.rs, and tests/steps/mod.rs to include these new modules
- Modified codec.rs decoding to preserve detailed EOF error context for accurate testing
- Completed ExecPlan in docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md marking item done
- Updated docs/wireframe-testing-crate.md and docs/roadmap.md to reflect test coverage and best practices

This commit completes roadmap item 9.7.4 by establishing a robust regression suite that verifies codec error classification, recovery policies, observability labels, and supports future maintenance with no change to public APIs.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
@devboxerhub devboxerhub Bot force-pushed the add-codecerror-regression-tests-qmk3tf branch from c5552f7 to 0414c9d Compare March 10, 2026 19:09
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (5)
tests/test_codec_error_regressions.rs (2)

32-95: 🧹 Nitpick | 🔵 Trivial

Extract duplicated codec test helpers into shared test infrastructure.

The helpers extract_eof_error, classify_eof, encoded_default_frame, truncated_payload_wire, and StrictRecoveryHook are duplicated between this file and tests/fixtures/codec_error_regressions.rs. Move them to a shared test module to prevent drift when codec behaviour changes.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_codec_error_regressions.rs` around lines 32 - 95, The test helpers
extract_eof_error, classify_eof, encoded_default_frame, truncated_payload_wire
and the StrictRecoveryHook are duplicated across tests; factor them into a
shared test utility module (e.g., tests/utils/codec_helpers or a new
tests::fixtures module) and update both tests/test_codec_error_regressions.rs
and tests/fixtures/codec_error_regressions.rs to import the helpers from that
shared module; ensure you move any dependent helpers (e.g., new_test_codec,
encode_frame, LENGTH_HEADER_SIZE, write_network_u32) or re-export them as needed
and adjust visibility (pub(crate)) so functions like extract_eof_error,
classify_eof, encoded_default_frame, truncated_payload_wire and
StrictRecoveryHook compile without changes to their callers.

257-273: 🧹 Nitpick | 🔵 Trivial

Assert structured codec taxonomy on the real decode path.

These cases drive bytes through decode_frames_with_codec but only match Display fragments. If the decoder changes the CodecError variant while keeping a similar message, this regression suite still passes. Downcast the cause and assert the error type and policy directly.

Note: The decode_frames_with_codec helper erases typed errors to io::Error text, so typed assertions require calling the decoder directly. Track this as a follow-up improvement.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_codec_error_regressions.rs` around lines 257 - 273, The test
currently only checks error Display fragments from decode_frames_with_codec;
change it to assert the concrete codec error by invoking the decoder directly
(use wireframe::codec::examples::HotlineFrameCodec::new(...) and call its decode
method instead of the helper) and downcast the returned error to the codec's
error type (CodecError) then match the specific variant(s) (e.g.,
PayloadTooLarge / TruncatedHeader or the variant names used by your CodecError)
and assert the associated fields like max_frame_length or bytes remaining;
replace the string-contains assertion with these typed assertions so the test
fails if the error variant/policy changes.
docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md (2)

339-343: ⚠️ Potential issue | 🟡 Minor

Remove the absolute MDLINT path from the validation recipe.

The plan should be runnable from a normal checkout. Hard-coding /root/.bun/bin/markdownlint-cli2 makes this step environment-specific and diverges from the documented project command.

✏️ Suggested fix
-set -o pipefail && make markdownlint MDLINT=/root/.bun/bin/markdownlint-cli2 2>&1 | tee /tmp/9-7-4-markdownlint.log
+set -o pipefail && make markdownlint 2>&1 | tee /tmp/9-7-4-markdownlint.log
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md` around lines
339 - 343, The recipe hard-codes an absolute MDLINT path
(/root/.bun/bin/markdownlint-cli2) making the step environment-specific; update
the markdownlint invocation to remove the absolute path and rely on the MDLINT
variable or system PATH instead (e.g., use MDLINT=markdownlint-cli2 or omit
MDLINT so the Makefile falls back to its default). Edit the line that sets
MDLINT in the command for the markdownlint step so it no longer embeds
/root/.bun/bin/markdownlint-cli2, ensuring the recipe runs from a normal
checkout and uses the project's documented command.

193-193: ⚠️ Potential issue | 🟡 Minor

Remove the absolute MDLINT path from the validation recipe.

Line 193 hard-codes /root/.bun/bin/markdownlint-cli2, making this step environment-specific. Use the project's standard make markdownlint invocation instead.

✏️ Suggested fix
-- `make markdownlint MDLINT=/root/.bun/bin/markdownlint-cli2`
+- `make markdownlint`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md` at line 193,
The recipe currently hard-codes the absolute MDLINT path
(`/root/.bun/bin/markdownlint-cli2`) in the validation step; update the docs to
remove that absolute path and show the project-standard invocation (`make
markdownlint`) (or a generic `make markdownlint MDLINT=...` if you want to
override) so the step is environment-agnostic—replace the line containing the
hard-coded `MDLINT=/root/.bun/bin/markdownlint-cli2` with the plain `make
markdownlint` invocation.
docs/roadmap.md (1)

440-441: ⚠️ Potential issue | 🟡 Minor

Update the roadmap wording to reflect the actual test location.

The ExecPlan explicitly states that executable regressions live under the repository-root tests/ directory because wireframe_testing is only a dev-dependency. The phrase "in wireframe_testing" misdirects readers. Replace with "backed by wireframe_testing" or similar.

✏️ Suggested wording
-- [x] 9.7.4. Add regression tests in `wireframe_testing` for the `CodecError`
-  taxonomy and recovery policy behaviours defined in 9.1.2. Requires 9.1.2.
+- [x] 9.7.4. Add regression tests backed by `wireframe_testing` for the
+  `CodecError` taxonomy and recovery policy behaviours defined in 9.1.2.
+  Requires 9.1.2.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/roadmap.md` around lines 440 - 441, Update the roadmap checklist item
that reads "9.7.4. Add regression tests in `wireframe_testing`..." to avoid
implying tests live under `wireframe_testing`; change the phrase "in
`wireframe_testing`" to "backed by `wireframe_testing`" (or similar wording) so
the item communicates that regressions under the repository-root `tests/`
directory are supported by the `wireframe_testing` dev-dependency; locate the
string "9.7.4. Add regression tests in `wireframe_testing` for the `CodecError`
taxonomy and recovery policy behaviours defined in 9.1.2. Requires 9.1.2." and
edit it accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md`:
- Line 257: The phrase "hand-written tests" should be corrected to the
single-word adjective "handwritten" in the documentation line that reads "Use
`#[rstest]` parameterization instead of repeated hand-written tests."; update
that sentence to "Use `#[rstest]` parameterization instead of repeated
handwritten tests." and ensure any other occurrences of "hand-written" in this
document are replaced with "handwritten" for consistent spelling.

In `@tests/fixtures/codec_error_regressions.rs`:
- Around line 132-144: Extract the duplicated match logic into a small helper
like a function that takes (expected: PartialEofKind, actual: &EofError) -> bool
(or returns Result/Unit) and use it from assert_partial_kind and the
classify_partial_inputs test; replace the inline match in assert_partial_kind
(and the match at lines 241-244 in classify_partial_inputs) with a call to that
helper, keeping the same pattern arms (PartialEofKind::MidHeader <->
EofError::MidHeader { .. } and PartialEofKind::MidFrame <-> EofError::MidFrame {
.. }) so behavior is unchanged.

---

Duplicate comments:
In `@docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md`:
- Around line 339-343: The recipe hard-codes an absolute MDLINT path
(/root/.bun/bin/markdownlint-cli2) making the step environment-specific; update
the markdownlint invocation to remove the absolute path and rely on the MDLINT
variable or system PATH instead (e.g., use MDLINT=markdownlint-cli2 or omit
MDLINT so the Makefile falls back to its default). Edit the line that sets
MDLINT in the command for the markdownlint step so it no longer embeds
/root/.bun/bin/markdownlint-cli2, ensuring the recipe runs from a normal
checkout and uses the project's documented command.
- Line 193: The recipe currently hard-codes the absolute MDLINT path
(`/root/.bun/bin/markdownlint-cli2`) in the validation step; update the docs to
remove that absolute path and show the project-standard invocation (`make
markdownlint`) (or a generic `make markdownlint MDLINT=...` if you want to
override) so the step is environment-agnostic—replace the line containing the
hard-coded `MDLINT=/root/.bun/bin/markdownlint-cli2` with the plain `make
markdownlint` invocation.

In `@docs/roadmap.md`:
- Around line 440-441: Update the roadmap checklist item that reads "9.7.4. Add
regression tests in `wireframe_testing`..." to avoid implying tests live under
`wireframe_testing`; change the phrase "in `wireframe_testing`" to "backed by
`wireframe_testing`" (or similar wording) so the item communicates that
regressions under the repository-root `tests/` directory are supported by the
`wireframe_testing` dev-dependency; locate the string "9.7.4. Add regression
tests in `wireframe_testing` for the `CodecError` taxonomy and recovery policy
behaviours defined in 9.1.2. Requires 9.1.2." and edit it accordingly.

In `@tests/test_codec_error_regressions.rs`:
- Around line 32-95: The test helpers extract_eof_error, classify_eof,
encoded_default_frame, truncated_payload_wire and the StrictRecoveryHook are
duplicated across tests; factor them into a shared test utility module (e.g.,
tests/utils/codec_helpers or a new tests::fixtures module) and update both
tests/test_codec_error_regressions.rs and
tests/fixtures/codec_error_regressions.rs to import the helpers from that shared
module; ensure you move any dependent helpers (e.g., new_test_codec,
encode_frame, LENGTH_HEADER_SIZE, write_network_u32) or re-export them as needed
and adjust visibility (pub(crate)) so functions like extract_eof_error,
classify_eof, encoded_default_frame, truncated_payload_wire and
StrictRecoveryHook compile without changes to their callers.
- Around line 257-273: The test currently only checks error Display fragments
from decode_frames_with_codec; change it to assert the concrete codec error by
invoking the decoder directly (use
wireframe::codec::examples::HotlineFrameCodec::new(...) and call its decode
method instead of the helper) and downcast the returned error to the codec's
error type (CodecError) then match the specific variant(s) (e.g.,
PayloadTooLarge / TruncatedHeader or the variant names used by your CodecError)
and assert the associated fields like max_frame_length or bytes remaining;
replace the string-contains assertion with these typed assertions so the test
fails if the error variant/policy changes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fd96ee71-a13e-42b0-83de-c33d8c74043b

📥 Commits

Reviewing files that changed from the base of the PR and between c5552f7 and 0414c9d.

📒 Files selected for processing (13)
  • docs/execplans/11-1-2-structured-logging-and-tracing-spans.md
  • docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md
  • docs/roadmap.md
  • docs/wireframe-testing-crate.md
  • src/codec.rs
  • tests/features/codec_error_regressions.feature
  • tests/fixtures/codec_error_regressions.rs
  • tests/fixtures/mod.rs
  • tests/scenarios/codec_error_regressions_scenarios.rs
  • tests/scenarios/mod.rs
  • tests/steps/codec_error_regressions_steps.rs
  • tests/steps/mod.rs
  • tests/test_codec_error_regressions.rs

Comment thread docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md Outdated
Comment thread tests/fixtures/codec_error_regressions.rs
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Mar 11, 2026

@coderabbitai Have the following now been resolved?

Annul any requirements that violate the en-GB-oxendict spelling (-ize / -yse / -our) conventions (for example a request to replace "normalize" with "normalise" or "artefact" with "artifact"), or where the requirement unnecessarily increases cyclomatic complexity.

Please address the comments from this code review:

## Overall Comments
- There’s quite a bit of duplicated helper logic between `tests/test_codec_error_regressions.rs` and `tests/fixtures/codec_error_regressions.rs` (e.g. `encoded_default_frame`, `classify_eof`, `extract_eof_error`, partial header/payload builders); consider extracting these into a shared test helper module to keep the regression logic in one place.
- In `partial_payload_wire` you hard-code `4` for the header size when allocating capacity; using `LENGTH_HEADER_SIZE` instead would keep the helper consistent with the production codec constants.

## Individual Comments

### Comment 1
<location path="tests/test_codec_error_regressions.rs" line_range="184" />
<code_context>
+        expected_clean_close: true,
+    }
+)]
+fn taxonomy_cases_emit_expected_recovery_labels(#[case] case: TaxonomyCase) {
+    assert_eq!(case.error.error_type(), case.expected_type);
+    assert_eq!(case.error.default_recovery_policy(), case.expected_policy);
</code_context>
<issue_to_address>
**suggestion (testing):** Add taxonomy cases for MidHeader and MidFrame EOF variants to fully lock in EOF policies and flags

The `taxonomy_cases_emit_expected_recovery_labels` test currently only covers `CodecError::Eof(EofError::CleanClose)` and misses the `MidHeader` and `MidFrame` variants. Please add `TaxonomyCase` entries for `EofError::MidHeader { .. }` and `EofError::MidFrame { .. }` to assert their `error_type()`, `default_recovery_policy()`, `should_disconnect()`, and `is_clean_close()` so EOF taxonomy is fully regression-tested for all variants, independent of the EOF classification helper tests.

Suggested implementation:

```rust
)]
#[case::clean_close(
    TaxonomyCase {
        error: CodecError::Eof(EofError::CleanClose),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: true,
    }
)]
#[case::mid_header(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidHeader {
            // TODO: fill in struct fields according to the EofError::MidHeader
            // definition, for example:
            // header_len: 10,
            // received_len: 5,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]
#[case::mid_frame(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidFrame {
            // TODO: fill in struct fields according to the EofError::MidFrame
            // definition, for example:
            // frame_len: 1024,
            // received_len: 512,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]
fn taxonomy_cases_emit_expected_recovery_labels(#[case] case: TaxonomyCase) {

```

1. Replace the `// TODO` field initializations in `EofError::MidHeader { .. }` and `EofError::MidFrame { .. }` with the actual field names and values from your `EofError` enum definition so the code compiles.
2. If `MidHeader` or `MidFrame` carry additional context that should affect taxonomy (e.g., different policies for certain sizes), adjust the `expected_policy`, `expected_disconnect`, and `expected_clean_close` values to match the real semantics. Currently these are set to `Disconnect`, `true`, and `false` respectively, assuming mid-stream EOFs are treated as non-clean disconnect-worthy errors.
</issue_to_address>

### Comment 2
<location path="tests/fixtures/codec_error_regressions.rs" line_range="191" />
<code_context>
+    Ok(wire)
+}
+
+fn classify_eof(bytes: &[u8], consume_frame_before_eof: bool) -> TestResult<EofError> {
+    let codec = LengthDelimitedFrameCodec::new(1024);
+    let mut decoder = codec.decoder();
</code_context>
<issue_to_address>
**suggestion:** Consider a regression test around EOF with zero-length payloads or header-only frames

Current tests exercise clean close, partial header, and partial payload, but always with a non‑empty payload. Please add a case with a zero‑length frame (header present, no payload) that goes through `classify_eof` and asserts the resulting `EofError` and metrics, either here or in `tests/test_codec_error_regressions.rs`, to confirm the new EOF context logic handles empty payloads correctly.

Suggested implementation:

```rust
    wire.extend_from_slice(
        payload
            .get(..partial_len)
            .ok_or("partial payload slice should be available")?,
    );
    Ok(wire)
}

#[test]
fn eof_with_zero_length_payload_frame_is_classified() -> TestResult<()> {
    // Construct a single frame with a valid header indicating a zero-length payload
    // (header present, no payload bytes).
    let mut wire = Vec::with_capacity(4);
    wire.extend_from_slice(&write_network_u32(0));

    // Do not consume any frame before EOF; we want EOF immediately after the header-only frame.
    let eof_error = classify_eof(&wire, false)?;

    // Basic sanity assertion that we got some EOF classification back.
    // The exact variant/metrics should be asserted in line with the other tests.
    let _ = eof_error;

    Ok(())
}

fn classify_eof(bytes: &[u8], consume_frame_before_eof: bool) -> TestResult<EofError> {

```

To fully implement the intent of your review comment:

1. Strengthen the assertion in `eof_with_zero_length_payload_frame_is_classified` to match the expected `EofError` variant and associated fields, following the pattern used by the other EOF regression tests in this file (e.g., `assert_eq!(eof_error, EofError::... )` or `assert!(matches!(eof_error, EofError::...))`).
2. If you are tracking metrics (counters/gauges) in other tests, also add assertions here to verify the metric values for the zero-length frame EOF case (e.g., frame count, bytes, EOF classification labels).
3. If tests are organized in `tests/test_codec_error_regressions.rs` as well, you may want to add a higher-level integration test there that uses this fixture and asserts the observable metrics exported by the codec layer for the zero-length payload EOF scenario.
</issue_to_address>

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 11, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== tests/test_codec_error_regressions.rs ==="
cat tests/test_codec_error_regressions.rs

echo ""
echo "=== tests/fixtures/codec_error_regressions.rs ==="
cat tests/fixtures/codec_error_regressions.rs

echo ""
echo "=== Search for LENGTH_HEADER_SIZE usage ==="
rg -n "LENGTH_HEADER_SIZE" --type rust

echo ""
echo "=== Search for partial_payload_wire ==="
rg -n "partial_payload_wire" --type rust -A5 -B2

echo ""
echo "=== Search for MidHeader/MidFrame in test files ==="
rg -n "MidHeader|MidFrame" --type rust -C2

echo ""
echo "=== Search for zero.length or zero_length ==="
rg -n "zero.length|zero_length|zero_payload" --type rust -C2

Length of output: 38810


@leynos: None of the four comments have been resolved yet. Applying your filter (annul violations of en-GB-oxendict and unnecessary cyclomatic complexity increases): none of the suggestions touch spelling conventions, and none introduce branching into existing functions, so all four remain standing. Here is a precise status:


Overall comment 1 — deduplicate helpers

Not resolved. encoded_default_frame, classify_eof, and extract_eof_error are independently defined in both tests/test_codec_error_regressions.rs and tests/fixtures/codec_error_regressions.rs. Extract these into a shared internal helper module (e.g. tests/support/codec_helpers.rs) and import from both files.


Overall comment 2 — LENGTH_HEADER_SIZE in partial_payload_wire

Not resolved. Line 181 of tests/fixtures/codec_error_regressions.rs still reads:

let mut wire = Vec::with_capacity(4 + partial_len);

LENGTH_HEADER_SIZE is not imported in that file. Add it to the wireframe::codec import block and replace the literal:

let mut wire = Vec::with_capacity(LENGTH_HEADER_SIZE + partial_len);

Comment 1 — MidHeader/MidFrame taxonomy cases

Not resolved. taxonomy_cases_emit_expected_recovery_labels covers EofError::CleanClose only. The default_codec_eof_classification_remains_stable test does exercise MidHeader/MidFrame classification, but that is distinct from asserting their taxonomy labels independently of the codec pipeline. Add these two cases:

#[case::mid_header(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidHeader {
            bytes_received: 2,
            header_size: LENGTH_HEADER_SIZE,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]
#[case::mid_frame(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidFrame {
            bytes_received: 3,
            expected: 4,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]

Comment 2 — zero-length payload EOF regression

Not resolved. No test covering a header-only frame (4-byte length prefix of 0, no payload bytes) through the EOF classification path exists in either regression file. Add one to tests/fixtures/codec_error_regressions.rs inside the existing #[cfg(test)] module:

#[test]
fn eof_immediately_after_zero_length_frame_header_is_classified() -> TestResult {
    let mut wire = Vec::with_capacity(LENGTH_HEADER_SIZE);
    wire.extend_from_slice(&write_network_u32(0));
    let actual = classify_eof(&wire, false)?;
    assert!(
        matches!(actual, EofError::MidFrame { bytes_received: 0, expected: 0 }),
        "expected MidFrame{{bytes_received: 0, expected: 0}}, got {actual:?}"
    );
    Ok(())
}

Note: import LENGTH_HEADER_SIZE in the outer module first (see Overall comment 2), then the inner test module inherits it via use super::*.

…odec error regression tests

- Introduce `tests/common/codec_error_regression_support.rs` for shared helper functions and types.
- Refactor `tests/fixtures/codec_error_regressions.rs` and `tests/test_codec_error_regressions.rs` to use shared helpers.
- Simplify EOF error classification and partial payload wire helpers.
- Remove duplicated code and improve test reliability and maintainability.
- Update roadmap and docs to reflect improved observability and testing.

This restructuring enhances test clarity and reuse without changing test behavior.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
tests/test_codec_error_regressions.rs (1)

204-219: ⚠️ Potential issue | 🟠 Major

Assert the structured codec taxonomy, not just Display text.

This test only matches Display fragments. If the decoder surfaces the wrong CodecError variant or recovery policy whilst keeping a similar message, this regression suite still passes. Downcast the cause and assert the error type/policy.

🤖 Prompt for AI Agents
In `tests/test_codec_error_regressions.rs`, update the
`wireframe_testing_fixture_cases_continue_to_surface_expected_errors` test to
assert the *structured* codec error, not merely the Display text.

Steps:

1. Add two new fields to the `#[rstest]` case attributes alongside `wire`,
   `max_frame_length`, and `expected_fragment`:
   - `expected_variant: &'static str` — the value returned by
     `CodecError::error_type()` for each case (e.g. `"framing"`).
   - `expected_policy: RecoveryPolicy` — the value returned by
     `CodecError::default_recovery_policy()` for each case.

2. Update the two existing cases with the expected variant and policy values.

3. Inside the function body, after obtaining the `error` from
   `decode_frames_with_codec`, traverse the error chain to locate the
   underlying `CodecError` and assert its `error_type()` and
   `default_recovery_policy()`.

4. Keep the existing `Display`-fragment assertion so both structural and
   message-text regressions are covered.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_codec_error_regressions.rs` around lines 204 - 219, Update the
test wireframe_testing_fixture_cases_continue_to_surface_expected_errors to
assert the structured CodecError and recovery policy: extend each #[case] in the
rstest to include expected_variant: &'static str (the string returned by
CodecError::error_type()) and expected_policy:
wireframe::codec::CodecError::RecoveryPolicy (or import RecoveryPolicy)
alongside wire, max_frame_length, expected_fragment; after calling
decode_frames_with_codec and getting error, traverse the error chain (e.g.,
using error.chain() or downcast_ref) to find the underlying CodecError, then
assert that codec_error.error_type() == expected_variant and
codec_error.default_recovery_policy() == expected_policy, while keeping the
existing Display-fragment assertion; reference symbols:
wireframe_testing_fixture_cases_continue_to_surface_expected_errors,
decode_frames_with_codec, CodecError, error_type(), default_recovery_policy(),
RecoveryPolicy.
tests/fixtures/codec_error_regressions.rs (1)

14-14: 🛠️ Refactor suggestion | 🟠 Major

Narrow pub to pub(crate) for test-internal APIs.

The TestResult re-export and subsequent public items (CodecErrorRegressionsWorld, fixture function, public methods) are only consumed within the same integration-test binary. Restrict visibility to pub(crate) to avoid implying external consumption.

🤖 Prompt for AI Agents
In `tests/fixtures/codec_error_regressions.rs`, narrow every unnecessarily broad
`pub` declaration to `pub(crate)`. All call sites are within the same
integration-test binary.

Specifically:

1. Line 14: `pub use wireframe_testing::TestResult;`
   → `pub(crate) use wireframe_testing::TestResult;`

2. Line 33: `pub struct CodecErrorRegressionsWorld`
   → `pub(crate) struct CodecErrorRegressionsWorld`

3. Line 51: `pub fn codec_error_regressions_world()`
   → `pub(crate) fn codec_error_regressions_world()`

4. All `pub fn` methods on `impl CodecErrorRegressionsWorld` (lines 56, 64, 72,
   80, 87, 94, 104, 119, 152, 156):
   → `pub(crate) fn`

Do not add `#[allow]` attributes. Verify compilation after changes.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/fixtures/codec_error_regressions.rs` at line 14, Change all
externally-visible test items to crate-only visibility: replace the top-level
reexport `pub use wireframe_testing::TestResult;` with `pub(crate)`, change the
type declaration `pub struct CodecErrorRegressionsWorld` to `pub(crate)`, change
the fixture constructor `pub fn codec_error_regressions_world()` to
`pub(crate)`, and change every `pub fn` on `impl CodecErrorRegressionsWorld`
(the methods defined at the noted lines) to `pub(crate) fn`; after edits run a
build to ensure no other call sites require public visibility.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/test_codec_error_regressions.rs`:
- Around line 119-127: The test taxonomy_cases_emit_expected_recovery_labels
only includes a CleanClose EOF case; add two new TaxonomyCase entries for
CodecError::Eof(EofError::MidHeader) and CodecError::Eof(EofError::MidFrame) so
the test covers all EofError variants. For each new case set expected_type:
"eof", expected_policy: RecoveryPolicy::Disconnect, expected_disconnect: true,
and expected_clean_close: false, and insert them alongside the existing
TaxonomyCase::clean_close entry so the test asserts error_type(),
default_recovery_policy(), should_disconnect(), and is_clean_close() for
MidHeader and MidFrame independently.
- Around line 148-163: Add a new ZeroLengthPayload EOF test case: update the
rstest cases to include
#[case::zero_length_payload(DefaultEofCase::ZeroLengthPayload,
EofError::CleanClose)] (or the expected EofError variant used for clean frame
consumption), add a ZeroLengthPayload variant to the DefaultEofCase enum,
implement its wire() arm to return a 4-byte zero header (vec![0,0,0,0]) and
ensure consumes_complete_frame() returns true for ZeroLengthPayload (i.e.,
matches!(self, Self::CleanClose | Self::ZeroLengthPayload)); this will exercise
the header-only frame followed immediately by EOF in
tests/test_codec_error_regressions.rs.

---

Duplicate comments:
In `@tests/fixtures/codec_error_regressions.rs`:
- Line 14: Change all externally-visible test items to crate-only visibility:
replace the top-level reexport `pub use wireframe_testing::TestResult;` with
`pub(crate)`, change the type declaration `pub struct
CodecErrorRegressionsWorld` to `pub(crate)`, change the fixture constructor `pub
fn codec_error_regressions_world()` to `pub(crate)`, and change every `pub fn`
on `impl CodecErrorRegressionsWorld` (the methods defined at the noted lines) to
`pub(crate) fn`; after edits run a build to ensure no other call sites require
public visibility.

In `@tests/test_codec_error_regressions.rs`:
- Around line 204-219: Update the test
wireframe_testing_fixture_cases_continue_to_surface_expected_errors to assert
the structured CodecError and recovery policy: extend each #[case] in the rstest
to include expected_variant: &'static str (the string returned by
CodecError::error_type()) and expected_policy:
wireframe::codec::CodecError::RecoveryPolicy (or import RecoveryPolicy)
alongside wire, max_frame_length, expected_fragment; after calling
decode_frames_with_codec and getting error, traverse the error chain (e.g.,
using error.chain() or downcast_ref) to find the underlying CodecError, then
assert that codec_error.error_type() == expected_variant and
codec_error.default_recovery_policy() == expected_policy, while keeping the
existing Display-fragment assertion; reference symbols:
wireframe_testing_fixture_cases_continue_to_surface_expected_errors,
decode_frames_with_codec, CodecError, error_type(), default_recovery_policy(),
RecoveryPolicy.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 88e76211-88de-4a8b-8b85-d27a57ae8395

📥 Commits

Reviewing files that changed from the base of the PR and between 0414c9d and 4d545d8.

📒 Files selected for processing (5)
  • docs/execplans/9-7-4-codec-error-taxonomy-regression-tests.md
  • docs/roadmap.md
  • tests/common/codec_error_regression_support.rs
  • tests/fixtures/codec_error_regressions.rs
  • tests/test_codec_error_regressions.rs

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

leynos commented Mar 13, 2026

@coderabbitai Have the following now been resolved?

Annul any requirements that violate the en-GB-oxendict spelling (-ize / -yse / -our) conventions (for example a request to replace "normalize" with "normalise" or "artefact" with "artifact"), or where the requirement unnecessarily increases cyclomatic complexity.

Please address the comments from this code review:

## Overall Comments
- There’s quite a bit of duplicated helper logic between `tests/test_codec_error_regressions.rs` and `tests/fixtures/codec_error_regressions.rs` (e.g. `encoded_default_frame`, `classify_eof`, `extract_eof_error`, partial header/payload builders); consider extracting these into a shared test helper module to keep the regression logic in one place.
- In `partial_payload_wire` you hard-code `4` for the header size when allocating capacity; using `LENGTH_HEADER_SIZE` instead would keep the helper consistent with the production codec constants.

## Individual Comments

### Comment 1
<location path="tests/test_codec_error_regressions.rs" line_range="184" />
<code_context>
+        expected_clean_close: true,
+    }
+)]
+fn taxonomy_cases_emit_expected_recovery_labels(#[case] case: TaxonomyCase) {
+    assert_eq!(case.error.error_type(), case.expected_type);
+    assert_eq!(case.error.default_recovery_policy(), case.expected_policy);
</code_context>
<issue_to_address>
**suggestion (testing):** Add taxonomy cases for MidHeader and MidFrame EOF variants to fully lock in EOF policies and flags

The `taxonomy_cases_emit_expected_recovery_labels` test currently only covers `CodecError::Eof(EofError::CleanClose)` and misses the `MidHeader` and `MidFrame` variants. Please add `TaxonomyCase` entries for `EofError::MidHeader { .. }` and `EofError::MidFrame { .. }` to assert their `error_type()`, `default_recovery_policy()`, `should_disconnect()`, and `is_clean_close()` so EOF taxonomy is fully regression-tested for all variants, independent of the EOF classification helper tests.

Suggested implementation:

```rust
)]
#[case::clean_close(
    TaxonomyCase {
        error: CodecError::Eof(EofError::CleanClose),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: true,
    }
)]
#[case::mid_header(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidHeader {
            // TODO: fill in struct fields according to the EofError::MidHeader
            // definition, for example:
            // header_len: 10,
            // received_len: 5,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]
#[case::mid_frame(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidFrame {
            // TODO: fill in struct fields according to the EofError::MidFrame
            // definition, for example:
            // frame_len: 1024,
            // received_len: 512,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]
fn taxonomy_cases_emit_expected_recovery_labels(#[case] case: TaxonomyCase) {

```

1. Replace the `// TODO` field initializations in `EofError::MidHeader { .. }` and `EofError::MidFrame { .. }` with the actual field names and values from your `EofError` enum definition so the code compiles.
2. If `MidHeader` or `MidFrame` carry additional context that should affect taxonomy (e.g., different policies for certain sizes), adjust the `expected_policy`, `expected_disconnect`, and `expected_clean_close` values to match the real semantics. Currently these are set to `Disconnect`, `true`, and `false` respectively, assuming mid-stream EOFs are treated as non-clean disconnect-worthy errors.
</issue_to_address>

### Comment 2
<location path="tests/fixtures/codec_error_regressions.rs" line_range="191" />
<code_context>
+    Ok(wire)
+}
+
+fn classify_eof(bytes: &[u8], consume_frame_before_eof: bool) -> TestResult<EofError> {
+    let codec = LengthDelimitedFrameCodec::new(1024);
+    let mut decoder = codec.decoder();
</code_context>
<issue_to_address>
**suggestion:** Consider a regression test around EOF with zero-length payloads or header-only frames

Current tests exercise clean close, partial header, and partial payload, but always with a non‑empty payload. Please add a case with a zero‑length frame (header present, no payload) that goes through `classify_eof` and asserts the resulting `EofError` and metrics, either here or in `tests/test_codec_error_regressions.rs`, to confirm the new EOF context logic handles empty payloads correctly.

Suggested implementation:

```rust
    wire.extend_from_slice(
        payload
            .get(..partial_len)
            .ok_or("partial payload slice should be available")?,
    );
    Ok(wire)
}

#[test]
fn eof_with_zero_length_payload_frame_is_classified() -> TestResult<()> {
    // Construct a single frame with a valid header indicating a zero-length payload
    // (header present, no payload bytes).
    let mut wire = Vec::with_capacity(4);
    wire.extend_from_slice(&write_network_u32(0));

    // Do not consume any frame before EOF; we want EOF immediately after the header-only frame.
    let eof_error = classify_eof(&wire, false)?;

    // Basic sanity assertion that we got some EOF classification back.
    // The exact variant/metrics should be asserted in line with the other tests.
    let _ = eof_error;

    Ok(())
}

fn classify_eof(bytes: &[u8], consume_frame_before_eof: bool) -> TestResult<EofError> {

```

To fully implement the intent of your review comment:

1. Strengthen the assertion in `eof_with_zero_length_payload_frame_is_classified` to match the expected `EofError` variant and associated fields, following the pattern used by the other EOF regression tests in this file (e.g., `assert_eq!(eof_error, EofError::... )` or `assert!(matches!(eof_error, EofError::...))`).
2. If you are tracking metrics (counters/gauges) in other tests, also add assertions here to verify the metric values for the zero-length frame EOF case (e.g., frame count, bytes, EOF classification labels).
3. If tests are organized in `tests/test_codec_error_regressions.rs` as well, you may want to add a higher-level integration test there that uses this fixture and asserts the observable metrics exported by the codec layer for the zero-length payload EOF scenario.
</issue_to_address>

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 13, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== tests/test_codec_error_regressions.rs ==="
cat tests/test_codec_error_regressions.rs

echo ""
echo "=== tests/fixtures/codec_error_regressions.rs ==="
cat tests/fixtures/codec_error_regressions.rs

echo ""
echo "=== tests/common/codec_error_regression_support.rs (if exists) ==="
cat tests/common/codec_error_regression_support.rs 2>/dev/null || echo "[NOT FOUND]"

echo ""
echo "=== tests/common/mod.rs (if exists) ==="
cat tests/common/mod.rs 2>/dev/null || echo "[NOT FOUND]"

echo ""
echo "=== Search for LENGTH_HEADER_SIZE usage in test files ==="
rg -n "LENGTH_HEADER_SIZE" --type rust

echo ""
echo "=== Search for MidHeader/MidFrame in taxonomy test ==="
rg -n "MidHeader|MidFrame" tests/test_codec_error_regressions.rs -C2

echo ""
echo "=== Search for zero_length or zero.length tests ==="
rg -n "zero.length|zero_length|zero_payload|eof_with_zero|eof_immediately" --type rust -C3

echo ""
echo "=== Check for hard-coded 4 in partial_payload_wire ==="
rg -n "with_capacity(4" --type rust -C3

echo ""
echo "=== Check for duplicated helpers ==="
rg -n "fn encoded_default_frame|fn classify_eof|fn extract_eof_error|fn partial_header_wire|fn partial_payload_wire|fn truncated_payload_wire" --type rust

Length of output: 22895


@leynos: Two of the four items are now resolved; two remain open.


✅ Overall comment 1 — deduplicate helpers — RESOLVED

tests/common/codec_error_regression_support.rs consolidates encode_default_frame, classify_eof, extract_eof_error, truncated_payload_wire, and StrictRecoveryHook. Both tests/test_codec_error_regressions.rs and tests/fixtures/codec_error_regressions.rs import from it via #[path = ...]. No local duplicates remain.


✅ Overall comment 2 — LENGTH_HEADER_SIZE in partial_payload_wireRESOLVED

tests/common/codec_error_regression_support.rs line 70 reads:

let mut wire = Vec::with_capacity(LENGTH_HEADER_SIZE + partial_len);

The literal 4 is gone; LENGTH_HEADER_SIZE is imported from wireframe::codec.


❌ Individual comment 1 — MidHeader/MidFrame taxonomy cases — NOT RESOLVED

taxonomy_cases_emit_expected_recovery_labels still carries only #[case::clean_close(...)] for EOF variants. The default_codec_eof_classification_remains_stable test does exercise MidHeader/MidFrame through the codec pipeline, but that is not a substitute for asserting their taxonomy labels (error_type(), default_recovery_policy(), should_disconnect(), is_clean_close()) in isolation. Add these two cases to taxonomy_cases_emit_expected_recovery_labels:

#[case::mid_header(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidHeader {
            bytes_received: 2,
            header_size: LENGTH_HEADER_SIZE,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]
#[case::mid_frame(
    TaxonomyCase {
        error: CodecError::Eof(EofError::MidFrame {
            bytes_received: 3,
            expected: 4,
        }),
        expected_type: "eof",
        expected_policy: RecoveryPolicy::Disconnect,
        expected_disconnect: true,
        expected_clean_close: false,
    }
)]

❌ Individual comment 2 — zero-length payload EOF regression — NOT RESOLVED

No test covering a header-only frame (4-byte length prefix of 0, no payload bytes) through classify_eof exists anywhere. Add this to the #[cfg(test)] module in tests/fixtures/codec_error_regressions.rs (or to tests/common/codec_error_regression_support.rs):

#[test]
fn eof_immediately_after_zero_length_frame_header_is_classified() -> TestResult {
    let mut wire = Vec::with_capacity(LENGTH_HEADER_SIZE);
    wire.extend_from_slice(&write_network_u32(0));
    let actual = classify_eof(&wire, false)?;
    assert!(
        matches!(actual, EofError::MidFrame { bytes_received: 0, expected: 0 }),
        "expected MidFrame{{bytes_received: 0, expected: 0}}, got {actual:?}"
    );
    Ok(())
}

LENGTH_HEADER_SIZE and write_network_u32 are already imported in tests/common/codec_error_regression_support.rs, so no additional imports are needed if the test lives there; adjust the expected field values to match the actual EofError::MidFrame semantics if they differ.

…estrict test code visibility

- Introduced a new DefaultEofCase variant `ZeroLengthPayload` representing an EOF with zero length payload.
- Added tests verifying the zero-length payload case is treated as a clean close.
- Updated exhaustive match branches and test cases to include this new EOF case.
- Restricted visibility of the `CodecErrorRegressionsWorld` struct and its methods from public to `pub(crate)` to encapsulate test fixtures and helpers.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
tests/test_codec_error_regressions.rs (1)

233-249: ⚠️ Potential issue | 🟠 Major

Preserve the concrete CodecError on this decode path.

Stop asserting only on the Display fragment. src/wireframe_testing/src/helpers/codec_ext.rs currently wraps decoder failures with io::Error::new(..., format!(...)), so the concrete CodecError is gone before this test runs; the regression still passes if the decoder emits the wrong variant or recovery policy with similar text. Preserve the source error in that helper, or add a companion helper that returns the concrete error, then assert error_type() and default_recovery_policy() here as well.

Verify the helper first. Expected result: if it still uses format!(...) inside io::Error::new, downcasting from this test is impossible.

#!/bin/bash
set -euo pipefail

helper_file="$(fd 'codec_ext\.rs$' . | head -n1)"
test_file="$(fd 'test_codec_error_regressions\.rs$' . | head -n1)"

test -n "$helper_file"
test -n "$test_file"

echo "== $helper_file =="
rg -n -C2 'decode_frames_with_codec|io::Error::new|codec decode failed|codec decode_eof failed' "$helper_file"

echo
echo "== $test_file =="
sed -n '233,249p' "$test_file"

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3bdcca56-97c7-4d20-9913-d29d154c41c1

📥 Commits

Reviewing files that changed from the base of the PR and between 4d545d8 and b862d5b.

📒 Files selected for processing (2)
  • tests/fixtures/codec_error_regressions.rs
  • tests/test_codec_error_regressions.rs

This change wraps CodecError variants inside io::Error without losing the original error type, allowing it to be recovered later via error source chaining. Tests were updated to traverse error sources for CodecError extraction. Added new regression tests to verify error preservation in decode failures.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

Refactored tests in test_codec_error_regressions.rs to replace raw wire byte vectors
and max_frame_length parameters with the DefaultEofCase enum to represent different EOF scenarios.
Updated test cases to use this enum for improved clarity and maintainability.
Also standardized codec creation with a fixed max frame length in the tests.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
codescene-delta-analysis[bot]

This comment was marked as outdated.

…st case

Shortened the expected_fragment string in the test to "premature EOF" instead of the longer message. This refinement keeps the test focused and less brittle to minor message changes.

Co-authored-by: devboxerhub[bot] <devboxerhub[bot]@users.noreply.github.com>
@leynos leynos merged commit 8476be5 into main Mar 14, 2026
6 checks passed
@leynos leynos deleted the add-codecerror-regression-tests-qmk3tf branch March 14, 2026 12:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant