Task: State the kind of a basket constituent
Table of Contents
This page documents a task in the Eight columns in the trading models hold JSON blobs where th… story. It captures the goal, current status, acceptance, and any notes or results.
1. Goal
A constituent states its kind and the code it names, and a write is refused when the kind's catalogue does not hold that code, so a mixed basket is representable and a basket cannot name an underlying that does not exist.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Eight columns in the trading models hold JSON blobs where th… |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-10-27 |
3. Acceptance
- A constituent row states a kind beside the code it names.
- A write whose kind's catalogue does not hold the code is refused at write time, with a message naming the kind and the code.
- An export writes the kind back as the document states it, and a roundtrip test proves it.
- A worst of basket whose constituents are FX pairs is representable.
4. Plan
4.1. What the kind is for
A constituent names a code, and a code means nothing without the vocabulary
that holds it. The corpus proves the point twice over: RIC:.SPX is an equity
because the equity catalogue holds it, and one EquityWorstOfBasketSwap in the
examples carries constituents whose Type is FX. A table that stored only
the code would file a currency pair as an equity and would have nothing to
check the code against.
4.2. The shape
- The column.
underlying_kindonequity_basket_constituent, text and not null, generated asequityso an existing row keeps the meaning it had. - The refusal. A check on the table calling
ores_trading_basket_constituent_resolves_fn(kind, code), which looks the code up in the catalogue the kind names and raises with both values when it is absent. It raises rather than returning false so the operator reads the kind and the code that disagree instead of a constraint name. - The projection. The document's
Underlying/Typeis read into the column and written back from it, so a round trip keeps the kind the document stated. - The tests. A round trip that asserts the kind, and a write that the catalogue must refuse.
4.3. Why the catalogues and not a list of kinds
A kind is only meaningful if there is a catalogue behind it. Three exist today – equities, currency pairs and commodities – and each is tenant scoped and carries its own policies, so the function runs as the writing account and sees only the catalogues that account may see. A fourth vocabulary becomes a branch in one function rather than a change to the schema.
4.4. The trap this will hit
The existing repository and eventing tests insert a generated constituent whose name comes from a faker, which no catalogue holds, so they are refused the moment the check exists. That is the check working, not a defect, and the tests have to publish an underlying before they can name one.
5. Measurements
Every number this task claims about a tree, with the command that produced it
and the commit it was measured at. A number without both is not a measurement,
because a clean-up record describes a tree and trunk moves under a branch: a
consumer count, a gate's component count and a suite's size all change with no
code changing, and the reader of a bare number cannot tell which tree it came
from. Where the raw output matters, put it in an evidence/ file beside the
task and name that file in the Command column.
| What | Value | Command | Commit |
|---|---|---|---|
| Resolver outcomes proved | 5 | compass sql -f tmp/kind_test.sql |
c12abc7458 |
| ORE suite | 475,649 assertions, 406 cases | ores.ore.core.tests |
c12abc7458 |
| Trading suite | 1,416 assertions, 221 cases | ores.trading.core.tests |
c12abc7458 |
| Database recreate | exit 0, no errors | compass db recreate |
c12abc7458 |
6. Notes
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 |
|---|---|
| #3948 | [trading] State the kind of a basket constituent |
9. Review
| Comment summary | File | Decision | Notes |
|---|---|---|---|
10. Result
A constituent states its kind, and a write is refused when the kind's catalogue does not hold the code. Five outcomes were exercised against the database:
| Kind and code | Outcome |
|---|---|
equity, .SPX |
accepted |
equity, RIC:.SPX |
accepted, which is the alias the catalogue resolves |
equity, BOGUS |
refused: "names 'BOGUS', and the equity catalogue does not hold it" |
nonsense, .SPX |
refused: "holds no such vocabulary. Known kinds: equity, fx, commodity" |
fx, .SPX |
refused: an equity code named as a currency pair |
The refusals raise rather than returning false, so the operator reads the kind and the code that disagree.
The corpus decided the mechanism. ORE states the kind as Underlying/Type, and
it is text and not an enumeration: reading it as a spelling threw
not an enumeration, the mapping catch swallowed it, and the whole worst-of
basket imported with no instrument at all. Reading it as text fixed it, and the
corpus round trip passes with the kind asserted.
The check needed the equity catalogue, which was not on main. It is now: it landed as its own PR, because a refusal that dereferences a table nobody has merged is a refusal that cannot run.
Nothing writes a basket through the C++ repository yet, so the check is proved against SQL and not through the service. The next task that books a basket will be the first to exercise it in code.