Task: Give every family its column roles

Table of Contents

This page documents a task in the Model every output ORE writes story. It captures the goal, current status, acceptance, and any notes or results.

1. Goal

Every family states which of its columns identify a row, which state the context of a figure, and which measure, so one reader can serve them all.

2. Status

Field Value
State DONE
Parent story Model every output ORE writes
Now Nothing.
Waiting on Nothing.
Next Nothing.
Last touched 2026-10-31

3. Acceptance

  • Each family states key_columns, qualifier_columns, measure_columns and whether its measures are open.
  • A column every variant of a family states is required; a column only some variants state is a qualifier another analytic added or an open measure, and the family says which.
  • A configuration-driven family states its measures as open, so a curve, factor or quantile the samples do not show is still a measure.
  • The catalogue's test fails when a family's required columns disagree with a sample it covers.

4. Plan

The corpus states what a column holds and the writers state what it is for. Every column gets exactly one role: a key, a qualifier or a measure.

The derivation is the corpus's own evidence. A column that every header variant of a family states is required, and a key is required by definition, so a name only some variants state is never a key. A text, date or time column that is not a key states context, so it is a qualifier; so does a number that names a position rather than a figure, such as ShiftSize_1, MaturityTime or DateIndex. Every other numeric column is a measure.

A family's measures are open when its variants disagree on which measures they state, because that is what a column filled from the configuration looks like: curves.csv states one column for each curve the run built, var.csv one for each quantile requested, dim_regression one for each regressor. A reader can then accept a measure it has not seen in that family and refuse one in a family whose measures are closed.

The roles are part of the generated data and the API exposes them through role_of. A test proves they partition the columns: no column without a role, no column with two, and the three lists together are the family's columns.

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
Columns with a role 1 584: 112 keys, 240 qualifiers, 1 232 measures ores.ore.core.tests "[output_catalogue]" 52dd57ee52
Families whose measures are open 5: curves, dim_evolution, dim_regression, stress_scenarios, var python3 projects/ores.ore/scripts/generate_output_catalogue.py --check 52dd57ee52
The roles partition the columns every column states exactly one role ores.ore.core.tests "[output_catalogue]" 52dd57ee52

6. Notes

The three causes of a variant, from the corpus: configuration columns (curves, dim regression, var, scenario), analytic augmentation (exposure under stress or sensitivity) and a stale expected file (the 25-column flows.csv in MinimalSetup is a subset of the writer's 27).

7. Notes

  • The three roles come from the corpus, not from a hand-written table, so a family added tomorrow states its own roles. The one judgement that is not the corpus's is which numbers name a position rather than a figure: ShiftSize_1, ShiftSize_2, MaturityTime, DateIndex, Depth and TimeStep are qualifiers by name, and the list is one constant in the generator.
  • Currency is a qualifier, not a measure, because it states what a figure is in rather than being one. The reader is expected to promote a column named exactly Currency to the metric's currency.
  • Openness is derived: a family is open when its variants disagree on their measures. That finds the five families a writer fills from the configuration where the samples show more than one shape. It cannot find a configuration column in a family the samples only ever show one shape of, so a reader that refuses an unknown measure must say so rather than guess.

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

PR Title
#4203 [ore] Give every output column a role

10. Review

Comment summary File Decision Notes
       

11. Result

Every family states the job of each of its columns. The catalogue reports 112 keys, 240 qualifiers and 1 232 measures over the same 1 584 columns, so the roles partition what the catalogue already named, and five families say their measures are open: curves, dim_evolution, dim_regression, stress_scenarios and var.

The suite proves the partition rather than trusting it: no column without a role, no column with two, and the three lists together equal the family's columns. It also proves a key is always a required column, and that npv states NPV and Notional as measures while Maturity and NpvCurrency are qualifiers.

Deriving the roles turned up two facts worth keeping. A column that only some variants state cannot be a key, which is why the keys come from the required set and not from the union of the samples. And openness can only be seen where the samples show more than one shape, so a family that gains a configuration column in a shape the corpus never shows reads as closed; the reader that refuses an unknown measure must say what it refused rather than guess.

Emacs 29.3 (Org mode 9.6.15)