Naming note (2026-09): folders were renamed to RCA product names (platform/Platform_RTE, application/RBC_GP, ...). Entries below keep the repository names they were written with; see the layout table in CLAUDE.md.
Open work only. When an item is done, delete it: history is in git. Defects go in ISSUES.dox, not here.
Capella architecture baseline (2026-10-02)
Gaps between the Capella model and the code; details in docs/architecture/CAPELLA_ARCHITECTURE_BASELINE.dox. All planned work for these gaps (architecture changes included) is listed here; ADRs and audit pages hold the design and the rationale, not the plan. Every step: unit tests, Docker --full suite and smoke.sh green before the next.
Order (owner priority 2026-10-06: G1 and G2 first):** G1.5 (5b-3b, 5c; 5a/5b-1/5b-2/5b-3a merged 2026-10-07) -> G2 once ADR-041 is accepted -> G4.5..G4.9 -> G3 (its peer/site-link item is done with G1.5c) -> G5..G7 (scoping first). G2 is blocked on owner acceptance of ADR-041 (seam step G2.1 done); it goes before G4.5 as soon as it is accepted.
- G1: move site-role negotiation, partner supervision and takeover verification from RBC_GP/.../ab_gp_channel_negotiate.c into RTE Redundancy Services; GP keeps the Site Role Client (IF-05). Design: Platform_RTE docs/architecture/ADR-040-site-role-service.dox (accepted 2026-10-02). Steps 1-4 done (rte_site_role_policy, rte_site_role, A/B agreement check rte_site_role_check_sibling, authenticated takeover token rte_site_role_on_takeover_token).
- Step 5: site link and A/B peer link on rte_flow (together with G3); rte_site_role reads the sibling state itself, GP stops forwarding it; delete GP copies; update RBC_GP CLAUDE.md (A3 decision) and the standby_mode comment in rte_redundancy_config.h. Also replace the /tmp startup-timestamp file shared by A and B with a peer-link exchange (ADR-040 risk; breaks on separate hosts). Steps 5a, 5b-1, 5b-2 and 5b-3a merged 2026-10-07 (Platform_RTE 384e6ae, RBC_GP 5d7fe44); 5b-3b and 5c open.
- Step 5b (planned 2026-10-06, owner priority G1 first; ADR-040 step 5 "`rte_site_role` reads the sibling site
state itself"; no design choice beyond ADR-040 - rule 7 and REQ-SITEROLE-014 already make the A/B sibling an input of the service). Today GP decodes the sibling's PEER_MSG_KIND_SITE_STATE frame (3 bytes is_online |
single_mode | ready, cached in ctx->peer_site_state_bytes by pre_execute.c on_peer_frame_received() and ab_gp_channel_checkpoint.c poll_for_checkpoint_frame()) in two places: ab_gp_channel_negotiate.c derives sibling_online / sibling_ready / sibling_reachable (frame within 3 cycles) for rte_site_role_local_t, and ab_gp_channel_crosscompare_check_site_state() feeds rte_site_role_check_sibling(). The seam: a sibling state source the service polls once per rte_site_role_execute(); RTE then owns the cache, the rx-cycle stamp, the derived facts and the agreement check. GP implements the source over its own peer link until step 5c puts the link on rte_flow and RTE implements the source itself. Sliced so that each part passes the gate alone: 5b-1 (Platform_RTE, additive, behaviour unchanged without a source), 5b-2 (RBC_GP wiring), 5b-3 (start-up adopts the running sibling's role - the 5a reviewer note: a channel restarting next to a long-running sibling keeps its own fresh timestamp and rte_dual_negotiator_update_states() decides from timestamps alone when its own state is IDLE/UNKNOWN, so A and B of one site can reach different inter-site verdicts). 5b-1, 5b-2 and 5b-3a merged 2026-10-07 (Platform_RTE 384e6ae, RBC_GP 5d7fe44); 5b-3b open below.
- Step 5b-3 (planned 2026-10-06; the 5a reviewer note: a channel restarting next to a long-running sibling keeps its own fresh timestamp - 5a's agree rule - and rte_dual_negotiator_update_states() decides from timestamps alone while its own state is IDLE/UNKNOWN, so A and B of one site can start with different inter-site verdicts and the REQ-SITEROLE-014 check then counts mismatches until rule 6/7 catches up (a readiness WAIT longer than 3 cycles ends in an AB_SITE_STATE_MISMATCH reboot). Split in two so each part passes the gate alone: 5b-3a (Platform_RTE, additive, behaviour unchanged without a sibling frame at start-up) and 5b-3b (RBC_GP, gets the sibling's frame to the source before rte_site_role_start()). Start-up rule (within ADR-040: 2oo2 agreement, REQ-SITEROLE-014, and rule 7 "follow the A/B sibling" applied before the first cycle; the inter-site tie-break itself, REQ-DUAL-NEGOTIATOR-003, is not changed - a channel joining a site whose role is already decided makes no initial decision, exactly as an ONLINE channel reconnecting today resumes its role through resume_own_state instead of re-litigating):** rte_site_role_start() polls the sibling source once (cycle 0) before the link is opened. Sibling known and ONLINE: start ONLINE (negotiator seeded RTE_DUAL_STATE_ONLINE). Sibling known and STANDBY, ready or not: start STANDBY (negotiator seeded RTE_DUAL_STATE_HOTSTANDBY; the negotiator refines HOT/COLD from the counterpart's degraded bit on contact as it does after any resume). ready and single_mode of the frame take no part: readiness gates promotions (REQ-SITEROLE-002), not the start-up verdict (today's timestamp verdict needs no readiness either), and single_mode is checked by the agreement check from the first rte_site_role_execute() on. Sibling unknown (no frame yet) or no source configured: the timestamp tie-break runs unchanged. The startup timestamp is not touched: rs->startup_timestamp_ms (5a's agreed value or the own clock) still seeds the negotiator and goes out in every beacon; with a resumed role this channel's negotiator never evaluates it, and the counterpart's negotiator only re-decides from timestamps while its own state is IDLE/UNKNOWN (contact lost for peer_lost_timeout_ms) - diagnostic only, since the counterpart's rs->online changes through rules 1-7 on site-role frames, never from its negotiator after start-up. Whether 5b-3b should also adopt the running sibling's timestamp (a change to 5a's agree() rule, GP-only) is decided in the 5b-3b plan, not here.
- Step 5b-3b (RBC_GP only, planned after 5b-3a; branch from todo/g1-5b-2-gp-sibling-source, needs 5b-3a): the start-up source needs the sibling's site-state frame before the peer-rx task of main.c step 10 exists. Outline: exchange_startup_timestamp() of 5a stores a PEER_MSG_KIND_SITE_STATE frame seen during its wait with ab_gp_sibling_state_store() (it does not end the wait); the running sibling answers a STARTUP_TS request with its current site-state frame as well (ab_gp_channel_negotiate_on_startup_ts_frame() sends send_site_state() of post_execute.c, moved to a shared place); after the STARTUP_TS frame ends the wait, a short bounded grace read (to be sized in the plan) collects the site-state frame if it is still in flight. Decide there whether a restarting channel also adopts the running sibling's startup timestamp (5a's agree() keeps the own fresh value; with the role resumed the reason for a fresh value is gone, but the change is to the 5a rule and its tests, smoke.sh log checks "adopted sibling" / "own
kept"). Log lines: the "site startup timestamp ..." line gains "sibling state ONLINE|STANDBY|none".
- Docker gate owed (2026-10-07) for the merged G1 steps 5a/5b-1/5b-2/5b-3a: the 5a run results-20261006-185240-60102 was 46/52 - three takeover-token failures (Replayed Takeover Confirmation
Is Rejected, Takeover Confirmation With Wrong Key Is Rejected, Takeover Needs Dispatcher Confirmation: 'the Gateway did not issue a token to both channels', c-east), IL Route Command Drives The Route FSM, Aggregated RBC Health Summary Is Populated On Both Sites ('SUMMARY on west does not see A up') plus one ISS-009 split-pair setup - not yet attributed (change vs host load). Before the next vital step merges: clean --full run on an idle host from the current masters + re-run of the failing suites; attribute each failure or record new ISSUES entries.
- Follow-ups from the 2026-10-07 merge and docs pass:
- Platform_RTE: clear rs->online on the error returns of rte_site_role_start(); fix the rte_site_role_sibling_source_fn typedef doc ("polled once per execute" -> also polled once at start, REQ-SITEROLE-017).
- Step 5c note: the RTE sibling check uses local->single_mode captured before GP's promotion reset, so the promotion cycle can cost one extra PENDING strike (worst case 2/3).
- Web runner: the Docker-mode live stream likely tails only the local testEnv/logs (the merged per-test logs do use docker logs) - verify and fix.
- Web runner listener: the process tag can mislabel a line logged with the peer's Source (e.g. rte_site_role.c:366 DEBUG) - the panel is unaffected, the log view mislabels.
- Re-check the ensure_west_is_online recovery path after G1 step 5b-3b.
- RBC_Test_Env CLAUDE.md "Local versus Docker": the claim about hard-coded ab-peer/ab-negotiate ports cites a nonexistent ISSUES entry - verify against common_config.h and correct.
- Doc/code mismatches from the 2026-10-07 docs pass (comment-only fixes):
- RBC_GP main.c:377-383 cites a nonexistent ab_gp_channel_io.c.
- RBC_GP main.c:93-97 lists setup steps 10-11 the body no longer calls.
- RBC_GP common_config.h:93-103,151-162 say AB_SAMPLE goes out only on fresh-data cycles, but post_execute stages it every ONLINE cycle.
- RBC_GP ab_gp_startup_timestamp.h:126 cites REQ-SITEROLE-014 for the tie-break (wrong REQ).
- Platform_RTE rte_dual_negotiator.c:13 still cites site.c.
- RBC_GP post_execute.c:56 hard-codes "size=343".
- G2: per-cycle output permission to an FSOU seam (IF-SCP-02/03). The proof of concept assumes no hardware output cut-off unit: 2oo2 output agreement is software-only (RTE checkpoint). Next: set ADR-041 to Rejected and decide whether the unused rte_fsou_* seam is deleted or kept for a platform variant with an FSOU. The sub-items below apply only if such a variant is ever tested.
- (FSOU variant only) accept ADR-041 (Platform_RTE docs/architecture/ADR-041-fsou-output-permission.dox, status Proposed) and settle its four open points: (1) hook point - rte_fsou_grant() inside rte_channel_checkpoint() or a separate rte_fsou_* call from the cycle driver; (2) grant window length vs cycle time, and whether cycle_id is the checkpoint ID or the application cycle counter; (3) outputs / grant while STANDBY; (4) escalation on a failed grant or revoke (safe-state reason, REBOOT). Not for the pipeline to decide; skip the items below until this is done.
- Platform_RTE: the checkpoint calls grant only after both channels agreed in the cycle; a fault flush or safe state calls revoke; rte_fsou_report_presence() called once at init. Waits for owner acceptance of ADR-041 (blocked item above). The seam itself (rte_osadapter_fsou_t, rte_fsou_*, REQ-FSOU-001..003) is done (G2.1) and has no caller yet.
- Platform_OS_POSIX: simulated FSOU - logs grant/revoke and counts a missing grant per cycle window; a unit test plus a Docker check that every ONLINE cycle is granted.
- G3: RBC_GP uses only PI API flows (no direct rte_netlink / rte_voter / rte_cross_comparator). Same work as the DDS items under Platform (RCA/OCORA) and Phase 2b (transparent voting under rte_flow).
- Inventory every direct call in RBC_GP and map it to an rte_flow operation; gaps go to an ADR.
- Peer and site links through rte_flow routes (done together with G1 step 5).
- Cross-compare / vote behind the flow (Phase 2b); then remove the direct includes from GP.
- G4: Platform_OS_POSIX against the OSA rules (docs/OSA_RULES_AUDIT.dox in that product). Audited, two bugs fixed, items 1-4, 6a-6d, 6e-1, 6e-2a, 6f, 7a, 7b-1 and 8 done (creation after init gated and reported, RT attributes reported, mutex PI mandatory, timed mutex lock, memory-pool lock bounded, task- and timer-thread attributes set before creation, socket open non-blocking, socket contract REQ-OAL-SOCKET-001/002 in Platform_RTE, IPC queue_depth enforced with whole messages, IPC/netlink waits above INT_MAX ms capped, socket buffer sizes configurable and checked, buffer sizes parsed from the redundancy JSON and the Gateway JSON, a listen-role channel-service send with no peer returns RTE_STATUS_NOT_CONNECTED and the Gateways treat it like OK, every timer/task thread joined, timer/task threads paced by an absolute CLOCK_MONOTONIC deadline on every host with a clock failure reported, a stop/suspend/destroy wakes the sleeping timer/task thread).
- Blocked - owner decision: timer-thread priority for vital timers (OSA R1, follow-up of item 4). Timer threads now copy the scheduling of the thread that calls rte_timer_start() (adapter-level, 4b), so the A/B cycle timer's priority is the starting thread's priority, not a declared value. Whether "creator's
priority" satisfies R1 "static priority" for a vital timer is a safety-owner call. Options: (1) keep the creator copy (current); (2) add a per-timer priority/stack_size field to rte_timer_config_t (Platform_RTE interface change, SRS + ADR-018 update). Not for the pipeline to decide. Note: the Linux Docker containers run without CAP_SYS_NICE, so the Docker gate never exercises real-time priority; a target needs the capability.
- Blocked - owner decision (2026-10-04): RBC_GP A/B reaction to a redundancy config that fails to load (ISS-024; blocks 6e-3 and the ISS-025 fix). Today any load failure silently falls back to defaults. Reviewer recommendation: absent file -> defaults; file present but invalid (incl. too large) -> fail start-up, same posture as NOT_SUPPORTED (ab_gp_channel.c:549-554); needs rte_redundancy_config_load() to give "file not openable" its own status (today fopen failure and "file too large" are both INTERNAL_ERROR). Vital A/B start-up path; owner/safety call, not for the pipeline to decide.
- Item 5, no DNS in operation (R4): resolve once and cache. Needs the startup-ordering answer of ISS-009 first. Blocked (2026-10-03):** how does a vital process get its peers' addresses when a peer is not resolvable at startup (channel-service lazy re-init and netlink reconnect both call getaddrinfo after init today)? Options: (1) numeric IPs in the redundancy/channel config, no resolver in operation (target-like; Docker compose then needs static addresses); (2) resolve during a bounded setup phase, cache, and treat a failure as a startup fault (changes RBC_GP main.c startup and the ISS-009 restart pattern); (3) cache after the first success, re-resolve only on a reconnect (keeps DNS in operation for reconnects, does not meet R4). Recommendation: (1), with (2) as the container fallback. Owner/safety call; skip until settled.
- Item 6, IPC and sockets (R5): socket buffer sizes from config, specific status for a dropped listen-role send. (6a, O_NONBLOCK at open in posix_socket_open(); 6b, socket contract in the Platform_RTE SRS with checked set_nonblocking in the UDP/TCP ProtocolAdapters; 6c, IPC queue_depth enforced with whole messages of at most PIPE_BUF, and its follow-up, shared posix_remaining_ms() capped at INT_MAX; 6d, optional rcvbuf_bytes/sndbuf_bytes in rte_netlink_config_t (REQ-OAL-NETLINK-015) applied and checked by the POSIX netlink and channel-service sockets; 6f, RTE_STATUS_NOT_CONNECTED for a listen-role send with no peer, REQ-CHANSVC-001; done. Left: 6e-2/6e-3, blocked below.)
- 6e (after 6d): set rcvbuf_bytes/sndbuf_bytes from the RBC_GP A/B and Gateway JSON config (ab_gp_config.c, gateway_c_config.c, etc/config/*.json) and RBC_GA gateways if they parse links; values sized from the link message size and depth, below the Docker rmem_max. Planned 2026-10-03 as three steps, each gated alone (unit tests, Docker --full, smoke.sh); RBC_GA needs no change (its rte_gateway_c_il/_ctc resolve links through RBC_GP's gateway_c_common.c / gateway_c_config.c, it has no link parser of its own). 6e-1 done (Platform_RTE rte_channel_def_t carries optional rcvbuf_bytes/sndbuf_bytes, checked parse, REQ-REDCFG-001). 6e-2a done (RBC_GP Gateway JSON reads optional per-channel rcvbuf_bytes/sndbuf_bytes with a checked parse and passes them to the POSIX channel service; A/B not touched).
- Blocked - owner decision (2026-10-04): A/B scope of 6e. RBC_GP A/B open their links through the flow OSAdapter over the DDS protocol adapter with a resolver (ab_gp_channel.c:647-655); every A/B channel (ab-peer, ab-crosscompare, ab-relay-*) goes through resolve_channel_flow() -> rte_channel_service_flow_osadapter (ensure_open() builds a rte_flow_config_t from name/oflags/message_size/timeout only) -> Platform_Protocol_DDS dds_open() (buffers 0), so sizes copied into rte_netlink_config_t by the A/B resolver do not reach the A/B links. Options: (1) carry the sizes through rte_flow_config_t / the DDS route (Platform_RTE interface change), then 6e-2; (2) reduce 6e to the Gateway (done in 6e-2a) and drop 6e-2. Not for the pipeline to decide.
- 6e-2 (RBC_GP, vital A/B resolver; waits for the A/B scope choice above - only useful with option (1)): copy the fields into rte_netlink_config_t in every A/B resolution path - ab_gp_channel.c try_resolve_from_redundancy_config(), the legacy .conf path (ab_gp_config.c apply_channel_setting() keys rcvbuf_bytes/sndbuf_bytes, ab_gp_config_find_channel() and _by_id(), ab_gp_config.h); the hardcoded fallbacks stay 0. Unit tests per path (values reach the resolved config; absent -> 0). Still no shipped config sets them.
- 6e-3: set the values in application/RBC_GP/etc/config/{a,b}_{west,east}.json, c_{west,east}.json (and the .conf files if still loaded anywhere), sized from message_size x the queue depth each link needs, below the Docker net.core.rmem_max/wmem_max; Docker check that no "socket buffer size capped" report appears in any A/B/C log, and smoke.sh on macOS. Blocked: the A/B half on ISS-024 (A/B silently fall back to the default redundancy config when the load fails, so a malformed value in one A/B file would go unnoticed and diverge A from B); the Gateway half (c_{west,east}.json) on ISS-026 (a Gateway config load failure leaves a half-filled channel active and is silently ignored).
- Follow-up of the 6f-1 doc notes: Platform_RTE SRS backfill for the traceability gaps recorded in SRS section 4. 6g-1, 6g-2a, 6g-2b, 6g-3, 6g-4a, 6g-4b and 6g-4c done (include-only 0; SRS-only 14 = the 13 documented exceptions REQ-OAL-BACKEND-001..003, REQ-APPMANAGER-008, REQ-RBC-001..009, plus the open gap REQ-APPMANAGER-013, ISS-031). Optional: a script that fails on a mismatch.
- 6g-4 (doc/contract follow-ups from the 6g-2b review, Platform_RTE comments + SRS, plus one RBC_GP and one Platform_OS_POSIX comment): gate as 6g-2b (configure + build + ctest Debug, comment-strip identity, REQ recount, doxygen warnings not above HEAD). Planned 2026-10-04 as steps each gated alone; 6g-4a (contract text: @return lists + SRS), 6g-4b (stale rationale, old product names and dead links in public headers), 6g-4c (SRS contract follow-ups), 6g-4e (REQ-RBC-007 wording), 6g-4f (post-lock test for rte_mutex_create / rte_mem_pool_create) and 6g-4h (post-lock test for the 13 OAL rte_osadapter_<service>_register() functions), 6g-4i (ISS-034 note on the rr/pubsub stub constructors in REQ-LIFECYCLE-001/-003) and 6g-4j (ADR-024 test guard for test_rte_lifecycle_osa_gates) done. Left: 6g-4g (blocked on owner) and optional 6g-4d (old-name sweep in src/, tests/, cmake/, CMakeLists.txt, RBC_GP comments).
- 6g-4g (owner decision, Blocked on owner; seen 2026-10-04, 6g-4f): the rr/pubsub IPC stub sources do not compile while their public headers are installed (ISSUES.dox ISS-034). Decide: implement them and wire them into a library target (then add tests/lifecycle/test_rte_lifecycle_ipc_stub_gates.c: after the lock rte_ipc_rr_server_create, rte_ipc_rr_client_create, rte_ipc_pubsub_topic_create each return RTE_STATUS_INVALID_STATE with one DEGRADED / SETUP_AFTER_INIT report), or remove the sources, the headers and their SRS mentions. The SRS rows REQ-LIFECYCLE-001/-003 now carry an ISS-034 note (6g-4i). Also consider when deciding: ADR-032-setup-phase-lock-coverage-extended.dox:66,113 names the three constructors too (dated design record).
- Optional (6g-4c review): channel_ab_* names remain in the historical ADR-025; leave as history unless the owner wants a dated note.
- 6g-4d (optional; comments only, gate: build + ctest, comment-strip identity vs HEAD, doxygen warnings not above HEAD): old product names / TODO.md in Platform_RTE src/, tests/, cmake/, CMakeLists.txt comments (~35 lines). Separately optional: the ~66 old-name comment lines in RBC_GP src/ / include/ (git grep -E "safeAPI|Freamwork" -- src include). Also seen in the 6g-4b review (comments only): RBC_GP common_config.h:798-803 describes encode_extra_payload() / decode_extra_payload(), which no longer exist; RBC_GP ab_gp_channel_util.c:10 names a nonexistent ab_gp_channel_io.c; optionally a note at the HOT enum value in Platform_RTE rte_redundancy_config.h that GP's HOT is a snapshot sync and does not match the generic HOT definition.
- 6g-5 (seen 2026-10-04, 6g-3 verification; RBC_GP comments + Platform_RTE SRS note, gate as 6g-3): 6g-5a (REQ-RBC-005 tags in RBC_GP ab_gp_saf_train.c / ab_gp_db.c and the SRS 3h file list) done. Left: optional 6g-5b.
- 6g-5b (optional, RBC_GA comments + SRS note): REQ-RBC-009 comment at the sim-channel set-up in gateway_c_il_handler.c:70 and gateway_c_ctc_handler.c:54, and change the SRS 3h note sentence "RBC_GA's IL and CTC Gateway handlers ... carry no tag" to list them. Gate: RBC_GA build + ctest, comment-strip identity, Platform_RTE doxygen warnings not above HEAD.
- 6g-6b (optional design item, seen 2026-10-04, 6g-6a): re-introduce a cycle-counter resync on A/B peer-link reconnect (behaviour change, own design: which side resets its cycle number, interplay with the relaxed checkpoint window and the cross-compare skew skips). Until then a peer reboot relies on the 60-skip REBOOT in ab_gp_channel_crosscompare.c.
- 6g-7 (seen 2026-10-04, 6g-5a review; RBC_GP vital code, each step with the full gate: unit tests, -Werror, Docker --full suite, smoke.sh): untested, unreachable public API in vital code (EN 50128). 6g-7a (the three uncalled ab_gp_db_train_* accessors removed from ab_gp_db.{h,c}) done. Left:
- 6g-7b (seen 2026-10-04, 6g-7a): remove the uncalled ab_gp_train_find_by_nid_engine(), ab_gp_train_get_nid_engine() and ab_gp_train_set_nid_engine() (ab_gp_train.{h,c}; definitions at ab_gp_train.c:441,468,488, declarations at ab_gp_train.h:368,376,390, and the header comment at ab_gp_train.h:22 names _find_by_nid_engine()). Recheck for callers first. The nid_engine field itself is live: written in ab_gp_train_add(), read by nid_engine_connected_elsewhere(). Recheck MISRA and doxygen.
- 6g-7c (seen 2026-10-04, 6g-7a planning): the DB nid_engine field (ab_gp_db_train_t, ab_gp_db.h:100) lost its ab_gp_db setter in 6g-7a. The planning note said nothing but the snapshot decode writes it any more; seen while committing: ab_gp_train_add() writes it through the DB slot (ab_gp_train.c:393, slot->nid_engine = nid_engine), so first confirm whether a writer is missing at all. Only if one is: decide to remove the field (changes the A/B snapshot layout) or wire a writer.
- Optional, small (6f-2 review): drop the redundant rte::core rte::oal from the link list of RBC_GP tests/posix_osadapter/test_rte_posix_osadapter_channel_service_listen.c in tests/CMakeLists.txt (extra ld duplicate-library warning).
- Optional follow-ups of 6c (review notes 2026-10-03, small, not blockers): (a) range-check connect_timeout_ms in RBC_GP config (ab_gp_config.c:201 (uint32_t)strtoul: a hand-written -1 becomes UINT32_MAX and now blocks up to 24.8 days per open attempt); (b) optionally move posix_remaining_ms() from rte_posix_osadapter_poll.h to its own header included only by ipc.c/netlink.c, so rte_posix_osadapter_socket.c does not pick up the new MISRA 21.10 (<time.h>) finding; (c) negotiation send TIMEOUT count was 263 in results-20261003-221141-13901 vs 150-190 before (accepted as variance): re-run only the partition/cold-switch suites twice once the sim images are current (ISS-023).
- Item 7, bounded shutdown (R2): bounded wait instead of pthread_join in suspend/stop. (7a, every created timer/task thread joined incl. a finished one-shot timer / run-once task, joinable written by the controlling thread only, self-stop / self-start detected through thread-specific data; done.)
- 7b: bounded stop - wait for exit with a deadline, and decide the status and safe-state reaction when the deadline passes (rte_timer_stop/rte_task_suspend @return list in Platform_RTE today has no TIMEOUT: interface + SRS change). (7b-1, a stop/suspend/destroy wakes the sleeping timer or periodic task thread through a process-wide PI mutex + condvar; done.) Also from the 7a review:
- Self-destroy + storage reuse: a callback destroys its own timer, then rte_*_create on the same storage memsets should_stop/joinable while the old thread is still in its callback -> it keeps looping and is never joined. Owner decides: NOT_SUPPORTED-after-stop on self-destroy, or document "storage not
reusable until a stop/destroy from another thread has returned".
- Add RTE_STATUS_INTERNAL_ERROR to the @return lists and the SRS for rte_timer_create/start/stop/destroy and rte_task_create/start/suspend/destroy (create returns it on a thread-key failure; stop/suspend/destroy on a join failure) - together with the planned TIMEOUT interface change.
- Dedicated safe-state reason code for the thread-specific-data mark failure and the monotonic-clock failure of item 8 (today both DEGRADED / RTE_SAFESTATE_REASON_OSA_RT_ATTRIBUTE + watchdog), or a stronger posture (e.g. start waits for the mark).
- 7b-2 (needs the owner decision named in 7b above: status and safe-state reaction when the join deadline passes, TIMEOUT in the @return lists + SRS): bounded join for a callback / entry that does not return.
- Item 9, logging (R2): fixed-size ring drained by a low-priority thread created at init.
- G5: RBC_GA adaptation points (KONF, RUCH, SRK, CMI) and the PKP PLK modules of RBC_GA_NCBIR.
- G6: scope the modelled GP functions not yet built (TSR, text messages, level transitions, emergency and MA shortening, RBC-RBC handover, SW update).
- G7: IF-01 and IF-AI-01..03 for RBC_TrainCommServer and RBC_AI_Diagnostic_Server.
Platform (RCA/OCORA)
- Real DDS wire protocol inside Platform_Protocol_DDS (CycloneDDS, Apache 2.0, C99-friendly): IDL and topic definitions for the A/B peer and site-negotiation links, replacing the stub's rte_netlink delegation with real pub/sub (this also removes the "one peer per name" limitation).
- Wire the DDS adapter into RBC_GP/RBC_GA: no route is registered for the real ab-peer / ab-negotiate names, and GP still calls rte_netlink, rte_voter and rte_cross_comparator directly (see the DDS product's CLAUDE.md).
- Safe communication for the RBC (REQ-SC-001..005): status/plan/blockers in docs/architecture/SAFE_COMM_INTEGRATION.dox — keep that current, not here. Plan step 3's first increment (train link terminated in A/B, off by default) and step 2 for the train sim (scenario suites pass with RTE_SAFECOMM_TRAIN_RBC_ID set) are done; next: step 1 (official Subset-037/076/098 vectors).
- Platform_RTE build-config hygiene (seen 2026-10-03, G2.1 review): a build with -DRTE_ENABLE_LOG=OFF does not link - src/oal/osadapter/rte_osadapter.c calls every OAL *_register function unconditionally, so test_rte_osadapter and the new tests/fsou tests fail to link (already so before G2.1; test_rte_lifecycle_osa_gates is guarded by its modules since 6g-4j). Guard the registration per enabled module or make the options consistent, and build the LOG-off configuration once to check.
- Platform_RTE @return completeness (seen 2026-10-03, G4.6c doc review; docs/comments only): document RTE_STATUS_INVALID_STATE (setup phase locked, ADR-026) in the @return of every lifecycle-gated OAL facade function - the callers of rte_lifecycle_check_setup_allowed(): task, timer, memory, log, nvm, netlink, clocksync, reboot, platform, random, ipc_pubsub, ipc_request_reply, ... Trace each facade's gated functions in source; not every function of a module is setup-only. Only rte_mutex.h, rte_fsou.h and rte_ipc.h document it today.
- Hot/warm standby: standby_mode accepted but not acted on in ab_gp_channel_negotiate.c. Design investigation done (2026-09-24), no vital code changed** — see RBC_GP's own docs/HOT_STANDBY_DESIGN.dox. Promising finding: STANDBY already receives every train/IL/CTC envelope Gateway relays (it discards them unprocessed at one gate in on_relay_envelope_received()), so the missing piece is "stop discarding, run the same
computation ONLINE runs" rather than a new data feed. Deliberately stopped at a design doc, not a patch: this reaches into SIL 4-target vital computation (ab_gp_logic.c/ab_gp_proc_*.c) and the design doc's own "Open questions" section (is that computation free of side effects beyond its own returned state? cycle timing budget running it twice?) needs a real audit, ideally a second reviewer, before any code changes.
- N-channel topologies (2oo3+): scoped in Platform_RTE's docs/architecture/ADR-039-n-channel-topology-primitives.dox. Step 2 fully done (2026-09-24)**: rte_election (N-way election, additive - no existing 2oo2 code path touched or even aware it exists) and rte_voter_vote_buffers() (N-way cross-compare, matching rte_cross_comparator_execute_buffers()'s own buffer-based shape). ctest 36/36 in both Debug and Release for both. Still not done: GP actually selecting either for a 2oo3/NMR topology (step 1 - neither has a caller yet, and both need a per-cycle N-way transport decision GP would own, left open on purpose), and a third-replica RBC_Test_Env scenario (step 4) to verify any of it against.
RBC_GP: new Gateway-hosted products (2026-09-22)
Not started. All of these are non-vital role-C functions, to be implemented as part of application/RBC_GP's Gateway (same process family as the existing status/gateway_c components), each its own module/interface:
- RBC Maintenance Web Server: v1 done (2026-09-23) - status view, see product's own README.md. SW update done (2026-09-27, application/RBC_Maintenance_Web's own CLAUDE.md/README.md/SRS.dox)**: opt-in mTLS (client-certificate auth) + Ed25519-signed upload/activate, restricted by a fixed allow-list to the four non-vital role-C binaries (rte_gateway_c_train/_il/_ctc/_status) - never the vital A/B binaries, deliberately out of scope. Two CTest suites plus a real end-to-end check against the actual rte_gateway_c_status binary. Not done: provisioning the mTLS PKI (issuing/rotating operator certificates) and the Ed25519 signing key are operational concerns, deliberately left out - see that product's own README.md "Out of scope, by design".
- services/RBC_TrainCommServer (placeholder repo created 2026-09-23, no code yet - see that product's own README.md/CLAUDE.md): the missing link in RBC_GP -> SafeComm -> RBC_TrainCommServer -> GSM-R ISDN/FRMCS. Installed on its own dedicated server (not in the RBC_GP/Gateway process family), communicates with the RBC via the Gateway. Distinct from test/RBC_Test_CommServer (that one is explicitly a *non-vital customer-network access point stub*** for testing); this would be the real ISDN/FRMCS- facing product. Needs its own scoping pass (what does "communicates via the Gateway" mean concretely - a new relay/util topic like JRU/KM114's, or something else; what does FRMCS actually require) before any implementation starts.
- services/RBC_AI_Diagnostic_Server (**placeholder repo created 2026-09-23, no code yet - see that product's own README.md/CLAUDE.md): its own dedicated server, collects logs from the RBC and RBC_TrainCommServer (above) and uses AI models to analyse them for potential issues. Likely relationship to existing work: could be a natural consumer of Platform_Protocol_JRU's own RFC 5424 syslog stream (already the workspace's chosen external-log-event format) rather than a third parallel log-collection mechanism, but that is a design decision for its own scoping pass, not assumed here.
Quality and safety (from safety_quality/REVIEW_2026-09-21.dox)
- MISRA compliance reports for RBC_GP, RBC_GA, Platform_OS_POSIX: all three now have a cppcheck --addon=misra screening* pass (docs/MISRA_COMPLIANCE_REPORT.dox in each — 1241/192/605 rule-number findings respectively, correctly scoped to each project's own source). Still needs the licensed rule text (or a licensed tool) to turn that into a real, individually-reviewed compliance verdict — every current finding is a rule number and a location only, not a confirmed violation.
Test environment
- ISS-012 (ISSUES.dox): RBC_GP smoke.sh failover phase. ISS-020 is fixed (UTIL open gate); what remains is B/WEST stalling 5.3-7.1 s twice per failover phase on CHECKPOINT_REQUEST retries inside the relaxed start-up checkpoint budget (RTE_EXAMPLE_AB_CHECKPOINT_RELAXED_MAX_DELAY_MS 10000, first 15 s), because smoke fault-injects A/WEST at cycle 10 and it reboots inside that window. Close ISS-012 once smoke passes both phases 3/3 with no "stalled ... while ONLINE" line.
- Next step (planner): decide whether smoke's fault injection should move after the relaxed checkpoint window (test change), or whether the relaxed-budget stall is a product issue (vital RBC_GP; may need owner input if it touches the checkpoint budget design).
- Docker Robot test for KM114 over UTIL with rte_gateway_c_status present: drop a KMC file and check A/B reassembly/decode. Today only ctest test_ab_gp_km114_client covers that path, and the ISS-020 UTIL open gate now gates it.
- railML: SW_E1 and the trigger balises of R_E_X1..X3_DN2 lie 80 m before those routes' start signals; confirm with the layout's author whether the signals or the switch are misplaced (doc/site_layout.svg shows it).
- CI: .github/workflows/test-env.yml (local suite per push, Docker suite nightly) nightly Docker job fails every night since 2026-09-27 (ISS-065); triage it from the run log. Needs the SUBMODULES_TOKEN secret.
- RBC_GP test hygiene (not vital): Linux gcc warns implicit declaration of function 'mkstemp' in application/RBC_GP/tests/gateway/test_ab_gp_takeover_key.c:131 (seen 2026-10-03, G4.3b Linux build); add the missing feature-test macro (_POSIX_C_SOURCE 200809L / _XOPEN_SOURCE) or include so the test builds clean.
- Docker image rebuild instructions (seen 2026-10-03, G4.3c verification): a plain docker compose build in test/RBC_Test_Env reports "No services to build" because every service sits in a profile. Fix test/RBC_Test_Env/doc/BUILD_GUIDE.dox (the docker compose build / up --build lines) and the gate steps in .claude/agents/todo-verifier.md and .claude/claude-ai-project-instructions.md to use docker compose --profile "*" build ... (or name the services / use setupDockerTestEnv.sh, which already builds named services).
- ISS-023 (ISSUES.dox): the Docker --full gate silently reuses stale simulator images when the sim image rebuild fails (Docker Hub python:3.12-slim timeouts). Label each sim image with the simcore git hash and make --full fail or warn when it does not match HEAD; and/or pin the base image by digest with a local mirror/cache so rebuilds do not depend on Docker Hub. Until fixed, verifier reports state the image dates.
Project weak-point review (2026-10-04)
Findings of a read-only review of the whole workspace. Defects are in ISSUES.dox (ISS-036 .. ISS-070); the items below are planned work and gaps. Vital first.
- Review defects, vital, fix in this order unless the owner says otherwise: ISS-049 (fail-open route validator), ISS-038, ISS-041, ISS-042, ISS-045, ISS-053, ISS-055, ISS-059, ISS-069. Confirm-first: ISS-040 (CRC-64 known-answer test), ISS-058 (channel build), ISS-062 (conan create), ISS-066 (Release run of test_rte_checkpoint). Owner decision needed: ISS-048, ISS-050 (scope), ISS-054, ISS-065 (CI for unpushed work), ISS-068, ISS-070, and ISS-049 (blocked below; ISS-036 step 1 merged 2026-10-06, Platform_RTE 2a0ccde, steps 2-3 still to plan; ISS-037 step 1 merged 2026-10-06, Platform_RTE 845df5f, raw-use follow-ups stay in ISSUES.dox; G1 steps 5a/5b-1/5b-2/5b-3a merged 2026-10-07 (Platform_RTE 384e6ae, RBC_GP 5d7fe44), Docker gate owed (see the G1 item above); the pipeline continues with G1 step 5b-3b; ISS-045 step 1 is deferred behind G1/G2, planned on todo/iss-045-posix-clock-deadline (Platform_OS_POSIX, no overlap with the queued branches; ISS-038/-041/-042 wait for the Platform_RTE SRS chain to merge).
- ISS-049 Blocked (2026-10-04): how does a train standing at a WEST station balise get its first route once the validator is default-deny? The fix direction ("a route with no balise is allowed only as an
extension of a route the train already holds") denies the first MA of the shipped scenarios: 16 Robot files set R_W_X1/X2/X3_UP1 (routes 4, 5, 6, balise_count = 0) as the first route of a train that reports balise 1001/1002/1003 (owned by routes 1, 2, 3 R_W_S*_X*) and holds no route; no scenario sets routes 1-3 (e.g. ma_tests/train_traverses_entire_track_layout.robot:94-122 expects CTC_MA_GRANTED seq 1). The EAST exit routes 11-13 (R_E_X*_DN2) carry their own balise (1009-1011) and are not affected. Options: (1) literal fix direction in validate_route_assignment(); rewrite the 16 scenarios so IL sets the station route R_W_S*_X* first (first MA on route 1-3, routes 4-6 become an extension; ma_seq and MA-length expectations change). (2) site data: give routes 4, 5, 6 a baliseNidLrbg in application/RBC_SA/etc/site/ab_site.railml.xml (the station balise 1001-1003 shared with routes 1-3, or a new balise past the exit signal), like routes 11-13; validator then denies every balise_count == 0 route unless it is an extension; scenarios unchanged if the shared balise is used. Vital site data; belongs with ISS-059 and the railML item under Test environment (layout author). (3) widen the validator rule: a no-balise route is also allowed when the train's last balise belongs to a route that ends at the candidate's start signal, held or not; no data or scenario change, but a vital rule beyond the ISS-049 fix direction. Recommendation: (2) with the shared station balise (data matches what the scenarios and Expected Remaining Length already assume, the validator rule stays the plain fix direction), then the validator change with unit tests as its own step. Independent of the choice and plannable once it is made: the :165 no-position return true becomes return false (GP's connect gate never calls the validator without a position, ab_gp_logic.c:72-85), the stale comment at :103-113, and a validator unit test in RBC_GP/tests/ through ab_gp_logic_connect_route_for_train(). Owner/safety call; not for the pipeline to decide.
- ISS-052 follow-up (doc only, RBC_GP docs/MISRA_COMPLIANCE_REPORT.dox Update 9): note that the new rte_types.h include brings five pre-existing Platform_RTE header findings (2.3 x1, 2.5 x3, 20.7 x1) into the ab_gp_standby_policy.c cppcheck run; they are not RBC_GP code (reviewer note, 2026-10-06).
- Pipeline: do not run host builds (Linux container builds, smoke rebuilds, the other lane's implementer builds) while a Docker --full run is in progress; macOS Docker containers starved by parallel builds trip the wall-clock watchdog (20 watchdog-timeout reboots in test/RBC_Test_Env/results-20261006-155554-81513/ vs 3 in the idle baseline; 7946 s vs 864 s). Options: nice -n 19 -j4 for lane-D builds, or serialise builds against the Docker gate (observed 2026-10-06, ISS-036 step 1 verification).
- Docs follow-up (reviewer, ISS-037 step 1, 2026-10-06): state the rte_checksum_crc64_init() precondition in rte_safechannel.h and rte_checkpoint.h (the dual facade now enforces it).
- ISS-045 step 1 (deferred behind G1/G2, owner priority 2026-10-06; vital path, low likelihood; Platform_OS_POSIX plus its RBC_GP-hosted tests; planned 2026-10-06; slug iss-045-posix-clock-deadline, branch todo/iss-045-posix-clock-deadline from master, no file in common with the two queued Platform_RTE branches): the netlink and channel-service OSAdapters stop using an unread timespec as a deadline or as "now" when clock_gettime(CLOCK_MONOTONIC) fails. Serves the ISS-045 fix direction ("return `INTERNAL_ERROR` and report, as the period code does"), OSA rule R3 of docs/OSA_RULES_AUDIT.dox ("a failed clock read is never used as time 0", already met by period.c, ipc.c, lock.c, timer.c) and Platform_RTE REQ-OAL-NETLINK-002/-003/-010..-012 (the bounds those requirements promise rest on a deadline that is now guaranteed to be a real clock value). No Platform_RTE interface, SRS or ABI change; no new status value (RTE_STATUS_INTERNAL_ERROR is already in every caller's non-OK handling: rte_dual_channel, rte_site_role, rte_channel_service, RBC_GP A/B and Gateway relay links).
- src/rte_posix_osadapter_netlink.c: compute_deadline() (:119) becomes static bool, the ipc.c pattern (rte_posix_osadapter_ipc.c:112): reads the clock into a local, adds the timeout and writes *out_deadline only on success; on failure writes nothing, logs one ERROR line ("RTE: clock_gettime(CLOCK_MONOTONIC) failed errno=d", the file's existing rte_log_write style) and returns false. Its six callers: open-listen (:205) and open-connect-UDP (:370, :371) on false close the socket, leave *out_handle and the storage unwritten and return RTE_STATUS_INTERNAL_ERROR; the in-loop re-HELLO deadline (:416) on false closes the socket and returns RTE_STATUS_INTERNAL_ERROR the same way (the handshake cannot continue without a clock); send (:544) and receive (:617) on false return RTE_STATUS_INTERNAL_ERROR before any poll(), send() or recv() (nothing sent, nothing consumed, the link kept). posix_remaining_ms() (rte_posix_osadapter_poll.h:40) already returns -1 on a failed read and is out of scope. Single exit point where the function already has one; no new includes. Update the file header's error-handling note and the three function comments.
- src/rte_posix_osadapter_channel_service.c: channel_now_ms() (:44) becomes static bool channel_now_ms(uint64_t *out_ms): writes *out_ms only when the read succeeds, else logs the same ERROR line and returns false. Its one caller, the connect-role branch of the receive (:323), on false returns RTE_STATUS_INTERNAL_ERROR before the HELLO/re-HELLO decision and before recv() (last_rx_ms, last_hello_ms, has_peer_addr untouched; the datagram, if any, stays queued for the next call). The listen-role branch reads no clock and is unchanged.
- docs/OSA_RULES_AUDIT.dox: R3 row adds "netlink and channel-service deadlines / re-HELLO time: a failed
<tt>CLOCK_MONOTONIC</tt> read is reported (one ERROR log) and the call returns <tt>RTE_STATUS_INTERNAL_ERROR</tt>, never
used as time 0, since 2026-10-06 (ISS-045, see "Fixed")"; a dated "Fixed" entry in the style of the item 7 b-1 entry (what was wrong, the two helpers, the per-caller outcome, "no Platform_RTE interface change"). docs/MISRA_COMPLIANCE_REPORT.dox: a dated entry only if the cppcheck screen of the two files shows a new finding.
- RBC_GP tests/posix_osadapter/test_rte_posix_osadapter_clock_refused.c (new, Linux only like test_rte_posix_osadapter_period_clock: GNU ld -Wl,--wrap=clock_gettime; macOS ld64 has no --wrap) and tests/CMakeLists.txt (an if(CMAKE_SYSTEM_NAME STREQUAL "Linux") block next to the period_clock one, linking rte::posix_osadapter rte::core rte::oal rte::channels, with a header comment naming ISS-045 and OSA rule R3). The wrap refuses every CLOCK_MONOTONIC read while a flag is armed (returns -1, errno =
EINVAL, counts refusals; other clock ids and an unarmed state pass through to __real_clock_gettime); the test arms it around exactly one adapter call and disarms after, so a log timestamp or another helper read inside the call cannot leak a one-shot refusal past the deadline read. Loopback UDP pairs on fixed test ports of their own (pattern: test_rte_posix_osadapter_netlink_restart.c, test_rte_posix_osadapter_channel_service_listen.c). Cases: (1) rte_netlink_open() in each role with the clock refused -> RTE_STATUS_INTERNAL_ERROR, *out_handle == NULL, refusals >= 1, and a following open with the real clock on the same ports succeeds (the socket was closed, the port is free); (2) a connected pair: rte_netlink_send() with the clock refused -> RTE_STATUS_INTERNAL_ERROR and the peer's receive (real clock, short timeout) -> RTE_STATUS_TIMEOUT (nothing was sent); (3) one message sent with the real clock, then the peer's rte_netlink_receive() with the clock refused -> RTE_STATUS_INTERNAL_ERROR, and the same receive with the real clock -> RTE_STATUS_OK with that message (nothing consumed); (4) a channel-service connect/listen pair through rte_channel_service_*: the connect-role receive with the clock refused -> RTE_STATUS_INTERNAL_ERROR, then with the real clock the HELLO/ack exchange and a PING/PONG round trip work as in the listen test (state untouched); (5) with the wrap unarmed the whole file's refusal counter is 0 at the end (no stray refusal).
- After the gate passes: delete the ISS-045 entry from ISSUES.dox (fix and reason in the commit message), delete this sub-item, bump the Platform_OS_POSIX and RBC_GP pointers and run ./syncProductDocs.sh at the root.
- Verify: Platform_OS_POSIX cmake -S . -B build && cmake --build build -j8 with no warning (-Werror build); cppcheck --enable=all --addon=misra --std=c99 -I include src/rte_posix_osadapter_netlink.c
src/rte_posix_osadapter_channel_service.c against the master baseline; RBC_GP on the bench rebuilds against the Platform_OS_POSIX source (cmake --build build -j8 + ctest --test-dir build; macOS: the existing test_rte_posix_osadapter_* and A/B tests unchanged, the new test not built); the new test runs on Linux (the RBC Docker image build or a Linux host: ctest --test-dir build -R
test_rte_posix_osadapter_clock_refused); vital path (A/B netlink, Gateway relay), so the clean Docker suite (setupDockerTestEnv.sh stop, rebuild the RBC image, start, runTests.sh --env docker --full) and application/RBC_GP/.claude/skills/run-RBC_GP/smoke.sh (no clock_gettime ERROR line in any log: the clock never fails on the bench; A/B and relay links behave as before).
- ISS-051 follow-up (not vital, after step 1): the Gateway services use the same unsynchronised count (C/gateway_c_common.c:178 cycle_ticks++ in the timer callback against :304-314 test and cycle_ticks--; gateway_c_types.h:66). A lost update there only shifts a relay cycle. Reuse ab_gp_cycle_ticks (move it to AB/common if the Gateway targets cannot include AB/GP/com) with a take-one variant, or record in ISSUES.dox if it is left.
- ISS-051 step 1 follow-up (vital code, low; reviewer note, non-blocking): a failed ab_gp_cycle_ticks_take() in ab_gp_channel_wait_cycle_tick() (com/ab_gp_channel.c) is returned to pre_execute at once, without the 10 ms sleep of the wait loop. A take that stays non-OK would spin the appmanager loop unpaced, one ERROR log per iteration (no reachable path found in review; a single lock TIMEOUT is rare: unit test 2 of 50 runs on Linux, 5 of 300 on macOS, none in Docker or smoke). And a lock TIMEOUT cannot be told from the no-tick watchdog TIMEOUT in the log. Pace the failure path (sleep, or a bounded retry count before the status is returned) and log a distinguishable status or text for the failed take; unit test for the paced path.
- RBC_GP / RBC_GA unit-test backfill (EN 50128 component test). No test references today: ab_gp_proc_dispatch_train_inbound, ab_gp_train_apply_envelope / _build_outputs, ab_gp_db_encode / _decode / _route_connect_train, ab_gp_logic_connect_route*, ab_gp_channel_stage_* / _commit_pending_sends, ab_gp_channel_crosscompare_execute, ab_gp_channel_checkpoint_backend_recv, ab_gp_channel_payload_decode_ab_sample, ab_ga_il_apply_envelope, ab_ga_il_on_route_context_changed, validate_route_assignment, ab_gp_build_ctc_alarm, ab_gp_km114_relay_on_frame. RBC_GA tests are all hosted in RBC_GP. One module per step, negative cases included; ISS-049 and ISS-053 bring ready test cases.
- RBC_GA CTC latch rule has no requirement: no REQ tag / SRS row covers "<tt>CTC_CONNECTED</tt> once and
<tt>CTC_MA_GRANTED</tt> first, then <tt>CTC_MA_EXTENDED</tt>, per session, latched when the output is confirmed forwarded
to C" (ab_ga_ctc.c, ab_ga_ctc_confirm_outputs_sent(), test RBC_GP/tests/ctc/test_ab_ga_ctc_outputs.c). Add the SRS row and tag code and test (reviewer note on the ISS-047 fix, 2026-10-04).
- RBC_GP unreachable vital API (extends G4 6g-7 to a sweep; remove, or wire and test under G6). No callers in src/: ab_gp_ertms_trigger_emergency_stop, _revoke_emergency_stop, _request_shunting, _authorize_shunting, _terminate_mission, _add_tsr, _send_text_message, _announce_handover, ab_gp_proc_position_has_exceeded_ma, _is_train_in_route, ab_gp_proc_ma_shorten, ab_gp_channel_stage_peer. The codec decodes Msg 130/147/150 but the dispatcher rejects them as unknown (ab_gp_proc_dispatch.c:476). Consequence to record in the SRS: the RBC does not supervise MA overrun and cannot issue an emergency stop.
- Platform_OS_POSIX has no test suite of its own: no tests/, no add_test, yet README.md:36-41 says to run ctest --test-dir build. All 18 tests live in application/RBC_GP/tests/posix_osadapter/. Move them into the product (RBC_GP consumes them), or record the reason and correct the README.
- Platform_Protocol_SafeComm: the initiator nonce RA comes from a fixed-seed LCG inside the vital library (src/saf/saf.c:84-100,266; same RA after every restart). Add a frame-driven initiator API that takes RA from rte_random_fill(), move the LCG to test code. Needed before any RBC-RBC initiator use.
- Platform_Protocol_KM114 / KM038: tests are not in any gate (RBC_GP/CMakeLists.txt:333 forces KM114_BUILD_TESTS OFF, CI builds neither); no CBC-MAC known-answer test; parse functions fill outputs before MAC verification (km114.c:370/380, 479/491, 717-737, every km038_parse_*); header length, version, auth_algo, E-ALGO not validated (km114.c:117, :469); key schedules and the KTRANS stack copy not zeroised (des3.c:240, ab_gp_km114_client.c:102); negative parse tests missing. (Sub-review, not re-verified.)
- CI covers less than the safety plan claims: build-test.yml:66-74 runs cppcheck on RBC_GP/GA only, with no --addon=misra; no ASan/UBSan, Valgrind or gcovr job (SAFETY_AND_QUALITY_PLAN.dox:98); SafeComm, JRU, KM114, KM038, RBC_Maintenance_Web and RBC_Test_CommServer tests never run; only Sim_Core pytest runs (Sim_Train / IL / CTC tests/ do not). Add per-product ctest matrix steps, a MISRA-count check against a committed baseline, one sanitizer job, pytest for all four simulators.
- Pipeline gate cannot see a regression in the flaky class ("known and passing on re-run = note it", .claude/agents/todo-verifier.md:24-27). (a) Ledger script over the xunit.xml of every results directory giving a per-test failure rate, the gate compares against it; (b) a failed teardown restore fails or tags the causing test and the setup message names the predecessor (ContainerSupportFunctions.py:1011-1036); (c) setup does a bounded settle / restore before asserting (generalises ISS-030); (d) a periodic N-run or random-order run to find the culprits. Serves ISS-009 / ISS-022.
- Vital behaviour never exercised in Docker or CI: train-link SaF is off by default (docker-compose.yml:158, RTE_SAFECOMM_TRAIN_RBC_ID in no Robot file or gate); cross-compare fault injection (RTE_EXAMPLE_XCOMPARE_FAULT_CYCLE) only in macOS smoke.sh; no degraded-network tests (netem loss / delay / duplication / corruption); A and B always the same gcc image (see ISS-058); hot_standby_failover_retains_routes.robot excluded as not-implemented; nightly CI uses --no-destructive. Add a gate pass with SaF on, a Docker DISAGREE test, a netem suite, a mixed-compiler image variant.
- Wire-mirror checks are weaker than their names: sync_wire_catalog.py:54-61,114-115 extracts the Python ENVELOPE_SIZE and struct format and never compares them with C; :88 checks only that a kind value exists in the C enum; :122-123 duplicate return 1. tests/test_rbc_wire.py:28-56 pins 12 of 26 kinds. Unchecked literals: train_sim.py:198, rbc_messages.py:222, il_wire.py:20-22; rbc_wire.py:2 cites the gone rbc_wire.c. Fix: golden vectors (a C test dumps encoded frames per codec, pytest asserts byte equality); the script compares format, all kinds by name and the 512 size. The layout matches today (checked).
- Verification evidence is not traceable: a results directory holds no manifest of product SHAs, dirty state or image IDs, and the directories are gitignored (35 directories, 1.6 GB, one machine) while ISSUES.dox cites them. prepare_results_dir (_lib.sh:22) writes manifest.txt (root and submodule SHAs with dirty flag, image IDs and dates, compose environment such as the SaF switch); add a retention / archive rule.
- Pipeline: a PARTIAL commit's Docker-gate debt is reported only in chat (todo-committer.md:14-16). The committer adds a TODO item Docker gate owed: todo/<slug> and the planner picks it first when Docker is available. Also todo-committer.md:23 hardcodes a model name in the commit trailer. No debt outstanding today.
- Reproducibility: pin robot/requirements.txt (robotframework>=7.0), the sim Dockerfile's pip install --upgrade pip build, base images by digest (extends the ISS-023 fix) and the Doxygen version in docs.yml:53. syncProductDocs.sh:22,56-58 silently drops a product whose submodule directory is present but empty: make it fail, and add a CI check of mirror SHA against pointer.
- RBC_GP / RBC_GA / RBC_SA small items: RBC_GA/src/C/il/gateway_c_logctl.c:51-58 latches the applied level before the broadcast (A/B that start later never get it) and pre_execute.c:137 returns before the SET_LOG_LEVEL branch when not ONLINE (STANDBY A/B never apply it, against RBC_GP CLAUDE.md); gateway_c_train_handler.c:98-101 on TIMEOUT A gets the frame and B does not, with no log; RBC_GP/tests/CMakeLists.txt sets no warning flags on the 36 test targets; RBC_SA/CMakeLists.txt:127,142 build the site-data libraries without -Wconversion -Wshadow -Werror; RBC_SA/__pycache__/conanfile.cpython-314.pyc is tracked in git; main.c:400 returns version "3.0.0" while RBC_GP/VERSION is 0.1.0; post_execute.c:56 logs a hardcoded "size=343"; Platform_Protocol_DDS stub has no NULL checks in dds_send / dds_close / dds_getattr (src/rte_protocol_adapter_dds.c:131-180).
- Stale documentation sweep (doc only):
- Platform_RTE: rte_checksum.c:5 "ERTMS-compliant CRC-64-CCITT" against :43-48; rte_checksum.h:197-199,275,
322-327 examples use functions that do not exist; rte_safechannel.c:30-33,49-54 describes a connect retry the code does not make (:55), :124 hard-codes a 5000 ms send timeout; rte_watchdog.c:357 and rte_checksum.c:435 cite docs/COVERAGE_REPORT.md (now .dox).
- Platform_OS_POSIX: rte_posix_osadapter_nvm.c:11-16 calls the CRC-64 tables "known-incomplete placeholders"; CMakeLists.txt:60-72 still uses the old safeAPIFreamwork names (6g-4d covers Platform_RTE only).
- Platform_Protocol_SafeComm: saf.c:10-13 and docs/safety/SUBSET_MAPPING.dox:26 say SAI is "not implemented" against SUBSET_MAPPING.dox:34 and sai.c.
- Platform_Protocol_JRU CLAUDE.md: "nothing in this workspace calls it yet" (gateway_c_jru.cpp does).
- KM114 / KM038 CLAUDE.md place the products under platform/protocol_adapters/ and say "not implemented yet"; docs/architecture/OVERVIEW.dox:67,136 "no consumer yet"; RBC_GP CLAUDE.md "decode not yet wired".
- RBC_GA CLAUDE.md describes ab_siteGA.h as a reduced hand-synced projection (it is generated and full); ab_ga_ma_logic_adaptation.c:103-113 (see ISS-049); ab_ga_dispatch.h:40-52 @param sessions says the table goes to "the CTC output producer" only, but the CTC confirm callback now writes through it too; ab_ga_ctc.c:222 comment says "(MAX_TRAINS*2)", the real factor is * 3U.
- RBC_SA CLAUDE.md, README.md, etc/site/README.md: hand-synced route tables and wrong counts.
- RBC_GP: main.c:381, ab_gp_channel_crosscompare.c:29,452 name the nonexistent ab_gp_channel_io.c; stale comments in rbc_util_frame.h:19-20,66-69 and CMakeLists.txt:122-125,211,277-279,510.
- Root CLAUDE.md Conan table against reality (see ISS-062).