diff --git a/context/repo-map.md b/context/repo-map.md index 059c28e..21fc761 100644 --- a/context/repo-map.md +++ b/context/repo-map.md @@ -93,10 +93,11 @@ pub struct Model { // set_cell(&mut self, key: CellKey, value: CellValue) // evaluate(&self, key: &CellKey) -> Option [formulas + raw data] // evaluate_aggregated(&self, key, none_cats) -> Option [sums over hidden dims] -// add_formula(&mut self, formula: Formula) [replaces same target+category] +// recompute_formulas(&mut self, none_cats) [fixed-point formula cache] +// add_formula(&mut self, formula: Formula) [replaces same target+category, adds item] // remove_formula(&mut self, target, category) // category_names(&self) -> Vec<&str> [includes virtual] -// regular_category_names(&self) -> Vec<&str> [excludes _Index, _Dim] +// regular_category_names(&self) -> Vec<&str> [excludes _Index, _Dim, _Measure] const MAX_CATEGORIES: usize = 12; // virtual categories don't count ``` @@ -114,8 +115,10 @@ pub struct CellKey(pub Vec<(String, String)>); // always sorted by category nam pub enum CellValue { Number(f64), Text(String), + Error(String), // formula evaluation error (circular ref, div/0, etc.) } // CellValue::as_f64() -> Option +// CellValue::is_error() -> bool pub struct DataStore { cells: HashMap, @@ -141,7 +144,7 @@ pub struct Category { // Category::add_item(&mut self, name) -> ItemId [deduplicates by name] // Category::ordered_item_names(&self) -> Vec<&str> [respects group order] -pub enum CategoryKind { Regular, VirtualIndex, VirtualDim, Label } +pub enum CategoryKind { Regular, VirtualIndex, VirtualDim, VirtualMeasure, Label } ``` ### Formula System @@ -480,8 +483,9 @@ examples). 1. **Commands never mutate.** They receive `&CmdContext` (read-only) and return `Vec>`. 2. **CellKey is always sorted.** Use `CellKey::new()` — never construct the inner Vec directly. 3. **`category_mut()` for adding items.** `Model` has no `add_item` method; get the category first: `m.category_mut("Region").unwrap().add_item("East")`. -4. **Virtual categories** `_Index` and `_Dim` always exist. `is_empty_model()` checks whether any *non-virtual* categories exist. +4. **Virtual categories** `_Index`, `_Dim`, and `_Measure` always exist. `is_empty_model()` checks whether any *non-virtual* categories exist. `_Measure` holds numeric data fields and formula targets; `add_formula` auto-adds the target item. 5. **Display rounding is view-only.** `format_f64` (half-away-from-zero) is only called in rendering. Formula eval uses full f64. +5b. **Formula evaluation is fixed-point.** `recompute_formulas(none_cats)` iterates formula evaluation until values stabilize, using a cache. `evaluate_aggregated` checks the cache for formula results. Circular refs produce `CellValue::Error("circular")`. 6. **Keybindings are per-mode.** `ModeKey::from_app_mode()` resolves the current mode, then the corresponding `Keymap` is looked up. Normal + `search_mode=true` maps to `SearchMode`. 7. **`effect_cmd!` macro** generates a command struct that just produces effects. Use for simple commands without complex logic. 8. **`.improv` format is markdown-like**, not JSON. See `persistence/mod.rs`. JSON is legacy only.