Task: Extend SyntheticBindingDialog to cover IR curve configs
Table of Contents
This page documents a task in the IR Rates synthetic data: dataset seeding, index cleanup, dual-curve, quoting conventions story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Discovered while manually verifying vintage-aware IR curve seeding
(task): ores_marketdata_feed_bindings_tbl is what makes the
marketdata service persist a synthetic feed's ticks as
market_observations (subscribing to synthetic.v1.tick.<source_name>
and republishing on the tenant-scoped stream) – without a binding, a
feed's ticks flow over NATS but are never stored, so there is no way
to inspect a curve's live/historical rate afterwards (e.g. via SQL, or
any screen backed by market_observations).
SyntheticBindingDialog (projects/ores.qt/marketdata/src/
SyntheticBindingDialog.cpp) is the existing manual tool for this –
it lists fx_spot_generation_config records and bulk-creates bindings
for the ones a user checks. It has no ir_curve_generation_config
equivalent at all: an IR curve feed's ticks can never be persisted,
even by hand, today. This story's own goal is bringing IR curve feeds
to FX's existing quality bar – this is one more gap in that parity.
Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | IR Rates synthetic data: dataset seeding, index cleanup, dual-curve, quoting conventions |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-07-27 |
Acceptance
SyntheticBindingDialog(or a sibling reachable the same way) listsir_curve_generation_configrecords alongside/instead of FX ones, with the same checklist-and-bulk-create-bindings behaviour, including pre-ticking rows that already have a binding.- After binding an IR curve feed and starting it, its ticks land in
ores_marketdata_market_observations_tblthe same way FX's already do – verifiable by SQL or any observation-backed screen. - No regression to the existing FX-only flow for callers that only ever bind FX configs.
Plan
(Implementation strategy. Written when work starts; key decisions
are distilled into the parent story's * Decisions at close, but the
plan itself stays — it is the historical record of what we did.)
SyntheticBindingDialog currently operates directly on
std::vector<fx_spot_generation_config> end to end (loadConfigs=/
=populateTable=/=createBindings). Rather than duplicating that whole
pipeline for IR, introduce one local, dialog-internal
BindableConfig { kind, ore_key, source_name } struct that both
config kinds convert into, and make the pipeline operate on
std::vector<BindableConfig> instead of the FX domain type directly:
loadConfigs()fires bothget_fx_spot_generation_configs_requestandget_ir_curve_generation_configs_request(existing defaults, matching current FX-only behaviour) and merges both into oneBindableConfiglist once both return.- FX's
ore_keyis already a stored field, used as-is. - IR curve configs have no
ore_keyfield –feed_binding.ore_keyis described as "an official ORE market series" key, andir_curve_feed.cppalready computes exactly that for its ownmarket_seriesqualifier lookup:currency_code + "/" + strip_currency_prefix(currency_code, index_name)(e.g."USD/LIBOR-3M"). Mirror that same computation locally (the prefix-stripping helper is already duplicated client-side inIrCurveEditor.cpp's anonymous namespace for the same reason – service-layer code isn't linkable from Qt). - Add a "Type" column (FX/IR) to the table so mixed rows aren't ambiguous once both kinds can appear together.
createBindings()is otherwise kind-agnostic already (it only ever readore_key=/=source_nameoff the FX struct) – no change needed there beyond the type change.
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 |
|---|---|---|
| Bind and verify an IR curve feed via SyntheticBindingDialog | PARTIAL PASS | Steps 1-5 (this task's own acceptance) PASS. Step 6 ("no regression to FX-only flow") failed for a pre-existing gap unrelated to this task's changes – feed_binding has no product-kind filter at all, so FxSpotGridWindow already rendered every binding as FX; IR bindings simply exposed it. Spun out as Task: Feed bindings have no product-kind filter. |
PRs
| PR | Title |
|---|---|
| #1735 | [qt] Extend SyntheticBindingDialog to cover IR curve configs |
Review
| # | Comment summary | File | Decision | Notes |
|---|---|---|---|---|
| 1 | FX Spot grid regression not called out in PR description | (PR body) | Accepted | Already tracked as a separate follow-up task; not blocking, but adding an explicit callout. |
| 2 | IR ore_key is bare qualifier, not FX's SERIES_TYPE/METRIC/QUALIFIER shape | SyntheticBindingDialog.cpp | Accepted | Added a comment explaining it's deliberate and harmless today (curve_feed_ingest_loop never reads feed_binding.ore_key for IR); flagged for the follow-up task. |
| 3 | loadConfigs() fails the whole dialog closed if IR service is unavailable | SyntheticBindingDialog.cpp | Accepted | IR fetch failure now logs a warning and falls back to FX-only rows instead of aborting the load. |
Result
SyntheticBindingDialog now lists ir_curve_generation_config records
alongside FX ones via a local BindableConfig merge, adds a Type
(FX/IR) column, and binds IR curve feeds through the same
createBindings() pipeline FX already used. Manually verified:
binding and starting an IR curve feed persists its ticks into
ores_marketdata_market_observations_tbl, matching FX's existing
behaviour; pre-ticking for already-bound rows works for both kinds.
Testing surfaced a pre-existing gap this task's own acceptance didn't
anticipate: feed_binding carries no product-kind discriminator, so
FX-only screens (FxSpotGridWindow confirmed, others likely) treat
every binding as FX regardless of what it actually binds. IR bindings
simply exposed a filtering gap that was always there. Tracked
separately as Task: Feed bindings have no product-kind filter rather
than blocking this task on it.
Also surfaced, unrelated to this task's code: Barclays Plc provisioning via the 2026-realistic bundle never seeds CRM topology (majors/ minors/exotics) – captured separately in the product backlog.