Skip to content

rewrite(phase4): mock.hpp batch A — wire server::Endpoint admission - #146

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

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

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. Phase 4 batch A of a four-batch mock.hpp port — the foundation the remaining three batches build on (B: response classifier + regmap-batch-B/discovery wiring; C: E2E RxSequenceGuard+StreamFaultTracker+RxWatchdog; D: fragmentation/respqueue + AVTPDU frame-level dispatch).

The gap was bigger than originally scoped

A fresh Phase 4 scoping pass found mock.hpp had no admission, queueing, or scheduling logic at all: server::Endpoint (the just-merged server.hpp) was never referenced anywhere; dispatch() was a flat byte_bus_id switch, and every dispatch_* handler ran synchronously and unconditionally behind only a lifecycle-state gate. Not a case of replacing ad hoc admission — this adds admission from scratch, matching c-RCP's own mock.c design.

Ported

  • Ten new server::Endpoint members, one per operational endpoint type.
  • admit_and_classify() (c-RCP's finish_admission), built on acf::make_response/acf::encode_error_payload plus a new make_acknowledge_rejected_response() for the Ack+err combo shape.
  • apply_cancellation() (ClearAll/ClearNonSafestate; ClearSingle deferred to batch D, needs a decoded frame).
  • Thin passthroughs: drain_one, tick, notify_trigger, notify_gptp_lock_state, pending_count, watchdog_purge.

dispatch_* changes

All ten now call admit_and_classify() right after the lifecycle gate; the handler body runs only on AdmitOutcome::ExecuteNow.

Behavioral contract change — verified backward-compatible

dispatch() can now return with no wire response at all for admission outcomes TC18 sends nothing for. Since every server::Endpoint defaults to enabled/not-suspended, all 8 external dependents get ExecuteNow unconditionally and needed zero changes — confirmed by full ctest passing before test_mock.cpp was touched.

Verification

All 49 pre-existing tests pass unmodified. 11 new cases added covering queued/suspended/rejected admission outcomes, REQ-SRV-015/016, REQ-PWRMODE-028, REQ-ACF-021, tick()/drain_one()/notify_trigger()/watchdog_purge(). mock.hpp: 917→1387 lines. test_mock.cpp: 1006→1285 lines, 49→60 TEST_CASEs (503 assertions).

Full tree rebuilds clean (0 errors/warnings), 58/58 ctest suites pass (100%) — independently re-verified from a fresh build against the merged regmap+server+discovery+adapt base.

Part of the v3.0.0 ground-up rewrite (cpp-RCP #129, ROADMAP.md Phase 17),
branch rewrite/v3-from-c-rcp. Phase 4 batch A of a four-batch mock.hpp
port -- the foundation the remaining three batches (B: response
classifier + regmap-batch-B/discovery wiring; C: E2E RxSequenceGuard +
StreamFaultTracker + RxWatchdog; D: fragmentation/respqueue +
AVTPDU frame-level dispatch) build on.

A fresh Phase 4 scoping pass found mock.hpp had NO admission, queueing,
or scheduling logic at all: server::Endpoint (the just-merged
server.hpp) was never referenced anywhere in mock.hpp; dispatch() was a
flat byte_bus_id switch, and every dispatch_gpio/dispatch_spi/etc.
handler ran synchronously and unconditionally behind only a
lifecycle-state gate. Not a case of replacing ad hoc admission -- this
adds admission from scratch, matching c-RCP's own mock.c design where
every endpoint slot embeds rcp_server_endpoint_t queue.

## Ported (c-RCP src/mock.c -> mock::Server)

- src/mock.c:35-233 (slot embedding rcp_server_endpoint_t queue) -> ten
  new server::Endpoint members, one per operational endpoint type.
- src/mock.c:1277-1300 (admission_reject_response_shape) ->
  mock::admission_reject_response_shape().
- src/mock.c:1361-1423 (finish_admission) + :1549-1551 (admit_with_ack
  call site) -> mock::Server::admit_and_classify(), built on
  acf::make_response/acf::encode_error_payload and a new
  mock::make_acknowledge_rejected_response() (the Ack+err combo
  acf::make_response() alone can't express).
- src/mock.c:1180-1245 (apply_cancellation) ->
  mock::Server::apply_cancellation() (ClearAll/ClearNonSafestate only;
  ClearSingle deferred, see below).
- src/mock.c:2856-2870,3587-3628,3670-3717,3785-3802 (drain_endpoint,
  tick, notify_trigger, notify_gptp_lock_state, pending_count,
  watchdog_purge) -> thin Server passthroughs onto server::Endpoint.
- REQ-SRV-015/016, REQ-PWRMODE-028, REQ-ACF-021, REQ-TIMED-012,
  REQ-CANCEL-012, REQ-SRV-018 citations preserved.

## dispatch_* changes

All ten (dispatch_gpio...dispatch_mdio) now call admit_and_classify()
immediately after the existing operational_requests_allowed()
lifecycle gate; the handler body runs only on
AdmitOutcome::ExecuteNow. Since every mock request is encoded ACF_ABB,
only ExecuteNow/Queued/Suspended/Rejected are reachable through
dispatch() -- Pending/Cancellation are implemented for classifier
completeness and exercised directly via the new admission() accessor.

## New Server API

admission(byte_bus_id), pending_count(), watchdog_purge(), drain_one(),
notify_trigger(), notify_gptp_lock_state(), tick(). tick()/drain_one()
deliberately don't decode+execute the returned frame -- this mock has
no generic byte-level handler (each type has its own decoded-struct
dispatch path) -- documented as the caller's job.

## Behavioral contract change (verified backward-compatible)

dispatch() can now return with no wire response at all (out_resp.rsp
== false) for admission outcomes TC18 sends nothing for -- signaled
via new mock::DispatchErrc{queued,pending,cancelled,suspended}. Since
every server::Endpoint defaults to enabled/not-suspended, all 8
external dependents (sim.hpp, cli.hpp, test_capi/test_relay/
test_redundancy/test_faultinject/bench_mock/command_latency_test) get
ExecuteNow unconditionally and needed zero changes -- confirmed by
full ctest passing before test_mock.cpp was touched.

## Deferred (TODO(phase4-batch-d) in-file)

apply_cancellation()'s ClearSingle case is a documented no-op --
REQ-CANCEL-012's chain-cascade needs a decoded target transaction_num
from a real GBB frame, unreachable until batch D's dispatch_frame().

## Verification

All 49 pre-existing test_mock.cpp cases pass unmodified (no
admission-aware setup was actually needed -- verified empirically, not
assumed). 11 new cases added: queued (no ack)/queued (with ack),
config-write bypassing a disabled queue (REQ-SRV-015),
admission_suspended (REQ-PWRMODE-028), REQ-ACF-021 response-as-request
rejection (both ack shapes), drain_one() round-trip, pending_count()/
watchdog_purge() against a directly-admitted Triggered request,
notify_trigger()/notify_gptp_lock_state() edge detection, two tick()
cases (TSCF gate due / fail-closed while unlocked).

mock.hpp: 917 -> 1387 lines. test_mock.cpp: 1006 -> 1285 lines, 49 ->
60 TEST_CASEs (503 assertions). Full tree rebuilds clean (0 errors, 0
warnings), 58/58 ctest suites pass (100%) -- independently re-verified
from a fresh build against the merged regmap+server+discovery+adapt
base, not just the porting agent's own report.

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