Skip to content

Implement explicit MemoryBudgets for the wireframe app#304

Merged
leynos merged 20 commits intomainfrom
configure-memory-budgets-wireframe-i5m7jv
Apr 22, 2026
Merged

Implement explicit MemoryBudgets for the wireframe app#304
leynos merged 20 commits intomainfrom
configure-memory-budgets-wireframe-i5m7jv

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Apr 10, 2026

Summary

  • Implement explicit MemoryBudgets for the wireframe app, moving from planning to concrete runtime budgeting in the Wireframe transport adapter. This includes derivation of budgets, wiring into the Wireframe app, tests, and documentation updates.

Changes

Documentation

  • Added docs/execplans/1-7-1-configure-explicit-memory-budgets-for-the-wireframe-app.md
    • The ExecPlan documents purpose, constraints, tolerances, risks, progress, surprises & discoveries, decision log, and outcomes & retrospective. It includes a Plan of Work with Stage A–E detailing proving, implementing, testing, documenting, and validating explicit memory budgets within the wireframe transport boundary.
    • Serves as a living planning artifact aligned with roadmap item 1.7.1.

Design & Roadmap Artifacts

  • The plan references existing design and user-facing documentation (docs/design.md, docs/users-guide.md) and the roadmap narrative (docs/roadmap.md) to ensure consistency across the project.

Planning Artifacts

  • This PR implements the budgeting approach described in the ExecPlan, establishing the planning runway for subsequent commits that actually enforce budgets in the wireframe app and related modules.

Implementation (Code)

  • Added explicit budget derivation and wiring:
    • src/server/wireframe/budgets.rs: explicit_memory_budgets() builds MemoryBudgets using HOTLINE_LOGICAL_MESSAGE_BYTES and exposes unit tests.
    • src/server/wireframe/mod.rs: wired budgets into HotlineApp via .memory_budgets(...).
    • Introduced wireframe::budgets module integration and supporting wiring for explicit budgets.
  • Wireframe transport adapter changes:
    • src/wireframe/message_assembly.rs: added HotlineMessageAssembler for in-flight assembly while respecting budgets.
    • src/wireframe/codec/frame.rs and related components adjusted to reflect the explicit budget model and logical budget handling.
    • src/wireframe/codec/physical_frame.rs: added helpers to decode physical Hotline frames as part of the new assembly path.
    • Updated tests to cover budget derivation and budget-based routing behavior (see Tests below).
  • Test coverage:
    • tests/wireframe_memory_budgets.rs: new integration tests for memory-budget enforcement and budget-related behavior.
  • Tests adapted to ensure runtime wiring is present and budgets take effect:
    • src/server/wireframe/tests.rs now validates app factory wiring includes a budgeted WireframeApp and a message assembler.

Tests

  • Added integration tests for memory budgets under tests/wireframe_memory_budgets.rs.
  • Added unit tests within budgets.rs to verify:
    • budgets match the full logical Hotline message envelope (20-byte header + up to 1 MiB payload).
    • non-zero invariants and equalities across per-message, per-connection, and in-flight budgets.

Validation / Aftercare

  • Validation focused on ensuring budgets are derived from Hotline limits and wired through the adapter boundary. This is complemented by unit tests and binary-backed integration tests.
  • Gate checks (fmt, lint, tests, docs) should pass as part of the normal CI flow.

Plan of Work (highlights)

  • Stage A: Prove architecture seam and sizing model
    • Inventory Hotline sizing authorities (MAX_FRAME_DATA, MAX_PAYLOAD_SIZE) and fragmentation handling to determine budgeting boundaries.
  • Stage B: Implement explicit budgets in the adapter
    • Derive BudgetBytes and MemoryBudgets from Hotline constants; wire budgets into Wireframe app builder via memory_budgets helpers.
  • Stage C: Add regression coverage (unit and binary-backed tests)
    • Implement rstest-based tests for budget derivations and edge cases; extend binary harnesses for budget/no-budget scenarios.
  • Stage D: Document delivered behaviour
    • Capture decisions, formulas, and operator-visible changes in docs/design.md and docs/users-guide.md; mark roadmap item as done where applicable.
  • Stage E: Run full validation and capture logs
    • Run repository gates (formatting, lint, tests, docs checks) with explicit logging; validate with pg_embedded_setup_unpriv for PostgreSQL-backed paths.

Validation / Aftercare (continued)

  • This is an implementation artifact. Subsequent PRs will finalize runtime behaviour, tests, and any operator-facing surfaces beyond the scope of 1.7.1.

Context

  • This ExecPlan is intended to be a living document, updated as work proceeds and decisions are made. It aligns with the repository’s hexagonal architecture approach and keeps transport concerns within the wireframe adapter boundary.

◳ Generated by DevBoxer ◰


ℹ️ Tag @devboxerhub to ask questions and address PR feedback

📎 Task: https://www.devboxer.com/task/99334822-1d9c-4854-beab-b7de13c18cfb

Summary by Sourcery

Configure explicit Wireframe memory budgets for Hotline request assembly and document the resulting behaviour and constraints.

New Features:

  • Introduce a Hotline-specific message assembler and logical message size constant to integrate Wireframe MemoryBudgets with Hotline fragmentation semantics.

Enhancements:

  • Wire the Hotline WireframeApp to use explicit per-message, per-connection, and in-flight memory budgets sized to a full logical Hotline request envelope.
  • Refine the Hotline frame codec to emit internal first/continuation payloads with timeout-based series tracking, aligning Wireframe assembly limits with Hotline protocol limits.
  • Update design, user, migration, and roadmap documentation to describe the new budgeting model, fragment handling, and completion of roadmap item 1.7.1.

Tests:

  • Add unit tests for budget derivation invariants and Hotline message-assembly metadata, plus binary-backed integration tests validating in-budget, oversized, and stalled fragmented request behaviour.

📎 Task: https://www.devboxer.com/task/f2676e40-37a8-46e6-98cd-15aa1ebb49d8

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 10, 2026

Note

Reviews paused

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

This pull request implements explicit memory budgets for the Wireframe Hotline adapter and refactors inbound fragment handling. Physical frame extraction now delegates to a dedicated helper; stateful reassembly moves from HotlineFrameCodec to HotlineMessageAssembler, with per-series timeouts and validation. The logical message budget is unified across all dimensions and passed through new adapter configuration seams.

Changes

Cohort / File(s) Summary
Configuration & build
Cargo.toml
Added new test target wireframe_memory_budgets guarded by test-support feature.
Design and roadmap documentation
docs/design.md, docs/roadmap.md, docs/execplans/1-7-1-configure-explicit-memory-budgets-for-the-wireframe-app.md, docs/wireframe-v0-3-0-migration.md
Updated design documentation to describe inbound fragment handling via HotlineMessageAssembler with explicit budgets, per-series timeouts, and deadline enforcement. Added comprehensive ExecPlan for roadmap item 1.7.1. Minor word-wrapping and grammar corrections.
User and migration guides
docs/users-guide.md, docs/wireframe-v0-2-0-to-v0-3-0-migration-guide.md, docs/migration-plan-moving-mxd-protocol-implementation-to-wireframe.md, docs/file-sharing-design.md, docs/repository-layout.md
Updated user-facing descriptions of transaction framing adapter and fragmentation timeouts. Added CI documentation validation section. Minor reflowing and spelling standardisation across multiple guides.
Budget configuration
src/server/wireframe/budgets.rs, src/server/wireframe/mod.rs, src/server/wireframe/tests.rs
Introduced explicit_memory_budgets() const function deriving MemoryBudgets from HOTLINE_LOGICAL_MESSAGE_BYTES. Integrated budget and message assembler configuration into HotlineApp construction. Added assertion of non-None message assembler in integration test.
Message assembly infrastructure
src/wireframe/message_assembly.rs, src/wireframe/mod.rs, src/wireframe/message_assembly_tests.rs
Implemented HotlineMessageAssembler with frame header parsing for first and continuation fragments, message key derivation, and internal payload construction helpers. Added comprehensive regression test suite validating frame header parsing and payload tampering detection.
Frame codec refactoring
src/wireframe/codec/frame.rs, src/wireframe/codec/framed.rs, src/wireframe/codec/mod.rs, src/wireframe/codec/physical_frame.rs, src/wireframe/codec/tests.rs, src/wireframe/codec/frame_tests.rs
Extracted physical frame parsing into take_hotline_frame() helper. Updated HotlineFrameDecoder to track InboundSeriesTracker state with per-series timeouts, explicit fragmentation validation, and series clearing on mismatches or timeouts. Changed max_frame_length() to report logical envelope size. Relocated and expanded decoder tests into external module.
Integration testing
tests/wireframe_memory_budgets.rs
Added end-to-end integration tests validating disconnection on oversized first fragments, stalled continuation fragments, and successful handling of valid fragmented requests within budget.

Poem

🌳 Fragments flow through their own halls now,

With trackers watching time slip away,

Budgets explicit, no more codec-bound rows—

The wire speaks clear: stay within or play.

🚥 Pre-merge checks | ✅ 8 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Testing ⚠️ Warning Review comments identify two unresolved test-related issues: missing unit test for zero-byte continuation fragment rejection and unaddressed test duplication in message_assembly_tests.rs. Add unit test validating InboundSeriesTracker::continue_series rejects zero-byte continuation fragments with InvalidData error. Extract assert_tampered_payload_rejected helper and apply rstest parametrisation to eliminate test duplication in message_assembly_tests.rs.
✅ Passed checks (8 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarises the main change: implementing explicit MemoryBudgets for the wireframe app, which is the core objective across all documentation, implementation, and test changes.
Description check ✅ Passed The description comprehensively covers the changeset scope: ExecPlan documentation, budget derivation and wiring, wireframe transport and assembly changes, and integration tests—all directly related to explicit MemoryBudget implementation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
User-Facing Documentation ✅ Passed The pull request documents all user-facing functionality changes in docs/users-guide.md (lines 40–48), covering explicit inbound Wireframe budgets, disconnection behaviour, timeout handling, and fragment routing.
Developer Documentation ✅ Passed All four new internal APIs (take_hotline_frame, InboundSeriesTracker, HotlineMessageAssembler, explicit_memory_budgets) are comprehensively documented in docs/design.md with clear architectural descriptions and responsibilities.
Module-Level Documentation ✅ Passed All new and modified Rust modules carry comprehensive module-level docstrings explaining their purpose, utility and function across transport adapters, codec implementations, and test modules.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch configure-memory-budgets-wireframe-i5m7jv

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

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Apr 10, 2026

Reviewer's Guide

Implements explicit Wireframe MemoryBudgets for the Hotline wireframe adapter by introducing a Hotline-specific message assembler and logical message-size budgeting, wiring these budgets into the server app factory, and adding regression tests and documentation updates to validate oversized and stalled fragmented request handling.

Class diagram for Hotline message assembly and budgeting

classDiagram
    class HotlineFrameCodec {
        +new() HotlineFrameCodec
        +decoder() HotlineFrameDecoder
        +wrap_payload(payload: Bytes) Vec~u8~
        +max_frame_length() usize
    }

    class HotlineFrameDecoder {
        -series: InboundSeriesState~Option~
        +new() HotlineFrameDecoder
        -build_first_frame_payload(header: FrameHeader, payload: [u8]) Result~Vec~u8~~
        -build_continuation_payload(header: FrameHeader, payload: [u8]) Result~Vec~u8~~
        +decode(src: BytesMut) Result~Option~Packet~~
    }

    class InboundSeriesState {
        -first_header: FrameHeader
        -message_key: MessageKey
        -remaining: usize
        -next_sequence: FrameSequence
        -deadline: Instant
    }

    class HotlineMessageAssembler {
        +new() HotlineMessageAssembler
        +parse_frame_header(payload: [u8]) Result~ParsedFrameHeader~
        -logical_header_bytes(header: FrameHeader) [u8]
    }

    class MessageAssembler {
        <<interface>>
        +parse_frame_header(payload: [u8]) Result~ParsedFrameHeader~
    }

    class FrameHeader {
        +flags: u16
        +is_reply: u16
        +ty: u16
        +id: u16
        +error: u16
        +total_size: u32
        +data_size: u32
        +from_bytes(bytes: [u8;20]) FrameHeader
        +write_bytes(dst: [u8;20]) void
    }

    class FrameSequence {
        +value: u32
        +checked_increment() Option~FrameSequence~
    }

    class MessageKey {
        +value: u64
    }

    class ParsedFrameHeader {
        +header() AssemblyFrameHeader
        +header_len() usize
    }

    class AssemblyFrameHeader {
        <<enum>>
        +First(FirstFrameHeader)
        +Continuation(ContinuationFrameHeader)
    }

    class FirstFrameHeader {
        +message_key: MessageKey
        +metadata_len: usize
        +body_len: usize
        +total_body_len: Option~usize~
        +is_last: bool
    }

    class ContinuationFrameHeader {
        +message_key: MessageKey
        +sequence: Option~FrameSequence~
        +body_len: usize
        +is_last: bool
    }

    class MemoryBudgets {
        +new(per_message: BudgetBytes, per_connection: BudgetBytes, in_flight: BudgetBytes) MemoryBudgets
        +bytes_per_message() BudgetBytes
        +bytes_per_connection() BudgetBytes
        +bytes_in_flight() BudgetBytes
    }

    class BudgetBytes {
        +new(bytes: NonZeroUsize) BudgetBytes
        +as_usize() usize
    }

    class HotlineBudgetsModule {
        <<module>>
        +explicit_memory_budgets() MemoryBudgets
        -non_zero(bytes: usize) NonZeroUsize
    }

    class HotlineApp {
        +default() HotlineApp
        +fragmentation(option: Option~()~) HotlineApp
        +memory_budgets(budgets: MemoryBudgets) HotlineApp
        +with_message_assembler(assembler: HotlineMessageAssembler) HotlineApp
    }

    class BudgetsConst {
        <<constant>>
        +HOTLINE_LOGICAL_MESSAGE_BYTES: usize
    }

    HotlineFrameCodec --> HotlineFrameDecoder
    HotlineFrameDecoder --> InboundSeriesState : manages
    HotlineFrameDecoder --> FrameHeader
    HotlineFrameDecoder --> MessageKey
    HotlineFrameDecoder --> FrameSequence
    HotlineFrameDecoder --> HotlineMessageAssembler : uses via Envelope payloads

    HotlineMessageAssembler ..|> MessageAssembler
    HotlineMessageAssembler --> FrameHeader
    HotlineMessageAssembler --> MessageKey
    HotlineMessageAssembler --> ParsedFrameHeader
    ParsedFrameHeader --> AssemblyFrameHeader
    AssemblyFrameHeader --> FirstFrameHeader
    AssemblyFrameHeader --> ContinuationFrameHeader

    HotlineBudgetsModule --> MemoryBudgets : builds
    HotlineBudgetsModule --> BudgetBytes : derives
    HotlineBudgetsModule --> BudgetsConst

    HotlineApp --> MemoryBudgets : configures
    HotlineApp --> HotlineMessageAssembler : installs

    BudgetsConst --> FrameHeader : derived from HEADER_LEN
    BudgetsConst --> FrameHeader : uses MAX_PAYLOAD_SIZE
Loading

File-Level Changes

Change Details Files
Introduce Hotline-specific logical message assembly and budgeting surface for Wireframe.
  • Add wireframe::message_assembly module with HotlineMessageAssembler that converts physical Hotline fragments into internal first/continuation frames consumable by Wireframe’s MessageAssembler API while preserving the existing header
Refactor Hotline frame decoding to emit assembler-friendly payloads and track fragmented-series state with timeouts.
  • Replace HotlineFrameDecoder’s inner HotlineCodec with explicit tracking of an optional InboundSeriesState containing the first header, message key, remaining bytes, next sequence number, and a deadline.
  • Add build_first_frame_payload and build_continuation_payload helpers that construct first/continuation internal payloads using message_key_for, first_frame_payload, and continuation_frame_payload, setting/clearing series state and enforcing remaining-size and sequence overflow checks.
  • Use take_hotline_frame to parse physical frames, then choose first vs continuation paths in Decoder::decode, and emit Envelopes with assembled payloads; add SERIES_TIMEOUT based on crate::transaction::IO_TIMEOUT to bound the inter-fragment gap.
  • Update max_frame_length() to return the logical envelope size (HEADER_LEN + MAX_PAYLOAD_SIZE) and expand tests to cover logical budget invariants and fragmented-request decoding behaviour.
src/wireframe/codec/frame.rs
src/wireframe/codec/framed.rs
Derive and apply explicit MemoryBudgets for the Hotline Wireframe app.
  • Add src/server/wireframe/budgets.rs with explicit_memory_budgets() that builds MemoryBudgets where bytes_per_message, bytes_per_connection, and bytes_in_flight are all set to HOTLINE_LOGICAL_MESSAGE_BYTES via BudgetBytes.
  • Wire the explicit budgets into the HotlineApp builder in src/server/wireframe/mod.rs via .memory_budgets(explicit_memory_budgets()) and install HotlineMessageAssembler::new() via .with_message_assembler(...).
  • Add unit tests to ensure the budgets match exactly one full logical Hotline request envelope and that the three budget dimensions are non-zero and equal.
src/server/wireframe/budgets.rs
src/server/wireframe/mod.rs
Add integration tests that exercise memory-budget enforcement for fragmented Hotline requests via the real server binary.
  • Register a new test target wireframe_memory_budgets in Cargo.toml guarded by the test-support feature.
  • Implement tests/wireframe_memory_budgets.rs to launch mxd-wireframe-server through existing test-util harnesses, perform a real Hotline handshake, and then send fragmented requests that (a) are large but within the explicit budget and confirm they still route and return an internal-server-error reply, (b) declare a total_size that exceeds MAX_PAYLOAD_SIZE and confirm the connection is closed on the first fragment, and (c) pause longer than IO_TIMEOUT between first and continuation fragments and assert the connection is closed when the continuation is sent.
  • Add helper utilities to construct large payloads from encoded Hotline fields, fragment transactions, read reply headers, and robustly detect closed TCP connections vs retryable timeouts.
Cargo.toml
tests/wireframe_memory_budgets.rs
tests/common.rs (via use)
test-util/* (indirect usage)
Tighten runtime wiring tests and documentation around budgeting, fragmentation, and roadmap status.
  • Update src/server/wireframe/tests.rs to assert that the app factory not only succeeds with handshake context present but also installs a message assembler (app.message_assembler().is_some()).
  • Extend docs/design.md with a detailed description of the new inbound fragment handling: HotlineFrameCodec now produces first/continuation payloads for HotlineMessageAssembler, fragmentation remains disabled at the Wireframe layer, MemoryBudgets are derived from HEADER_LEN + MAX_PAYLOAD_SIZE, and a five-second inter-fragment timeout is enforced when continuations arrive.
  • Update docs/users-guide.md to describe the new behaviour where oversized fragmented inputs and stalled fragmented requests beyond five seconds are disconnected predictably, while valid in-budget fragmented requests continue to route normally.
  • Mark roadmap item 1.7.1 as completed in docs/roadmap.md and add a dedicated ExecPlan document docs/execplans/1-7-1-configure-explicit-memory-budgets-for-the-wireframe-app.md capturing constraints, plan of work, decisions, and outcomes.
  • Make minor formatting and clarification edits to existing docs (file-sharing-design.md, migration guides, hexagonal-architecture doc, repository-layout, CONTENTS) to keep narrative and tables consistent with current behaviour and style.
src/server/wireframe/tests.rs
docs/design.md
docs/users-guide.md
docs/roadmap.md
docs/execplans/1-7-1-configure-explicit-memory-budgets-for-the-wireframe-app.md
docs/file-sharing-design.md
docs/wireframe-v0-2-0-to-v0-3-0-migration-guide.md
docs/execplans/wireframe-v0-3-0-migration.md
docs/wireframe-users-guide.md
docs/migration-plan-moving-mxd-protocol-implementation-to-wireframe.md
docs/adopting-hexagonal-architecture-in-the-mxd-wireframe-migration.md
docs/repository-layout.md
docs/CONTENTS.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.

@leynos leynos changed the title Plan MemoryBudgets for Wireframe (1.7.1) Implement explicit MemoryBudgets for the wireframe app Apr 13, 2026
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 13, 2026

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix:

src/wireframe/message_assembly.rs

Comment on file

pub(crate) fn first_frame_payload(
    message_key: MessageKey,
    header: &FrameHeader,
    body: &[u8],
) -> Result<Vec<u8>, io::Error> {
    let body_len = u32::try_from(body.len()).map_err(|_| {
        io::Error::new(
            io::ErrorKind::InvalidData,
            "Hotline first-frame body length exceeds u32",
        )
    })?;
    let mut payload = Vec::with_capacity(FIRST_FRAME_HEADER_LEN + HEADER_LEN + body.len());
    payload.push(FIRST_FRAME_TAG);
    payload.extend_from_slice(&u64::from(message_key).to_be_bytes());
    payload.extend_from_slice(&header.total_size.to_be_bytes());
    payload.extend_from_slice(&body_len.to_be_bytes());
    payload.extend_from_slice(&logical_header_bytes(header));
    payload.extend_from_slice(body);
    Ok(payload)
}

❌ New issue: Code Duplication
The module contains 2 functions with similar structure: continuation_frame_payload,first_frame_payload

@coderabbitai

This comment was marked as resolved.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 17, 2026

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response. Ensure that this is validated against the current version of the codegraph.

If further refinement to address this finding would be deleterious, please supply a clear explanatory one to two paragraph markdown message I can paste into the CodeScene web ui's diagnostic suppression function so this diagnostic can be silenced.

Code Duplication

src/wireframe/message_assembly.rs:

What lead to degradation?

The module contains 2 functions with similar structure: continuation_frame_payload,first_frame_payload

Why does this problem occur?

Duplicated code often leads to code that's harder to change since the same logical change has to be done in multiple functions. More duplication gives lower code health.

How to fix it?

A certain degree of duplicated code might be acceptable. The problems start when it is the same behavior that is duplicated across the functions in the module, ie. a violation of the Don't Repeat Yourself (DRY) principle. DRY violations lead to code that is changed together in predictable patterns, which is both expensive and risky. DRY violations can be identified using CodeScene's X-Ray analysis to detect clusters of change coupled functions with high code similarity. Read More
Once you have identified the similarities across functions, look to extract and encapsulate the concept that varies into its own function(s). These shared abstractions can then be re-used, which minimizes the amount of duplication and simplifies change.

@coderabbitai

This comment was marked as resolved.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 20, 2026

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

src/wireframe/message_assembly.rs

Comment on lines +84 to +103

fn assemble_frame_payload(
    tag: u8,
    message_key: MessageKey,
    middle: &[u8],
    body: &[u8],
    metadata: &[u8],
    body_len_err: &'static str,
) -> Result<Vec<u8>, io::Error> {
    let body_len = u32::try_from(body.len())
        .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, body_len_err))?;
    let capacity = 1 + 8 + middle.len() + 4 + metadata.len() + body.len();
    let mut payload = Vec::with_capacity(capacity);
    payload.push(tag);
    payload.extend_from_slice(&u64::from(message_key).to_be_bytes());
    payload.extend_from_slice(middle);
    payload.extend_from_slice(&body_len.to_be_bytes());
    payload.extend_from_slice(metadata);
    payload.extend_from_slice(body);
    Ok(payload)
}

❌ New issue: Excess Number of Function Arguments
assemble_frame_payload has 6 arguments, max arguments = 4

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 20, 2026

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

src/wireframe/message_assembly.rs

Comment on file

//! Hotline-specific protocol message assembly helpers for Wireframe.

❌ New issue: Primitive Obsession
In this module, 44.8% of all function arguments are primitive types, threshold = 30.0%

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

codescene-delta-analysis[bot]

This comment was marked as outdated.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos leynos marked this pull request as ready for review April 21, 2026 15:45
sourcery-ai[bot]

This comment was marked as resolved.

@coderabbitai coderabbitai Bot added the Roadmap label Apr 21, 2026
coderabbitai[bot]

This comment was marked as resolved.

codescene-delta-analysis[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as resolved.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 22, 2026

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

src/wireframe/message_assembly.rs

Comment on file

//! Hotline-specific protocol message assembly helpers for Wireframe.

❌ New issue: Primitive Obsession
In this module, 34.4% of all function arguments are primitive types, threshold = 30.0%

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 22, 2026

@coderabbitai Please suggest a fix for this issue and supply a prompt for an AI coding agent to enable it to apply the fix. Include the file and symbol names indicated in the issue at the head of your response.

src/wireframe/message_assembly_tests.rs

Comment on lines +126 to +142

fn first_frame_parser_rejects_logical_header_total_mismatches() {
    let header = header(10, 4);
    let mut payload =
        first_frame_payload(message_key_for(&header), &header, b"data").expect("payload");
    payload[29..33].copy_from_slice(&9u32.to_be_bytes());

    let err = HotlineMessageAssembler::new()
        .parse_frame_header(&payload)
        .expect_err("logical header total must match declared first-frame total");
    assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
    assert!(
        err.to_string().contains(
            "Hotline first-frame logical header length does not match declared total length",
        ),
        "unexpected error: {err}"
    );
}

❌ New issue: Code Duplication
The module contains 3 functions with similar structure: continuation_parser_rejects_declared_body_length_mismatches,first_frame_parser_rejects_declared_body_length_mismatches,first_frame_parser_rejects_logical_header_total_mismatches

@coderabbitai

This comment was marked as resolved.

leynos added 4 commits April 22, 2026 10:36
Move the zero-byte continuation guard in `InboundSeriesTracker`
behind the remaining-byte lookup so the tracker can treat an empty
continuation as a no-progress protocol error and clear the active
series before returning.

Add regression coverage for the tracker-level state-clearing path and
align the existing decoder test with the new error message.
Extract the shared payload-tampering assertion used by the
message-assembly rejection tests so the three body-length and
logical-header mismatch cases differ only in their payload source and
u32 field offsets.

Keep the rest of the test module unchanged while preserving the same
error checks and targeted test coverage.
Insert the missing blank line before `first_frame_payload` so the
internal payload builder and the following Rustdoc stay visually
separated.

Update `docs/file-sharing-design.md` to remove the remaining
first-person phrasing in the verified metadata paragraph, and extend the
Wireframe migration guide with the required Markdown validation CI job
for Mermaid-bearing documentation.
Update `docs/design.md` to describe the actual
`InboundSeriesTracker` error-handling contract. Document that
`validate_fragment_consistency()` preserves the active series on header
mismatch, and list the specific completion and error paths that clear
state.

Extract the repeated zero-progress tracker setup in
`src/wireframe/codec/frame_tests.rs` into a small helper so the two
tests keep only their distinct assertions.
@lodyai lodyai Bot force-pushed the configure-memory-budgets-wireframe-i5m7jv branch from f5910c6 to fe4767c Compare April 22, 2026 08:39
codescene-delta-analysis[bot]

This comment was marked as outdated.

coderabbitai[bot]

This comment was marked as resolved.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 22, 2026

@coderabbitai pause

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

✅ Actions performed

Reviews paused.

@leynos

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

Update the memory-budget execplan and related documentation so the
shipped contract is described precisely. Remove the stale pacing claim,
rewrite the cited first-person passages in `docs/file-sharing-design.md`,
and normalize the requested spelling fixes in the migration and layout
guides.

Replace three near-duplicate message-assembly rejection tests with a
single `#[rstest]` table. Keep the same payload builders, tamper ranges,
and expected error substrings while removing duplicated arrange/act/
assert scaffolding.
codescene-delta-analysis[bot]

This comment was marked as outdated.

Reduce primitive-argument density in the Hotline message assembly
helpers by introducing `ParseError` for static parse contexts and
`IsLast` for continuation last-flag handling.

Thread the newtypes through `PayloadCursor`, payload parsing, and the
Wireframe frame decoder so the continuation payload path keeps the same
behaviour while exposing fewer raw primitives at call sites.

Update the message-assembly tests to pass the new continuation flag
wrapper and rerun the full Rust gates.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 22, 2026

@coderabbitai Please investigate the cause of the following test failure and provide an AI coding agent prompt for the fix:

error: test failed, to rerun pass `-p validator --lib`
test hx_client::tests::explicit_override_wins_when_present ... ok
test server_binary::tests::sqlite_resolution_uses_default_target_path ... ok
test hx_client::tests::timeout_probe_is_treated_as_non_helix ... FAILED

failures:

---- hx_client::tests::timeout_probe_is_treated_as_non_helix stdout ----

thread 'hx_client::tests::timeout_probe_is_treated_as_non_helix' (3004) panicked at validator/src/hx_client.rs:271:14:
timeout probe should still accept non-Helix hx: Probe { path: "/tmp/.tmp7kiXhk/hx", source: Os { code: 26, kind: ExecutableFileBusy, message: "Text file busy" } }
stack backtrace:
   0: __rustc::rust_begin_unwind
             at /rustc/843f8ce2ebc01d35a30484eadc8a84cdc6130844/library/std/src/panicking.rs:698:5
   1: core::panicking::panic_fmt
             at /rustc/843f8ce2ebc01d35a30484eadc8a84cdc6130844/library/core/src/panicking.rs:80:14
   2: core::result::unwrap_failed
             at /rustc/843f8ce2ebc01d35a30484eadc8a84cdc6130844/library/core/src/result.rs:1862:5
   3: validator::hx_client::tests::timeout_probe_is_treated_as_non_helix
   4: core::ops::function::FnOnce::call_once
   5: core::ops::function::FnOnce::call_once
             at /rustc/843f8ce2ebc01d35a30484eadc8a84cdc6130844/library/core/src/ops/function.rs:250:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.


failures:
    hx_client::tests::timeout_probe_is_treated_as_non_helix

test result: FAILED. 31 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.01s

make: *** [Makefile:110: test-validator-sqlite] Error 101
Error: Process completed with exit code 2.

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 22, 2026

@coderabbitai Have the following now been resolved?

⚠️ Outside diff range comments (2)

docs/repository-layout.md (2)

32-32: ⚠️ Potential issue | 🟡 Minor
Use Oxford spelling in the section heading.
Replace organisation with organization to match the repository's en-GB-oxendict convention requiring -ize suffixes.
Triage: [type:spelling] [type:docstyle]

Proposed fix
-## Source code organisation (`src/`)
+## Source code organization (`src/`)

As per coding guidelines "Use British English based on Oxford English Dictionary (en-GB-oxendict), including: -ize suffixes (realize, organization)".

🤖 Prompt for AI Agents

59-59: ⚠️ Potential issue | 🟡 Minor
Use Oxford spelling in the paragraph.
Replace organised with organized to match the repository's en-GB-oxendict convention requiring -ize suffixes.
Triage: [type:spelling] [type:docstyle]

Proposed fix
-Documentation is organised by purpose and audience.
+Documentation is organized by purpose and audience.

As per coding guidelines "Use British English based on Oxford English Dictionary (en-GB-oxendict), including: -ize suffixes (realize, organization)".

🤖 Prompt for AI Agents

@coderabbitai

This comment was marked as resolved.

Treat `ExecutableFileBusy` from the Helix version probe as a
non-Helix result so a transient `execve(2)` race does not surface as a
probe failure.

Update the timeout-probe test to write the script through a file handle
and call `sync_all()` before execution. This closes the Linux `ETXTBSY`
window that appears when the inode is still considered writable.
codescene-delta-analysis[bot]

This comment was marked as outdated.

@coderabbitai

This comment was marked as resolved.

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 22, 2026

@coderabbitai Have the following failed checks now been resolved?

If further work is required, please provide an AI agent prompt for the remaining work to be done to address these failures.

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Testing ⚠️ Warning Review comments identify two unresolved test-related issues: missing unit test for zero-byte continuation fragment rejection and unaddressed test duplication in message_assembly_tests.rs. Add unit test validating InboundSeriesTracker::continue_series rejects zero-byte continuation fragments with InvalidData error. Extract assert_tampered_payload_rejected helper and apply rstest parametrisation to eliminate test duplication in message_assembly_tests.rs.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 22, 2026

Tip

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== src/wireframe/codec/frame_tests.rs ==="
fd -e rs -p "frame_tests\.rs$" | grep -v target | xargs cat

echo ""
echo "=== src/wireframe/message_assembly_tests.rs ==="
fd -e rs -p "message_assembly_tests\.rs$" | grep -v target | xargs cat

echo ""
echo "=== zero-byte guard in frame.rs ==="
grep -n "zero\|no progress\|empty\|is_empty" src/wireframe/codec/frame.rs | head -30

Length of output: 9697


@leynos — both sub-issues are fully resolved in the current commit.

Sub-issue Status
Zero-byte continuation rejection — InboundSeriesTracker::continue_series guard emitting "continuation fragment made no progress"
decoder_rejects_zero_byte_continuation_fragment test
continue_series_clears_active_state_on_zero_progress_fragment test (also verifies state is cleared)
assert_tampered_payload_rejected helper extracted in message_assembly_tests.rs
Three tamper tests merged into a single #[rstest] parametrised tampered_payloads_are_rejected with three #[case] entries

The Testing check should now be satisfied.

Replace the remaining American `normalized` spellings in the scoped
wireframe doc comments with the repository's en-GB-oxendict
`normalised` form.

Keep the change limited to the four requested documentation
occurrences and rerun `cargo test` to confirm there is no behavioural
regression.
Copy link
Copy Markdown

@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 Passed
6 Quality Gates Passed

See analysis details in CodeScene

Quality Gate Profile: Pay Down Tech Debt
Install CodeScene MCP: safeguard and uplift AI-generated code. Catch issues early with our IDE extension and CLI tool.

@leynos leynos merged commit c11ee62 into main Apr 22, 2026
10 checks passed
@leynos leynos deleted the configure-memory-budgets-wireframe-i5m7jv branch April 22, 2026 21:54
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