Releases: emulette/cellrune
Releases · emulette/cellrune
Release list
v0.1.2
Added
- A single data-driven conformance expectation suite.
conformance/holds redistributable
matrices — every literal, every formula, and the value a recorded oracle saved for it — and
the normal workspace test run reconstructs every matrix and compares CellRune's calculation
against the oracle. New functions and syntax extend the same data set.
The first matrix is the Apache POIFormulaEvalTestDatacorpus (Apache-2.0): 1,295 cases
against a saved Microsoft Excel 2013 calculation cache, 1,290 matching within a
scale-relative1e-8and 5 divergences documented case by case. A documented divergence is
enforced in both directions, so neither the oracle side nor the CellRune side of it can drift
silently, and a divergence without an explanatory note fails the test. An extraction tool
(extract_conformance_matrix) accepts ordinary and resolved shared formulas and rejects
workbook metadata the v1 matrix cannot reproduce. - A semver invariant inside the existing test suite (
tests/public_api.rs). The sixteen exported
enums that are notnon_exhaustiveare matched without wildcard arms with every variant
payload bound at its exact type, and function-pointer constants pin the positional signatures
ofWorkbookSnapshot::new_with_metadataand the monomorphic read → calculate → write entry
points. This remains one test as the API grows.
Changed
- Rust dependency requirements now declare the oldest API-compatible, advisory-clean versions
instead of using the release that happened to be newest when each manifest was edited. All
workspace requirements live in the root manifest, the lockfile still selects the reproducible
current graph, and every release family a broad range admits is exercised by the floor or the
newest-compatible suite. Fifteen of the twenty external workspace floors moved down; five
remain at their current releases because they are the first secure version or belong to the
same release family (quick-xml, PyO3 and its build helper, andcalamine), or because their
types appear in CellRune's public signatures and a public dependency must stay within one
semver family (cap-std). The fuzz crate'slibfuzzer-sysstays exact-pinned as a tool
input: its graph is excluded from the workspace and always built--locked, so no suite
could exercise a range there. - The
conformance/fixtures now live inbinding-contract/, which is what they are: a
cross-binding API behavior contract exercised by the Rust interop, Python, and Node test
suites. Two 1 KB fixtures cannot carry an Excel conformance claim, so theconformance/name
is reserved for the Excel expectation suite that can. - The nightly sanitizer campaign remains one job over four stable trust boundaries. It records
every target's result before failing, so one crash cannot starve later campaigns and new
functions do not create new fuzz jobs. - The MSRV check covers
--all-targetsrather than--lib, so tests, benches, and the
extraction tool must also build on the declared floor. - The 50k benchmark is demoted from a scheduled nightly job and a required release gate to an
explicit observational command, documented inCONTRIBUTING.md, and its output-verifier
script is removed with the jobs. Release gates are deliberately limited to stable validation
boundaries that guard irreversible failures; the benchmark keeps its internal correctness
assertions, and functional correctness remains covered by the generated-workbook tests. - Release publish jobs are re-run safe. The crates.io, npm, and GitHub-release jobs probe for
what is already live and skip it — the GitHub release also counts its attached bundles, so an
interrupted asset upload is completed rather than skipped — and the PyPI upload passes
skip-existing. A rerun of a partially published tag therefore converges on fully published
instead of ending red: the final runs of both prior releases stayed red because their
already-published registries could only fail again or be rejected by hand.
Fixed
- A workbook containing an empty sheet was rejected with
xlsx.invalid_worksheet. Excel and
every mainstream producer serialize an empty sheet as a self-closing<sheetData/>, which
the reader's required-sheetData rule did not recognize as the element's empty form, so even a
brand-new workbook saved by Excel failed to open. Empty sheets now read as sheets with no
cells; a duplicated<sheetData/>is still rejected.
Documentation
- The README carries a Verification section: the public conformance-suite numbers with their
exact oracle, and the private-audit results (Excel for Mac 16.111 corpus recalculation,
14-workbook full-span audits, the 250k-formula timing, and the 4-of-4 producer matrix) with
their provenance and non-distribution stated.
v0.1.1
Changed
- Linux wheels target a
manylinux_2_28(glibc 2.28) baseline instead ofmanylinux_2_35. The
previous tag came from whichever glibc the build runner happened to ship, and it excluded RHEL 9
and Amazon Linux 2023 by 0.01 of a glibc version; both fell back to the source distribution,
which requires a Rust toolchain the installing user rarely has. The baseline is now an explicit
build input, produced with the same pinned Zig the npm platform packages already use, and the
resulting platform tag is asserted during release verification rather than assumed. - Dependency requirements of the published
cellrunecrate are caret ranges instead of=pins.
An exact pin made the crate unresolvable alongside any dependent needing a newer patch of the
same dependency, with no remedy available to that dependent. Build reproducibility continues to
come from the committedCargo.lock. Two new scheduled gates bound the ranges: one runs the test
suite against the declared floors on the minimum supported Rust version, and one runs it against
the newest compatible graph. Both resolve live rather than from the lockfile, so they are
scheduled alongside the advisory tier rather than gating pull requests: a failure there means
upstream moved, not that the commit under test did.
Fixed
- Quoted external-workbook references such as
'[1]Sheet1'!A1were reported as supported and
evaluated to#REF!. Because that is a spreadsheet error value rather than an engine issue,
IFERRORcould hide it, so a workbook could return a plausible number for a formula the engine
cannot evaluate. Both the capability scan and evaluation now reject the external prefix. The
unquoted spelling was already rejected, as the formula lexer has no bracket token. A reference
built at run time byINDIRECTis the deliberate exception: the scan cannot read inside the
text argument, so it reports the cell as supported, and evaluation answers#REF!there as
Excel does rather than an engine issue the scan never predicted and no caller could recover
from. An external prefix written as a saved path keeps its drive letter and is reported once,
not also as a 3-D sheet range the formula does not contain. - Calculated zeros could be negative.
Iterator::sumforf64folds from-0.0,f64::minand
f64::maxmay return either operand when both compare equal, andIterator::productinherits
the sign of an odd number of negative factors, soSUM,MIN,MAX,PRODUCT, and the*A
variants could each report-0where Excel reports0. The boundary every calculated value
crosses now normalizes negative zero, rather than each kernel being expected to. - Formula parse-error details labelled every position as
token N, but a lexing failure has no
token stream and was reporting a character offset under that label. Lexing failures now report
character Nand parsing failures continue to reporttoken N. - The lambda function group dispatched without inspecting the normalized function name, unlike
every sibling group. A second function in that group would have silently evaluated asMAP. - A release version bump had to be repeated by hand in more places than the release checklist
listed, and the ones it missed — a pnpm lockfile, a generated loader shim, the packaged-consumer
lockfile, and the release verification scripts — fail only during a release run. Every version
is now derived from the workspace manifest where possible, and a new gate asserts that the
remaining declarations agree, including the install commands and the supported-version statement
that ship on the registry project pages. Every check in that gate fails when its pattern matches
nothing, so a moved file or a regenerated shim cannot report the same green result as a correct
bump, and the gate has its own tests. - A Linux wheel could declare a compressed platform-tag set whose first component was a legacy
alias, which hid a newer glibc requirement behind it from the release verification. Every
component of the set is now checked against the supported baseline. - The nightly fuzz tier could not install its fuzzer.
taiki-e/install-actionhas no cargo-fuzz
manifest, the job deliberately disables the binstall fallback, and the schedule had never fired
since the repository went public, so the defect surfaced only on the tier's first manual
dispatch. cargo-fuzz is now built from crates.io withcargo install --locked, which keeps the
exact-version pin and the registry checksum verification. - The npm publish job could not authenticate. Trusted publishing requires npm 11.5.1 to exchange
the job's OIDC identity for a registry credential, and Node 22 bundles npm 10, which publishes
without credentials and receives the rejection masked as E404. The nine-package dry-run gate
cannot catch this because a dry run never authenticates, so the failure surfaced on the first
real upload — before any package was published, leaving the retry clean. The job now upgrades
to a pinned npm 11 before publishing.
Documentation
- The 0.1.0 entry claimed capability detection for unsupported external, structured, and
spill-postfix formula forms. Only 3-D and data-table forms have dedicated detection; the other
three surface ascalculation.parse_error, and structured references and spill-postfix
references still do after this release. The entry has been corrected. - Added
docs/NUMERICS.md, which records where calculated values deliberately differ from Excel,
the Excel build each statement was measured against, and which function families are unmeasured.
It is linked absolutely: both published READMEs are also the long description crates.io, PyPI,
and npm render, none of which resolve a repository-relative path, and a gate now enforces that. - Installation instructions no longer describe the registry artifacts as pending.
v0.1.0
Added
- Bounded
.xlsxpackage inspection and reading from paths, byte slices, andRead + Seek
streams, with ZIP, XML, workbook, formula, text, relationship, and allocation limits. - Immutable sparse workbook snapshots with typed values, formulas, saved results, shared and array
metadata, defined names, sheet visibility, date systems, number formats, diagnostics,
and provenance. - Package-backed
.xlsxand.xlsmdocuments with exact SHA-256 source identity that preserve
unknown and unchanged parts without executing macros, following external links, or reading
host-time inputs. - Static formula capability scans and deterministic recalculation into a separate owned result
snapshot, including direct formula cells, legacy-array regions, and dynamic-spill regions. - A catalog of 278 official Excel-facing function names, comprising 265 official calculation
kernels and 13 compatibility aliases, plus one non-official OOXML dummy-function marker,
workbook function-demand reports, and stable sample locations. - Explicit deterministic inputs for
TODAY()andNOW(), bounded calculation work, stable
per-formula issue codes, and spreadsheet error values kept distinct from unsupported engine
capabilities. - Formula parsing and evaluation for scalar, range, lookup, logical, aggregate, math,
trigonometric, combinatoric, engineering, information, text, date/time, dynamic-array,
statistical, and financial function groups. - Excel-compatible
INDEXzero row/column references, including scalar implicit intersection,
reference composition, incremental dependencies, and row, column, or full-rectangle array
materialization. - Capability detection for unsupported external, 3-D, structured, spill-postfix, data-table, and
other statically recognizable out-of-scope formula forms. - Verified recalculation writing that binds results to the exact source, updates typed caches,
removes stale calculation chains, preserves unrelated package content, and supports strict or
explicit cache-invalidation policy. - Canonical workbook creation with dynamic-formula authoring, plus preservation-aware
WorkbookDraftediting for typed cells, normal formulas, sheets, defined names, number formats,
date systems, and calculation properties. Existing document-backed dynamic formulas can be
recalculated and cache-rewritten, while adding or replacing them fails closed. - Atomic typed edit batches with semantic revisions, complete rollback on validation failure,
no-op revision and calculation preservation, and Save As path writes that refuse implicit
destination replacement. - SpreadsheetML phonetic annotation inspection and authoring, row/column phonetic-visibility
handling, and default frozen-pane inspection and authoring under separate presentation revisions. - Persistent
WorkbookCalculationSessionstate with incremental recalculation, conservative full
fallback, optimistic revision checks, request-owned cooperative cancellation, stale-result
rejection, and bounded paged result deltas. - Typed Python 3.10–3.14 bindings built with PyO3 and maturin.
- Typed Node.js 22+ CommonJS and ESM bindings built with napi-rs and exact-version native platform
packages. - Explicit, idempotent native-session cleanup through Python context managers and Python/Node.js
close(), including cooperative cancellation of active calculation and stable closed-session
errors. - A local stdio-only MCP server with 11 high-level workbook tools, explicit approved roots,
bounded TTL/LRU sessions, capability-bound bounded input reads, byte-bounded responses and
resource pagination, cooperative cancellation, and capability-bound atomic Save As behavior. - Stable validation, read, write, calculation, session, diagnostic, and spreadsheet-value error
boundaries with machine-readable codes, including a core-ownedValidationErrorCodecovering
every currentValidationErrorvariant. - Runnable examples for inspection, capability scanning, error handling, saved-versus-calculated
values, calculation, canonical authoring, recalculation Save As, dynamic arrays, phonetic
inspection, and phonetic authoring. - Generated workbook integration tests, binding conformance tests, MCP protocol tests, fuzz
targets, MSRV checks, dependency-policy checks, package-consumer verification, and
cross-platform CI.
Known limitations
- Public CI uses generated, redistributable workbook fixtures. The private external formula corpus,
user workbook corpus, and native-producer evidence used during development are not distributed
with 0.1.0 and are not represented as release gates.