monthView folds from the start of the dataset, so it costs O(months) per
call. The summary sheet and every per-post sheet each called it once per
(post, month), making a full export O(posts x months^2). buildWorkbook now
takes one pass, indexes the figures by post, and hands that to the sheets.
TODO called this "fine at personal-budget scale". Measured against the old
code it is not, once history accumulates: 30 posts over 10 years went from
7983 ms to 135 ms (59x), and that work is synchronous on the main thread, so
it was a visible freeze on clicking Export. 10 posts x 2 years: 44 ms -> 2.5 ms.
content.xml is byte-for-byte identical on a fixture exercising every sheet
(versioned rules, an override, an archived post, a percent split, a fixed
split and a finance plan).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Generated in-browser with fflate, so export works offline. mimetype is
stored first and uncompressed as the ODS spec requires.
Also adds datasetMonthSpan to the domain views layer, which determines
the month range an export should cover: from the fold start through
the latest month touched by any month record or purchase slice,
including future finance-plan slices.
Widened the mimetype-header test's byte slice from 64 to 96 bytes: the
zip local-file header for "mimetype" is 38 bytes and ODS_MIMETYPE is
46 characters, so 64 bytes could never contain the full string
regardless of implementation.