Skip to content

[c-RCP-AUDIT-01] Wire TC18 Table 27's 16 unmapped error codes to real response paths #163

Description

@SoundMatt

Background

include/rcp/errors.h defines rcp_wire_error_t, the 17 numbered wire error codes assigned by TC18's own Table 27 (the values an RC Server places in an Acknowledge/Response frame's err field to tell an RC Client what went wrong). REQ-WIREERR-001 covers the enum itself.

The header's own comment is already honest about the gap:

"This header intentionally does not attempt to wire every internal rcp_errc_t/rcp_<mod>_errc_t value in the codebase onto one of these seventeen codes... rcp_e2e_wire_error() below is the one concrete mapping this milestone adds... Additional mappings (e.g. sequencer.h's REQUEST_NOT_FOUND-shaped failures, authz.h's UNAUTHORIZED_ACCESS-shaped failures) are real future work, not modeled here."

Confirmed by grep (2026-08-07): only errors.c/errors.h reference the 17 RCP_ERROR_* constants anywhere in the codebase. No endpoint module, server.c, authz.c, sequencer.c, or any request_*.c actually populates a real error response's err field with the correct numbered code for most failure conditions. Only 1 of 17 codes is wired to a real path today: RCP_ERROR_POCI_FAILURE via rcp_e2e_wire_error() (CRC32/E2E mismatch).

This is safety-relevant: an RC Client's ability to correctly diagnose why a request failed depends on the RC Server returning the right numbered code, not a generic/wrong one or none at all.

The 16 unmapped codes and their TC18 meaning

RCP_ERROR_UNSUPPORTED_CMD           = 1,  // the addressed operation/endpoint doesn't support the requested command
RCP_ERROR_SEQUENCER_NOT_KNOWN       = 2,  // the referenced sequencer index isn't configured
RCP_ERROR_UNAUTHORIZED_ACCESS       = 3,  // the caller isn't permitted to perform this request
RCP_ERROR_LOCKED_MEM_ACCESS         = 4,  // the addressed register/memory is locked against this access
RCP_ERROR_REQUEST_CANCELED          = 5,  // the request was canceled before it completed
RCP_ERROR_REQUEST_NOT_FOUND         = 6,  // the referenced request (e.g. to cancel) is not known
RCP_ERROR_EP_ERROR                  = 7,  // the addressed endpoint reported an internal fault
RCP_ERROR_EP_NOT_FOUND              = 8,  // the addressed endpoint (byte_bus_id) does not exist
RCP_ERROR_PWM_IN_NO_SIGNAL          = 9,  // a PWM input endpoint has no signal to report
RCP_ERROR_REQUEST_STORAGE_OVERFLOW  = 10, // the request-storage capacity is exhausted
RCP_ERROR_REQUEST_REJECTED          = 11, // the request was well-formed but rejected on other grounds
// 12 (POCI_FAILURE) already wired
RCP_ERROR_PRESENTATION_TIME_TOO_FAR = 13, // a timed request's presentation_time is outside the acceptable window
RCP_ERROR_GPTP_FAIL                 = 14, // gPTP time sync is unavailable or has failed
RCP_ERROR_INVALID_PARAMETER         = 15, // a request field's value is out of range or otherwise invalid
RCP_ERROR_CHAIN_ABORTED             = 16, // a chained request sequence was aborted before completion
RCP_ERROR_CHAIN_ERROR               = 17, // a chained request sequence failed internally

What needs to happen (for the agent picking this up)

  1. Scope first, don't just start wiring. For each of the 16 codes, find every internal failure condition in the codebase that semantically matches it. Candidate locations, not exhaustive: server.c (routing/dispatch — EP_NOT_FOUND, UNSUPPORTED_CMD), authz.c (UNAUTHORIZED_ACCESS, LOCKED_MEM_ACCESS), sequencer.c/request_compound.c (SEQUENCER_NOT_KNOWN, REQUEST_STORAGE_OVERFLOW), request_cancel.c (REQUEST_CANCELED, REQUEST_NOT_FOUND), request_chained.c (CHAIN_ABORTED, CHAIN_ERROR), request_timed.c (PRESENTATION_TIME_TOO_FAR, GPTP_FAIL), every ep_*.c (EP_ERROR, PWM_IN_NO_SIGNAL in ep_pwm.c specifically), and general request validation (INVALID_PARAMETER).
  2. Verify against TC18 text directly which specific conditions each code is meant to cover — don't guess from the enum's one-line paraphrase alone. errors.h's own comment says the numeric values are "the protocol's on-wire contract" reproduced exactly, but the enumerator names/descriptions are this implementation's own paraphrase, not the spec's wording — go back to the primary source (OA_TC18_specification_v_0.5.1_RC.pdf, Table 27 and the surrounding per-request-type error prose) for each mapping.
  3. Wire each mapping into the real response-construction path — likely a per-module rcp_<x>_wire_error() function mirroring rcp_e2e_wire_error()'s existing shape, called wherever that failure is actually detected and a response is being constructed.
  4. Test each mapping — a real request that triggers the failure condition and asserts the response's err field carries the correct code, not just that an error occurred.
  5. Add/update .fusa-reqs.json entries with real tc18 citations to TC18's Table 27 and the specific per-request-type error-condition prose, following this repo's per-function //cfusa:req tagging convention.
  6. Verify with a freshly-built, CI-pinned cfusa (check the exact tag in .github/workflows/ci.yml, never trust a cached binary) — check 0 errors, trace --req-coverage 100 --sec-tested 100.
  7. Given the size (potentially touching every module), consider whether this should ship as several smaller PRs (e.g. grouped by which module owns the mapping) rather than one large one — this repo's established pattern favors small, fully-verified PRs over big-bang changes.

Not in scope for this issue

  • Codes 1 and 12 already have real mappings (UNSUPPORTED_CMD is presumably already used somewhere for command rejection — verify this as part of scoping rather than assuming; POCI_FAILURE is confirmed wired via rcp_e2e_wire_error()).
  • This issue is about wiring existing internal failures to the right wire code — it is not about inventing new failure detection that doesn't exist today (e.g. if nothing in the codebase currently detects "gPTP sync unavailable" at all, that's a separate, larger feature gap worth its own issue, not silently folded into this one).

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions