Task: Add the generic instrument-family verb units

Table of Contents

This page documents a task in the Manage trading entities from the shell story. It captures the goal, current status, acceptance, and any notes or results.

1. Goal

ores.shell extends the trading command folder to the six generic families: activity_types, bond, commodity, composite, credit and scripted. Each family is one entity served by a single-handler registrar (registrar_bond.cpp and siblings), keyed by string id, so each gets one unit cloned from the fx-batch skeleton. The batch first establishes the service surface: whether every family subject (list, save, delete, history) is composed into the registrar fan-out and backed by the DB layer. Any family the service does not serve, or whose tables are missing, is either fixed or recorded as a finding with its owner. It then runs the live generic-batch system test per family, with the composite legs exercised where the family carries them.

2. Status

Field Value
State DONE
Parent story Manage trading entities from the shell
Now Nothing.
Waiting on Nothing.
Next Trade-side surface (task 1D07E7C3).
Last touched 2026-09-08

3. Acceptance

  • The unit exists per served family under projects/ores.shell/src/app/commands/trading/ and compiles; trading_commands registers them; the shell cmake component files regenerate with no drift.
  • The per-family service-surface audit is recorded: subjects served, DB tables present, gaps fixed or findings recorded with owners.
  • Live against the fleet: add, list and page, history and delete round-trip every served family; each save lands a DB row (verified via psql) and emits the changed event.
  • Full preset build and ctest green; shell cmake-sources drift clean. The batch lands on feature/shell-trading-instrument-verbs as one [ores.shell] commit.

4. Plan

The five units clone the fx-batch skeleton with their own declared data: trading.v1. subject family (bond_instruments and siblings), save columns from the per-family org, and the shared instrument_id string key. The generator's first pass emitted the per-family *_instrument_protocol.hpp include the fx units use, but the five generic families have no per-family protocol headers — their messaging classes live in the consolidated instrument_protocol.hpp, and the shell build caught the missing header. The units include the consolidated protocol, and the aggregator registers five plural menus.

The batch opens with the service-surface audit this task requires, covering the wire contract, the DB layer and the display layer. The audit confirmed the consolidated registrar serves every family subject (list/save/delete/history, plus get-legs for composite), all five family tables exist under the acme tenant with per-family CHECK constraints and insert-plus-notify triggers, and the table renders already exist per family. Two recorded gaps came out of it. G2: activity_types is served list-only — no save/delete/history protocol or event chain — so no CRUD unit is possible; recorded with the trade-side task (1D07E7C3) as owner. G3: the composite add signature expresses the header only, so shell-added composites carry no legs; the save request's legs member has no shell producer and the legs subject is read-only; recorded with the composite modeling owner. G1 — the five families had no changed-event registrar or eventing header at all (the service application registered nothing), so the batch clones the fra per-family changed-event pattern into the api and service components and wires the five register_*_instrument_event_mapping calls in application.cpp.

Live-test protocol per family: scripted shell run as tenant_admin@acme adds two probes and a get, histories and deletes both probes, then adds an event probe, deletes it and exercises the family's CHECK gate with a negative add. Every add is verified at the DB layer (psql open row) and on the changed-event stream with the subscriber on the prefixed subject ores.dev.brave_hopper.ores.trading.>; every delete soft-closes the row out of the live view. The - spellings for the estr and odbl optional columns are exercised where the family has them (commodity option type and strike), and the refdata vocabularies for the credit payment frequency are exercised with the registry spellings.

5. Notes

6. 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
     

7. PRs

PR Title
   

8. Review

Comment summary File Decision Notes
       

9. Result

Shipped five instrument-family verb units under projects/ores.shell/src/app/commands/trading/: bond_instrument_commands.{hpp,cpp}, commodity_instrument_commands, composite_instrument_commands, credit_instrument_commands and scripted_instrument_commands, each cloning the fx-batch skeleton with its own trading.v1 subject family and positional add arguments from the org columns. trading_commands.cpp registers the five plural menus; component_files.cmake lists the units. The batch is two commits on feature/shell-trading-instrument-verbs: af564bfda9 [ores.shell] (the units) and 7175414576 [ores.trading] (the event chain for the five families). activity_types shipped no unit: the audit found its surface list-only (G2), recorded with the trade-side task 1D07E7C3 as owner.

The service-surface audit is recorded: the consolidated instrument_protocol.hpp serves every family subject through the registrar fan-out and the per-family request and response classes all carry the instruments response member — nothing legacy to delete, unlike the rates families. The DB layer holds all five family tables under the acme tenant, each with CHECK constraints and insert-plus-notify temporal triggers. G1 (no changed-event chain) was fixed in this batch: the five eventing headers, five registrar pairs and the application.cpp wiring landed with 7175414576. G2 and G3 are recorded with their owners in the Plan.

Live acceptance met on brave_hopper against the fleet. A scripted matrix per family as tenant_admin@acme round-tripped add x2, get, history and delete for all five families. Every add landed an open DB row (psql, valid_to = 9999-12-31) and every delete soft-closed it; per-family psql checks confirmed open rows went 2 to 0 with no residue. Changed events were captured on the prefixed subject ores.dev.brave_hopper.ores.trading.> — two per family (probe add and probe delete), proving the wired mappings emit add-to-NATs and delete-to-NATs on the family subject. Per-family CHECK enforcement was seen live: the composite and scripted negatives were rejected at the application registry gate (Invalid trade_type with the full instrument-kind list) and the bond, commodity and credit negatives by DB CHECKs (coupon_rate, option_type and recovery_rate), with zero negative rows in every family table. The - spellings persisted as DB NULL where the family carries the optional columns (commodity probe with Call/85.5 option data and NULL fixed price and start date), and the credit refdata vocabulary round-tripped with the registry spelling Semiannual.

Closing battery green: full preset build exit 0; ctest 71/71 passed (904 s); roundtrip check exit 0 (pre-existing partial-fidelity baseline, no outputs touched); shell cmake-sources drift clean; codegen drift clean (--all); working tree clean after drift regeneration.

Status at close: Batch committed (af564bfda9, 7175414576); full preset build, ctest 71/71 and the roundtrip, cmake-sources and codegen drift checks green. Live matrix green for all five served families.

Emacs 29.3 (Org mode 9.6.15)