Skip to content

feat: RELAY spec v0.2 conformance — relay:: namespace, Channel<T>, Adapt() - #7

Merged
SoundMatt merged 1 commit into
mainfrom
feat/relay-conformance
Jun 17, 2026
Merged

SoundMatt merged 1 commit into
mainfrom
feat/relay-conformance

Conversation

@SoundMatt

Copy link
Copy Markdown
Owner

Summary

Implements RELAY spec §18.2 C++ bindings in cpp-RCP, closing issue #5.

  • include/relay/relay.hpp: New relay:: namespace header with:

    • relay::Protocol enum (§3) — CAN=1…SOMEIP=6
    • relay::Message universal envelope (§4)
    • relay::Errc error category named "relay" with four mandatory sentinels: ErrClosed, ErrNotConnected, ErrTimeout, ErrPayloadTooLarge (§5.1)
    • relay::Context — lightweight deadline context (§18.2), now the canonical definition
    • relay::BackPressurePolicy + relay::SubscriberOptions with default depth 64 (§14, §18.2)
    • relay::Channel<T> — generic typed bounded channel; bool push() returns false when full or closed (§18.2)
    • relay::Node and relay::Caller abstract classes (§18.2)
    • relay::kRelaySpecVersion = "0.2" (§19.4)
  • include/rcp/rcp.hpp: Updated:

    • rcp::Context → alias for relay::Context (§18.2)
    • rcp::StatusChannel → alias for relay::Channel<Status> (§18.2)
    • rcp_category()::equivalent() maps rcp::Errc → relay::Errc via std::error_condition equivalence (§5.2, §5.3)
  • include/rcp/adapt.hpp: New file:

    • rcp::Adapt(shared_ptr<Controller>) → unique_ptr<relay::Caller> (§10.3)
    • zone_to_relay_id / zone_from_relay_id for PascalCase zone names (§4.2)
    • status_to_message / response_to_message / message_to_command (§15.7.5)
    • RcpCallerAdapter implementing all three relay::Node/Caller virtual methods
  • tests/test_relay.cpp: 23 new conformance tests — all 27/27 tests pass locally.

Spec gaps raised on RELAY repo (issue #6)

8 issues filed on SoundMatt/RELAY covering: SpecVersion inconsistency (§17.12 vs §19.4), Channel<T> by-value in subscribe() signature, missing C++ Adapt() signature, missing std::error_condition equivalence example, rcp.healthy meta key absent from §4.3, missing C++ ToMessage()/FromMessage() signatures, ErrAlreadyExists wrapping ErrClosed semantically wrong, and CLI conformance undefined for header-only C++ libraries.

Test plan

  • Local build with clang++ / C++17 — all 27/27 CTest cases pass
  • rcp_relay conformance test — 51 assertions in 23 test cases
  • CI: Ubuntu clang-14/gcc-12, macOS clang, Windows MSVC matrix

Implements RELAY spec §18.2 C++ bindings for cpp-RCP (closes issue #5):

- include/relay/relay.hpp: relay:: namespace with Protocol enum, Message
  envelope, Errc error category with ErrClosed/ErrNotConnected/ErrTimeout/
  ErrPayloadTooLarge sentinels, Context, BackPressurePolicy, SubscriberOptions,
  Channel<T> generic typed channel, Node and Caller abstract classes, and
  kRelaySpecVersion = "0.2" constant.

- include/rcp/rcp.hpp: rcp::Context aliased to relay::Context; rcp::StatusChannel
  aliased to relay::Channel<Status>; rcp_category() gains equivalent() mapping
  rcp::Errc codes to relay::Errc conditions (§5.2, §5.3).

- include/rcp/adapt.hpp: rcp::Adapt() wrapping Controller as relay::Caller;
  zone_to_relay_id/zone_from_relay_id helpers; status_to_message/
  response_to_message/message_to_command conversions (§15.7.5).

- tests/test_relay.cpp: 23 conformance tests covering spec version, Protocol
  enum values, all four mandatory error sentinels (§5.1), error_condition
  equivalence mappings (§5.2), Channel<T> push/recv semantics, SubscriberOptions
  defaults (§14), Context alias, StatusChannel alias, and Adapt() call/send/
  subscribe/close behaviour (§10.3). All 27/27 tests pass.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Matt Jones <47545907+SoundMatt@users.noreply.github.com>
@SoundMatt
SoundMatt merged commit 60296ca into main Jun 17, 2026
19 checks passed
@SoundMatt
SoundMatt deleted the feat/relay-conformance branch June 17, 2026 00:04
SoundMatt added a commit that referenced this pull request Aug 22, 2026
…ivation (#157)

Part of the v3.0.0 ground-up rewrite (cpp-RCP #129, ROADMAP.md Phase 17),
branch rewrite/v3-from-c-rcp. Phase 6 (requirement catalog), batch 3 of 13
-- the largest single-concern batch so far.

## Scope

request.hpp's conditional-request cluster: Compound (REQ-CMP-*, 29
c-RCP entries), Triggered (REQ-TRIG-*, 13), Chained (REQ-CHAIN-*, 12),
Timed (REQ-TIMED-*, 13), Cancellation (REQ-CANCEL-*, 15), and the
scheduler (REQ-SCHED-*, 8) -- 90 c-RCP entries total, all already
orphan-cited across request.hpp/test_request.cpp. c-RCP splits this
across three files (request.c/request_sequencer.c/scheduler.c);
cpp-RCP's rewrite deliberately keeps its own prior unification into
one file (documented cpp-RCP design choice, not re-split), while
keeping c-RCP's id-prefix scheme per RELAY docs/RCP-ARCHITECTURE.md's
canonical choice #7.

## New catalog entries (70)

- REQ-CMP-{001-003,010-029} (23)
- REQ-TRIG-{001,004-013} (11)
- REQ-CHAIN-{002,004-007,010-012} (8)
- REQ-TIMED-{002-011} (10)
- REQ-CANCEL-{002-015} (14)
- REQ-SCHED-{002,003,007,008} (4)

Each verified against real request.hpp code/test_request.cpp tests,
not rubber-stamped from the pre-existing orphan-tag manifest. Two new
tests added (REQ-CHAIN-005, REQ-TIMED-004) that had no dedicated test
before.

## Genuine gaps found (7 new, filed to .fusa-reqs-pending.json, total now 19)

- REQ-CMP-008/009, REQ-TRIG-003, REQ-CHAIN-003: encode_compound_
  request()/encode_triggered_request()/encode_chained_member() never
  validate their type/payload-size before encoding -- they forward
  straight to acf::encode_acf_gbb(), which by design never rejects --
  and their plain std::vector<uint8_t> return type has no channel to
  signal rejection at all, unlike encode_timed_request()'s own
  std::optional<...> (confirmed: request.hpp:569/745/970 return bare
  std::vector, request.hpp:1077 returns std::optional -- the exact
  asymmetry this finding describes). No test exercised these paths.
  Removed the false orphan tags claiming coverage, documented the
  finding in-file (request.hpp:242-249).
- REQ-CHAIN-008: RequestLedger::submit() never rejects a Chained
  request with no chained_predecessor; no CHAIN_ERROR-equivalent
  exists (c-RCP's rcp_chained_advance() returns
  RCP_CHAINED_MEMBER_CHAIN_ERROR for exactly this case, TC18
  §11.2.2.6).
- REQ-TIMED-012/013: no dispatch/admission entry point anywhere in
  cpp-RCP threads a real TSCF avtp_timestamp into timed_admit()/
  timed_due() -- the primitives exist, the loop doesn't. c-RCP's own
  entries describe a real dispatch-layer TSCF-threading feature
  (rcp_mock_server_dispatch_tscf() and its E2E-aware siblings);
  cpp-RCP's mock.hpp has no equivalent entry point yet. Matches this
  file's own documented "no scheduler thread" scope -- a real,
  TC18-cited gap, not force-fit as implemented.

## Duplicate-coverage mappings (no new entry, no gap)

CMP-004, TRIG-002, CHAIN-001, TIMED-001, CANCEL-001 -> pre-existing
REQ-SEQ-009 ("RequestErrc is a distinct error category with
non-empty, distinct messages") -- cpp-RCP unified all per-kind
strerror requirements into one shared error category. SCHED-001 ->
pre-existing REQ-SEQ-002 (category_of() already documents this
classification). Note: cpp-RCP's REQ-SEQ-* is its own, pre-existing,
differently-scoped prefix about this same file -- unrelated to
c-RCP's request_sequencer.h REQ-SEQ-*, left untouched, out of scope.

## Judgment calls, already documented in-file (no new action)

CMP-005/006/007 (peek_request_type) and SCHED-004/005/006
(frame-splitting) -- both already explicitly documented in request.hpp's
own header as deliberate non-ports, composable via other already-covered
functions. CHAIN-009 -- covered by RequestLedger's graph-based
cascade_cancel()/propagate_chain_completion(), already documented as
strictly more capable than c-RCP's positional model.

## REQ-SCHED-* prefix decision

Code's own orphan tags already used REQ-SCHED-* verbatim, matching
c-RCP -- kept as-is, no rename needed.

## Stale pre-existing gap entries found, not touched (out of this batch's scope)

.fusa-reqs-pending.json's pre-existing REQ-SEQ-013/014/015 (filed
2026-08-07, describing missing Compound exec_delay/repetitions,
Triggered trigger fields, Timed presentation_time) appear stale --
current request.hpp code genuinely implements all three (CompoundStep,
TriggeredStep, TimedRequest + timed_admit()/timed_due()). Left as-is
since fixing them means touching the REQ-SEQ-* prefix; flagging here
for whoever picks up REQ-SEQ-* in a later batch.

## Verification

Independently re-verified (not just the porting agent's own report):
semantic id-keyed diff confirms zero pre-existing catalog entries
modified/deleted, exactly the 70 new ids added matching the report's
own breakdown per prefix exactly. Confirmed no new entry carries
"severity": "cybersecurity" -- sec-tested count holds exactly at
72/544, matching the absolute-count floor fixed in batch 1. Spot-
verified the encode_*_request asymmetry claim directly against
request.hpp's real function signatures, and REQ-CHAIN-008/REQ-TIMED-
012/013's c-RCP source citations directly against c-RCP's own
.fusa-reqs.json entries -- both check out. Full tree rebuilt from
scratch: 0 errors, 0 warnings, 58/58 ctest suites pass (100%),
test_request alone: 137 TEST_CASEs, 615 assertions.

.fusa-reqs.json: 474 -> 544 entries (+70, 4378 -> 5203 lines).
.fusa-reqs-pending.json: 12 -> 19 entries (+7, 123 -> 192 lines).
include/rcp/request.hpp: 1508 -> 1537 lines. tests/test_request.cpp:
1685 -> 1717 lines.

Signed-off-by: Matt <47545907+SoundMatt@users.noreply.github.com>
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
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