wireframe 0.3.0

Simplify building servers and clients for custom binary protocols.
Documentation
# Add `WireframeApp::memory_budgets(...)` builder method (8.3.1)

This ExecPlan is a living document. The sections `Constraints`, `Tolerances`,
`Risks`, `Progress`, `Surprises & Discoveries`, `Decision Log`, and
`Outcomes & Retrospective` must be kept up to date as work proceeds.

Status: COMPLETE

No `PLANS.md` exists in this repository as of 2026-02-17.

## Purpose / big picture

Roadmap item `8.3.1` introduces a first-class way for application builders to
set per-connection memory budgets on `WireframeApp`.

After this change, library consumers can configure a single, explicit
`memory_budgets(...)` builder step that captures:

- bytes buffered per message;
- bytes buffered per connection; and
- bytes buffered across in-flight assemblies.

This milestone is configuration surface only. Enforcement, soft back-pressure,
hard-cap abort behaviour, and derived defaults are implemented in roadmap items
`8.3.2` through `8.3.5`.

Success is observable when:

- `WireframeApp::memory_budgets(...)` exists as a public builder method;
- unit tests (`rstest`) prove defaults and builder composition semantics;
- behavioural tests (`rstest-bdd` v0.5.0) prove the public builder API is
  usable in scenario style;
- design decisions are recorded in the relevant design document(s);
- `docs/users-guide.md` documents the new public builder surface; and
- `docs/roadmap.md` marks `8.3.1` as done after all quality gates pass.

## Constraints

- Scope is strictly roadmap item `8.3.1`: add the builder configuration
  surface, not enforcement logic.
- Preserve current runtime behaviour when budgets are not configured.
- Do not implement soft-limit back-pressure or hard-cap termination in this
  milestone.
- Do not add new external dependencies.
- Keep API additions minimal and explicit; avoid broad public-surface drift.
- Keep source modules under the 400-line project guidance.
- Validate with `rstest` unit tests and `rstest-bdd` behavioural tests.
- Record the API-shape decision in a relevant design document.
- Update `docs/users-guide.md` for the new library-consumer-facing method.
- Mark roadmap item `8.3.1` done only after validation gates pass.

## Tolerances (exception triggers)

- Scope: if this work requires touching more than 12 files or exceeds 500 net
  lines of code (LOC), stop and escalate.
- Interface: if implementing `memory_budgets(...)` requires additional public
  APIs beyond the configuration value type and builder method, stop and
  escalate.
- Dependencies: if any new crate is required, stop and escalate.
- Ambiguity: if ADR/design docs do not provide enough clarity on the config
  shape, stop and present options with trade-offs.
- Iterations: if the same failing test/lint issue persists after 3 focused
  attempts, stop and escalate.
- Time: if any stage exceeds 3 hours elapsed effort, stop and escalate.

## Risks

- Risk: API shape may overfit future enforcement internals.
  Severity: medium Likelihood: medium Mitigation: keep the config type narrowly
  scoped to the three documented budget dimensions and avoid
  enforcement-coupled fields.

- Risk: behavioural tests may become superficial because enforcement is out of
  scope for `8.3.1`. Severity: medium Likelihood: medium Mitigation: make BDD
  scenarios explicitly verify public builder usability and composition with
  existing builder flows.

- Risk: introducing budgets may accidentally reset or conflict with existing
  fragmentation configuration paths. Severity: medium Likelihood: low
  Mitigation: add unit tests proving codec/builder transitions preserve budget
  configuration unless explicitly changed.

## Progress

- [x] 2026-02-17 00:49Z Drafted ExecPlan for roadmap item `8.3.1`.
- [x] 2026-02-17 22:31Z Added `MemoryBudgets` type and threaded optional
      `memory_budgets` state through `WireframeApp` storage/rebuild paths.
- [x] 2026-02-17 22:31Z Added `WireframeApp::memory_budgets(...)` builder
      method in `src/app/builder/config.rs`.
- [x] 2026-02-17 22:31Z Added `rstest` unit tests for defaults, setter
      behaviour, and composition with `with_codec`/`serializer`.
- [x] 2026-02-17 22:31Z Added `rstest-bdd` feature, fixture, steps, and
      scenarios for memory-budget configuration behaviour.
- [x] 2026-02-17 22:31Z Updated `docs/adr-002-...`, `docs/users-guide.md`,
      and marked `docs/roadmap.md` item `8.3.1` as done.
- [x] 2026-02-17 22:31Z Ran full quality gates with `tee` logs.

## Surprises & Discoveries

- Observation: the repository already uses `rstest-bdd` `0.5.0` in
  `Cargo.toml`, so no dependency migration is needed for this feature.
  Evidence: `Cargo.toml` dev-dependencies. Impact: behavioural-test work can
  focus on scenario coverage only.

- Observation: no dedicated memory budget type or builder storage currently
  exists in `src/app/`. Evidence: `WireframeApp` fields in
  `src/app/builder/core.rs` and builder methods in `src/app/builder/config.rs`.
  Impact: this milestone must introduce a new configuration value and wire it
  through builder reconstruction paths.

- Observation: behavioural guidance for this work should come from
  `docs/rstest-bdd-users-guide.md`. Evidence: repository testing updates are
  aligned to rstest-bdd. Impact: behavioural test implementation should follow
  rstest-bdd patterns consistently.

- Observation: strict clippy configuration rejects structs whose fields share a
  common prefix or suffix. Evidence: `make lint` failures from
  `clippy::struct-field-names` while introducing `MemoryBudgets`. Impact:
  internal field names were revised to mixed names while preserving public
  getter names and API semantics.

## Decision Log

- Decision: introduce a dedicated `MemoryBudgets` value type and pass it into
  `WireframeApp::memory_budgets(...)` instead of accepting three bare `usize`
  arguments. Rationale: avoids primitive-obsession/integer-soup APIs and gives
  a stable, documented configuration unit for future enforcement stages.
  Date/Author: 2026-02-17 / Codex.

- Decision: keep `8.3.1` focused on configuration surface only; enforcement and
  derived-default runtime semantics remain in `8.3.2`-`8.3.5`. Rationale:
  aligns with roadmap sequencing and avoids mixing behavioural changes across
  milestones. Date/Author: 2026-02-17 / Codex.

- Decision: avoid lint suppressions for field-name warnings and instead rename
  internal fields to satisfy `clippy::struct-field-names`. Rationale: project
  policy requires keeping lints strict unless suppression is a last resort.
  Date/Author: 2026-02-17 / Codex.

## Outcomes & Retrospective

Completed.

- `MemoryBudgets` was added as a dedicated public app configuration value with
  non-zero byte caps and documented accessors.
- `WireframeApp` now stores optional memory budgets and exposes
  `memory_budgets(...)` as a fluent builder method.
- Type-changing builder paths preserve configured budgets.
- New `rstest` unit tests and `rstest-bdd` behavioural scenarios validate the
  configuration surface.
- Documentation was updated and roadmap item `8.3.1` was marked done.
- Full quality gates passed with captured logs.

## Context and orientation

`WireframeApp` is defined in `src/app/builder/core.rs` and currently stores
routing, middleware, codec, fragmentation, and optional message-assembler
settings. Builder configuration methods live in `src/app/builder/config.rs`,
`src/app/builder/codec.rs`, and `src/app/builder/protocol.rs`.

Inbound message assembly currently derives limits in
`src/app/frame_handling/assembly.rs` from fragmentation config or frame budget,
but there is no per-connection memory-budget configuration object yet.

Relevant requirements and rationale are captured in:

- `docs/roadmap.md` section `8.3.1`.
- `docs/adr-002-streaming-requests-and-shared-message-assembly.md` section
  "Configurable per-connection memory budgets and back-pressure".
- `docs/generic-message-fragmentation-and-re-assembly-design.md` section
  `9.3 Memory budget integration`.
- `docs/the-road-to-wireframe-1-0-feature-set-philosophy-and-capability-maturity.md`
  hardening subsection on memory caps.
- `docs/hardening-wireframe-a-guide-to-production-resilience.md` for resilience
  constraints.

Testing topology for this feature:

- Unit tests use `rstest` in crate-local modules (for example,
  `src/app/builder/core.rs`).
- Behavioural tests use `rstest-bdd` fixtures/scenarios under `tests/features/`,
  `tests/fixtures/`, `tests/steps/`, and `tests/scenarios/`.

## Plan of work

### Stage A: add configuration model and builder surface

Create a dedicated memory-budget configuration type and wire it into
`WireframeApp` storage.

Expected edits:

- Add a new module, `src/app/memory_budgets.rs`, defining a public
  `MemoryBudgets` value type with clear field names and constructor/getter
  methods.
- Export the type from `src/app/mod.rs`.
- Add an optional `memory_budgets` field to `WireframeApp` in
  `src/app/builder/core.rs` and thread it through `Default` and
  `rebuild_with_params`/`RebuildParams`.
- Add `WireframeApp::memory_budgets(...)` in `src/app/builder/config.rs`.

Go/no-go: if adding this method forces unplanned public APIs or runtime
behaviour changes, stop and update `Decision Log` before proceeding.

### Stage B: add unit coverage (`rstest`)

Add focused unit tests for configuration behaviour:

- defaults: no memory budgets configured on `WireframeApp::new()`;
- setter: `memory_budgets(...)` stores the configured value;
- composition: type-changing builder paths (`with_codec`, `serializer`) preserve
  the configured budgets.

Place tests in existing builder test modules (preferred:
`src/app/builder/core.rs` test module) to allow direct inspection of
crate-visible builder fields.

Go/no-go: if tests suggest runtime enforcement changes are needed to assert the
feature, stop and keep scope at configuration semantics only.

### Stage C: add behavioural coverage (`rstest-bdd` v0.5.0)

Add a small behaviour feature that validates public API usability in scenario
form (for example, builder creation and composition with existing builder
methods).

Expected edits (or equivalent minimal set):

- `tests/features/memory_budgets.feature`
- `tests/fixtures/memory_budgets.rs`
- `tests/steps/memory_budgets_steps.rs`
- `tests/scenarios/memory_budgets_scenarios.rs`
- registration updates in `tests/fixtures/mod.rs`, `tests/steps/mod.rs`, and
  `tests/scenarios/mod.rs`

Keep scenarios explicit that this stage validates configuration surface, not
budget enforcement behaviour.

### Stage D: documentation, roadmap, and quality gates

Update docs to reflect the new public interface and record design decisions:

- update `docs/adr-002-streaming-requests-and-shared-message-assembly.md` with
  the concrete `memory_budgets(...)` API shape adopted in code;
- update `docs/users-guide.md` with builder usage examples and scope note that
  enforcement follows in later roadmap items;
- if needed for consistency, add a brief alignment update in
  `docs/generic-message-fragmentation-and-re-assembly-design.md`.

After code and doc updates, mark roadmap entry `8.3.1` as done in
`docs/roadmap.md` and run full gates.

Go/no-go: do not mark roadmap done until all gates pass.

## Concrete steps

Run from repository root (`/home/user/project`).

1. Implement the API surface and tests.

    rg -n "struct WireframeApp|impl<S, C, E, F> WireframeApp" src/app
    rg -n "message_assembler|fragmentation" src/app/builder

2. Run focused tests first.

    set -o pipefail
    cargo test --all-features src::app::builder 2>&1 | tee /tmp/wireframe-8-3-1-unit.log

    set -o pipefail
    cargo test --test bdd --all-features memory_budgets 2>&1 | tee /tmp/wireframe-8-3-1-bdd.log

Expected transcript snippets:

- unit: `test result: OK.` with new builder-memory-budget tests listed.
- bdd: scenario names from `memory_budgets.feature` pass.

1. Run repository quality gates.

    set -o pipefail
    make fmt 2>&1 | tee /tmp/wireframe-8-3-1-fmt.log

    set -o pipefail
    make markdownlint 2>&1 | tee /tmp/wireframe-8-3-1-markdownlint.log

    set -o pipefail
    make check-fmt 2>&1 | tee /tmp/wireframe-8-3-1-check-fmt.log

    set -o pipefail
    make lint 2>&1 | tee /tmp/wireframe-8-3-1-lint.log

    set -o pipefail
    make test 2>&1 | tee /tmp/wireframe-8-3-1-test.log

    set -o pipefail
    make nixie 2>&1 | tee /tmp/wireframe-8-3-1-nixie.log

2. If any command fails, inspect the corresponding `/tmp/wireframe-8-3-1-*.log`
   file, fix the issue, and rerun that command before continuing.

## Validation and acceptance

Acceptance criteria:

- Public API: `WireframeApp::memory_budgets(...)` is available to consumers.
- Configuration semantics: unit tests prove default and setter/composition
  behaviour.
- Behavioural coverage: rstest-bdd scenarios pass for public builder usage.
- Documentation: design decision and user guide updates are present and
  accurate.
- Roadmap: `docs/roadmap.md` marks `8.3.1` done only after gates pass.

Quality criteria:

- Tests: focused unit + behavioural tests and full `make test` pass.
- Lint/type/docs: `make lint` passes with no warnings.
- Formatting: `make fmt` and `make check-fmt` pass.
- Markdown: `make markdownlint` passes.
- Mermaid validation: `make nixie` passes.

## Idempotence and recovery

All edits are additive and safe to rerun. If an intermediate step fails:

- keep local changes;
- fix the specific failure; and
- rerun only the failed command, then continue the pipeline.

Avoid destructive git commands. If rollback is needed, revert only files
changed for this roadmap item.

## Artefacts and notes

Expected artefacts after completion:

- New/updated app configuration files for `MemoryBudgets` and builder wiring.
- New `rstest` unit tests covering memory-budget builder behaviour.
- New `rstest-bdd` feature/fixture/steps/scenario for builder API behaviour.
- Updated design docs (Architecture Decision Record `ADR 0002` and related
  alignment notes), `docs/users-guide.md`, and `docs/roadmap.md`.
- Gate logs:
  `/tmp/wireframe-8-3-1-impl-{fmt,markdownlint,check-fmt,lint,test,nixie}.log`.

## Interfaces and dependencies

At the end of this milestone, the following interfaces must exist.

In `src/app/memory_budgets.rs`:

    pub struct MemoryBudgets { … }

    impl MemoryBudgets {
        pub const fn new(
            bytes_per_message: std::num::NonZeroUsize,
            bytes_per_connection: std::num::NonZeroUsize,
            bytes_in_flight: std::num::NonZeroUsize,
        ) -> Self { … }

        pub const fn bytes_per_message(&self) -> std::num::NonZeroUsize { … }
        pub const fn bytes_per_connection(&self) -> std::num::NonZeroUsize { … }
        pub const fn bytes_in_flight(&self) -> std::num::NonZeroUsize { … }
    }

In `src/app/builder/config.rs`:

    impl<S, C, E, F> WireframeApp<S, C, E, F> {
        #[must_use]
        pub fn memory_budgets(self, budgets: crate::app::MemoryBudgets) -> Self { … }
    }

In `src/app/builder/core.rs`:

- `WireframeApp` stores optional memory budget configuration.
- Type-changing rebuild paths preserve this configuration.

Dependencies:

- No new crates.
- Testing remains on `rstest` and `rstest-bdd` v0.5.0 already present in
  `Cargo.toml`.

## Revision note

- Updated this ExecPlan from `DRAFT` to `COMPLETE`.
- Recorded implemented work, discovered lint constraints, and final outcomes.
- Replaced planned log paths with the actual `-impl` gate logs used for
  verification.