Task: Configure every seeded report from the ORE examples

Table of Contents

This page documents a task in the Configure every seeded report from the ORE examples story. It captures the goal, current status, acceptance, and any notes or results.

1. Goal

Give every report ACME is seeded with the configuration it needs to run, so the chain executes it rather than failing before it starts.

A report is scoped to a root portfolio. The configuration names that portfolio, and the run resolves it to every book beneath it – that resolution is the population the run executes over, and it needs a method that answers it.

Concretely: go through the reports acme_demo seeds, take the analytics each one implies from the external/ore examples, and create the configuration each needs, scoped to the root portfolio that report belongs to.

Some reports have no meaningful portfolio scope – a data-quality or system-health report is about the installation, not about a book – so the task also decides what "scope" means for those, or records that they deliberately carry none.

2. Status

Field Value
State BACKLOG
Parent story Configure every seeded report from the ORE examples
Now The scope half is settled, and a pricing run showed that ORE recognises the analytic codes. That run stopped because the package carries no quotes for the run's as-of date.
Waiting on Market data at the run's as-of date, then a run per analytic family.
Next Make the gathered market data cover the as-of date, then run one report per family and record the engine's verdict for each code.
Last touched 2026-10-25
  • Every report definition acme_demo seeds for ACME either carries a configuration that resolves to at least one book, or is recorded as deliberately unscoped with the reason it has no scope.
  • A configuration is built from the external/ore example that matches the report's analytics: its observation model, market data type and analysis switches (NPV, cashflow, curves, sensitivity, simulation, XVA, stress) come from that example rather than being guessed.
  • A report names a root portfolio, and a SQL method returns every book under that root. The run uses that method as its scope, so a report added beneath the root is picked up without editing the configuration.
  • The configuration is created where its definition is created, so their ids line up by construction.

3. Plan

(Implementation strategy. Written when work starts; key decisions are distilled into the parent story's * Decisions at close, but the plan itself stays — it is the historical record of what we did.)

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

5. Notes

What the chain does today. report_execution_handler::gather_trades resolves the configuration by definition id and then requires a scope:

const auto config = config_repo.find_by_definition_id(tenant_ctx, req.definition_id);
if (!config) { /* "risk_report_config not found for definition " */ }
const auto book_ids = config_repo.resolve_book_ids(tenant_ctx, config_id);
if (book_ids.empty()) { /* "no books or portfolios in scope" */ }

A configuration alone is therefore not enough: it must resolve to at least one book, or the run fails one step later with a different message.

Why this cannot be a seed. A static seed cannot reference a definition, because ores_reporting_publish_report_definitions_from_dq_fn in projects/ores.sql/create/reporting/reporting_publish_from_dq_create.sql inserts gen_random_uuid() for every definition it publishes, so the ids differ in every tenant. The configuration has to be created in that function, where the definition it names is being created.

Nothing in the tree inserts a risk report configuration today: the only populate hit is an unrelated FSM lifecycle file.

How this differs from the minimal unblock. C39230E7 asks for at least one configuration so a run can be attempted at all. This task is the full pass – every seeded report, each built from the matching external/ore example.

Open questions.

  • Ordering. Definitions are published during the bundle step. Do the party's portfolios and books exist by then? If not, a configuration created there resolves to nothing and fails exactly as today, only later.
  • The root relation. A method returning every book under a root portfolio needs a defined parent/child relation between the two. Whether that is a column on the portfolio, one on the book, or an existing hierarchy decides the method's shape, so it is the first thing to settle.

What the proof settled, and what it did not. Read on 2026-10-25, after the report ran on a database built from nothing.

Settled:

  • Scope. Every one of the 78 definitions resolves to at least one book through its configuration (measured: 78 of 78, 46 portfolio scope rows, no unscoped definition). The root relation exists as a portfolio parent, and ores_trading_get_book_ids_by_portfolio_fn expands a root to its subtree; ores_reporting_resolve_book_ids_for_config_fn uses it, and the run took 20 books from Global Portfolio.
  • Ordering and the id relation. The configuration is created in ores_reporting_publish_risk_report_configs_from_dq_fn, alongside the definition, so the ids line up by construction. The party's portfolios exist by then, which is why the scope publishes.

Not settled, and the reason this task stays open:

  • The switches may not come from the examples. The vendored examples use eleven analytic types: npv, cashflow, curves, xva, simulation, sensitivity, stress, calibration, scenario, creditcurves, amc. The seed switches on codes no example names: portfolio_details, saccr, pfe, parametric_var, historical_var, credit_curves, pnl_explain. ores.ore holds no table mapping a platform code to an ORE type, so the code is passed to the engine as written.
  • What the second run showed. "Board Risk Dashboard" (npv, saccr, parametric_var) was triggered on the same database. ORE named all three: PRICING, PARAMETRIC_VAR and SA_CCR. So the engine does recognise these codes; the doubt about them was wrong. It then failed each one with Failed to build market: There are no quotes available for date October 23rd, 2026, so the failure is the market data the package carries, not the switch. The instance went to failed and the result carried the engine's own message, which is the verdict fix holding on a real report.
  • Only portfolio_details has a passing run. The pricing families need market data for the run's as-of date before anything can be said about their switches.

Next on this task. Two things, in order. First, make the gathered market data cover the run's as-of date, which is what stopped the second run. Then run one report per analytic family and record the engine's verdict for each code. The holding party's definitions cover portfolio_details, npv, saccr, parametric_var and cashflow; the legal entities' definitions cover curves, credit_curves, sensitivity, simulation, pfe, xva and historical_var, and reaching those needs a run grant for the entity's party. Close this task when every code has either a passing run or a mapping.

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

7. PRs

PR Title
   

8. Review

Comment summary File Decision Notes
       

9. Result

Emacs 29.3 (Org mode 9.6.15)