Task: Inverse projection: ORE key to oresmd identifier, canonical form contract
Table of Contents
This page documents a task in the Adopt oresmd as the native market data identity across simulator, UIs, and shell story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Give the ORE-format import boundary a tested inverse projection: an ORE key string becomes an oresmd identifier. Pin the canonical URI form so equality lookup is reliable. The URI builder receives the canonical values (tenor, point) as a supplied container; oresmd keeps no dependency on the refdata repositories.
Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Adopt oresmd as the native market data identity across simulator, UIs, and shell |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-08-11 |
Acceptance
- The inverse projection maps ORE key strings to oresmd identifiers,
seeded by the
series_key_registrydecomposition table and following the forward projections in reverse. - Series types without an oresmd mapping (e.g. BOND) are rejected.
- The FX/RATE convention correction survives: it swaps the identifier's pair at parse time.
- Round-trip tests pin the canonical form:
parse(to_uri(id)) =id=,to_uri(parse(uri)) =uri=, and equality of semantically-equal identifiers. - The URI builder takes canonical values from a supplied container (tenor, point) and rejects unknown spellings.
- The stored string is the percent-encoded canonical form; matching uses the same form.
Plan
oresmd_projections::from_ore_key(new): ORE key string tomarket_data_identifier. Follows the forward quote-key projections in reverse. Seeded by theseries_key_registrydecomposition table: every type in that table is either mapped or explicitly rejected (std::nullopt). The mapping covers the forward-emittable types (FX, FXFWD, the 13 IR families incl. SWAPTION vol, EQUITY x3, COMMODITY x3 incl. CPR, CREDIT x5, INFLATION x3, CORRELATION); BOND and the option/capfloor families have no oresmd mapping and are rejected, as are unknown types and malformed keys.- The FX/RATE convention correction survives: an overload takes the
fx_quote_convention_checkerand applies the pair swap at parse time. Samecheck()function, new target – the identifier's pair instead of the qualifier string. The checker header moves from PRIVATE to PUBLIC on the core library. - Fixing keys are out of scope here: fixings import as
FIXING/RATE/<index-name>, an index-name key space the registry table does not seed. The reverse ofto_index_namelands with the identity-core task, which wires the fixing boundary. - Canonical form contract, pinned by tests: string-level round trip
to_uri(parse(uri)) =uri=; inverse/forward equalityfrom_ore_key(to_quote_key(id)) =id=; acanonical_valuescontainer the URI builder matches tenor/point against, rejecting unknown spellings; the stored string is the encoded formto_uriproduces, and matching uses the same form.
Notes
- The canonical form always carries an explicit metric:
from_ore_keysetsid.metricexplicitly, andto_urialways serializes it. The invariantfrom_ore_key(to_quote_key(id)) =id= therefore holds for identifiers whose metric is already explicit (to_quote_keyemits one, so the round trip is closed); an identifier withmetricleftstd::nullopt(relying ondefault_metric()) is not canonical-form and is not reconstructed equal.
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 |
|---|---|
| #1963 | [ores.marketdata] Inverse projection: ORE key to oresmd identifier, canonical form contract |
Review
| # | Comment summary | File | Decision | Notes |
|---|---|---|---|---|
| 1 | to_uri(identifier, canonical_values) is never exercised against an IR vol identifier |
oresmd_oresmd_parser_tests.cpp | Fixed | The container must hold the composite "5y,2y,atm" as one point literal; accept/reject tests added |
| 2 | from_fx_spot calls check() before upper-casing the key segments, so a lower-case pair skips the correction |
oresmd_projections.cpp | Fixed | Segments are upper-cased before the check; regression test added |
| 3 | from_fx_spot / from_fx_fwd concatenate currency segments of any length into pair |
oresmd_projections.cpp | Fixed | is_currency_code (exactly 3 alphabetic chars) rejects malformed keys; 4 tests added |
| 4 | from_ore_key always emits an explicit metric; the round-trip invariant is scoped to explicit-metric identifiers |
oresmd_projections.cpp | Noted | Invariant scope documented in * Notes |
Result
oresmd_projections::from_ore_key (new) maps ORE quote-key
strings to market_data_identifier, following the forward
quote_key_* projections in reverse and seeded by the
series_key_registry decomposition table. Every registry type is
either mapped (FX, FXFWD, IR_SWAP, DISCOUNT, the 10 indexed and
no-index IR families, SWAPTION vol, EQUITY x3, COMMODITY x3 incl.
CPR, CREDIT x5, INFLATION x3, CORRELATION) or rejected
(std::nullopt: BOND, the option and capfloor families, unknown
types, malformed keys). The ORE spellings it dispatches on are
constexpr constants shared with the forward ore_type() /
ore_metric() / ore_vol_model() tables, so a rename stays in sync
in both directions.
The FX/RATE convention correction survives as an overload that
applies the fx_quote_convention_checker to the identifier's pair at
parse time (same check(), new target); the checker header moved
PUBLIC on ores.marketdata.core.
oresmd_parser::to_uri(identifier, canonical_values) (new) matches
the identifier's tenor and point against the supplied refdata
container and rejects unknown spellings with oresmd_exception;
identifiers without tenor/point are unaffected.
Acceptance met: inverse projection seeded by the registry and
following the forward projections in reverse; BOND et al rejected;
convention correction survives; round trips pinned
(parse(to_uri(id)) = id=, to_uri(parse(uri)) = uri=, semantic
equality); builder takes canonical values from a supplied container
and rejects unknown spellings; stored string is the canonical
encoded form to_uri emits, and matching uses the same form.
Fixing keys (an index-name key space the registry does not seed)
stay out of scope, per the plan.