Files
improvise/crates/improvise-formula
Edward Langley 56b1ff898a refactor(core): extract shared eval helpers (improvise-kdp, improvise-nrs)
model/types.rs carried four copy-pasted blocks across its two evaluation
paths (cached and uncached). All four copies were byte-identical — no
drift yet, but any change to aggregation or item lookup had to be made
twice to stay correct.

- apply_agg(values, func) — cell aggregation, shared by
  evaluate_aggregated and aggregate_raw. Absorbs the callers' emptiness
  guards so "empty means absent, not zero" is stated once.
- eval_agg(...) — formula-level SUM/AVG/MIN/MAX/COUNT, shared by
  eval_expr_cached and eval_expr. This pair was a second instance of the
  same defect, not named in either ticket but the same 27 duplicated
  lines. It keeps its own emptiness rule (0 where an identity exists,
  error otherwise) and now expresses that by delegating to apply_agg.
- Model::find_item_category — was a nested fn defined identically in
  both eval paths.

Filter joins the improvise-formula re-exports so eval_agg can name it.
Tests cover each helper directly, including the deliberate emptiness
asymmetry between the two aggregation paths.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-07-31 17:45:30 -07:00
..