Files
gridcraft/docs/target-app-parity.md
T
PranavandFredApps 3379f12a56 Data: Solver Sensitivity report (#501)
* Data: Solver Sensitivity report

Builds on the Answer and Limits reports. reports: [sensitivity] (on
data.solver and data.solverReport) writes a Sensitivity report for
models solved by Simplex LP or GRG Nonlinear without integer
constraints and with a Max or Min objective.

Simplex LP: the model is linearised at the solution and solved again,
and the report is read from the final tableau: each variable's reduced
cost and the range of its objective coefficient over which the basis
stays optimal, and each constraint's shadow price and the range of its
right side over which that price holds (1E+30 for no limit).

GRG Nonlinear: difference gradients at the solution give each binding
constraint's Lagrange multiplier (a least-squares fit on the variables
inside their bounds, dropping constraints whose multiplier has the
wrong sign) and each variable's reduced gradient.

The Solver Results dialog offers the report.

* Data: Solver Results offers the Sensitivity report only where it applies

Integer and binary models, the Evolutionary method and Value Of goals
have no Sensitivity report, and choosing it with other reports made the
whole report request fail. Solver Results now disables the Sensitivity
choice for such models (with the reason on hover) and leaves it out of
the request, so the other chosen reports are still written.

sensitivity_applies (in cmd::solver) reads the model from data.solver
params, as the dialog holds them; a test checks that it agrees with the
report for each kind of model.

* Data: Solver bounds the nonlinear Sensitivity report's work

The Lagrange multipliers of a GRG Nonlinear model are found by least
squares over the binding constraints; a constraint whose multiplier has
the wrong sign is dropped and the rest are solved again. Each pass costs
about 2·k²·f operations for k binding constraints and f free variables,
and each pass drops at most one constraint, so a model at the
1,000-constraint limit could take minutes and hold the window.

The passes now share a limit of about 10⁹ operations (about a second).
Past it the report is refused with a message, before anything changes:
the workbook and the Undo history stay as they were, as for the other
report refusals. The limit is lowered in tests so the refusal can be
reached with a small model.

* Data: Solver refuses a Simplex Sensitivity report for a point that is not optimal

The Simplex LP Sensitivity report solves the linearised model again to
read its final tableau, but shows the final values it was given.
data.solverReport accepts any values, so a report could pair values that
are not optimal (or not feasible) with the shadow prices, reduced costs
and ranges of the true optimum. The report now checks that the given
point satisfies every constraint and bound and reaches the optimal
objective (both within the constraint precision; another optimal point
with the same objective is accepted) and is refused otherwise, before
anything changes.

* Data: Solver compares the Sensitivity report's objective in both directions

The check that a point is optimal compared its objective with the
optimum in one direction only, as for an inequality. A point just
outside a bound (within the constraint precision) can still have an
objective far below the minimum when its costs are large, and that
point was accepted. The objective is now compared by the size of the
difference, so such a point is refused.

* Data: Solver refuses a nonlinear Sensitivity report for a point that is not optimal

data.solverReport accepts any finite variable values. The Simplex LP
report already refuses values that are not optimal, but the GRG
Nonlinear report described whatever point it was given: for example, a
minimisation of A1^2 given A1 = 1 found no binding rows and reported a
reduced gradient of 2 instead of requiring the optimum at A1 = 0.

The nonlinear report now checks, from the gradients it already
computes, that the values are a Karush-Kuhn-Tucker point before
anything changes: every constraint holds within the tolerance the
nonlinear method accepts a solution within, every bound holds within
the constraint precision, each variable inside its bounds has a reduced
gradient near zero, and a variable at a bound has a reduced gradient
that points only out of that bound for the objective's direction. A
binding row whose multiplier has the wrong sign is still dropped, and
the gradient it would have explained now causes the refusal. The
stationarity tolerance is 1E-3 of the largest objective-gradient
component (at least 1), well above the reduced gradients left at optima
the method solves.

* Data: Solver writes the other reports when the Sensitivity report does not apply to the solution

Since the nonlinear Sensitivity report refuses values that are not
optimal, data.solver with reports that include sensitivity failed as a
whole when the run stopped before an optimum (an evaluation limit) or
the values were not one, so the solution and the Answer and Limits
reports were lost. Solver Results also offered Sensitivity after any
solve, and ticking it with Answer after such a run wrote no report.

data.solver now writes the Sensitivity report only when the run reached
an optimal or converged solution that the report accepts. Otherwise the
solve still applies, the other reports are written, and the result
lists the report in skippedReports with the reason. Models that have no
Sensitivity report (integer, Evolutionary, Value Of) are refused as
before. data.solverReport still refuses values that are not optimal;
its new skipNotOptimal parameter leaves the report out instead. Solver
Results offers Sensitivity only after an optimal or converged status,
with the reason on hover, passes skipNotOptimal, and shows the reason
when the report is left out.

* Data: Solver skips a Sensitivity report in a protected workbook without refusing the call

Structure protection is now checked only when a report sheet will be written. A data.solverReport request with skipNotOptimal whose only report is skipped changes nothing, so it succeeds in a workbook whose structure is protected and returns skippedReports; a request that would write a sheet is still refused.

* Data: Solver refuses report sheets in a protected workbook before building them

A request that must write a report sheet (any Answer or Limits report, or a Sensitivity report that is not allowed to be skipped) is refused before any report is built, so a protected workbook does not run the Limits report's optimisations first. The check after the reports are built remains for a Sensitivity report that may be skipped.

* Data: Solver reports Simplex sensitivity only at the vertex it describes

The Simplex LP Sensitivity report solves the linearised model again and
takes its prices and ranges from that final tableau, but it discarded
the vertex the solve returned and showed the values it was given. When
the optimum is not unique, another optimal point passed the optimality
check, so the report paired those values with the ranges of a different
vertex. The report now also requires the given values to match the
re-solved vertex within the constraint precision, and refuses another
optimum with a message that says so. A Sensitivity report that data.solver
or Solver Results may skip is left out instead, as for other points the
report does not support. Values from a Simplex LP solve still match, so
the usual Solver Results flow is unchanged.

* Data: Solver gives a redundant constraint's right side no allowable change

The Simplex LP Sensitivity report ranges each right side over the basic
values of the real columns only. A row that the other rows make
redundant (max x with x = 2 and 2x = 4) keeps its artificial column
basic at zero after phase one, and changing either right side alone
moves that artificial, so no change has a solution. The report showed
1E+30 and 2 for the first row instead. When a basic artificial has a
nonzero entry in the column of the right side being changed, both
allowable changes are now 0. The objective-coefficient ranges are
unaffected: such a row has no cost and no entries in the real columns,
and a cost change does not affect feasibility.

* Data: Solver builds the Simplex Sensitivity report's program at the solve's start values

The Simplex LP solve linearises the model at the start values, but the
Sensitivity report linearised it again at the solution. The difference
coefficients then differ in their last bits, and when the optimum is
not unique that can break a tie between pivots the other way: the
report's solve returned the other vertex and refused the solve's own
values. With max 0.1x + 0.1y over a tied edge, more than half of the
sampled starting points were refused.

The solve and the report now build the program with one function,
simplex_program, and the report builds it from the start values it is
given (data.solver's start values, which Solver Results passes back as
original), so its solve repeats the solve's pivots and returns the same
vertex. Start values at which the model cannot be evaluated fall back
to the solution, and values that are not the solve's are still refused
by the vertex check.

* Data: Solver's Sensitivity report sets its noise levels from the coefficients, not the objective's value

The figures a Sensitivity report prints as 0 were those below 1E-9 of the objective's value (1E-6 for the nonlinear figures), so a constant in the objective hid real prices: max 1E9 + x with x <= 10 wrote the row's shadow price, exactly 1, as 0, although the constant changes nothing about the optimisation. A shadow price and a reduced cost are combinations of the objective coefficients, so Simplex LP now takes the noise level from the largest coefficient; a reduced gradient is a part of the objective's gradient and a Lagrange multiplier objective per unit of its row's gradient, so GRG Nonlinear takes it from the gradient's size, and the multipliers' sign test compares lambda times the row's gradient size with it. Allowable changes keep the tableau's pivot tolerance as before.

* Data: Solver Sensitivity report tests for variables at a bound and for both goals

Hand-derived cases pin the report's conventions. Simplex LP: a maximum's variable at its upper bound (reduced cost 1, Allowable Increase 1E+30, Allowable Decrease 1), a minimum with a >= row and a variable at its upper bound (reduced cost -1, Allowable Increase 1, Allowable Decrease 1E+30), and Winston's Dakota Furniture problem, whose variable at zero has reduced cost -5 with Allowable Increase 5 and Allowable Decrease 1E+30, with every shadow price and allowable range worked out from the final basis. GRG Nonlinear: the Lagrange multiplier is the derivative of the optimal objective with respect to the right side and the reduced gradient that with respect to the variable's bound for a minimum (-1) and the negated maximum (+1), and the mirror image of the existing minimum with a variable at its bound (multiplier +2, reduced gradient -4).

* Docs: ROADMAP.md records the Solver Sensitivity report

The detail documents (docs/gaps.md, docs/target-app-parity.md) record the report, but the roadmap summary did not: its header change note, progress log and revision history now carry it.

* Data: Solver's Sensitivity report bounds each figure's rounding noise by its own terms, not the model's largest coefficient or gradient

The noise level a figure had to exceed to print was 1E-9 of the largest objective coefficient (Simplex LP) or 1E-6 of the largest gradient component (GRG Nonlinear) for every figure, so an unrelated large coefficient hid real values: max 1E9*x + y with x <= 1 and y <= 1 as rows wrote the second row's shadow price, exactly 1, as 0, and the same model's Lagrange multiplier 1 and a third variable's reduced cost or gradient -1 went the same way. The rounding error of a sum scales with the sum of its terms' sizes, so each figure now has its own bound from the terms it is made of. Simplex LP: a shadow price y_i = sum over the basis rows of c_B(r) * Binv(r, i) is bounded by 1E-9 of those terms' sizes (the row's unit column of the final tableau holds Binv's column i); a reduced cost cf_j - sum of a_ij * y_i by 1E-9 of |cf_j| plus |a_ij| times each price's term sizes, so a price that is a small difference of large terms carries their error into the reduced costs it is used in. GRG Nonlinear: a multiplier solved from its row of the normal equations is bounded by 1E-6 of its own terms (the row's gradient times the objective's, and its coupling terms with the other active rows times their multipliers) over the row's squared norm; the multipliers' sign test uses the same bound, so a row leaves the active set on the criterion the report rounds with; a reduced gradient is bounded by 1E-6 of its own component and the multipliers' terms plus the multipliers' bounds times |g_ij|. Nearly parallel active gradients amplify every multiplier's error beyond a bound local to a row; such multipliers print as computed. A constant in the objective still changes no bound, since none depends on the objective's value. The nonlinear method stops on the 1E9 model from (0, 0) with "unbounded", so its two regression tests ask for the report at the optimum through data.solverReport.

* Data: Solver's Sensitivity report tests a nonlinear point's optimality by each variable's and row's own scale, not the model's largest

The Karush-Kuhn-Tucker check that refuses a Sensitivity report for a point that is not optimal accepted a reduced gradient within 1E-3 of the largest gradient component, and a row violation within ten times the constraint precision of the largest constant right side. Both scales were the model's, not the figure's: on max 1E9*x + y with x <= 1 and y <= 1 as rows the tolerance was 1E6, so (1, 0.5), where raising y gains 1 per unit, passed as optimal and the report was written for it; on max y - (x - 2)^2 with x <= 1E9 and y <= 1, (2, 1.0001) passed although the second row is over by 1E-4 against its own precision of 2E-5. Each reduced gradient is now tested against 1E-3 of the terms it is made of (the objective's component and the multipliers' parts, at least 1, the same floor as before), and each row against ten times the constraint precision of its own right side. The nonlinear method itself accepts a solution relative to the largest constant right side; a row over by more than its own precision is not satisfied whatever the other rows' sizes, so the report refuses it. The term sizes are shared with the reduced gradients' rounding bound. Two regression tests, each proving the workbook is left as it was and that the optimum is still reported.

* Data: Solver refuses a Sensitivity report the model has none of before any report is built or the solve runs

The refusals that apply to the model rather than the solution (integer or binary constraints, the Evolutionary method, a Value Of goal) were made inside the report loop, when it reached the Sensitivity report, so a request listing the Limits or Answer report first built those reports for an error: a Value Of model asking for limits and sensitivity ran the Limits report's two optimisations per variable and received only the refusal, and data.solver ran its whole solve before it. prepare_reports now checks the model's refusal before the loop, in both modes (a refusal of the model was already an error in both; only the solution's not-optimal refusal is skipped under skipNotOptimal), and data.solver checks it before the solve. The regression test asks for limits and sensitivity on an integer model, which now gets the Sensitivity refusal instead of the Limits report's, and on a Value Of model, which gets the Sensitivity refusal with no sheet written.

---------

Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-02 09:46:01 +01:00

34 KiB
Raw Blame History

Target-app parity: GridCraft vs Microsoft Excel

Last reviewed: 2026-10-11 · Last updated: 2026-11-02 · Change: minor (what-if and analysis: Solver Sensitivity report; no score change; earlier: chart resizing no longer listed as missing; no score change; earlier: what-if and analysis: Analysis ToolPak has all 19 tools; earlier: page layout and print: Page Setup's page order; no score change; earlier: charts: data tables with XLSX round-trip and print/PDF; no score change; earlier: what-if and analysis: Solver Options; the Insert Function dialog is named as in Excel; no score change; earlier: Solver Load/Save Model and Reset All; automation: macro interface; catalog count 276 / 292, as cargo xtask parity measures; automation: typed macros in the engine; several windows: a native window per workbook window, New Window on the same workbook, Arrange All; no score change) · Target: Microsoft Excel (Microsoft 365)

This is the authoritative parity assessment. ROADMAP.md summarizes it, gaps.md lists every shortfall, and the area checklists hold the detail: functions, charts, file formats, UI, hardware, localization. The generated ribbon checklist is parity-checklist.md.

Summary

Number Value Kind
Feature breadth (weighted by use) ~75% estimated from the area table below; anchored on two measurements
Ribbon and menu catalog 276 / 292 (94.5%) measured: cargo xtask parity (crates/engine/src/catalog.rs ∩ registered command ids)
Worksheet functions, by name 513 / 523 (98.1%) measured: registered functions vs Microsoft's published function list (method below)
Worksheet functions that do real work 504 / 523 (96.4%) measured: excludes 9 stubs (7 CUBE functions, WEBSERVICE, FILTERXML)
Ready for real work ~50% estimated; written weights below (51.6 computed)
Mainstream practitioner ~50% estimated; method (69.5 depth × 0.90 × 0.92 × 0.88 = 50.6)
Essentials user ~63% estimated; method (80.2 depth × 0.92 × 0.95 × 0.90 = 63.1)
Stage alpha see Stage
Remaining to beta ~160–240 Opus 5.5 agent-hours estimated; roadmap.md
Remaining to full parity ~700–1,100 Opus 5.5 agent-hours estimated; sum of the rows below

Readiness by audience

Audience Ready % Opus 5.5 agent wall-clock hours to ~95% Work that dominates
Full target (ready for real work) ~50% ~650–1,050 Get & Transform and the data model, localization (twelve languages), charts depth, file fidelity (.xls, corpus, pass-through), PivotTables, collaboration, mobile
Mainstream practitioner ~50% ~200–310 File exchange with Excel users (corpus and Excel verification, pass-through, large files, .xls, encryption: 63–97 h), common-chart depth (30–45 h), PivotTables (20–30 h), keyboard and interaction (18–28 h), calc correctness and functions (20–33 h)
Essentials user ~63% ~60–100 Opening files people send (.xls import and saving with a password 24–36 h; macOS Finder open 2–4 h), launch stability (6–10 h), basic chart polish (5–8 h), print and Page Layout (8–12 h), small editing and UI fixes (10–16 h)

Each tier is a subset of the one above, so its hours are too. Calibrated as in Effort and calibration (~6–10 h per readiness point for the remaining, verification-heavy work; single features measured from PRs #66, #100, #101). Parallelism: the full and mainstream work splits ~65–70% across 4–6 agents by area; the essentials work is mostly small fixes plus one long .xls track, so about half parallelizes (≈30–50 wall-clock hours with three agents).

What we measured against, and how

  • Target: Microsoft Excel (Microsoft 365 channel). Version measured: Excel for Mac 16.113.4, installed on the owner's Mac (version read from Spotlight metadata with mdls). Where Excel for Windows has more (Power Pivot, VBA editor depth, COM add-ins, 3D Maps), the Windows feature counts as part of the target.
  • Clean-room limits. This repo's rule (AGENTS.md, "Non-negotiables") forbids reading anything inside the Office bundle, so the bundle's Info.plist, .lproj folders and resources were deliberately not inspected, and Excel was not launched for this pass. Excel's file formats, functions and features come from Microsoft's public documentation, the owner's earlier black-box observation (plan/excel/observed-ui.md, local only), and knowledge of the product.
  • Function list: Microsoft's "Excel functions (alphabetical)" support page, fetched 2026-10-10 and parsed (506 rows), plus 15 names the page lists under combined entries (FIND/FINDB, LEFT/LEFTB, LEN/LENB, MID/MIDB, REPLACE/REPLACEB, RIGHT/RIGHTB, SEARCH/SEARCHB, BETA.INV) and COPILOT and PY: 523 functions. Ours: every f!(…) spec in crates/functions/src/*.rs plus SPECIAL_FUNCTIONS in crates/calc/src/eval.rs (evaluator special forms), minus the test-only ADD2: 505, all of them Excel names.
  • Ribbon catalog: crates/engine/src/catalog.rs (292 unique ids across 15 tabs) against the 313 command ids registered in crates/engine/src/cmd/*.rs, recomputed from source by script and identical to the committed parity-checklist.md. The catalog is our own transcription of Excel's main ribbon tabs; it leaves out most contextual tabs (Picture Format, Shape Format, Header & Footer, Sparkline, Slicer, Timeline), the Developer and Help tabs and sub-menu items, so 89% of it is roughly 60–65% of Excel's full command surface (estimated).
  • Depth and readiness: source reading (the model types in crates/model/src/features.rs, readers and writers in crates/xlsx/src, the evaluator), 478 #[test] functions, and the issue tracker: 60 open issues and 50 open PRs on 2026-10-10, 82 issues filed in total.
  • No cargo build or test ran for this pass (disk constraints); numbers come from source.

Weights

Percentages are weighted by what Excel users actually do, not by item count. Feature-area weights (sum 100) reflect a typical business, finance and analyst workload: formulas, functions, editing and formatting dominate; Power Query, VBA and the data model matter to fewer users but are decisive for those who use them.

Dimension weights for ready for real work: features 45, file formats 15, UI/UX 12, performance 8, stability 8, localization 4, hardware 2, platforms 2, ecosystem 2, AI 2.

Feature areas

Area Weight Breadth Ready Hours Evidence
Formula language and calculation 18 ~92% ~72% 20–30 A1/R1C1 parser, reference adjustment, dependency-graph recalc, dynamic arrays and #SPILL!, A1#, LET/LAMBDA and helpers, structured references, names, 3-D references. Open correctness bugs: 15-digit equality (#57), stale spills after structural edits and cleared blockers (#133, #139), 3-D span endpoint deletion (#140), sheet rename and qualified names (#134). Single-threaded
Worksheet functions 12 98.1% (measured) ~82% 16–26 513 / 523 names, 504 working. Missing: GETPIVOTDATA, IMAGE plus cloud functions. No conformance suite against Excel-computed oracles; edge-case bugs keep surfacing (#137, #138). function-parity.md
Editing, navigation, clipboard, fill 12 ~90% ~70% 15–25 Point mode, F4, AutoComplete, Paste Special, AutoFill, Flash Fill, Find/Replace, Go To Special. Bugs: rectangular drag-select (#28), monthly fill (#132), cut across sheets (#128), Insert Copied Cells missing (#21), key tips only on part of the Home tab (#43; #33, #49). ui-parity.md
Cell formatting, styles, conditional formatting 10 ~95% ~80% 8–14 Full number-format language, borders, 47 cell styles, 60 table styles, all CF rule kinds including data bars, colour scales and icon sets. Gaps: font weights beyond regular/bold (#168), system fonts list (#4), themes
Sort, filter, tables, validation, outline 8 ~82% ~70% 10–16 Multi-level sort, AutoFilter, Advanced Filter, tables with totals, validation, outline, subtotals, consolidate. Advanced Filter copy-to preserves cells outside its result and rejects worksheet overflow (#1031). Bugs: subtotal header (#131), validation edits (#129), table style panic caught (#130); no slicers on tables
PivotTables 7 ~65% ~45% 25–40 Insert/Recommended, field list, three layouts, values on rows or columns, date grouping, show-values-as, refresh, calculated fields, XLSX round-trip. Missing: slicers, timelines, calculated items, PivotCharts, value/label filters, number grouping, GETPIVOTDATA, data-model pivots. Round-trip never checked in Excel
Charts and sparklines 8 ~50% ~30% 40–60 25 chart kinds, all 2-D. The chart model holds title, legend position, a data-labels flag, gridlines flag, axis titles and chart data tables (legend keys, borders, XLSX round-trip and print/PDF); no axis scaling, trendlines, error bars, per-point formatting, chart sheets, 3-D, surface, map, Pareto. Several kinds don't survive XLSX round trip (open PRs #158, #161). chart-parity.md
Page layout, print, PDF 5 ~80% ~55% 12–20 Page setup, print titles, breaks, page order, Page Break Preview, headers/footers, PDF export and printing. Paper sizes match Japanese Excel: B4/B5/B6 are the JIS sizes, ISO B4/B5/B6 stay reachable by name, and Japanese Postcard (はがき), Japanese Double Postcard (往復はがき), the chou/kaku envelopes and A6 are available. No true Page Layout view; the PDF writer uses only the 14 standard fonts without embedding (no CJK or other non-Latin text in PDF); web print only exports (#141, #143)
Charts and sparklines 8 ~50% ~30% 40–60 25 chart kinds, all 2-D. The chart model holds title, legend position, a data-labels flag, gridlines flag, axis titles and chart data tables (legend keys, borders, XLSX round-trip and print/PDF); no axis scaling, error bars, per-point formatting, chart sheets, 3-D, surface, map, Pareto. Kinds survive XLSX round trip (#158, #161). chart-parity.md
Page layout, print, PDF 5 ~80% ~55% 12–20 Page setup, print titles, breaks, page order, Page Break Preview, headers/footers, PDF export and printing. No true Page Layout view; the PDF writer uses only the 14 standard fonts without embedding (no CJK or other non-Latin text in PDF); web print only exports (#141, #143)
What-if and analysis 4 ~50% ~40% 22–35 Goal Seek, Scenario Manager, data tables, Analysis ToolPak (all 19 tools, no charts), Solver (Simplex LP, a local nonlinear method and Evolutionary; Answer, Sensitivity and Limits reports; Load/Save Model, Reset All and Solver Options; no Population report), Forecast Sheet. Missing: Analyze Data
Get & Transform, external data, data model 5 ~15% ~10% 60–100 Import of CSV/TSV, JSON, HTML. No Power Query editor, no From Web, database or folder sources, no connections or refresh, no relationships or data model, no external workbook links (dropped with a warning)
Insert objects 3 ~55% ~45% 25–40 Pictures, 8 shape kinds (Excel has ~170), text boxes, own icon set, ink with Ink to Shape, hyperlinks, checkboxes. Missing: SmartArt, WordArt, equations, signature line, objects, 3-D models, screenshot, pictures in cells (PR #105)
Review, comments, protection, collaboration 4 ~55% ~40% 35–55 Threaded comments, notes, spelling (system dictionary), thesaurus, sheet and workbook protection, Allow Edit Ranges with Excel-compatible password hashes (#307). Missing: comment navigation, Show Changes, notes-to-comments conversion, accessibility checker, co-authoring, opening password-encrypted files (refused with a message since #17)
Automation 4 ~30% ~20% 12–20 Recorded, editable GridCraft scripts (Automate tab). Typed macros in the engine (macro.*: recorder, runner with input checks and a footprint dry run, debugger; macros.md), recorded from Automate › Macros, edited and debugged in a step editor, and run from the Macros dialog or a Ctrl+Shift shortcut. VBA is out of scope by owner decision: an .xlsm keeps its VBA project unchanged on save and never runs it. No Office Scripts compatibility
Weighted 100 ~75% ~59% 300–485

Dimensions

Dimension Weight Ready Hours Evidence
Features 45 ~59% 300–485 Table above
File formats 15 ~50% 80–120 XLSX read/write is broad but unproven on a real corpus and in Excel; XLSB and ODS are values-only import; no XLS, XML Spreadsheet 2003, SYLK, DIF, PRN; VBA dropped; 100 MB XLSX fails (#175). file-format-parity.md
UI/UX fidelity 12 ~55% 50–80 Excel-style ribbon, galleries, dialogs, formula bar, status bar; 59 commands with shortcuts vs Excel's 200+; key tips on part of the Home tab only; short context menu; a native window per workbook window on the desktop (one on the web). ui-parity.md
Performance 8 ~35% 35–55 Performance
Stability 8 ~60% 15–25 Never-crash rules enforced by lint, every command fuzzed with hostile params, random command sequences fuzzed against undo/redo, XLSX round-trip and full-recalc invariants, last-resort guard in Session::execute. Field reports: Windows Intel GPU crash (#120), error on close (#117), freeze opening from Finder (#166), screen flashing (#76)
Localization 4 ~10% 100–165 Ribbon-only catalog in five languages (ja, zh, ko, pt-BR, ru; ~12% of strings each), CJK/Thai/Hebrew font fallback, no shaping or RTL. localization-parity.md
Hardware 2 ~40% 25–40 GPU UI via wgpu; single-threaded calc; no pen pressure; a native window per workbook window, Arrange All on one monitor. hardware-parity.md
Platforms 2 ~80% 30–60 Platforms
Ecosystem / add-ins 2 ~10% 25–40 Ecosystem and AI
AI features 2 ~15% 30–50 Ecosystem and AI
Ready for real work 100 ~50% (51.6 computed: 0.45 × 59.0 features + the other rows × their weights) ~700–1,100

How the full number is built: features ready is the weighted mean of the area table (59.0 with charts at 30%); ready for real work is the weighted mean of this table with the weights written under Weights. Re-checked after the 10-10 merges: charts were corrected from 38% to 30% (round-trip loss, #190 chart resize) and localization rose from 5% to 10% (#31, #104, #82, #38). The two moves cancel: 51.6 before and after, so ~50% stands.

Mainstream practitioner

The typical professional Excel user: an analyst, accountant or manager who builds and maintains models, cleans and summarizes data, makes charts and pivots, and exchanges workbooks with Excel users every week. Left out: Power Query and the data model, VBA and add-ins, Copilot and cloud functions, co-authoring and admin, specialist hardware, and languages beyond the user's own (localization is reported separately).

Area (weekly use) Weight Depth Basis
Formula language and calculation 20 72 Feature-area table
Common worksheet functions 15 85 Missing functions are niche (ETS, odd-period bonds, cloud); edge bugs in common ones (#137, #138, #57)
Editing, navigation, clipboard, fill 15 70 Feature-area table
Cell formatting, styles, conditional formatting 13 80 Feature-area table
Sort, filter, tables, validation 10 70 Feature-area table
PivotTables (core: fields, layouts, grouping, refresh) 8 60 Slicers and calculated fields excluded as less frequent
Charts (column, bar, line, pie, scatter, combo) 9 45 Common kinds work and survive save; trendlines read, written and drawn; no axis options; moved and resized from eight handles (#190)
Page layout, print, PDF 5 60 Latin text exports
Comments, notes, protection 3 55 Feature-area table
Pictures and shapes 2 45 Feature-area table
Average depth 100 69.5

Discounts for what still stops real work:

Discount Factor Evidence
Interaction fidelity × 0.90 59 command shortcuts vs Excel's 200+; key tips only on part of the Home tab (#43); rectangular selection bug (#28); missing horizontal scrollbar report (#176)
Stability on real machines × 0.92 Never-crash lints, fuzzed commands and the Session::execute guard; but field reports of a startup crash on Intel UHD (#120), an error on close (#117), a freeze opening from Finder (#166) and screen flashing (#76)
File exchange with Excel users × 0.88 Excel opening our output is unverified across features; unmodelled parts dropped on save; advanced chart kinds lose their type; 100 MB files fail (#175); .xls and encrypted files are refused with a clear message (#17) rather than opened. Harsher than a drawing app's discount because spreadsheets are exchanged constantly

Mainstream practitioner: 69.5 × 0.90 × 0.92 × 0.88 = 50.6 → ~50% (estimated). Unlike most apps it is not higher than the full number: GridCraft's breadth is wide (functions, formatting, ribbon), so excluding the long tail removes little, while the discounts land on exactly what mainstream users do every week (exchange files with Excel users).

Essentials user

Someone who only touches the core: opens a workbook someone sent, types data and simple formulas, formats, sorts, makes a basic chart, saves and prints. Advanced options, pro workflows and exchange edge cases are left out, along with everything excluded from the mainstream number.

Core feature Weight Depth Basis
Typing data, simple formulas, AutoSum (SUM, AVERAGE, arithmetic) 20 88 Solid; 15-digit equality (#57) is rare at this level
Basic formatting: fonts, bold, fills, borders, currency/percent/date formats 15 85
Copy, paste, fill handle, undo/redo 15 78 Selection bug (#28), monthly fill (#132)
Rows and columns: insert, delete, widths, AutoFit 10 82 AutoFit fixed (#42, #88); rows auto-fit oversized fonts on open and row formatting (#833)
Sort and filter 10 82
Save, Save As, reopen XLSX 10 85
A basic chart 8 55 Created easily; moved and resized from eight handles (#190)
Print and PDF 7 65 Desktop works; web PDF gives no file or feedback (#141)
Find and replace 5 85
Average depth 100 80.2
Discount Factor Evidence
Launch and stability × 0.92 Startup crash on some Intel GPUs (#120), "Issue executing" (#59), error on close (#117)
Discoverability and UI clarity × 0.95 The Excel-style ribbon is familiar and labelled; system language by default (#31); small gaps (#176 scrollbar, #170 macOS window controls)
Opening files people send them × 0.90 Double-clicking a workbook in Finder freezes or errors on macOS (#166, #69; drag-and-drop works; fixes in PRs #164, #167); .xls and encrypted files are refused with a message

Essentials user: 80.2 × 0.92 × 0.95 × 0.90 = 63.1 → ~63% (estimated).

User evidence

Counted from all 83 GitHub issues and 109 PRs on 2026-10-10; none of the issues were filed by the maintainer.

  • Praise: 3 explicit ("this is brilliant. Tiny fast native binaries", #16; "Thanks for the great work on GridCraft", #61; "i didnt have excel kind app on my macos", #69), plus polite thanks in feature requests (#39, #45, #142).
  • "Switched from Excel" reports: 0. One counter-signal: "without macro support most professionals cannot switch from excel" (#6).
  • Issues by kind: 50 core-path bugs (30 open, 20 closed) and 33 niche or feature requests (25 open, 8 closed). 18 of the core-path bugs came from one auditing contributor (coygeek).
  • Contributors: 104 PRs from 28 people outside the maintainer in five days, which shows strong interest but not yet daily use.

Performance

Excel recalculates on every core (multi-threaded recalculation), streams large files, and handles 1,048,576 × 16,384 sheets with millions of formulas.

Measure GridCraft Excel Kind
Sheet size limits 1,048,576 × 16,384 same measured (crates/core/src/addr.rs)
Recalc threads 1 all cores measured (no threading in crates/calc)
Edit → recalc, 100k dependents ~0.4 s (2026-10-07), target < 100 ms tens of ms measured on the owner's machine; #66 since made range-formula recalc linear, not re-timed
Grid scrolling virtualised, O(log n) geometry with custom row heights smooth measured in code
Open a ~100 MB XLSX fails (#175) opens user report
Whole-sheet operations Fill and Remove Duplicates on a whole-sheet selection run out of memory or time (fix in PR #152) fine open PR

Work: streaming XLSX reader with shared-string and style dedup, multi-threaded recalc of independent chains (native only; WASM stays single-threaded), whole-column reference clamping, a cargo xtask bench with fixed workbooks so the numbers become measured.

Platforms

Platform Excel GridCraft
Windows x64 / arm64 yes yes (signed MSI and portable zip; also x86)
macOS (Apple silicon, Intel) yes yes (signed, notarized universal DMG)
Web Excel for the web yes (WASM; local files, no cloud)
iOS / iPadOS / Android yes no
Linux no yes (AppImage, Flatpak, deb, rpm, tarball; x86_64, aarch64, riscv64)
FreeBSD no yes

Mobile is the gap (30–60 h for a touch layout over the same engine). GridCraft is ahead on Linux, BSD and RISC-V, where Excel doesn't run.

Ecosystem and AI

  • Add-ins: Excel has Office JavaScript add-ins, COM/XLL add-ins, VBA, Office Scripts and Power Automate. GridCraft has its own recorded scripts, plus a control channel, MCP server and CLI that reach every command. VBA is out of scope (owner decision). A plugin or custom-function API (for example LAMBDA libraries and WASM custom functions) is the open-equivalent path: 25–40 h.
  • AI: Excel has Copilot, the COPILOT() function, Analyze Data, Python in Excel and Flash Fill. GridCraft has Flash Fill and best-in-class agent control (any MCP client can drive every command headless or live), but no in-app assistant, no natural-language formulas and no Analyze Data. Local-model equivalents: 30–50 h; model choice needs the owner.

Stage

Alpha. All six core workflows in the alpha gate pass end to end on macOS with save and reopen (two pass with non-blocking fidelity loss). Core workflows exist end to end, but depth, fidelity and file compatibility are rough (ready ~50%, inside the 40–75% alpha band). Not beta: the main format, XLSX, has not been proven on real-world files or confirmed to open in Excel without repair, large files fail, .xls is missing and text in several scripts doesn't render. Distance to beta: ~25 points of readiness and ~160–240 h, itemized in roadmap.md.

Effort and calibration

Hours are Opus 5.5 agent wall-clock hours, one agent working sequentially, including tests and verification.

Calibrated against this repo's history:

  • First pass, 2026-10-05 → 10-07: M0–M13 (about 72,000 lines of Rust: engine, 478 functions, XLSX, UI, charts, PivotTables, PDF, MCP, CLI, web, packaging) landed in commits from 22:09 on 10-05 to 02:08 on 10-06, built by several parallel agents with work that preceded the first commits; we put it at ~50–80 agent-hours for 0 → ~50% ready, so ~1–1.5 h per point for the broad first pass.
  • Recent single features: ODS import (#100, +2,232 lines with tests) and XLSB import (#101, +1,212 lines) each fit in one agent session of roughly 2–3 h; the linear-recalc fix (#66, +477 lines) about 1 h; single-function fixes (ROUND, DATE 1900, SUMIF sizing) 0.3–0.5 h each. That is roughly 600–1,000 lines per agent-hour including tests.
  • Tail factor: what remains is verification-heavy (Excel as the oracle for files, functions and rendering), and much of it is large self-contained subsystems (Power Query, Solver, localization, .xls). We apply 5–7× the first-pass rate: ~6–10 h per point of readiness.

Parallelism: ~70% of the work splits cleanly by area (functions, charts, pivots, formats, localization, Power Query) across 4–6 agents with one integrator; with five agents, beta is about 40–60 wall-clock hours away. Needs a human: checking our files in Excel (the owner's Mac), native-speaker review of every language, scope decisions (co-authoring, cloud functions, in-app AI models, mobile), and Windows hardware for GPU-driver crashes.

What works today

The inventory carried over from the 2026-10-07 ROADMAP.md, updated for what landed since. Presence, not parity: the tables above grade depth.

  • Engine: A1/R1C1 formula parser with reference adjustment, dependency-graph recalculation with dynamic arrays (spill + #SPILL!), cycle detection, LET/LAMBDA/MAP/REDUCE/SCAN/BYROW/BYCOL/ MAKEARRAY, structured table references, defined names, INDIRECT/OFFSET/INDEX references, 505 worksheet functions (478 at M0) (math, statistics and distributions, text and regex, lookup incl. XLOOKUP/FILTER/SORT/UNIQUE/VSTACK, dates, financial incl. bonds, engineering incl. complex numbers and Bessel, database, information).
  • Number formats: Excel's full format-code language (sections, conditions, colours, dates and elapsed time, fractions, scientific, accounting fill), General narrowing to column width.
  • Files: XLSX read/write (styles, themes, merges, CF, validation, tables, comments, hyperlinks, charts, pictures, sparklines, print settings, defined names, shared/array/dynamic formulas), CSV/TSV with encoding and delimiter detection, HTML export, JSON; XLSB and ODS data import (values only, 10-10).
  • Editing: cell entry with type detection and auto-formats, in-cell and formula-bar editing, point mode (click/drag/arrow references), reference colouring, F4 anchor cycling, function autocomplete and argument hints, copy/cut/paste and Paste Special (values, formats, transpose, operations, link, skip blanks), AutoFill series (numbers, dates, months, weekdays, custom lists, text+number), Fill Series, Flash Fill, find/replace with wildcards, Go To / Go To Special, undo/redo with history, format painter. Quick selection drags retain their final endpoint; the fill handle explains how to fill versus select cells.
  • Formatting: fonts, fills, all border styles, alignment (wrap, indent, rotation, merge), number formats, 47 cell styles, 60 table styles, conditional formatting (cell rules, text, dates, duplicates, top/bottom, averages, data bars, colour scales, icon sets, formulas), automatic row heights, autofit, hide/unhide, freeze panes. Border presets include visual diagrams; Format Cells previews draft borders before applying.
  • Data: sort (multi-level, by colour, custom lists), AutoFilter (values, custom, top 10, average, colour), tables with totals rows, remove duplicates, text to columns, data validation with error alerts, grouping/outline, subtotals.
  • PivotTables: Insert/Recommended PivotTables, field list pane, compact/outline/tabular layouts, values on rows or columns, date grouping, sort, filters, show-values-as, refresh, and XLSX round-trip.
  • Page layout & print: Page Break Preview, print settings, PDF export and printing.
  • What-if: Goal Seek, scenarios, data tables. Spelling (system word list) and thesaurus.
  • Draw: pen, highlighter, eraser, ink strokes and Ink to Shape. Task panes: Comments (threaded replies, resolve), Watch Window, Selection, Format Chart.
  • Charts: column, bar, line, area, pie, doughnut, scatter, bubble, radar, histogram, waterfall, funnel, treemap, sunburst, box & whisker, stock and combo charts; sparklines.
  • UI (egui): Excel-style title bar with Quick Access Toolbar and AutoSave, the full ribbon with galleries (cell styles, table styles, colour palettes, conditional formatting menus), contextual Table/Chart Design tabs, formula bar with Name Box, virtualised grid (smooth scrolling, zoom, frozen panes, text overflow), sheet tabs (rename, reorder, colour, hide), status bar with Sum/Count/Average and zoom, dialogs (Format Cells, Insert Function, Find and Replace, Sort, Name Manager, Data Validation, Paste Special…), command palette, dark mode.
  • Agents: every action is an engine command; JSON control channel in the desktop app (pointer, keyboard, dialogs, screenshots); MCP server (headless or bridged); CLI (info, convert, eval, cat, run, commands, functions, mcp, send).
  • Platforms: macOS, Windows, Linux, FreeBSD; web (WASM via trunk). Release workflows for signed/notarized macOS universal DMG, signed Windows x64/x86 MSI + zip, Linux AppImage/deb/rpm/ tar.gz + Flatpak manifest, FreeBSD tarball and a web zip.

Not measured yet

  • Pixel comparison against Excel screenshots (planned; screenshots stay in plan/excel/).
  • Function results against Excel-computed oracles (a corpus repo is the planned home).
  • Recalc and open-time benchmarks on fixed workbooks (no cargo xtask bench yet).
  • Whether Excel opens our XLSX output without repair, across features.

Revision history

Date Change Summary
2026-11-02 minor What-if and analysis: Solver Sensitivity report (no score change)
2026-11-02 minor Charts move and resize from eight handles like every floating object (#190): the Essentials chart work is polish only (5–8 h), and the chart rows and the interaction discount no longer list resizing as missing; the Mainstream chart row no longer lists trendlines as missing (no score change)
2026-11-01 minor What-if and analysis: Analysis ToolPak has all 19 tools (was 13 of 19; no charts); no score change
2026-11-01 minor Charts: data tables for column, bar, line, area and compatible combo charts, with legend keys and borders; live source values, native XLSX round-trip and shared print/PDF rendering. Readiness estimates unchanged.
2026-11-01 minor Page layout and print: Page Setup's page order (Down, then over or Over, then down), kept in XLSX; no score change
2026-10-31 minor The Insert Function dialog is named as in Excel (it was called Formula Builder); no score change
2026-10-31 minor What-if and analysis: Solver Options (no score change)
2026-10-31 minor What-if and analysis: Solver Load/Save Model and Reset All; Forecast Sheet moved from Missing to the list of tools, as gaps.md §13 records (no score change)
2026-10-25 minor Automation: macro interface (Automate › Macros, the Macros and Record Macro dialogs, the step editor, shortcuts) (no score change)
2026-10-25 trivial Catalog count 276 / 292 in the summary table and the method, as cargo xtask parity measures (no score change)
2026-10-22 minor Several windows on the desktop: a native window per workbook window, New Window on the same workbook, Switch Windows and Arrange All; "one window" removed from UI/UX fidelity, Hardware and the interaction-fidelity discount; no score change
2026-10-21 minor Page Setup paper sizes: B4/B5/B6 are the JIS sizes Japanese Excel uses (ISO B4/B5/B6 by name), and Japanese Postcard, Japanese Double Postcard, the chou/kaku envelopes and A6 are added; PDF MediaBox and file.print follow, and the Size menu lists them
2026-10-18 trivial Stale chart notes: all chart kinds survive XLSX round-trip (PRs #158, #161) and trendlines landed
2026-10-16 minor Advanced Filter copy-to clears only its actual output and rejects overflow without changing cells (#1031)
2026-10-15 minor Row auto-fit: line breaks count only in wrapping cells (Excel: wrap off shows one line, AutoFit gives one line); unwrapped multi-line cells from files no longer grow rows on open (no score change)
2026-10-21 minor Automation: typed macros in the engine and macro.* commands, no interface yet (no score change); catalog 274 / 290 → 275 / 291 (View › Macros › Record Macro)
2026-10-12 minor Essentials AutoFit evidence: rows auto-fit oversized fonts on open and row formatting (#833)
2026-10-12 minor Sheet tabs: reveal the selected tab on navigation and resize while preserving manual scrolling (#681); no score change
2026-10-12 minor PivotTables: values on rows (Σ Values in Rows at any position, all three layouts; pivot.moveField and the field pane move it; dataOnRows round-trips) (no score change)
2026-10-11 minor Stability: command-sequence fuzz harness (crates/engine/tests/it/command_sequence_fuzz.rs) checks random command sequences against undo/redo, XLSX round-trip, full-recalc and structure invariants; the sequence bugs it found are fixed (no score change)
2026-10-11 minor Password-encrypted workbooks open (#11): Essentials file-opening work 24–36 h
2026-10-11 minor Worksheet functions 505 / 523 (96.6%; 496 working): ODDFPRICE, ODDFYIELD, ODDLPRICE, ODDLYIELD
2026-10-11 minor Worksheet functions 503 / 523 (96.2%; 494 working): PERCENTOF, EUROCONVERT
2026-10-11 minor Worksheet functions 502 / 523 (96.0%; 493 working): BAHTTEXT
2026-10-11 minor Worksheet functions 502 / 523 (96.0%; 493 working): TRIMRANGE
2026-10-11 minor View › Formula Bar and Zoom 100% are engine commands (CLI/MCP); catalog 258 → 260 / 290 (#289)
2026-10-11 minor Review › Allow Edit Ranges; catalog 258 → 259 / 290 (#307)
2026-10-11 minor PivotTables: calculated fields (pivot.calculatedField)
2026-10-11 minor PivotTables: PivotCharts (insert.pivotChart)
2026-10-10 minor Readiness-by-audience table: hours to ~95% for each of the three numbers (full 650–1,050, mainstream 200–310, essentials 60–100). Full number confirmed as the additive weighted sum over the written dimension weights (no change)
2026-10-10 minor Added Mainstream practitioner (~50%) and Essentials user (~63%) with written weights and discounts, and user-evidence counts; re-checked the full number after the 10-10 merges (charts 38→30, localization 5→10; still 51.6, ~50%)
2026-10-10 minor Stage checked against the new alpha gate (six core workflows, all pass): stays alpha
2026-10-10 major Created. Full re-measure against Excel for Mac 16.113.4: functions 501 / 523 measured against Microsoft's list, catalog 258 / 290, breadth ~75%, ready ~50%, alpha; replaces the estimate tables previously in ROADMAP.md and keeps its "Working today" inventory