Task: Fix fx_spot_subscription hardcoded rfl::json, ignoring wire codec
Table of Contents
This page documents a task in the Make NATS wire format configurable: JSON/MessagePack, decided once at startup story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Switch fx_spot_subscription.cpp from a hardcoded rfl::json::read to
ores::nats::default_wire_codec().decode<T>(), matching the pattern
already used by crm_client.cpp, so FX spot ticks deserialise
correctly regardless of ORES_NATS_WIRE_FORMAT. Also surface
deserialisation failures to the UI instead of only logging a WARN
(add an error_handler callback wired to the existing
=errorOccurred=/status-bar mechanism), since a silently-failing stream
is otherwise invisible to the user.
Discovered during manual QA of an unrelated task (controller
decommission, sprint 24): under msgpack, FX Spot Monitor and
Cross-Rates Matrix showed no data at all, with the only signal a WARN
in ores.marketdata.client.fx_spot_subscription's log
(Failed to deserialise fx_spot_tick: ...).
Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Make NATS wire format configurable: JSON/MessagePack, decided once at startup |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-08-02 |
Acceptance
fx_spot_subscription.cppdecodes viaores::nats::default_wire_codec()instead of hardcodedrfl::json::read.fx_spot_subscription's constructor gains an optionalerror_handlerinvoked on deserialisation failure, in addition to the existing WARN log.FxSpotGridWindow::subscribewires that callback toerrorOccurred(status-bar message), so a wire-format mismatch or corrupt stream is visible to the user, not just the log.- Manually verified against a running msgpack environment: FX Spot Monitor and Cross-Rates Matrix receive live ticks with zero deserialisation-failure log lines.
Plan
Root cause: fx_spot_subscription.cpp was the one NATS-tick call site
missed by the wire-format migration story's sweep (it isn't a
service-to-service request_sync call, which is what that sweep
grepped for — it's a fire-and-forget subscription handler). Fixed by
switching to default_wire_codec().decode<T>(), following the
already-correct pattern in crm_client.cpp. Also added an
error_handler callback since the existing code only
logged a WARN on failure — invisible to a user with no server-log
access, and the actual symptom that made this bug hard to diagnose
during manual QA (grids just silently stayed empty).
Notes
Test Scenarios
Manual QA scenarios (scaffolded via compass add test_scenario, run
through the QA Validation Runner panel) that verify this task. Link
new ones here as they're created; the scenario doc itself links back
via its "Verifies task" field.
| Scenario | State | Notes |
|---|---|---|
PRs
| PR | Title |
|---|---|
| #1809 | [marketdata,qt] Fix fx_spot_subscription hardcoded rfl::json, ignoring wire codec |
Review
| # | Comment summary | File | Decision | Notes |
|---|---|---|---|---|
| 1 | FxSpotChartWindow uses the same fx_spot_subscription class but only reports subscribe failures, not per-tick decode failures | FxSpotChartWindow.cpp | Accepted | Wired the on_error callback the same way as FxSpotGridWindow, mirroring the pattern rather than deferring to a follow-up. |
| 2 | No dedicated unit test for the decode-failure -> on_error path | fx_spot_subscription_tests.cpp | Declined | Matches existing convention for this NATS-facing class (crm_client.cpp's equivalent decode path is also untested at this granularity); client isn't easily mockable. |
| 3 | default_wire_codec() called inline per-message instead of bound once, unlike crm_client.cpp | fx_spot_subscription.cpp | Declined | Cheap const& to a process-wide singleton; not a performance concern, purely stylistic. |
Result
Fixed fx_spot_subscription.cpp to decode via
ores::nats::default_wire_codec() instead of hardcoded
rfl::json::read, and added an error_handler callback wired to
FxSpotGridWindow's errorOccurred status-bar signal so
deserialisation failures are visible to the user, not just logged.
Verified manually against a running msgpack environment (FX Spot
Monitor and Cross-Rates Matrix receiving live ticks, zero
deserialisation-failure log lines after the fix) and locally: build
clean (linux-clang-debug-make), ctest 71/71 passed (100%).
Review round 1: also wired the on_error callback into
FxSpotChartWindow (same class of gap the reviewer flagged, mirrors
FxSpotGridWindow's wiring). Two minor style/test-coverage points
declined as consistent with existing project convention.