improvise-lnkb: the folded category reads as absent to IS and WHERE, as on None

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
Edward Langley
2026-09-22 23:25:54 -07:00
parent 689c7665da
commit 94e8f0f08e
2 changed files with 49 additions and 10 deletions
+27 -10
View File
@@ -222,7 +222,10 @@ fn eval_expr(
agg_filter.as_ref(),
&|e, at| eval_expr(e, at, model, target_category, depth, Reach::Record),
),
Expr::Is(filter) => Ok(eval_is(context, filter)),
Expr::Is(filter) => Ok(eval_is(
model.read_coordinate(context, &filter.category, reach),
filter,
)),
Expr::If(cond, then, else_) => {
match eval_bool(cond, context, model, target_category, depth, reach)? {
true => eval(then),
@@ -270,10 +273,8 @@ fn eval_bool(
/// `Cat IS Item` as a number. A cell with no `Cat` coordinate is **not** that
/// item, matching `Formula::filter`'s own `unwrap_or(false)` — §13.
fn eval_is(context: &CellKey, filter: &Filter) -> f64 {
context
.get(&filter.category)
.is_some_and(|v| v == filter.item.as_str()) as i32 as f64
fn eval_is(coordinate: Option<&str>, filter: &Filter) -> f64 {
coordinate.is_some_and(|v| v == filter.item.as_str()) as i32 as f64
}
/// Whether a grid hides dimensions a cell key does not name. The emptiness of
@@ -678,6 +679,23 @@ impl Model {
}
}
/// A coordinate as a formula reads it. At a fold a group's name is no item, so
/// the folded category reads as absent, as on `Axis::None` (improvise-lnkb).
fn read_coordinate<'k>(&self, context: &'k CellKey, cat: &str, reach: Reach) -> Option<&'k str> {
let value = context.get(cat)?;
match reach {
Reach::Fold { .. } if self.names_a_group(cat, value) => None,
Reach::Fold { .. } | Reach::Record => Some(value),
}
}
/// Whether `name` is a group of `cat` rather than one of its items.
fn names_a_group(&self, cat: &str, name: &str) -> bool {
self.category(cat).is_some_and(|c| {
!c.items.contains_key(name) && !c.items_in_group(name).is_empty()
})
}
/// The contexts an aggregate inside a formula pools over at `context`.
fn contexts_of(&self, context: &CellKey, reach: Reach) -> Vec<CellKey> {
let members = match reach {
@@ -717,10 +735,9 @@ impl Model {
agg: Aggregation,
reach: Reach,
) -> Option<CellValue> {
let applies = formula
.filter
.as_ref()
.is_none_or(|f| key.get(&f.category) == Some(f.item.as_str()));
let applies = formula.filter.as_ref().is_none_or(|f| {
self.read_coordinate(key, &f.category, reach) == Some(f.item.as_str())
});
if !applies {
return self.fold_stored(key, members, agg);
}
@@ -905,7 +922,7 @@ impl Model {
eval_expr(e, at, model, target_category, depth, Reach::Record)
},
),
Expr::Is(filter) => Ok(eval_is(context, filter)),
Expr::Is(filter) => Ok(eval_is(context.get(&filter.category), filter)),
Expr::If(cond, then, else_) => {
let cv = eval_bool_cached(cond, context, model, target_category, none_cats)?;
if cv {
+22
View File
@@ -1819,6 +1819,28 @@ mod tests {
}
}
/// improvise-lnkb: the folded category reads as absent, as on `Axis::None` — see
/// context/test-evidence/core.md.
#[test]
fn a_fold_answers_is_and_where_on_its_category_as_the_none_axis_does() {
let formulas = [
"Flag = Month IS \"Q1\"",
"Marked = Revenue * 2 WHERE Month = \"Q1\"",
];
for measure in ["Flag", "Marked"] {
let mut folded = margin_book(&formulas);
folded.active_view_mut().toggle_group_collapse("Month", "Q1");
let fold = grid_value(&mut folded, "Q1", measure);
let mut none = margin_book(&formulas);
none.active_view_mut().set_axis("Month", Axis::None);
let over_none = grid_value(&mut none, "", measure);
assert_eq!(fold, over_none, "{measure}: the fold and the None axis differ");
}
let mut folded = margin_book(&formulas);
folded.active_view_mut().toggle_group_collapse("Month", "Q1");
assert_eq!(grid_value(&mut folded, "Q1", "Flag"), Some(0.0), "false, not absent");
}
/// improvise-eccl's guard on the other side: an aggregate INSIDE the formula
/// still pools every record the fold covers.
#[test]