refactor: make Model::formulas private, expose read-only accessor

Previously `pub formulas: Vec<Formula>` allowed any code to call
`model.formulas.push(formula)` directly, bypassing the dedup logic in
`add_formula` that enforces the (target, target_category) uniqueness
invariant.

Making the field private means the only mutation paths are
`add_formula` and `remove_formula`, both of which maintain the invariant.
A `pub fn formulas(&self) -> &[Formula]` accessor preserves read access
for the UI and tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Ed L
2026-03-24 00:18:43 -07:00
parent d99d22820e
commit 5434a60cc4
3 changed files with 10 additions and 6 deletions

View File

@ -595,7 +595,7 @@ impl App {
fn handle_formula_panel_key(&mut self, key: KeyEvent) -> Result<()> {
// Clamp cursor in case the formula list shrank since it was last set.
let flen = self.model.formulas.len();
let flen = self.model.formulas().len();
if flen == 0 { self.formula_cursor = 0; }
else { self.formula_cursor = self.formula_cursor.min(flen - 1); }
@ -605,8 +605,8 @@ impl App {
self.mode = AppMode::FormulaEdit { buffer: String::new() };
}
KeyCode::Char('d') | KeyCode::Delete => {
if self.formula_cursor < self.model.formulas.len() {
let f = &self.model.formulas[self.formula_cursor];
if self.formula_cursor < self.model.formulas().len() {
let f = &self.model.formulas()[self.formula_cursor];
let target = f.target.clone();
let target_category = f.target_category.clone();
command::dispatch(&mut self.model, &Command::RemoveFormula { target, target_category });
@ -618,7 +618,7 @@ impl App {
if self.formula_cursor > 0 { self.formula_cursor -= 1; }
}
KeyCode::Down | KeyCode::Char('j') => {
if self.formula_cursor + 1 < self.model.formulas.len() { self.formula_cursor += 1; }
if self.formula_cursor + 1 < self.model.formulas().len() { self.formula_cursor += 1; }
}
_ => {}
}