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.cpp decodes via ores::nats::default_wire_codec() instead of hardcoded rfl::json::read.
  • fx_spot_subscription's constructor gains an optional error_handler invoked on deserialisation failure, in addition to the existing WARN log.
  • FxSpotGridWindow::subscribe wires that callback to errorOccurred (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.

Emacs 29.3 (Org mode 9.6.15)