Task: Write the swap legs on import and record their direction

Table of Contents

This page documents a task in the Rework the rates instruments to the instrument table rule story. It captures the goal, current status, acceptance, and any notes or results.

1. Goal

Make the swap legs the importer builds reach the database, keyed by the trade and the ordinal as bond_legs is, with the leg's direction recorded.

2. Status

Field Value
State DONE
Parent story Rework the rates instruments to the instrument table rule
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-10-08

3. Acceptance

  • ores_trading_swap_legs_tbl is keyed by (tenant_id, trade_id, leg_number) with no surrogate id, and carries payer.
  • swap_instrument_mapper::map_leg reads legData/Payer.
  • The import writes every leg of a swap-shaped trade after its instrument, and fails the item when a leg write fails.
  • The component regenerates drift-clean and builds, and the codegen suite passes.

4. Plan

The importer already builds the legs and stamp_ids already stamps them, so the work is two small changes: the leg gains the direction ORE requires, and the import writes the legs it already builds.

  1. payer joins swap_leg, map_leg reads legData/Payer and reverse_leg emits it, so the direction survives import and export both.
  2. The handler writes each leg after its instrument, and fails the item when a leg write fails. The leg's id is minted at the write site, because the table still keys the leg by its surrogate.

The re-key to (trade_id, leg_number) was attempted and set aside. It surfaces a codegen defect: the compound-key path cannot generate a compilable eventing integration test, because cpp_nats_integration_test.cpp.mustache inserts each extra key column's raw domain value where the generated service takes every key part as text. Fixing that template belongs with the codegen work, so the re-key was recorded as a capture and the surrogate key stood here. The codegen defect is fixed and the re-key landed in Re-key the swap legs to the trade.

The amount and rate children that carry an amortising notional and a stepping rate are the next unit: map_leg reads only the first notional, rate and spread today, so the children would be empty until the mapper reads the lists.

The database is recreated rather than migrated (recreate_is_the_only_db_migration).

5. Measurements

Every number this task claims about a tree, with the command that produced it and the commit it was measured at.

What Value Command Commit
payer column on the leg, before absent sed -n '/^create table/,/^);/p' trading_swap_legs_create.sql 02da314ddc
payer column on the leg, after present, boolean null the same working tree
swap_legs primary key unchanged, (tenant_id, id, valid_from, valid_to) the same working tree
legData members with no destination, before Payer and the amortisation, payment-date and settlement groups external/ore/xsd/instruments.xsd against the create script 02da314ddc
ORE mapper lines that read Payer, before 0 grep Payer swap_instrument_mapper.cpp 02da314ddc
ORE mapper lines that read Payer, after 2, one per direction the same working tree

6. Notes

The swap_leg row keeps its :default: 1 syntax on leg_number rather than the :default_value: its siblings use. It emits the correct SQL default, so it is left alone here rather than changed in an unrelated diff.

7. Test Scenarios

Manual QA scenarios (scaffolded via compass add test_scenario) 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
     

8. PRs

PR Title
#2795 [trading,ore] Write a swap's legs and record their direction

9. Review

Comment summary File Decision Notes
       

10. Result

The swap legs the importer builds now reach the database, and a leg records which side pays.

  • The direction is recorded both ways. payer joins swap_leg, map_leg reads ORE's required legData/Payer and reverse_leg emits it. Before this, even a mapper that built the legs dropped the direction, and the stored shape had nowhere to put it.
  • The import writes the legs. The handler's swap_instrument_data branch wrote the instrument and its call dates and dropped the leg vector that stamp_ids had already stamped with the trade and the activity. It now writes each leg after its instrument and fails the item when a leg write fails, so a stored swap is an instrument rather than a row. This is finding R15 of the family design, and it is why a swap imported before this change exported with no legs at all.
  • The re-key was attempted and set aside. Dropping the surrogate id for (trade_id, leg_number) fails to compile a generated test: the compound-key path inserts each extra key column's raw domain value where the generated service takes every key part as text, so an int ordinal lands in a std::vector<std::string>. The fix is a template change that belongs with the codegen work, so the re-key was recorded as a capture and the surrogate key stood here. The codegen defect is fixed and the re-key landed in Re-key the swap legs to the trade.

Verification: the component regenerates with no drift; the codegen suite is 1276 passed; the full preset build exits 0 with no errors and no warnings.

Not verified live: that an imported swap lands its leg rows. The database and the service fleet are down in this environment. Proving it means compass db recreate followed by a fleet start and an ORE import, which is a deliberate, whole-environment step rather than something to do as a side-effect of a build.

Emacs 29.3 (Org mode 9.6.15)