docs: update design-principles for _Measure and fixed-point eval

Add VirtualMeasure to CategoryKind description, document _Measure as
third always-present virtual category, add section on fixed-point
formula evaluation strategy.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Edward Langley
2026-04-09 02:44:41 -07:00
parent 326e245c48
commit 001744f5cf

View File

@ -60,12 +60,14 @@ editing) is two commands composed at the binding level, not a monolithic handler
- `Binding` is `Cmd | Prefix | Sequence`. The keymap lookup returns one of these
three shapes; dispatch pattern-matches exhaustively.
- `CategoryKind` is `Regular | VirtualIndex | VirtualDim | Label`. Business rules
(e.g., the 12-category limit counts only `Regular`) are enforced by matching
on the enum, not by checking name prefixes. Virtual categories (`_Index`,
`_Dim`) exist solely for drill-down mechanics and must never leak into
user-facing logic — use `Model::regular_category_names()` when selecting a
default category for formulas, prompts, or other user-visible choices.
- `CategoryKind` is `Regular | VirtualIndex | VirtualDim | VirtualMeasure | Label`.
Business rules (e.g., the 12-category limit counts only `Regular`) are
enforced by matching on the enum, not by checking name prefixes. Virtual
categories (`_Index`, `_Dim`, `_Measure`) always exist: `_Index` and `_Dim`
support drill-down/records mode; `_Measure` holds numeric data fields and
formula targets (added automatically by `add_formula`). Use
`Model::regular_category_names()` when selecting a default category for
prompts or other user-visible choices.
### When You Add a Variant, the Compiler Finds Every Call Site
@ -157,6 +159,16 @@ A formula is a serializable struct: raw text, target name, category, AST, option
filter. It is stored in the model alongside regular data. The evaluator walks the
AST at read time. Formulas never become closures or runtime-generated code.
### Formula Evaluation Is Fixed-Point
`recompute_formulas(none_cats)` iterates formula evaluation until values
stabilize. Each pass evaluates all formula cells using the current cache
(for formula-derived values) and raw data aggregation (for data values).
This avoids recursive evaluation through `evaluate_aggregated` and
naturally handles chained formulas (`Margin = Profit / Revenue` where
`Profit = Revenue - Cost`). Circular references converge to
`CellValue::Error("circular")` after `MAX_EVAL_DEPTH` iterations.
### Display Rounding Is View-Only
Number formatting (`format_f64`) rounds for display. Formula evaluation always