fit: fold the member record onto partial, not onto context

Self-review of the commit before it. The record key the fold evaluates at was
built by folding the record's coordinates onto `context`, which still carries
the formula's own target coordinate. Harmless for a `_Measure` target, because
`Expr::Ref` overwrites `_Measure` on the way in — and not harmless for a formula
targeting any other category: the record key keeps `Levy=Tax`, `evaluate_depth`
matches the same formula again at that key, and the cell converges to
`Error("circular")`. A formula silently self-referencing through its own
aggregate.

`partial` is `context.without(target_category)` plus any inline WHERE, so
folding onto it drops the target coordinate by construction. Every member
satisfies `partial` by definition — that is what selected them — so nothing
constraining is lost.

`a_formula_targeting_another_category_still_folds_over_its_records` is the
guard; restoring the `context` fold fails it with `Error("circular")` against
`11.0` and leaves the other eight passing. Evidence in
`context/test-evidence/core.md`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Edward Langley
2026-09-20 11:54:29 -07:00
parent 022e12f9b4
commit 0edd26b1b5
2 changed files with 36 additions and 1 deletions
+19
View File
@@ -477,3 +477,22 @@ missing cell, a categorical column and a date column, so all four roles appear.
Fault injected: swapping the `Numeric` and `Missing` pushes in `feature_roles`
fails this test **and** `encode_row_replays_the_training_expansion`, which is
the pair that would have disagreed.
### a_formula_targeting_another_category_still_folds_over_its_records
Found by self-review, not by the ticket. The fold evaluates the inner expression
at each member record's key, and the first version built that key by folding the
record's coordinates onto **`context`** — which still carries the formula's own
target coordinate. For the ordinary `_Measure` target that is harmless, because
`Expr::Ref` overwrites `_Measure` on the way in. For a formula targeting any
other category it is not: the record key keeps `Levy=Tax`, so `evaluate_depth`
matches the formula again at that key and the whole cell converges to
`Error("circular")` — a formula quietly self-referencing through its own
aggregate.
The key is now folded onto `partial` (`context.without(target_category)`, plus
any inline `WHERE`), which drops the target coordinate by construction rather
than by every caller remembering to. Fault injected by restoring the `context`
fold: this test fails with `Error("circular")` against `11.0` and the other
eight pass, which is why it is a separate test and not an extra assertion on one
of them.