fix(incremental): pushdown takes the source alias, refuses cell edits, shares Eager's reads and pins stem order and refresh snapshots (improvise-rnak)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VdfEGXA7aJ6ftMsCc9PJze
This commit is contained in:
committed by
Edward Langley
parent
00cc83281e
commit
53868bb4d6
@@ -458,7 +458,30 @@ change log, no stems. These are the readings taken.
|
||||
same thing.
|
||||
5. **`define(edit)` takes a formula or an aggregation edit and refreshes.** A cell edit is the source's:
|
||||
`Model::set_cell` refuses it in a debug build.
|
||||
6. **What is and is not proven.** The tests run against `Remote` (`tests/support/remote.rs`), a scanning
|
||||
6. **What the differential proves, and what it does not.** `value`, `raw_fold`, `covered` and `total` are
|
||||
the same four functions for `Eager` and `Pushdown` (`reads.rs`; they were copies, and are shared now),
|
||||
so a Pushdown-against-Eager differential cannot see a mistake in them. `Pushdown::members` repeats
|
||||
`Eager::group_holds` in a different form (a span list against a predicate), and that repetition
|
||||
is compared. What the differential proves is the **source's** semantics: that `summarize`, `count`
|
||||
and `distinct_without` give, for every select the evaluator and the views make, the answers a
|
||||
`DataStore` gives. The evaluator over a source is proven equal to the evaluator over the owned
|
||||
store in `improvise-core` (`over_tests`). Nothing else is claimed.
|
||||
7. **A refresh wants one snapshot.** `refresh` asks `distinct_without` and then folds, so a source that
|
||||
changes between the queries can serve them from different revisions. The passes heal what they
|
||||
can: a write between two folds is read again by the next pass, and the cache ends equal to the new
|
||||
state's values (`writes_between_two_queries_of_a_refresh_are_healed_by_the_fixed_point`). A stem
|
||||
that appears after the stem list was taken has no cell until the next refresh
|
||||
(`a_stem_that_appears_between_the_stem_list_and_the_folds_waits_for_the_next_refresh`). A real source
|
||||
should serve a refresh from one read transaction; nothing here can ask it to.
|
||||
8. **The order of the stems is part of the contract.** The passes of the fixed point visit stems in the
|
||||
order `distinct_without` lists them, and a document whose stems read each other settles in as many
|
||||
passes as its dependency chain runs against that order, with a bound of sixteen. A chain of
|
||||
eighteen stems settles in one pass listed along the chain and not at all listed against it
|
||||
(`the_order_stems_are_listed_in_decides_a_result_and_a_source_must_keep_it`). No fixture before it
|
||||
had a result that depended on the order, and a source listing stems sorted passed everything.
|
||||
The first-seen order is `DataStore`'s insertion order; a source with no order of its own must
|
||||
fix one.
|
||||
9. **What is and is not proven.** The tests run against `Remote` (`tests/support/remote.rs`), a scanning
|
||||
in-memory table with counters, that shares no evaluator with `Eager` and answers queries over rows.
|
||||
Without a real SQL engine only the **contract** is proven: that a source answering these six
|
||||
queries as specified gives `Eager`'s answers, and what each read costs in queries. Nothing here
|
||||
|
||||
@@ -924,3 +924,36 @@ The same for `ClearCell`.
|
||||
|
||||
Review of #358: two backends over one feed; one write; `a.sync(); b.sync()`. The first sees it, the
|
||||
second does not. This pins the behaviour as documented rather than as a guarantee: a drain is destructive.
|
||||
|
||||
### the_order_stems_are_listed_in_decides_a_result_and_a_source_must_keep_it
|
||||
|
||||
Review of #360: stem order was invisible to every differential (a sorted `distinct_without` went
|
||||
uncaught). Eighteen products are stored in chain order with names that sort the other way, and one nested
|
||||
`IF` formula reads the product before it. Along the chain it settles in one pass (the last link is 18);
|
||||
sorted it needs one pass per link and the bound of sixteen leaves it `circular`. The test asserts both
|
||||
values, that a sound source passes the differential and that a source listing the stems sorted is a
|
||||
divergence. Rival: `DataStore::distinct_without` sorting fails it (the oracle then gives `circular`, so
|
||||
the first assertion fails). Before it, a source sorting its stems passed every differential; only the core stems test (which compares two stores) saw a sort.
|
||||
|
||||
### writes_between_two_queries_of_a_refresh_are_healed_by_the_fixed_point
|
||||
|
||||
Review of #360: a source that changes between the queries of one refresh. Another client's writes land
|
||||
right after the first fold; the cached Profit of Product A ends at 53, the new state's value, and not at
|
||||
13 (the old revenue less the new cost). The documented guard is one snapshot per refresh. Rival:
|
||||
none; this pins a behaviour that the fixed point gives and the note says may not be relied on.
|
||||
|
||||
### a_stem_that_appears_between_the_stem_list_and_the_folds_waits_for_the_next_refresh
|
||||
|
||||
The stem list is taken, then Product C is written: it has no formula cell until the next refresh,
|
||||
which has it (5).
|
||||
|
||||
### a_cell_edit_on_a_pushdown_is_refused
|
||||
|
||||
Review of #360: `define` applied a cell edit to the model, whose guard was a `debug_assert`; now an
|
||||
`assert!` of its own, with its own message. Rival: the assert removed fails it (the model's message
|
||||
differs).
|
||||
|
||||
### a_pushdown_can_be_built_over_the_exported_source_alias
|
||||
|
||||
`Pushdown::new` took a generic `Arc<Q>` that could not take a `SharedSource`; the test builds one from
|
||||
the alias and did not compile against the generic signature.
|
||||
|
||||
Reference in New Issue
Block a user