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_columnsand 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,DepthandTimeStepare qualifiers by name, and the list is one constant in the generator. Currencyis 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 exactlyCurrencyto 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.