Task: Decide the FX discriminators and the doubled vocabularies
Table of Contents
+#+blocked_since: +#+created: 2026-10-16 +#+updated: 2026-10-16 +#+environment: +#+todo: DISCOVERED BACKLOG STARTED BLOCKED | DONE ABANDONED
This page documents a task in the Rework the FX instruments to the instrument table rule story. It captures the goal, current status, acceptance, and any notes or results.
1. Goal
Settle the three Minor findings the FX review left open. Each one is a choice the model states in two places, or states in prose and refuses in a check. This unit decides each and makes the tree enforce the decision.
2. Status
| Field | Value |
|---|---|
| State | DONE |
| Parent story | Rework the FX instruments to the instrument table rule |
| Now | Nothing. |
| Waiting on | Nothing. |
| Next | Nothing. |
| Last touched | 2026-10-18 |
3. Acceptance
fx_barrier_option_instrumentstates which barrier levels thebarrier_typeengages, and a check refuses a row that fills a level its type does not use.fx_digital_option_instrumentstates the same forstrike,lower_barrierandupper_barrier, or records why no discriminator is possible.fx_vanilla_option_instrumentnames one closed exercise-style set in its prose and admits the same set in its check. Bermuda is either admitted by both or refused by both, with the reason recorded.- The four closed vocabularies that are stated in a table and in a check are kept equal by a mechanism, or the duplicate is removed and the reason recorded.
- Every decision this unit makes is distilled into the parent story's
* Decisions.
4. Decisions
- The exercise style admits Bermuda. ORE's
exerciseStyleis the closed set European, Bermudan and American, the lookup already seeds all three, and the model's prose states all three, so the check is the one that is wrong. The check is removed with the other duplicates, which leaves the lookup as the statement of the set, and the prose states it once. - The lookup table is the single statement of each closed vocabulary. Five
vocabularies (
long_short,option_type,barrier_type,exercise_style,moment_type) are stated in a lookup and again in the table's check. The foreign-key unit keyed every one of them to its lookup, so the check is the copy that goes; the lookup is what a reader edits and what the store enforces. - A single barrier's level sits in the column its direction names. An
Up...orFixingCapstyle engages the upper level, aDown...orFixingFloorstyle the lower one, and the other column stays null. The two columns are positional today: the mapper writes the document's first level intolower_barrierwhatever the style, so anUpAndOutoption cannot be stated without inventing a lower level. - A product that states two levels is the exception, and its trade type says
so. A double or generic barrier holds a level per side, so the directional
check applies to
trade_type_code = 'FxBarrierOption'alone; the double and generic codes require the two levels they read. - The digital option keys its levels on the trade type.
FxDigitalOptionstates a strike and no barrier,FxTouchOptionone barrier and no strike,FxDoubleTouchOptionboth barriers and no strike, andFxDigitalBarrierOptiona strike and a barrier. The table is shared by the four codes, so the check readstrade_type_code.
5. Plan
The analysis found these disagreements between prose, check and mapper:
| Model | Prose says | The check admits | The mapper writes |
|---|---|---|---|
| vanilla option | European or American, then the closed ORE set of three | European, American | the document's value |
| barrier option | the style names the direction | any of the ten styles with any level | the first level into lower_barrier whatever the style |
| digital option | the four codes state different fields | nothing about levels | one level into lower_barrier |
- Widen the vanilla check to the three ORE styles and state the set once.
- Delete the five
in (...)checks whose vocabulary is now a lookup. - Make
lower_barriernullable, add the directional checks keyed ontrade_type_code, and place the document's level by direction infill_barrierand in the two hand-written forward functions. - Add the digital option's type-keyed checks.
- Regenerate, recreate the database, and update the barrier repository test
that writes
UpAndInwith a lower level. - Add a case per decision that refuses the shape it should refuse.
6. 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 | |
|---|---|---|---|---|
| Duplicated vocabulary checks removed | 10 | =git diff origin/main – 'projects/ores.trading/modeling/*.org' \ | grep -c '^-.* in (', in =evidence/fx-vocabularies.txt |
the PR head |
| Level checks on the barrier table | 6 of its 13 | grep -c 'check (' projects/ores.sql/create/trading/trading_fx_barrier_option_instruments_create.sql gives 13; the six level checks are the ones naming a barrier column, listed in evidence/fx-vocabularies.txt |
the PR head | |
| Digital checks keyed on the trade type | 4 | grep -c 'check (("trade_type_code"' projects/ores.sql/create/trading/trading_fx_digital_option_instruments_create.sql, in evidence/fx-vocabularies.txt |
the PR head | |
| Trading core suite | pass | compass test run --preset linux-clang-release-ninja -- -R ores.trading.core.tests |
the PR head | |
| ORE core suite | pass | the same command with ores.ore.core.tests |
the PR head | |
| Refusing cases | 2 (an Up style with a lower level, a double barrier with one level) | an_up_style_refuses_a_lower_level in projects/ores.trading/core/tests/repository_fx_barrier_option_instrument_repository_tests.cpp |
the PR head | |
| Economic-digest suite | rotted, not wired | =grep -rn digest_tests –include=CMakeLists.txt projects/ \ | wc -l= returns 0, so the suite is outside the build; a local wiring run failed four cases on an empty digest, recorded in evidence/fx-digest-suite.txt |
the PR head |
7. Notes
- The evidence for this task is Investigation: FX family data model review, findings 6, 8 and 9.
- These are decisions, not defects with one right answer. A decision to keep the current shape is a valid outcome if it is recorded.
8. 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 |
|---|---|---|
9. PRs
10. Review
| Comment summary | File | Decision | Notes |
|---|---|---|---|
11. Result
12. Findings
- The economic-digest suite is rotted, and not by this unit. No CMakeLists
adds
projects/ores.trading/core/digest_tests, so the suite is outside the build. Wiring it in and running it fails four cases, one of them forScriptedTrade, a family this unit never touches, because the digest column is empty before and after the write. The suite was therefore left unwired and is recorded as its own defect. - The wire twins and the goldens are corrected here. Both TS files now type
the lower level as
string | null, and the barrier golden records the level inupper_barrierwith a note that says so. - The direction is a second list. The check names the Up and Down styles
beside the lookup that holds them. Encoding the direction on
ores_trading_barrier_types_tblis the right shape and is captured as its own work.
The duplicated vocabularies are gone. Ten in (...) checks named a set the
lookup table now validates, so the checks were the second copy and are removed.
The vanilla option's check was one of them, which settles the exercise style:
the lookup holds European, Bermudan and American, so the store admits all three
and the prose states that set once instead of contradicting it.
The barrier option now states which level its style engages. A single
FxBarrierOption with an Up style or a cap holds its level in upper_barrier
and leaves lower_barrier null; a Down style or a floor does the reverse; the
styles that name no direction state one of the two. lower_barrier became
nullable for that reason, and the mapper places the document's level by
direction instead of by position, so an UpAndOut option no longer needs a lower
level invented for it. A double or generic barrier holds a level per side and
is exempt, because its trade type says so.
The digital option keys its checks on the trade type. Each of its four codes states the fields it engages: a plain digital a strike, a touch one barrier, a double touch both barriers, and a digital barrier a strike and a barrier. The checks require those fields and tolerate another code's, because the one synthetic generator fills a strike and both barriers on its single row, so a check that refused a field the code does not engage would refuse that row.
The decisions are in the parent story's * Decisions.