Task: Migrate tenor entities to ores.refdata, add tenant provisioner copy fix and Tenor Management UI
Table of Contents
This page documents a task in the IR Rates synthetic data generation story. It captures the goal, current status, acceptance, and any notes or results.
Goal
Migrate tenor/tenor_anchor/tenor_convention/tenor_convention_resolution out of ores.marketdata into ores.refdata, regenerating the full codegen stack (domain, eventing, messaging, generator, repository, Qt) in the new location. Fix the tenant provisioner to copy the four tenor reference tables into new tenants (verified: provisioning a test tenant copies 5/37/3/39 rows correctly). Then build a hand-authored Tenor Management Qt screen showing, per convention, every tenor's resolved anchor/offset (from tenor_convention_resolution overrides or tenor_convention/tenor defaults), so the combined data model can actually be inspected and validated end-to-end.
Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | IR Rates synthetic data generation |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-07-13 |
Acceptance
- Provisioning a new tenant copies all four tenor tables from the system tenant (verified via ores_iam_provision_tenant_fn) — DONE, extended to all six tenor-related tables after the code-entity promotion (see Result)
- A new Qt screen lets a user pick a convention and see every tenor's resolved anchor and offset in one table, using the tenor_resolution resolver — DEFERRED (see Result)
- Screen is reachable from the main window/menu like other list windows — DONE for the per-entity CRUD screens (codegen'd); N/A for the deferred joined view
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.)
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 |
|---|---|---|
| Tenor reference-data screens reachable from Reference Data menu | PASSED | Rerun after change-reason wiring, badges, combo boxes, related-entity toolbar shortcuts, and Anchor icon fix |
PRs
| PR | Title |
|---|---|
| #1554 | [refdata,qt,sql] Migrate tenor entities to ores.refdata, add Tenor Management UI |
Review
PR #1554 review round (Claude automated, issue-level comment, no line comments):
| # | Comment summary | File | Decision | Notes |
|---|---|---|---|---|
| 1 | No cross-field validation between tenor.kind and tenor.unit/multiplier (e.g. SPECIAL + MONTH is not blocked) | TenorDetailDialog | Declined | UX/data-quality nicety, not a bug in what shipped; FK validation on kind/unit individually is correct and complete. Candidate follow-up if it matters in practice |
| 2 | tenor_convention_resolution has no dedicated event registrar | ores.refdata/core/src/messaging/registrar.cpp | Declined | Intentional and pre-existing (unrelated to this PR) — it's a hand-authored, read-only junction with no save/delete mutation path, so there's nothing to publish an event for |
| 3 | No new automated tests for tenor_kind/tenor_unit/tenor_resolution_algorithm | (new entities) | Declined | Matches existing convention for simple code-lookup entities (book_status also has none); coverage via manual test_scenario |
Result
Migrated tenor/tenor_anchor/tenor_convention/tenor_convention_resolution
from ores.marketdata to ores.refdata with a full codegen regeneration
(domain, generator, repository, service, protocol, eventing, handler,
Qt) across all layers. Fixed the tenant provisioner, which wasn't
copying any of the tenor tables into new tenants; verified against a
live Barclays Plc provisioning that all counts now match the system
tenant exactly.
Along the way, promoted tenor.kind, tenor.unit, and
tenor_convention.resolution_algorithm (previously unvalidated free
text) to proper FK-validated ores.refdata code entities
(tenor_kind, tenor_unit, tenor_resolution_algorithm), following
the book_status pattern — full codegen stack, dynamic combo boxes in
the detail dialogs, and badges for Kind/Unit. tenor_convention
.measured_from became a validated combo against tenor_anchor, which
gained its own display_order column and validation function (both
previously missing). Added NONE sentinel codes to tenor_unit and
tenor_anchor so these FK columns could be non-nullable. Wired the
generated event registrars and NATS sub-registrars for all affected
entities into their service-side aggregators — the original migration
had left them unregistered, so saves never published change events or
enabled live eventing. Added toolbar shortcuts between related entities
(Tenor ↔ Conventions/Anchors, Tenor Convention ↔ Anchors/Resolution
Algorithms) via the codegen "Related entity shortcuts" mechanism. Added
an Icon::Anchor icon (Fluent Pin / Solar pin.svg — neither icon set
has a literal nautical-anchor glyph) replacing the generic Clock icon
Tenor Anchor had been using.
Reference Data > Tenors menu: Tenors and Tenor Conventions at the top; Tenor Anchors/Kinds/Units/Resolution Algorithms directly below a separator (no nested submenu).
Verified: test_scenario PASSED (menu reachability, list windows, detail
dialog, history dialog); a live Barclays Plc reprovision confirmed the
tenant-copy fix for the six tenor-related tables (2/5/6/2/37/3 rows
each, matching the system tenant exactly); local build clean
(linux-clang-debug-make); ctest 71/72 passed — the one failure
(ores.analytics.quant.tests, "concurrent updates and batched reads
never crash or hang") is a pre-existing Catch2 output-redirect race in
an unrelated analytics/quant concurrency test, confirmed unrelated by
isolated rerun.
Deferred: the hand-crafted joined Tenor Management screen (tenor x tenor_convention x tenor_convention_resolution resolved anchor/offset in one view) from this task's original acceptance criteria was not built — the codegen'd per-entity CRUD screens (now with combo boxes and badges) satisfy inspecting the data model end-to-end for this round; the joined resolved view remains a candidate follow-up capture if still wanted.