Skip to content

feat(competitors): aspose-cells-foss + zavora-xlsx adapters, Tier 4, mutation + calc lanes - #45

Merged
wolfiesch merged 11 commits into
masterfrom
feat/competitor-snapshot-2026-09
Sep 8, 2026
Merged

wolfiesch merged 11 commits into
masterfrom
feat/competitor-snapshot-2026-09

Conversation

@wolfiesch

@wolfiesch wolfiesch commented Sep 8, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Extends the scored matrix to 22 features and 14 Python adapters, adds two competitor adapters, and ships two new decision-surface lanes (template mutation, formula recalculation). Snapshot artifacts: results-2026-09-08/{xlsx,mutation,calc,cross-language}.

What's included

Adapters

  • aspose-cells-foss 26.7 (Python lane, opt-in aspose extra): 11/22 green features; explicit unsupported surfaces for pivots/chart rendering/math evaluation.
  • zavora-xlsx 0.1.2 (cross-language lane only): Rust helper in tools/external-oracles/zavora over the existing external-oracle JSON contract. Upstream defects are scored, not hidden: mutate/open-save corrupts hyperlink relationships (mutation lane: integrity-failed, preservation 0), and recalculate() writes no caches (calc lane: 0/133).

Tier 4 fidelity features (sheet_protection, page_setup, chart_anchor)

  • Fixtures are openpyxl-structural (generator: openpyxl-structural, excel_version: none) because no Excel app is available here; expectations are verifier-grade openpyxl readbacks. Documented in DEC-023.
  • Write-only keys (password, chart data_ref/categories_ref) ride in the manifest and are stripped pre-compare.

Template-mutation lane (excelbench mutation)

  • Two-cell surgical edit on fixtures/mutation/template_corporate_model.xlsx, measured in isolated subprocesses: median wall time, median peak RSS, package-preservation score; outputs must reopen with the verifier or the engine is integrity-failed.
  • Results: wolfxl 100% preservation (ZIP patching), openpyxl 60%, aspose-cells-foss 60%, zavora-xlsx 0 (relationship corruption).

Calc tier (excelbench calc)

  • fixtures/calc/financial_model.xlsx is a 133-formula financial DAG that ships no cached values; the builder asserts cache-freedom. Oracle values come from a throwaway LibreOffice headless recalculation (version pinned in the artifact).
  • Strict status semantics: anything below a full oracle match is failed with matched/total (DEC-026).
  • Results: LibreOffice 133/133, wolfxl 55/133 (calculator returns None for the ^ power-operator family and dependents), aspose-cells-foss 25/133 (FOSS FormulaEvaluator has no value for 107 formulas), zavora 0/133.

wolfxl adapter

  • Ported to the WolfXL 2.1.0 public API (2.1 removed the old internal backends). 19/22 in this snapshot; recorded gaps: conditional-formatting read 0, named-range write 2, print-title write 2.

Fidelity headline (14 Python adapters, 22 features)

  • openpyxl 22/22, wolfxl 19/22, aspose-cells-foss 11/22, xlsxwriter 15/18 (April snapshot), remaining adapters unchanged from their snapshot denominators.

Verification

  • uv run pytest: 1235 passed, 79 skipped, 6 xfailed
  • uv run ruff check .: clean
  • uv run excelbench benchmark --tests fixtures/excel --output results-2026-09-08/xlsx --adapter ... (14 Python-lane adapters): rendered, 308 score rows
  • uv run excelbench cross-language-context --output results-2026-09-08/cross-language: zavora-xlsx write lane
  • uv run excelbench mutation --output results-2026-09-08/mutation: 4 engines, results.json + README
  • uv run excelbench calc --output results-2026-09-08/calc: 4 engines vs LibreOffice oracle
  • Fixture builders rerun end to end: build_tier4_fixtures.py, build_mutation_template.py, build_calc_fixture.py (cache-free assertion active)

Notes for reviewers

  • Counts from different snapshots are not comparable: /18 = 2026-04-29 release snapshot, /22 = this snapshot (Tier 4 added). docs/public-reporting.md updated accordingly.
  • results-2026-09-08/calc/*/ contains per-engine recalculated workbooks as evidence.
  • DEC-023..DEC-026 added; METHODOLOGY, TRACKER, architecture, README tables updated.
  • Some shared harness files carry incidental reformatting (line-wrapping only); ruff and the full suite are green on the result.

Merge note

Do not merge before the WolfXL 2.1.0 gaps are triaged upstream if the public README headline is meant to stay at 18/18; otherwise this PR's headline intentionally reflects 2.1.0 as-is.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

…n + calc lanes

- aspose-cells-foss adapter (Python lane, 'aspose' extra): 11/22 green
- zavora-xlsx external-oracle adapter (cross-language lane) + Rust helper;
  upstream 0.1.2 defects scored honestly (hyperlink rel corruption, no recalc)
- Tier 4 fidelity features (sheet_protection, page_setup, chart_anchor) with
  openpyxl-structural fixtures; 22 scored features total
- wolfxl adapter ported to WolfXL 2.1.0 public API (19/22; CF-read and
  print-title-write gaps recorded)
- Template-mutation lane: wall time, peak RSS, package preservation
- Calc tier: cache-free 133-formula financial DAG fixture, LibreOffice oracle,
  strict pass/fail semantics
- CLI: 'excelbench mutation' and 'excelbench calc'; zavora in cross-language lane
- Snapshot artifacts: results-2026-09-08/{xlsx,mutation,calc,cross-language}
- Docs: DEC-023..DEC-026, README tables, METHODOLOGY, TRACKER, architecture

Verification: uv run pytest (1235 passed, 79 skipped, 6 xfailed); ruff clean.
…extra

- base.unsupported_operation now annotated NoReturn (it always raises);
  downstream use is unreachable and mypy-clean without local asserts
- restore pyumya mypy override clobbered by the aspose override entry;
  add aspose/aspose.* overrides for the untyped installed package
- type the wolfxl adapter pivot/table fallbacks, calc suite status/reason
  locals, aspose merged-ranges return
- guard optional module imports in modifiable.py with the registry pattern
- pytest.importorskip for aspose-cells-foss when the extra is absent

Verification: ruff clean; mypy 0 issues in 149 files; pytest 1235 passed,
79 skipped, 6 xfailed.
openpyxl stamps dcterms:modified with save time, so the committed fixture
drifted on every test run that rebuilt it. The builder now rewrites the
modified timestamp to the fixed epoch in its ZIP repack stage; the artifact
and manifest are regenerated against the pinned bytes and the recorded
template_sha256 matches the committed fixture again. The regenerable
tier4_manifest_fragment.json merge byproduct is untracked.

Verification: two builds 2s apart produce identical bytes; mutation suite
rerun preserved scores (60/100/60/0) with matching artifact SHA;
tests/test_mutation_suite.py 7 passed.
importorskip ran after the module-level adapter import, which raises
ImportError when the extra is missing; the guard now precedes it so CI
environments without the 'aspose' extra collect-skip the module.
CI runners have no soffice binary at the hardcoded homebrew path. Resolve
the binary via PATH first (homebrew fallback kept), and skip the three
LibreOffice-dependent tests (calc builder regeneration, engine smoke,
mutation template PDF render) when it is absent. The wolfxl calc-engine
assertion engages only on wolfxl >= 2.1, matching the calculate() API
the engine requires.

Verification: ruff clean; mypy 0 issues; pytest 1235 passed locally;
with soffice hidden the two calc tests skip with reason and the mutation
LO test carries the same guard.
The tier4 builder test regenerates the merge byproduct with a fresh
timestamp on every suite run, dirtying the tree; manifest.json is the
merged source of truth.
Adds 28 contract tests for paths CI can execute without LibreOffice,
aspose-cells-foss, or the Rust helper: strict calc-tier status semantics
with synthetic engines, expected-payload validation, cache-free fixture
invariants, engine-unavailable reporting, mutation-suite control flow
(unavailable/failed/integrity/passed rows, repeats guard, manifest
parsing, time-output parsing, package integrity helpers), modifiable
engine guards, mutation-report verdict branches, and Zavora adapter
payload/error contracts.

Harness fixes the tests exposed:
- run_calc_suite now contains engine exceptions as failed rows instead
  of aborting the suite
- LibreOfficeCalcEngine reports unavailable (not failed) when the
  binary is missing

Verification: ruff clean; mypy 0 issues in 150 files; full suite 1263
passed, 79 skipped, 6 xfailed.
Adds seven round-trip tests exercising WolfxlAdapter through the public
WolfXL API: value/boolean/blank round-trips, source-path bookkeeping,
format/border/dimension/merge, formula, hyperlink, and structural
features (freeze panes, named ranges, comments, tables). All operations
verified identical on WolfXL 2.0.1 (PyPI) and 2.1.0 (local wheel), so
the tests run ungated in CI.

Adapter coverage: 1% -> 45% (261 of 586 statements).

Verification: ruff clean; mypy 0 issues; full suite 1270 passed, 79
skipped, 6 xfailed; every test re-run against wolfxl 2.0.1 in a
throwaway venv.
The test job previously installed only the dev extra, so wolfxl and
aspose-cells-foss were absent on CI: the wolfxl adapter tests skipped
and roughly a thousand adapter statements could never count toward
coverage, pinning the suite at 63.8% against the 65% gate.

Both extras are pure installs from PyPI (wolfxl 2.0.1 wheel,
aspose-cells-foss py3-none-any wheel). Verified in a CI-parity venv
(python 3.12, wolfxl 2.0.1, aspose-cells-foss 26.7.0, no soffice):
1270 passed, 79 skipped, 6 xfailed, exact coverage 66.43%.
The test job's new rust extra resolved to the lock's ancient wolfxl
0.1.0, whose Workbook lacks the remove() API the adapter and its
round-trip tests rely on. Upgrades the single lock entry to 2.0.1
(plus its new defusedxml dependency); no other packages change.

Verified in a venv synced exactly from the updated lock (python 3.12,
wolfxl 2.0.1, aspose-cells-foss, no soffice): 1270 passed, 79 skipped,
6 xfailed, exact coverage 66.31%.
@wolfiesch
wolfiesch merged commit 464b078 into master Sep 8, 2026
6 checks passed
@wolfiesch
wolfiesch deleted the feat/competitor-snapshot-2026-09 branch September 8, 2026 07:29
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