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_registry decomposition 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 to market_data_identifier. Follows the forward quote-key projections in reverse. Seeded by the series_key_registry decomposition 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_checker and applies the pair swap at parse time. Same check() 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 of to_index_name lands 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 equality from_ore_key(to_quote_key(id)) = id=; a canonical_values container the URI builder matches tenor/point against, rejecting unknown spellings; the stored string is the encoded form to_uri produces, and matching uses the same form.

Notes

  • The canonical form always carries an explicit metric: from_ore_key sets id.metric explicitly, and to_uri always serializes it. The invariant from_ore_key(to_quote_key(id)) = id= therefore holds for identifiers whose metric is already explicit (to_quote_key emits one, so the round trip is closed); an identifier with metric left std::nullopt (relying on default_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.

Emacs 29.3 (Org mode 9.6.15)