Data Import Session and Workflow Partial-Success
Full ORE data import pipeline; pending trade staging; non-live marker for reference data; structured workflow failure reporting
Table of Contents
- Related Plans
- Import Tracks
- Problem Statement
- Trades imported directly into live books — no safety checkpoint
- All non-trade data imported directly with no isolation
- Import entry point is scattered and badly placed
- Import workflow is monolithic and mistakenly named
- Workflow status does not reflect partial failure
- Failed items are not surfaced as a structured list
- Design Overview
- Data Import Session Window
- Pending Book
- Non-Live Marker for Reference Data
- Schema Design
- Trade Status FSM — New
pendingState - Workflow:
data_importWorkflow Type - Workflow:
completed_with_warningsState - Workflow: Failed Items in Step Summary
- ORE Examples Import Unit Analysis
- Files to Change
- Implementation Steps
- Expected Outcome
- Additional Notes
Related Plans
- ORE Import Error Reporting and Step Warning State (COMPLETE) — implements
the
completed_with_warningsworkflow step outcome, thestep_log_entrystructured log, and the per-step warning badge inWorkflowStepsWidget. This plan builds on that foundation: the session/pending-book design assumes the warning infrastructure is already in place. - Server-Side ORE Import — earlier design covering the server-side import handler architecture. The current plan supersedes the import handler section of that design; the rest remains valid reference.
- Workspace Design (PROPOSED, PREREQUISITE for Track 1) — isolated
workspace concept required for ORE sample import. This plan covers two
import tracks: Track 1 (educational/sample import, blocked on workspace
implementation) and Track 2 (production live import, independent). The
Pending Book and
is_livemechanisms in this plan serve Track 2 only.
Import Tracks
This plan covers two fundamentally different import use cases. They share the Data Import Session window but differ in where data lands.
| Track | Source | Target | Isolation mechanism |
|---|---|---|---|
| 1 — Educational | ORE sample directory | Named workspace | Workspace (see workspace plan) |
| 2 — Production | External trades (FpML, CSV) | Live (workspace 0) | Pending Book + is_live flags |
Track 1 is blocked on Workspace implementation. All phases below address Track 2 only unless otherwise noted.
Problem Statement
Trades imported directly into live books — no safety checkpoint
The current ORE import workflow writes trades directly into
ores_trading_trades_tbl (live books) with no intermediate validation or
enrichment stage. Real-world trade data is routinely dirty: missing
counterparties, zero amounts, unrecognised instrument parameters, mismatched
currencies. Accepting this data directly into live books is dangerous because:
- Bad trades appear in risk/compute runs immediately.
- There is no structured way to bulk-fix missing reference data (counterparty, book) before committing.
- Instrument creation failures leave orphaned trade rows.
- There is no clear user workflow from "imported" to "verified and live."
All non-trade data imported directly with no isolation
Market data, conventions, curves, and pricing engine configurations land in the main tables immediately and are indistinguishable from manually curated or Bloomberg-sourced data. Users have no way to know which data came from an ORE import and which is production-quality.
Import entry point is scattered and badly placed
ORE import actions appear in both the Trades window toolbar and Portfolio Explorer. The import entry point should be a dedicated Data Import facility, not the live-book views.
Import workflow is monolithic and mistakenly named
The existing workflow conflates trade staging with market data, conventions, curves, and pricing configuration — all of which have different lifecycle requirements.
Workflow status does not reflect partial failure
The workflow instance FSM only has completed and failed terminal states.
A partial import shows completed — indistinguishable from a clean run.
Failed items are not surfaced as a structured list
ore_import_execute_result.item_errors is already collected but only
surfaced as flat log text. There is no way to render a table of failed
trade IDs with files and error messages.
Design Overview
Core concepts
Three concepts drive the new design:
- Data Import Session — a single import event that brings in a full ORE
data set (trades + market data + conventions + curves + pricing configs).
Everything imported in one session shares a common
session_idfor lineage. - Pending Book — a system-defined book that holds imported trades before they are enriched and promoted to a live book. Trades in the Pending Book are visible in the normal trade views but clearly marked. They cannot be used in compute runs until booked into a real book.
- Non-live marker — a simple
is_live boolean not null default falseon every reference-data table touched by ORE import (conventions, curves, pricing engine configs, market data). Only rows withis_live = trueare used by compute runs and visible in normal reference-data views. The import session notebook lets users review and activate imported rows explicitly.
Full ORE import from day one
The import handler processes a complete ORE data directory in a single pass:
- Portfolio XML files → Pending Book trades (pending trade staging)
- Market data files → market data tables with
is_live = false - Conventions XML → convention tables with
is_live = false - Curve configs → curve config tables with
is_live = false - Pricing engine configs → pricing engine tables with
is_live = false
All rows created in a session carry import_session_id for lineage. There
is no deferred "Phase 2" for reference data — it is imported together with
trades from the start.
Data Transfer menu — kept and extended
The "Data Transfer" top-level menu is kept and extended:
Data Transfer ├── Data Import → opens Data Import Session window └── Data Export → (future)
The scattered import actions in the Trades window and Portfolio Explorer are removed; all import activity flows through Data Transfer → Data Import.
Import flow
User clicks Data Transfer → Data Import
│
▼
Directory picker (selects an ORE data directory or group)
│
▼
data_import workflow triggered
│
├── Portfolio XML → Pending Book trades (staged, validated)
├── Market data → market data tables (is_live = false)
├── Conventions → convention tables (is_live = false)
├── Curves → curve config tables (is_live = false)
└── Pricing cfg → pricing engine tables (is_live = false)
│
▼
Data Import Session window auto-opens (or refreshes) showing new session
Data Import Session Window
Overview
A persistent MDI window accessible via Data Transfer → Data Import. Shows import sessions with a two-level selector at the top. The body is a notebook with one tab per data type. Both selectors scope all tabs simultaneously.
+-------------------------------------------------------------------------------------+ | DATA IMPORT SESSION [New Import] [Refresh] | | Batch: [ 2026-05-17 10:15 — ORE XML — /ore/examples ▼ ] | | Unit: [ All units (34) ▼ ] | +-------------------------------------------------------------------------------------+ | [ Trades (847) ] [ Market Data (312) ] [ Conventions (45) ] [ Curves ] [ Pricing ] | +-------------------------------------------------------------------------------------+ | [ tab-specific grid + actions ] | +-------------------------------------------------------------------------------------+
Batch selector
Dropdown listing recent import batches, most recent first. Each entry shows: the batch timestamp, source type (ORE XML, FpML, …), source directory (truncated), and a summary badge (e.g. "34 units · 847 trades · 12 invalid"). A search/filter allows finding batches by date or path.
Unit selector
Searchable dropdown scoped to the selected batch. First entry is always "All units (N)". Remaining entries are the display names derived from each unit's relative orchestration XML path (see naming heuristic below). Selecting a unit narrows every tab to that unit's data only.
Unit display name heuristic
Given the orchestration XML path relative to the batch root:
- Split into directory components; drop the filename.
- Remove uninformative folder names:
Input,ExpectedOutput,Notebooks,Calc,bak,xlwings,Helpers,Dependencies. - Join remaining components with
·(e.g.Legacy · Example_1). - If the orchestration filename stem is not plain
ore, strip theore_prefix (or_oresuffix) and append the variant name (e.g.MarketRisk · sensi,CurveBuilding · BootstrapConsistency · EUR_xois). - If two units in the same batch produce the same display name, append a numeric suffix to make them unique.
Examples:
| Relative path | Display name |
|---|---|
Legacy/Example_1/Input/ore.xml |
Legacy · Example_1 |
MarketRisk/Input/ore_sensi.xml |
MarketRisk · sensi |
MarketRisk/Input/ParConversion/ore.xml |
MarketRisk · ParConversion |
ExposureWithCollateral/Input/FirstMpor/ore.xml |
ExposureWithCollateral · FirstMpor |
Academy/TA002_IR_Swap/Input/ore.xml |
Academy · TA002_IR_Swap |
CurveBuilding/BootstrapConsistency/Input/EUR_xois_ore.xml |
CurveBuilding · BootstrapConsistency · EUR_xois |
Trades tab (Pending Book view)
This is the actionable tab — trades in the Pending Book need user enrichment before they can be booked into a live book.
Layout: filter bar → action bar → virtual-scroll grid → inspector panel (bottom 30% when a row is selected).
Filter bar:
- Status: All / Invalid / Ready / Booked / Rejected
- Error Type: All / Missing Book / Missing Counterparty / Zero Amount / …
- Trade Type: All / FxForward / IRS / FxOption / …
- Free-text search (External ID, raw counterparty)
Action bar (bulk actions activate on selection):
| Action | Enabled when | Behaviour |
|---|---|---|
| Assign Book | ≥1 row selected | Book picker; re-validates |
| Assign Counterparty | ≥1 row selected | Counterparty picker with fuzzy-search |
| Validate | ≥1 row selected | Re-runs validation |
| Book Selected | ≥1 ready row selected |
Promotes to live trade table |
| Reject | ≥1 row selected | Marks rejected; prompts for reason |
| Value Selected | ≥1 ready row (future) |
Runs ORE engine; populates NPV |
Grid columns:
| Column | Notes |
|---|---|
| ☐ | Multi-select |
| Status | ● red Invalid / ○ green Ready / ↻ staged / ✓ booked / ✗ rejected |
| External ID | From source; monospace |
| Errors | Badge: count of blocking errors |
| Trade Type | |
| Book | "(unassigned)" in amber if null |
| Counterparty | Raw source string in amber if unmatched |
| NPV | "—" until valued (future) |
| Source File | Filename from source_position |
Cell-level error highlighting: cells with invalid data render with an amber
background and a hover tooltip from validation_errors explaining the
specific error and suggested fix. Grid uses virtual/lazy rendering
(QAbstractItemModel + proxy) to stay responsive with large portfolios.
Inspector panel (bottom ~30%, shown on single-row selection):
Left column — Trade Parameters:
- Parsed fields from
raw_data(read-only) - Source provenance: session, directory, file, element index
- NPV if valued
Right column — Validation Errors + Audit Trail:
- Errors table: Severity | Field | Message | Fix hint (blocking first in red, warnings in amber)
- Audit trail: timestamped log of system and user actions
Post-import behaviour:
- Window auto-opens (or refreshes) filtered to new session
- Summary banner: "N trades staged — M ready, K invalid"
- If all valid: "Book All Ready" prompt shown
- If some invalid: filter pre-set to Invalid subset
Market Data tab
Read-only grid showing market data rows imported in the session, with their
is_live status. Columns: Name | Type | Date | Is Live | Source.
Bulk actions: "Mark as Live" (sets is_live = true on selection) and
"Discard" (deletes non-live rows). Warning shown at activation time if an
existing live row with the same key would be shadowed.
Conventions tab
Same pattern as Market Data. Lists convention rows from the session. Bulk "Mark as Live" / "Discard." Dedup warning if an existing live convention has the same code.
Curves tab
Curve configuration rows from the session. Same is_live model.
Pricing Config tab
Pricing engine configuration rows from the session. Same is_live model.
Pending Book
Concept
The Pending Book is a system-defined book created at database initialisation. It is not selectable by users when creating trades manually. Its sole purpose is to hold imported trades before enrichment.
Pending Book properties:
- Fixed UUID, seeded in populate scripts
- Name: "Pending" (or "Import Staging")
is_system = trueon the book record — filtered out of book picker dropdowns- Visible in the trade list view as a special book with an amber indicator
Trade lifecycle in the Pending Book
- Import handler inserts trade into
ores_trading_trades_tblwithbook_id = pending_book_id,status = pending(new FSM state), andvalidation_errorspopulated. - User sees trade in Data Import Session → Trades tab (and in the main Trades window filtered to Pending Book).
- User assigns book and counterparty; validation re-runs; status moves to
ready. - User clicks "Book Selected" → booking service reassigns
book_idto the target book, clearsvalidation_errors, transitions status frompendingtonew.
Constraint relaxation
Trades in pending status must tolerate nullable counterparty_id and nullable
book_id (the pending book is assigned but the real book is not yet known).
This means the NOT NULL constraints audit defers to the booking service: the
service enforces that a real book and counterparty are assigned before
transition from pending to new.
Non-Live Marker for Reference Data
Mechanism
Add is_live boolean not null default false and import_session_id uuid null
to every reference-data table touched by ORE import:
| Table | Notes |
|---|---|
| conventions | Day count, business day, calendar conventions |
| curve configs | Yield curve construction configuration |
| pricing engine configs | Pricing engine model parameters |
| market data | Fixings, FX rates, yield curve data points |
At import time all rows land with is_live = false. Compute runs and normal
UI data-loading queries filter on is_live = true (or current live rows only).
Activation
User reviews rows in the relevant tab of the Data Import Session notebook.
Bulk "Mark as Live" sets is_live = true on selected rows.
Dedup strategy: before activation, the service checks for an existing live row with the same natural key. If found, it warns the user: "Activating this row will supersede existing live [Convention / Curve / …] with code X." User can proceed or cancel.
Visibility in normal views
Non-live rows are hidden from normal reference-data grids by default. A "Show Non-Live" toggle (or filter) reveals them with an amber "Pending" badge. This keeps normal data management views clean while preserving the data for review in the Data Import Session.
Schema Design
Data import sessions table
create table ores_data_import_sessions_tbl ( id uuid not null default gen_random_uuid(), source_type text not null, -- ore_xml | fpml | csv | api | manual source_reference text not null, -- directory path, URL, system name source_checksum text null, -- hash of directory manifest for dedup source_metadata jsonb null, -- file counts, schema versions, etc. workflow_run_id uuid null, imported_by text not null, imported_at timestamptz not null default now(), constraint ores_data_import_sessions_tbl_pk primary key (id) );
Note: this replaces the earlier ores_trading_import_sessions_tbl design.
The session table lives in a shared schema (not trading-specific) since it
spans all data types.
Pending trades
Trades in the Pending Book remain in ores_trading_trades_tbl. Additional
columns needed:
alter table ores_trading_trades_tbl add column if not exists import_session_id uuid null, add column if not exists validation_errors jsonb null, add column if not exists source_position text null, -- "filename:index" add column if not exists raw_data text null; -- original XML fragment
The status_id FK already exists (pointing to the trade status FSM).
A new pending state is added to the FSM (see below).
Lineage on live trades
After booking (pending → new), the lineage columns persist:
import_session_id and source_position remain set so that auditors can trace
any live trade back to its source file and import session.
NPV columns (future valuation)
alter table ores_trading_trades_tbl add column if not exists npv numeric null, add column if not exists npv_currency text null, add column if not exists npv_computed_at timestamptz null;
Included now to avoid a future migration.
is_live on reference data tables
-- Example pattern applied to each affected table: alter table ores_refdata_conventions_tbl add column if not exists is_live boolean not null default false, add column if not exists import_session_id uuid null;
Full list of tables to audit and patch is part of Phase 1 work.
Trade Status FSM — New pending State
Add to the existing trade status machine (dq_fsm_trade_status_populate.sql):
| Addition | Type | Description | |
|---|---|---|---|
pending |
state | Trade is in the Pending Book; awaiting enrichment and booking | |
stage |
transition | (import) → pending | Trade landed from import |
book |
transition | pending → new | User books trade into a real book |
reject_pending |
transition | pending → cancelled | User rejects pending trade |
The existing new → live → expired / cancelled chain is unchanged.
pending is a pre-entry state that sits before new.
Workflow: data_import Workflow Type
The existing monolithic ORE import workflow is renamed data_import.
It processes a full ORE directory in a single pass, delegating to sub-handlers
per data type. The DB workflow definition record is updated accordingly.
Workflow: completed_with_warnings State
Add to the workflow instance FSM:
| Addition | Type | Description |
|---|---|---|
completed_with_warnings |
state (terminal) | Completed but some items could not be staged or validated |
complete_with_warnings |
transition | in_progress → completed_with_warnings |
UI: amber badge in workflow list; tooltip "Completed with warnings"; step details show "Show in Data Import Session" link.
Step result message: "N trades staged (M ready, K invalid); P market data items; Q conventions; R curve configs."
Workflow: Failed Items in Step Summary
struct workflow_failed_item { std::string item_id; // trade external_id or data item key std::string source_file; // filename within scanned directory std::string message; // parse or validation error }; struct workflow_step_summary { // ... existing fields ... std::vector<workflow_failed_item> failed_items; };
Rendered in step details as a table: Item ID | Source File | Error, with a "Show in Data Import Session" link.
ORE Examples Import Unit Analysis
Analysis performed 2026-05-17 using Opus 4.7 on external/ore/examples.
Top-level structure
19 top-level subdirectories with mixed PascalCase / hyphenated naming:
Academy, AmericanMonteCarlo, CreditRisk, CurveBuilding, Exposure,
ExposureWithCollateral, InitialMargin, Input, Legacy, MarketRisk,
MinimalSetup, ORE-API, ORE-Python, Performance, Products,
ScriptedTrade, TradeGenerator, XvaRisk.
Two are meta-containers:
Legacy/— 75 numbered child examples (Example_1…Example_78, with gaps).Academy/— 3 prefix-coded children (FC003_…,TA001_…,TA002_…).
Two are non-runnable and must be skipped:
Input/— shared fixture files, noore.xml, noportfolio.xml.TradeGenerator/— only aReadme.md.
Internal structure and file distribution
The universal layout is <Group>/Input/<files> with <Group>/ExpectedOutput/
alongside. All simulation files live inside Input/, never at the group root
(with one anomaly: Legacy/Example_48 has an ore.xml at the group root as
well as under Input/).
Max nesting depth: 5 levels (ORE-Python/Notebooks/Example_8/Input/Example_57/ore.xml).
Key file distribution:
ore.xml/ore_*.xml/*_ore.xml— always insideInput/(or a nestedInput/<Variant>/sub-directory).portfolio*.xml— insideInput/; naming is highly variable (see below).market*.txt,fixings*.txt,conventions*.xml,curveconfig*.xml,pricingengine*.xml,todaysmarket*.xml— insideInput/; for multi-variant groups, common copies sit atInput/and per-variant copies sit atInput/<Variant>/.
Orchestration file counts per group
The plain-name ore.xml is rare in modern groups. Most multi-variant groups
use only ore_*.xml variants (no plain ore.xml). Selected counts:
| Group | ore_*.xml count |
Notes |
|---|---|---|
Exposure |
34 | No plain ore.xml |
MarketRisk |
26 top + ParConversion/ore.xml |
Mixed flat+nested |
InitialMargin |
21 (Dim) + 15 (Dim2) + 7 (Simm) + 1 (DimValidation) | |
ExposureWithCollateral |
13 + FirstMpor/ore.xml |
Nested sub-run |
Performance |
11 | |
AmericanMonteCarlo |
8 | No plain ore.xml |
ORE-Python/Notebooks |
1 per Notebook/Example_N + 2 deeply-nested | |
CurveBuilding/BootstrapConsistency |
3 × *_ore.xml suffix (not prefix) |
Suffix outlier |
Portfolio XML naming patterns
Naming is highly variable — portfolio.xml is only the most common variant:
portfolio.xml(~60 occurrences)portfolio_<thing>.xml(very common — swap, swaption, capfloor, fxtarf, etc.)portfolio<N>.xml/portfolio_{1..5}.xml(CreditRisk,Legacy/Example_43,Legacy/Example_6)- Instrument-named files:
irswap.xml,eqoption.xml,swap_eur.xml(Academy,InitialMargin/Dim) portfolio_cpr_{0,5,…}.xml(parametric suffix —Legacy/Example_65)- Never
Portfolio.xml(capitalised) ortrades.xml
Portfolio XLM is not reliably discoverable by name alone. The orchestration
XML explicitly names the portfolio file in its <Portfolio> element.
Trade counts in portfolio XMLs
| Portfolio | Trades |
|---|---|
Academy/TA002_IR_Swap/Input/irswap.xml |
1 |
MinimalSetup/Input/portfolio_swap.xml |
1 |
MarketRisk/Input/Correlation/portfolio.xml |
2 |
ExposureWithCollateral/Input/portfolio.xml |
3 |
AmericanMonteCarlo/Input/portfolio.xml |
11 |
Legacy/Example_1/Input/portfolio.xml |
12 |
Exposure/Input/portfolio_swap.xml |
39 |
Legacy/Example_43/Input/portfolio100.xml |
100 |
Products/Input/portfolio.xml |
181 |
Typical range: 1–15 for didactic examples; 30–200 for benchmark portfolios.
Anchor file
Neither ore.xml alone nor the top-level group folder is a reliable anchor:
- Literal
ore.xmlmisses the majority of runs in modern groups (which useore_*.xmlor*_ore.xml). - Top-level group folder is too coarse:
Legacy/wraps 75 unrelated examples.
The reliable anchor is any orchestration XML — a file matching the glob
ore*.xml OR *_ore.xml in any non-output, non-backup directory. The
orchestration XML then serves as the manifest: it explicitly names every
input file (portfolio, market, fixings, conventions, curveconfig, pricingengine,
todaysmarket, simulation). The import handler must parse the orchestration
XML to discover the actual file set rather than relying on directory globs.
Rule-breakers requiring special-casing
Legacy/andAcademy/are meta-containers — one group session per child, not per top-level folder.ORE-Python/has its ownInput/ore.xmlplus 9 independent notebook sub-examples and 2 deeply-nested sub-runs.MarketRisk/— 27 distinct orchestrations in one folder; must be treated as 27 units, not one.Exposure/— 34ore_*.xmlorchestrations, flat layout.ExposureWithCollateral/— 13 top-level orchestrations plus a self-containedFirstMpor/nested run (its ownore.xml, portfolio, market data).CurveBuilding/BootstrapConsistency/— uses*_ore.xmlsuffix (EUR_xois_ore.xml,ois_ore.xml,USD_xois_ore.xml); globore*.xmlalone misses these. Discovery glob must also match*_ore.xml.Legacy/Example_48—ore.xmlat group root ANDInput/ore.xml; if identical (packaging artefact) keep one; if different, keep both as two units.Input/(top-level) — shared fixtures only; must be skipped.TradeGenerator/— no simulation files; skip.Products/Example_Trades/andProducts/SupportedTrades/— trade catalogues, not runnable simulations; skip.- Editor backup files (
#ore_sensi.xml#, etc.) — filter with regex^#.*#$. ExpectedOutput/trees — never recurse into directories namedExpectedOutput,bak,Calc,xlwings,Helpers.
Resolution: recommended strategy
Option D — Batch import with parent/child sessions, anchored on orchestration XML, with file set discovered by parsing the orchestration XML.
Import unit definition
One import unit = the file-set referenced by a single ORE orchestration XML
(ore.xml, ore_*.xml, or *_ore.xml). The unit boundaries are determined
by parsing the orchestration XML's <Portfolio>, <Markets>, <Conventions>,
<CurveConfig>, <PricingEngine> and <TodaysMarket> elements.
Session hierarchy (parent_session_id is required)
A nullable self-referential FK parent_session_id on
ores_data_import_sessions_tbl is required. Recommended two-level hierarchy:
- Batch session (
parent_session_id = NULL): one per import action; records the user-selected root path and timestamp. - Unit session (
parent_session_id = batch): one per orchestration XML discovered; holds imported trades, market data, etc.
An optional third level (group session for Legacy/, Academy/) may be added
later without schema changes.
Orchestration XML discovery algorithm
1. Recursively walk from the user-selected root. 2. Skip entire subtrees named: ExpectedOutput, bak, Calc, xlwings, Helpers, Notebooks/Dependencies, ExampleScripts, Example_Trades, SupportedTrades. 3. Skip top-level Input/ and TradeGenerator/ that contain no ore*.xml at any level. 4. At each directory: collect files matching ore*.xml OR *_ore.xml, filtering out editor backups (^#.*#$). 5. Each matched file becomes one unit session anchor. 6. Parse each orchestration XML to enumerate the actual file set for that unit. 7. Resolve referenced file paths relative to the orchestration XML's directory, then walk up to the nearest Input/ ancestor if not found locally (handles MarketRisk variants referencing ../conventions.xml).
Handling groups with many orchestrations
Groups like MarketRisk (27 orchestrations) and Exposure (34) produce 27 or
34 unit sessions under a single batch. The Data Import Session UI must support
filtering/grouping by batch and by the source group folder. Deduplication: if
two unit sessions in the same batch reference the same portfolio file, record
the file once and link both sessions to it.
Exceptions handled by the algorithm above
All rule-breakers listed in the previous section are covered:
- Meta-containers (
Legacy/,Academy/): the recursive walk finds orchestration XMLs in children and creates a unit session per orchestration. - Suffix outlier (
*_ore.xml): the double glob covers it. - Nested sub-runs (
ExposureWithCollateral/FirstMpor/,ORE-Pythondeep nests): the recursive walk finds them. Legacy/Example_48rootore.xml: deduplicated againstInput/ore.xmlby comparing file content hash.- Non-runnable folders: excluded by the skip list in step 2.
Files to Change
Database
| File | Change |
|---|---|
projects/ores.sql/create/trading/trading_create.sql |
Include new alter scripts |
projects/ores.sql/create/shared/data_import_sessions_create.sql |
New: shared import sessions table (with nullable parent_session_id FK for batch/unit hierarchy) |
projects/ores.sql/create/trading/trading_trades_pending_columns_add.sql |
Alter: add import_session_id, validation_errors, source_position, raw_data, npv columns |
projects/ores.sql/populate/trading/trading_pending_book_populate.sql |
New: seed Pending Book record |
projects/ores.sql/populate/dq/dq_fsm_trade_status_populate.sql |
Add pending state + stage/book/reject_pending transitions |
projects/ores.sql/populate/dq/dq_fsm_populate.sql |
Add completed_with_warnings state + transition to workflow instance FSM |
projects/ores.sql/populate/workflow/… |
Rename workflow definition to data_import |
| Reference data table alter scripts | Add is_live, import_session_id to conventions, curves, market data, pricing config tables |
projects/ores.sql/service_registry/… |
Grants for new session table |
Trading API and core
| File | Change |
|---|---|
projects/ores.trading.api/include/…/domain/trade.hpp |
Add validation_errors, source_position, raw_data, npv fields |
projects/ores.trading.core/…/trade_entity.* |
Map new columns |
projects/ores.trading.core/src/service/booking_service.cpp |
New: pending → new promotion service (validate → create instrument → update book/status) |
projects/ores.trading.service/src/messaging/… |
New NATS handlers: list_pending, book_pending, reject_pending |
ORE / data import service
| File | Change |
|---|---|
projects/ores.ore.service/src/messaging/ore_import_execute_handler.cpp |
Rename to data_import_execute_handler.cpp; process full ORE directory; stage trades to Pending Book; stage ref data with is_live=false |
projects/ores.ore.core/planner/ore_import_planner.* |
Update to discover all ORE artefact types; return classified file list |
projects/ores.ore.core/scanner/ore_directory_scanner.* |
Update to classify files by type (portfolio XML, market data, conventions, etc.) |
Workflow
| File | Change |
|---|---|
projects/ores.workflow.api/include/…/messaging/workflow_query_protocol.hpp |
Add workflow_failed_item and failed_items |
projects/ores.workflow.core/src/messaging/workflow_query_handler.cpp |
Populate failed_items from response_json |
projects/ores.workflow.core/src/messaging/… (step completion handler) |
Use complete_with_warnings transition |
Qt UI
| File | Change |
|---|---|
projects/ores.qt.trading/include/…/DataImportSessionController.hpp |
New |
projects/ores.qt.trading/src/DataImportSessionController.cpp |
New: owns import action, session management |
projects/ores.qt.trading/include/…/DataImportSessionWindow.hpp |
New: MDI window with session selector + tab notebook |
projects/ores.qt.trading/src/DataImportSessionWindow.cpp |
New |
projects/ores.qt.trading/include/…/PendingTradesTab.hpp |
New: Trades tab (filter bar, action bar, virtual grid, inspector) |
projects/ores.qt.trading/src/PendingTradesTab.cpp |
New |
projects/ores.qt.trading/include/…/ImportedDataTab.hpp |
New: reusable tab for market data / conventions / curves / pricing config |
projects/ores.qt.trading/src/ImportedDataTab.cpp |
New |
projects/ores.qt.trading/src/TradeController.cpp |
Remove onImportTradesRequested, book-selection dialog, related signals |
projects/ores.qt.trading/src/TradeMdiWindow.cpp |
Remove import toolbar action and importTradesRequested signal |
projects/ores.qt.trading/src/ImportTradeDialog.* |
Delete |
projects/ores.qt.workflow/src/WorkflowMdiWindow.cpp |
Amber badge for completed_with_warnings; failed_items table; "Show in Data Import Session" link |
projects/ores.qt.app/src/MainWindow.cpp |
Data Transfer menu: add Data Import item; wire DataImportSessionController |
| Portfolio Explorer source file | Remove import action |
Implementation Steps
Phase 1: Directory analysis and import unit decision (RESOLVED)
Analysis completed 2026-05-17. See "ORE Examples Import Unit Analysis"
section above for full findings. Decision: Option D (batch import with
parent/child sessions) anchored on orchestration XML, file set discovered by
parsing the orchestration XML. parent_session_id is required on the session
table. Phase 2 may proceed.
Phase 2: Database and schema
- Create
ores_data_import_sessions_tblwith nullableparent_session_id(batch → unit session hierarchy; see analysis section). - Add pending columns to
ores_trading_trades_tbl. - Seed Pending Book record.
- Add
pendingstate + transitions to trade status FSM. - Add
completed_with_warningsto workflow instance FSM. - Add
is_live+import_session_idto reference data tables. - Rename workflow definition to
data_import. - Add grants; run
recreate_database.sh; run schema validation.
Phase 3: Trading API, core, and service
- Add new columns to trade domain type and entity.
- Implement
booking_service: validate → create instrument → update book/status. - Wire NATS handlers: list_pending, book_pending, reject_pending.
- Unit tests.
Phase 4: Data import handler
- Rename to
data_import_execute_handler. - Implement full directory scan: classify files by type.
- Stage trades to Pending Book; stage ref data with
is_live = false. - Return
completed_with_warningsfor invalid entries. - Update planner/scanner.
Phase 5: Workflow UI
- Amber badge for
completed_with_warnings. failed_itemstable in step details.- "Show in Data Import Session" link.
- Update step-completion handler.
Phase 6: UI reorganisation
- Remove import actions from Trades window and Portfolio Explorer.
- Delete
ImportTradeDialog. - Add Data Import item under Data Transfer menu.
- Wire
DataImportSessionController.
Phase 7: Data Import Session UI
DataImportSessionWindow: session selector + notebook.PendingTradesTab: filter bar, action bar, virtual grid, inspector panel.ImportedDataTab: reusable for market data / conventions / curves / pricing.- Bulk actions: Assign Book, Assign Counterparty, Validate, Book Selected, Reject, Mark as Live, Discard.
- Post-import auto-open and summary banner.
- Reserve NPV column and "Value Selected" (disabled placeholder).
Expected Outcome
| Metric | Before | After |
|---|---|---|
| Trade with import errors | Written to live book; may crash UI | Staged in Pending Book; never enters live table until booked |
| Orphaned instruments | Possible | Impossible — created only at booking time |
| Non-trade data isolation | None — all data immediately live | is_live = false until user activates |
| Workflow after partial import | Shows completed (misleading) |
Shows completed_with_warnings in amber |
| Failed items | Only flat log text | Structured table in step details |
| Import entry point | Scattered | Single: Data Transfer → Data Import |
| Book required at import time | Yes | No — assigned post-staging |
| ORE engine during import | Yes — slow | No — pure parse-and-stage |
| Data traceability | None | import_session_id on every imported row |
| Full ORE data set | Trades only | Trades + market data + conventions + curves + pricing configs |
Additional Notes
Previous import_failed FSM plan superseded
Bad trades stay in the Pending Book rather than reaching the live table in a
broken state. The import_failed state, import_error column, and
mark_trade_import_failed endpoint from earlier design iterations are not
required.
Pending trades and compute runs
Only trades with status = new (or later) in a real book are visible to
compute runs. Pending Book trades are invisible to the risk engine by design.
Compute runs and is_live
The compute service must be audited to ensure all reference-data queries filter
on is_live = true. This is a correctness requirement, not just a UI concern.
Dedup and shadowing
When the user activates a non-live row that has the same natural key as an
existing live row, the service must warn before overwriting. The previous live
row should be archived (is_live = false, superseded_at timestamp) rather
than deleted, to preserve history.
Data Transfer → Data Export (future)
The Data Transfer menu is designed to accommodate export alongside import. Export is out of scope for this plan but the menu structure should reflect it.
Workflow definition DB record
The old workflow type name must be updated to data_import. Historical run
records carry the old name — no backfill required.
Workflow instance FSM state vs step outcome
step_outcome::completed_with_warnings is a step property. The workflow
instance completed_with_warnings state is distinct: one partially-failing
import step causes the entire run to be marked accordingly.
Data lineage is structural, not commentary
Provenance is stored as FK/column data, enabling relational queries. Human- readable notes can be derived but are not the source of truth.