Task: Migrate currency_pair_convention.advance_calendar onto the calendar model

Table of Contents

This page documents a task in the Model calendars as proper ORE Studio reference data story. It captures the goal, current status, acceptance, and any notes or results.

Goal

currency_pair_convention.advance_calendar is currently a comma-joined free-text value (e.g. "UnitedStates,SouthKorea") with no validation. Replace it with a junction table validated against the calendar entity, mirroring the currency-to-calendar relationship. Resolve the naming question along the way: is advance_calendar an idiomatic name for this field, or should it just be holiday_calendar=/=calendar (matching currency's field name)?

Status

Field Value
State DONE
Parent story Model calendars as proper ORE Studio reference data
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-07-17

Acceptance

  • [X] A junction table links currency_pair_convention to one or more calendar rows, replacing the free-text advance_calendar column.
  • [X] Naming decision made and recorded in this story's * Decisions; applied consistently across domain/SQL/UI.
  • [X] Existing seeded data (from Add librarian support for currency pairs) migrated onto the new model.

Plan

Modelled currency_pair_convention_calendar as an ores.codegen.junction and, for the first time in this story, generated the full C++ layer (domain/generator/repository) via codegen rather than hand-authoring it — the parent story's junction-codegen gap (Fix domain/generator/repository Mustache templates for junction-shaped data) was closed by a separate story between task 3 and this one. Required adding a * C++ ** Flags block with :subcomponent: api to the model (mirroring tenor_convention_resolution.org) to get the generated files into the correct api=/=core path split.

Naming decision: kept advance_calendar rather than renaming to calendar=/=holiday_calendar, since it matches ORE's own AdvanceCalendar XML field verbatim and denotes a distinct concept (date-advancing via Calendar::advance(), not business/settlement-day membership) per the existing AdvanceCalendar knowledge doc.

Retiring the free-text column broke ores.ore's conventions_mapper (XML export/import), which read/wrote convention.advance_calendar directly. Fixed by carrying the calendar codes on mapped_fx instead (same pattern already established for spot_days: the mapper has no database access), building/parsing the comma-joined XML value at the mapper boundary — this substantially delivers task 6's goal for the FX convention case specifically.

Notes

PRs

PR Title
#1612 [refdata,ore] Migrate currency_pair_convention.advance_calendar onto the calendar model

Review

Comment summary File Decision Notes
       

Result

Modelled currency_pair_convention_calendar as an ores.codegen.junction, generated end-to-end via codegen (domain, JSON/table I/O, generator, repository entity/mapper/repository) rather than hand-authored — the first junction in this story to use the newly-completed junction C++ codegen path. Wired create/drop scripts into the manifests (depends on both currency_pair_conventions and calendars, so creates after both, drops before both) and added its RLS tenant-isolation policy up front.

Seeded 16 real pair-to-calendar mappings (e.g. EUR/USD -> TARGET, UnitedStates.Settlement) via a SQL populate script only — ores.codegen.junction doesn't yet support a "real data" custom generator section the way ores.codegen.entity does, so the dual C++-generator-plus-SQL-populate seed pattern from tasks 2/3 couldn't be fully replicated here; captured as a gap for a future ores.codegen.junction enhancement rather than hand-editing the generated generator file.

Retired currency_pair_convention.advance_calendar by removing the field from its org model and regenerating the entity via codegen. Fixed the one non-codegen-owned consumer this broke: ores.ore's conventions_mapper, whose mapped_fx struct now carries advance_calendars (a std::vector<std::string>) instead of reading/writing the retired domain field, following the same "mapper has no DB access" pattern already used for spot_days. xml_fx_convention_mapper_roundtrip_tests.cpp's round-trip test (comparing the raw XML AdvanceCalendar string before/after map_fx=/=reverse) continues to exercise this path unchanged.

Verified locally before the final sync: full monorepo build clean; ctestores.refdata.core.tests (includes the new junction's repository tests), ores.ore.core.tests, ores.ore.api.tests, and ores.ore.service.tests all passed; the only failure across the whole suite was the same pre-existing, unrelated contact_type generator test seen throughout this sprint; validate_schemas.sh clean (0 warnings); compass db recreate verified with 16 currency_pair_convention_calendars rows seeded. The branch was re-synced twice more after that verification pass to keep up with a fast-moving main (each rebase was a clean, conflict-free replay); the full suite was not re-run to completion after the final sync before this push, per explicit instruction to push without re-verifying — the specific suites this change touches were last confirmed green pre-sync, and both rebases were clean fast-forward replays with no conflicting hunks in the touched files.

Emacs 29.3 (Org mode 9.6.15)