Skip to content

feat(odf): a write takes the cached result of what reads it away - #888

Open
andiwand wants to merge 1 commit into
feat/stale-formulasfrom
feat/ods-stale-cache
Open

feat(odf): a write takes the cached result of what reads it away#888
andiwand wants to merge 1 commit into
feat/stale-formulasfrom
feat/ods-stale-cache

Conversation

@andiwand

@andiwand andiwand commented Sep 11, 2026

Copy link
Copy Markdown
Member

🤖 Generated with Claude Code

Stacked on #887#886#885#884 — this PR's diff is the fifth commit. Last of the step-3 stack.

Step 3.4 of docs/design/spreadsheet-editing.md.

The problem

An edited input leaves every formula reading it computing an old number, and the saved .ods went on showing the result its producer cached. An .xlsx has a switch for exactly this — calcPr/@fullCalcOnLoad, which every save already sets. ODF has none.

What it does

So the result goes instead. drop_stale_results asks SheetDependencies which cells read the written position — directly or through another formula — and takes the attributes stating a value off each. The text:p showing it goes as an element rather than as a node, so the registry keeps no dangling one.

<!-- before --><table:table-cell table:formula="of:=SUM([.A1:.A2])" office:value-type="float" office:value="3"><text:p>3</text:p></table:table-cell>
<!-- after  --><table:table-cell table:formula="of:=SUM([.A1:.A2])"/>

The formula, the cell's style and a drawing anchored in the cell all stay. A cell stating a formula and no result is one a reader has to compute, and none can show a wrong number for.

A formula whose references could not be read keeps its result. Nothing says it is wrong, and blanking every named-range formula on an unrelated edit would cost more than it is worth. Document::unresolved_formulas() is what names them.

The cost until step 4: a cleared cell renders empty here too. That is the trade the design accepted — an empty cell says "not computed", a stale one says nothing.

The spike, as far as a CLI can answer it

LibreOffice's --convert-to recomputes whatever a file cached — a file whose cached result I hand-edited to 999 converted back to 3 — so it cannot show what a reader that does not recompute would display, and setting ODFRecalcMode to "never" in a scratch profile changed nothing. ODF states no recalculation switch at all, so the rule the file itself can carry is what is left.

End-to-end check: a real LibreOffice-written .ods, edited through Sheet::set_cell and saved by us, opens as a valid package and LibreOffice computes the cell we cleared (10 / 2 / 12, where the file states no result for the third).

Test

test/src/internal/odf/odf_sheet_stale_test.cpp, 7 cases from inline fixtures: the direct reader, the chain, a formula reading something else, a reader on another sheet, what the cell keeps, the saved file, and a write nothing reads.

Reference output: as said on #887, the output repos get one commit and one pin advance after the whole stack has landed.

An edited input leaves every formula reading it computing an old number, and
the saved file went on showing the result its producer cached. ODF states no
switch asking a reader to recompute - ooxml's `fullCalcOnLoad`, which every
xlsx save already sets - so the result goes instead: a cell stating a formula
and no result is one a reader has to compute, and none can show a wrong
number for.

`drop_stale_results` asks `SheetDependencies` which cells read the written
position, directly or through another formula, and takes the attributes
stating a value off each. The `text:p` showing it goes as an element rather
than as a node, so the registry keeps no dangling one. The formula, the
cell's style and a drawing anchored in the cell all stay.

A formula whose references could not be read keeps its result: nothing says
it is wrong, and blanking every one of them on an unrelated edit would cost
more than it is worth. Until the evaluator lands, a cleared cell renders
empty here too.

The spike, as far as a CLI can answer it: LibreOffice's `--convert-to`
recomputes whatever a file cached - a hand-edited wrong result came back
corrected - so it cannot show what a reader that does not recompute would
display, and its `ODFRecalcMode` setting changed nothing. An end-to-end check
confirms the saved package is valid and that LibreOffice computes the cell we
cleared.

Step 3.4 of `docs/design/spreadsheet-editing.md`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VVmjmddv2Ui17Nptc1ggue
@andiwand
andiwand force-pushed the feat/ods-stale-cache branch from ae5ed82 to f105f4d Compare September 11, 2026 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant