Skip to content

rewrite(phase4): mock.hpp batch D2 — AVTPDU frame-level dispatch, closes out Phase 4 - #150

Merged
SoundMatt merged 1 commit into
rewrite/v3-from-c-rcpfrom
phase4/mock-d2
Aug 22, 2026
Merged

SoundMatt merged 1 commit into
rewrite/v3-from-c-rcpfrom
phase4/mock-d2

Conversation

@SoundMatt

Copy link
Copy Markdown
Owner

Part of the v3.0.0 ground-up rewrite (#129, ROADMAP.md Phase 17), branch rewrite/v3-from-c-rcp. Second of two sub-batches (D1/D2) making up Phase 4's fourth and FINAL batch. This completes mock.hpp — the last module of Phase 4 — and closes out the server/dispatch layer in full.

Ported

  • split_frame_members() — the AVTPDU multi-member splitting logic (request.hpp's own header notes this lives nowhere else in the rewrite; c-RCP keeps it mock.c-local too).
  • dispatch_frame()/dispatch_frame_e2e() — routes each split member through the existing single-member dispatch/E2E/fragmentation machinery, no duplicated logic.
  • Chain-group/position bookkeeping (REQ-CANCEL-012) via a shared dispatch_frame_impl() template.
  • apply_cancellation()'s ClearSingle case — open since batch A — now decodes the real target, cascades via cancel_chain_from().

Bug found and fixed (beyond the literal ask)

admit_and_classify() always re-encoded ABB from req/payload, silently stripping any genuine GBB conditional/cancellation opcode's semantics — meaning ClearSingle/Chained frames were never actually reachable before this batch. Refactored to take the raw frame directly (mechanical edit across its 10 call sites, zero behavior change for them) and added conditional-opcode-aware routing, so dispatch_frame() and every existing E2E/fragment dispatch caller can now genuinely admit Chained/Compound/Triggered/Timed/Cancellation GBB members.

Final Phase-4 sweep

Grepped the whole file for TODO(phase4-batch-*) markers: only the ClearSingle stub existed, now resolved. No dangling markers remain.

Verification

mock.hpp: 2723→3413 lines. test_mock.cpp: 2349→2775 lines, 101 TEST_CASEs (863 assertions). Full tree rebuilds clean (0 errors/warnings), 58/58 ctest suites pass (100%) — independently re-verified from a fresh build.

Phase 4 complete

mock.hpp grew from its pre-Phase-4 baseline of 917 lines to 3413 lines across four batches: A (admission), B (response suppression + regmap/discovery), C (RxSequenceGuard/StreamFaultTracker/RxWatchdog — closing a gap flagged since PR #134), D1 (fragment.hpp/respqueue.hpp wiring — closing a gap open since Phase 1), D2 (this PR — AVTPDU frame-level dispatch). Combined with regmap, server.hpp, discovery, and adapt (all merged earlier in Phase 4), the server/dispatch layer is now complete with no phase-4-scoped work left deferred.

…ses out Phase 4

Part of the v3.0.0 ground-up rewrite (cpp-RCP #129, ROADMAP.md Phase 17),
branch rewrite/v3-from-c-rcp. Second of two sub-batches (D1/D2) making
up Phase 4's fourth and FINAL batch. This completes mock.hpp -- the
last module of Phase 4 -- and closes out the server/dispatch layer in
full. Built on batches A (admission), B (response suppression +
regmap/discovery), C (single-member E2E dispatch), and D1 (E2E
fragmented dispatch).

## Ported (c-RCP src/mock.c/src/scheduler.c/src/request.c, REQ-MOCK-019/
020/029, REQ-E2E-033, REQ-CANCEL-012)

- split_frame_members() -- ported from rcp_sched_split_frame_members()
  (scheduler.c:63-106), a new namespace-scope helper (request.hpp's own
  header explicitly notes this splitting logic lives nowhere else in
  the rewrite -- c-RCP keeps it mock.c-local too).
- FrameMemberResult + Server::dispatch_frame()/dispatch_frame_e2e() --
  ported from rcp_mock_server_dispatch_frame()/_dispatch_frame_e2e()
  (mock.c:3068-3382). Each returns per-member results (mirrors c-RCP's
  own result-array shape -- c-RCP does not aggregate members' responses
  into one outgoing wire frame either, confirmed by source read).
- Chain-group/position bookkeeping (REQ-CANCEL-012, ported from
  rcp_chained_advance/is_chained_member/last_pending_index,
  mock.c:2950-3231, request.c:673-694) -- via a new shared
  dispatch_frame_impl() template, using request::should_execute_chained()
  for the cs-polarity predicate and a new last_pending_index() helper.
- apply_cancellation()'s ClearSingle TODO (open since batch A) filled
  in: decodes request::decode_clear_single() from the raw frame,
  captures the target's chain_group/chain_position before removing it,
  cascades via cancel_chain_from().

## Bug found and fixed (beyond the literal ask)

admit_and_classify() always re-encoded ABB from req/payload, silently
stripping any genuine GBB conditional/cancellation opcode's semantics
-- meaning ClearSingle/Chained frames were never actually reachable
before this batch, regardless of how they'd been decoded. Refactored
to take the raw frame directly (mechanical edit across its 10 call
sites, zero behavior change for them) and added
decode_and_dispatch()'s own conditional-opcode-aware routing branch, so
dispatch_frame()/dispatch_frame_e2e() -- and every existing
dispatch_e2e()/dispatch_e2e_fragment() caller -- can now genuinely
admit Chained/Compound/Triggered/Timed/Cancellation GBB members. Also
extracted dispatch_e2e_core()/dispatch_e2e_fragment_core() with an
apply_seq_gate flag so the frame-level sequence gate runs exactly once
per frame (matching the pre-existing doc comment's own stated intent),
not once per member.

## Delta from c-RCP (documented in-file)

dispatch_frame_e2e() routes every member through
dispatch_e2e_fragment_core() rather than plain dispatch_e2e_core() --
c-RCP has no frame-level fragment-aware dispatch at all; this is a
safe superset since the fragment-core function falls back identically
for non-fragmented members.

## Test-writing findings (documented, not library bugs)

split_frame_members() requires each member's declared
acf_msg_length*4 to exactly match its real encoded byte count, but
acf::encode_acf_abb()/e2e::wrap_framed() never auto-pad payloads to
quadlet boundaries (documented as caller-owned in acf.hpp) -- never
mattered for single-member dispatch before; all new multi-member test
frames use quadlet-aligned payloads with an explanatory comment.
Confirmed DispatchErrc::unknown_bus is unreachable in this codebase
(acf.hpp's decode is deliberately lenient vs c-RCP's strict decode) --
documented as defensive-only with a test pinning the actual lenient
behavior.

## Final Phase-4 sweep

Grepped the whole file for TODO(phase4-batch-*) markers: only
apply_cancellation()'s ClearSingle stub existed, now resolved. No
dangling phase-4 markers remain anywhere in mock.hpp.

## Verification

New split_frame_members()/dispatch_frame()/dispatch_frame_e2e() +
ClearSingle cascade, tested end-to-end via multi-member AVTPDU frames.
include/rcp/mock.hpp: 2723 -> 3413 lines. tests/test_mock.cpp: 2349 ->
2775 lines, test_mock: 101 TEST_CASEs (863 assertions). Full tree
rebuilds clean (0 errors, 0 warnings), 58/58 ctest suites pass (100%)
-- independently re-verified from a fresh build, not just the porting
agent's own report.

## Phase 4 complete

mock.hpp grew from its pre-Phase-4 baseline of 917 lines to 3413 lines
across four batches: A added server::Endpoint admission wiring, B
added Table 24 response suppression plus regmap/discovery storage, C
wired RxSequenceGuard/StreamFaultTracker/RxWatchdog into single-member
E2E dispatch (closing a gap flagged since PR #134), D1 wired
fragment.hpp/respqueue.hpp for E2E fragmented dispatch (closing a gap
open since Phase 1), and this D2 batch added AVTPDU frame-level
multi-member splitting/routing/chain-cascade cancellation. Combined
with regmap (batches A/B), the new server.hpp, discovery, and adapt --
all merged earlier in Phase 4 -- the server/dispatch layer is now
complete with no phase-4-scoped work left deferred.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.com>
@SoundMatt
SoundMatt merged commit 73fc51e into rewrite/v3-from-c-rcp Aug 22, 2026
22 checks passed
@SoundMatt
SoundMatt deleted the phase4/mock-d2 branch August 22, 2026 08:33
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