Families-comparison view: overlay a family's members in one chart (aura chart <family>) #107

Closed
opened 2026-06-21 17:31:55 +02:00 by Brummel · 1 comment
Owner

Capability

A families-comparison view: aura chart <family> overlays the chosen tap (default equity) of all members of a family in one self-contained uPlot page — consistent across sweep / MC / walk-forward families. Today aura chart <name> charts a single run (and aura chart <name>/<member> a single member); this adds the cross-member comparison view that the single-run trace charts (#101) deferred.

The view is decoupled from family production: it consumes a "set of runs to compare" (Vec<(label, RunTraces)>); a family is the first producer of such a set. This is the deliberate first step toward the programmable analysis meta-level (C21) — sweep/MC/WFO becoming composable tools that feed a general comparable-run-set — without rebuilding the orchestration axes in this cycle.

Ratified design (in-context brainstorm, Approach A + write-guard)

  • aura-engine — unchanged (headless serializer, C14). join_on_ts + ColumnarTrace already do the alignment.
  • aura-registry (owner of the trace store + families lineage, C18) — the "set of runs" resolver + name classification:
    • TraceStore::name_kind(name) -> {Run, Family, NotFound}: top-level index.jsonRun; else member subdirs (each with index.json) → Family; else NotFound.
    • TraceStore::read_family(name) -> Result<Vec<FamilyMember{ key, traces }>>: enumerate immediate subdirs with index.json, read each via the existing read(), sorted by key (deterministic, C1).
    • TraceStore::ensure_name_free(name, kind): the write-guard, called once per command before any write — a single-run write refuses if name is already a family; a family write refuses if name is already a single run (exit 2, refuse-don't-guess, C10/C18).
  • aura-clibuild_comparison_chart_data(members, tap) -> ChartData (one Series per member, labelled by member_key, aligned on the union-ts spine via existing join_on_ts; mirror of build_chart_data with members-as-sides); emit_chart branches on name_kind; new --tap <name> flag (default equity); --panels reused for small-multiples.

Cross-kind consistency from one mechanism: sweep/MC members share the window → union spine = shared axis → true overlay; walk-forward members are disjoint OOS windows → null-complementary on the union spine → the stitched curve. Ordinal x (cycle 0057) carries both. No per-family-kind special-casing.

Name-resolution guarantee (the gating condition)

aura chart <name> resolves to exactly one of {single-run, family, not-found} — a total function. The read-rule is structural; the only ambiguous on-disk state (a name used by both a run and a family) is made unreachable by the write-guard, which refuses cross-kind name reuse. Same-kind re-run (overwrite) stays allowed.

Scope / non-goals

  • In scope (one iteration): name_kind + read_family + ensure_name_free + build_comparison_chart_data + the emit_chart branch + --tap + tests.
  • Out of scope (unblocked follow-ons): the run-context header on the chart (#102); the multi-output viewer case (#47); the orchestration-composability rebuild — sweep/MC/WFO as composable tools in a programmable analysis meta-level (the larger C21 cycle, deliberately deferred); stale-member cleanup on family re-run.

Provenance

Settled in an in-context brainstorm under /boss (2026-06-21). The user chose Approach A (auto-detecting aura chart, resolver in aura-registry) conditional on a guaranteed unambiguous name resolution, which the write-guard supplies, and ratified all design sections. Scope boundary (view now, meta-level rebuild later) confirmed by the user.

Ledger anchors

C21 (the World / meta-level is the product), C22 (playground = trace explorer, web-from-disk), C18 (run registry / families lineage), C14 (headless engine, web face is a downstream consumer).

## Capability A **families-comparison view**: `aura chart <family>` overlays the chosen tap (default `equity`) of **all members of a family** in one self-contained uPlot page — consistent across sweep / MC / walk-forward families. Today `aura chart <name>` charts a single run (and `aura chart <name>/<member>` a single member); this adds the cross-member comparison view that the single-run trace charts (#101) deferred. The view is **decoupled from family production**: it consumes a "set of runs to compare" (`Vec<(label, RunTraces)>`); a family is the *first* producer of such a set. This is the deliberate first step toward the programmable analysis meta-level (C21) — sweep/MC/WFO becoming composable tools that feed a general comparable-run-set — **without** rebuilding the orchestration axes in this cycle. ## Ratified design (in-context brainstorm, Approach A + write-guard) - **`aura-engine`** — unchanged (headless serializer, C14). `join_on_ts` + `ColumnarTrace` already do the alignment. - **`aura-registry`** (owner of the trace store + families lineage, C18) — the "set of runs" resolver + name classification: - `TraceStore::name_kind(name) -> {Run, Family, NotFound}`: top-level `index.json` → `Run`; else member subdirs (each with `index.json`) → `Family`; else `NotFound`. - `TraceStore::read_family(name) -> Result<Vec<FamilyMember{ key, traces }>>`: enumerate immediate subdirs with `index.json`, read each via the existing `read()`, **sorted by key** (deterministic, C1). - `TraceStore::ensure_name_free(name, kind)`: the **write-guard**, called once per command before any write — a single-run write refuses if `name` is already a family; a family write refuses if `name` is already a single run (exit 2, refuse-don't-guess, C10/C18). - **`aura-cli`** — `build_comparison_chart_data(members, tap) -> ChartData` (one `Series` per member, labelled by `member_key`, aligned on the union-ts spine via existing `join_on_ts`; mirror of `build_chart_data` with members-as-sides); `emit_chart` branches on `name_kind`; new `--tap <name>` flag (default `equity`); `--panels` reused for small-multiples. **Cross-kind consistency from one mechanism:** sweep/MC members share the window → union spine = shared axis → true overlay; walk-forward members are disjoint OOS windows → null-complementary on the union spine → the stitched curve. Ordinal x (cycle 0057) carries both. No per-family-kind special-casing. ## Name-resolution guarantee (the gating condition) `aura chart <name>` resolves to **exactly one** of {single-run, family, not-found} — a total function. The read-rule is structural; the only ambiguous on-disk state (a name used by *both* a run and a family) is made **unreachable** by the write-guard, which refuses cross-kind name reuse. Same-kind re-run (overwrite) stays allowed. ## Scope / non-goals - **In scope (one iteration):** `name_kind` + `read_family` + `ensure_name_free` + `build_comparison_chart_data` + the `emit_chart` branch + `--tap` + tests. - **Out of scope (unblocked follow-ons):** the run-context header on the chart (#102); the multi-output viewer case (#47); **the orchestration-composability rebuild** — sweep/MC/WFO as composable tools in a programmable analysis meta-level (the larger C21 cycle, deliberately deferred); stale-member cleanup on family re-run. ## Provenance Settled in an in-context `brainstorm` under `/boss` (2026-06-21). The user chose Approach A (auto-detecting `aura chart`, resolver in `aura-registry`) **conditional on a guaranteed unambiguous name resolution**, which the write-guard supplies, and ratified all design sections. Scope boundary (view now, meta-level rebuild later) confirmed by the user. ## Ledger anchors C21 (the World / meta-level is the product), C22 (playground = trace explorer, web-from-disk), C18 (run registry / families lineage), C14 (headless engine, web face is a downstream consumer).
Brummel added the feature label 2026-06-21 17:31:55 +02:00
Author
Owner

Design reconciliation (specify)

Spec: 0061-families-comparison-view. One load-bearing fork surfaced while writing the spec; recording the derived decision before the spec is signed.

  • Fork: y-axis scale of the comparison overlay → all member-series of a family share one y-scale.
    Basis: derived. The comparison overlays the same tap (default equity, pips) across members, so the series measure one identical quantity; a shared y-scale is what makes their magnitudes comparable — per-series auto-ranging (the single-run path's behaviour, where the overlaid series are different taps with disjoint ranges, #101/cycle 0056) would defeat the comparison. So: single-run overlay keeps per-series scales (different taps); family-comparison overlay uses one shared scale (same tap across members). --tap exposure likewise shares one scale across members.
## Design reconciliation (specify) Spec: 0061-families-comparison-view. One load-bearing fork surfaced while writing the spec; recording the derived decision before the spec is signed. - **Fork: y-axis scale of the comparison overlay** → all member-series of a family **share one y-scale**. Basis: derived. The comparison overlays the *same* tap (default `equity`, pips) across members, so the series measure one identical quantity; a shared y-scale is what makes their magnitudes comparable — per-series auto-ranging (the single-run path's behaviour, where the overlaid series are *different* taps with disjoint ranges, #101/cycle 0056) would defeat the comparison. So: single-run overlay keeps per-series scales (different taps); family-comparison overlay uses one shared scale (same tap across members). `--tap exposure` likewise shares one scale across members.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Brummel/Aura#107