Story: Record trade activities and trade links

Table of Contents

This page documents a story in Sprint 27. It captures the goal, current status, acceptance criteria, and the tasks that compose it.

1. Goal

Add trade_activity with its type, and trade_link with its type, so every component version names its cause and every relation between trades is typed and directed.

2. Status

Field Value
State DONE
Parent sprint Sprint 27
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-10-08

3. Acceptance

  • Every component version carries a foreign key to the trade_activity that caused it; the activity type states the economic, confirmable and real axes and the priority.
  • trade_link joins two trades with a type from trade_link_type, which names both roles and the economic effect.

4. Tasks

Task State Start End Description
Give the activity type its axes and priority DONE 2026-10-05 2026-10-05 Extend the trade activity type reference data with the economic, confirmable and real axes and the priority order the design states, so an activity says what kind of event it is.
Record each business event as a trade activity DONE 2026-10-05 2026-10-05 Add trade_activity, an append-only record of each business event with its type, actor, time, comment and operational-error flag, and make booking a trade write one.
Point every component version at its activity DONE   2026-10-06 Give the booking, state, identifier, party role, additional field, portfolio and instrument tables a foreign key to the trade_activity that wrote each version, replacing the bare activity type code.
Join trades with typed links DONE 2026-10-08 2026-10-08 Add trade_link (from trade, to trade, type) and trade_link_type, which names both roles and whether the link has an economic effect, seeded from the link catalogue including exercise and roll.
Book a trade through the repositories DONE 2026-10-06 2026-10-07 Booking a trade writes the trade, its activity, its booking and its state with SQL inserts in ores_trading_book_trade_fn, bypassing the generated repositories. Give ores.database a unit of work so several repository writes share one transaction, move booking onto the repositories, and add an architectural rule, enforced by a check, that application code writes entity tables only through repositories.

5. Decisions

5.1. The trade activity is a stamp, and a process run is not

Taken 2026-10-07 with the owner. Two records that had been read as one are separate. A trade activity is stamped on a trade amendment to say what the amendment was about, so risk buckets by amendment type; it stands alone and names no other trade. A process run records one execution of a process over a set of trades, with its inputs, its outputs and the time point it read them at, so the process can be undone or repeated. Where a process generates an amendment it stamps its own activity, and that match is incidental: nothing requires a stamp to point at a run, and most stamps have no run behind them.

The process run is its own subject and its own story: Trace a process run and the trade groups it creates. The three tasks that hung process structure off the activity moved there, and the story waits on one process with a real client.

5.2. The create aggregators stay hand-written, and a check guards them

Taken 2026-10-08 with the owner. A component's `*_create.sql` names its table files in the order psql must run them, and a new entity means a new line in it. Nothing generates that file: all 22 aggregators are hand-written, no template emits one, and neither `compass add` nor `codegen regenerate` writes an include.

It is hand-written because the order is the content, and the order is not something a model states. An alphabetical include set cannot build the schema at all: in `create/trading/`, `trading_trade_identifiers_create.sql` and `trading_trade_links_create.sql` both sort before `trading_trades_create.sql` and both carry a foreign key to it. Nor is the order purely foreign keys: the product type discriminator enum must precede the tables whose columns use the type, and no key records that edge.

The cost showed itself in this story. Two link tables had create files that matched their models and that no aggregator named, so no database ever created them, and every other check passed. A check now walks the include directives from the schema entry points and fails on any create file nothing reaches. Generating the order topologically was considered and rejected: it would mean touching all 22 files and modelling the ordering edges that today live in comments, to save one line per entity.

6. Out of scope

7. Promoted from capture

Captured 2026-10-02 in the product backlog; promoted preserving the UUID.

7.1. Goal

Implement sections 4, 8 and 12 of the trade shape investigation: one activity per business event, acts as activities with participants, and pairwise typed links.

7.2. Status

Field Value
State BACKLOG
Parent sprint Sprint 26
Now Not yet started.
Waiting on Nothing.
Next Break the story into tasks.
Last touched 2026-10-02

7.3. Acceptance

  • Every component version carries a foreign key to the trade_activity that caused it; the activity type states the economic, confirmable and real axes and the priority.
  • A process run names its inputs and outputs, and compression, merge, allocation, a roll or a sweep and a bulk book move record their own facts against the run. The trade activity is the stamp on an amendment, not the parent of either.
  • trade_link joins two trades with a type from trade_link_type, which names both roles and the economic effect; successor_trade_id is gone.

7.4. Tasks

Task State Start End Description
         

Emacs 29.3 (Org mode 9.6.15)