* Objects: one selection for charts, pictures, shapes and slicers, with eight resize handles
The sheet tracked the selected object as a bare id in `selected_chart`, so
only charts and text boxes drew a selection frame, only the bottom-right
corner resized, and the kind of the selected object had to be guessed from
the id. The selection is now `SheetApp::selected_object: Option<ObjRef>`,
with `selected_chart()` kept for the Chart Design tab and the Format Chart
pane.
- Model: `ObjKind` (chart, image, shape, slicer) and `ObjRef { kind, id }`;
`Sheet` helpers find, move and remove an object by `ObjRef` and walk every
object's anchor in a fixed order. `next_object_id` saturates instead of
overflowing on an id at `u32::MAX` read from a file.
- Commands: `object.delete`, `object.move` and `object.setAnchorMode` accept
the four kinds through one parameter check, refuse an unknown kind or id
instead of succeeding silently, and clamp hostile offsets. `object.delete`
replies with the deleted object. Arrange and the Selection Pane include
slicers, which stack above the other objects.
- Sheet: the selected object of any kind draws a frame with eight handles
over every object. Each handle resizes only its own edges, which never
cross; the body moves the object, and the first drag frame already applies
the pointer's movement. The pointer shows the handle's resize cursor or a
move cursor, with the diagonals swapped on a right-to-left sheet, where the
frame moves with its object.
- Keys: Escape drops the object selection; Delete and Backspace keep
deleting the selected object (#213). A selection whose object disappears
(undo, redo, delete, sheet switch) is cleared.
- Double-click: `open_object` routes by kind (a text box edits in place, a
chart opens Format Chart).
- Control protocol: `ui.inspect` reports `selectedObject {kind, id}` and
keeps `selectedChart`; `ui.object.select` selects any object and replies
with its rect. The snapshot example takes `--object <id>`.
Tests: engine tests for every kind by kind and id, the Selection Pane and
hostile parameters; UI tests for selecting each kind (a slicer over a chart
takes the click), all eight handles on four kinds, cursors, Delete,
Backspace and Escape, undo and redo, double-click routing, and resizing on a
right-to-left sheet. Existing tests use the new selection API.
* Objects: every kind follows edits; chart series follow cut-moves and sheet deletes
Structural edits and sorts kept three hand-indexed lists (charts, images,
shapes) in step in two places, and slicers were left out of both, so a
slicer stayed put when rows were inserted above it. Chart series were
rewritten for inserted and deleted lines and for sheet renames, but not for
cut-moves or sheet deletes, which left them pointing at the old cells.
- Inserting and deleting rows and columns and sorting walk
`Sheet::object_anchors` and `object_anchors_mut`, one fixed order over
every kind, so slicers now follow their cells by their anchor mode like
the other objects, and a new kind cannot be forgotten in one of the
passes.
- `rewrite_cell_links` is the one place that rewrites the references
floating objects hold (chart series values, categories and names,
and the source block a chart was made from).
`rewrite_all_formulas` calls it, which covers inserting and deleting
lines and cells and cut-moves on one sheet or across sheets; renaming and
deleting a sheet call it too, so a series into a deleted sheet becomes
#REF!, as a formula does.
- Copying a sheet gives its charts, pictures, shapes and slicers fresh ids,
keeping ids unique across the workbook, which object selection and the
`{kind, id}` commands rely on.
Tests: every kind through row and column inserts and deletes, an absolute
shape, a sort and undo; a slicer through inserted rows; chart series
through a cut-move, a sheet rename, a sheet delete and undo; ids after a
sheet copy.
* Objects: bubble sizes follow edits like the other series references
`rewrite_cell_links` rewrote a chart series' values, categories and name
but not its bubble sizes, so inserting or deleting lines, a cut-move or a
sheet rename left a bubble chart's sizes pointing at the old cells. They
are now rewritten with the rest.
Test: bubble sizes through an inserted row, a cut-move and a sheet rename.
* Objects: a resize handle under the headers leaves the press to them
A selected object's handles reach a few points outside it, and a press
was matched against them before any check of where it landed, so a press
on the column or row header beside an object at the sheet's edge resized
the object instead of selecting the column or row. The cursor already
ignored handles outside the cells.
`chartview::selected_handle` finds the selected object's handle under a
point only over the cell area, as `hit` does, and not while objects are
hidden; the press and the cursor both use it.
Test: presses within a handle's reach over the column header and the row
header neither move nor resize the object.
* Objects: each drag of an object is its own undo step
A drag merges its frames into one undo step by dropping a new step whose
label matches the one before it. Its first frame did the same, so a second
drag of an object (a move after a move, or a resize after a move) merged
into the first drag's "Move Object" step, and one undo took back both.
`Drag::Object` records whether the drag has made its step; only the later
frames of the same drag merge into it.
Test: a move and then a resize of a picture take two undos to reverse,
the first restoring the moved picture.
* Objects: the parity and gap docs no longer list chart resizing as missing
gaps.md (§4), target-app-parity.md (the Essentials tier's work, the
Mainstream chart row, the interaction discount and the Essentials chart
task) and chart-parity.md (the element table and the work list) still
described charts as impossible to resize (#190). Charts move and resize
from eight handles like every floating object, so those statements now
say so; the 2026-10-10 revision rows and the 10-10 re-check stay as
history. Scores and the 40-60 h chart estimate are unchanged (resizing
was 1-2 h, within the rounding).
* Objects: one chart evidence paragraph in gaps.md; trendlines are not missing
gaps.md §4 carried two evidence paragraphs, an older one saying PRs #158
and #161 were open and a newer one saying all 2-D kinds survive XLSX round
trip, both repeating the resize, smooth-line, Switch Row/Column and
trendline statements. It is one paragraph with the current status again.
The Mainstream chart row in target-app-parity.md listed trendlines as
missing; they are read, written and drawn (`Series::trendlines`, the XLSX
chart reader and writer, `chart.addElement`), as chart-parity.md records.
The row now says so and keeps "no axis options". No score change.
* Objects: only the selected object's handles resize; a press elsewhere on an object moves it
A primary drag looked for a handle under the press on whatever object it
grabbed, so pressing near the edge or corner of an object that was not
selected started a resize, while the pointer over that spot showed the
Move cursor (handles are only shown, and only offered by the cursor, on
the selected object). The press now takes its handle from
`chartview::selected_handle`, the same lookup the cursor uses; a press on
any other object selects and moves it.
Test: dragging an unselected shape by its bottom-right corner shows the
Move cursor, then selects and moves the shape without resizing it.
* Docs: ui.object.select says what it replies when it clears the selection
* Objects: a test pins that both anchor accessors visit the same objects in the same order
Sorting and row or column edits read every anchor through
`object_anchors`, compute the new ones and write them back through
`object_anchors_mut` in step. Nothing checked that the two accessors
visit the same objects in the same order; a kind of floating object
reaching only one of them would have paired objects with other objects'
anchors silently.
Test: two objects of every kind are inserted in a mixed order, each
anchor is marked with its position through the mutable accessor, the
marks are read back through the shared one in the same sequence, the
count matches the per-kind collections, and the mark is found on the
object `object_anchor` names by kind and id. The test's constructor
matches on `ObjKind` exhaustively, so a new kind does not compile until
the test covers it.
* Objects: sorting keeps the size of a "move and size" picture whose lines swap places
A picture anchored to move and size with cells and spanning two rows
(or columns) was re-fitted between its top-left and bottom-right lines
after a sort. When the sort put the bottom line above the top one, the
fitted extent was negative and the picture collapsed to a zero height
or width. It now keeps its old size on that axis and travels with its
top-left line, like a "move only" picture.
Tests: for a sort by rows and one by columns, "move and size" and
"move only" pictures inside one line travel with it (the first
re-fitted to the same line, the second at its own size), an absolute
picture stays while the cells move under it, a two-line picture whose
lines swap keeps its size, and undo restores every anchor.
* Objects: a copied sheet's objects get free ids even when a file used the largest id
`Workbook::next_object_id` returned one more than the largest id in use,
saturating at `u32::MAX`. A workbook read from a file can carry an object
with that id; every later insert (a chart, picture, shape, table or
slicer) then got `u32::MAX` again, and so did each object of a copied
sheet, whose ids also came from a saturating counter. Lookups and
selection take the first object with an id, and `object.delete` removes
every one.
`Workbook::free_object_ids(count)` now returns distinct unused ids: those
above the largest in use while they last, then the lowest free ones from
1. `next_object_id` takes the first of them, and the sheet copy takes one
per copied object (and refuses if the id space were ever exhausted). The
model test that recorded the saturation now checks the free ids instead,
and a new one covers a file that used the largest ids: the free ids come
from below, 100,000 of them distinct and in order.
Test: object_ids_stay_unique_when_a_file_used_the_largest_id gives a
shape id u32::MAX, inserts two shapes and copies the sheet; every shape id
is distinct across both sheets. It fails without the fix (both new shapes
get 4294967295).
* Objects: main's chart data table compiles with the object selection and the model's object test
Two leftovers of the merge of origin/main (25881a8e), neither a textual
conflict: `Chart` gained a `data_table` field, which the `push_object`
helper of the model's object test did not set (it is `None`, as in
`insert.chart`); and chart_data_table.rs set the `selected_chart` field
this branch replaced by `selected_object`. The test selects its chart as
a floating object, as the branch's other tests do.
* Objects: object.move and chart.set keep a size a file made larger than 10,000
`object.move` clamped `width` and `height` to 10,000 points, the most it
gives a new size, while the XLSX reader accepts anchors far past that.
A resize of a picture a file made 12,000 wide passed 11,990 through the
clamp and jumped to 10,000; `chart.set`, whose Format Chart pane sends
the unchanged dimension back with the edited one, clamped the same way.
Each dimension is now capped at 10,000 or the object's current size,
whichever is larger (`size_cap`): such an object keeps its size when it
is moved, shrinks by what a resize asks and never grows further, and a
hostile size is still capped. The params doc of `object.move` and the
control protocol notes say so.
Tests: an_oversized_imported_object_keeps_its_size_when_moved_and_shrinks_only_by_a_resize
makes a picture 12,000 by 300, writes and reads it back as a file, then
moves it without a size (12,000 stays), asks 12,010 (stays 12,000),
11,990 (11,990, no jump) and 50,000 by 50,000 (11,990 by 10,000).
chart_set_keeps_a_chart_size_a_file_made_larger_than_the_limit does the
same through `chart.set`. Both fail without the fix (width 10,000).
* Objects: dragging an object's body sends its position only, not its size
`drag_object` sent `width` and `height` with every step of a body drag,
so moving a picture a file made 12,000 wide shrank it to the 10,000 that
`object.move` gives a new size. Only a handle drag sends a size now; a
body move leaves the engine's size alone.
Tests (real input): dragging_the_body_of_an_oversized_imported_object_keeps_its_size
reopens the workbook with a 12,000 by 60 picture, drags its body by
30 by 25 and checks the size is untouched, the picture moved with the
pointer and the journaled `object.move` carries no width or height; it
fails without the fix (the journaled command carries both, and without
the engine's cap the picture is 10,000 wide).
a_handle_drag_on_an_oversized_imported_object_resizes_by_the_drag_only
moves the left handle 10 px right: the picture is 10 points narrower in
the window and keeps a width near 12,000, with no jump to the limit.
* Objects: the Format Chart Size fields show a chart's real size and send only the edited dimension
The Width and Height fields ranged 40 to 4,000 and sent both values on
every edit. egui clamps an existing value into a field's range, so a
chart a file made 12,000 wide showed "Width 4000", and typing a new
height sent that 4,000 as the width: the chart shrank although only its
height changed, and the cap `chart.set` keeps for an existing size
cannot help once the pane itself sends 4,000. Each field's range now
reaches the larger of 4,000 and the chart's current size, so the field
shows the real size, and a commit sends only the dimension that differs
from the chart's (`chart.set` reads `width` and `height` independently).
Test (real input): the_size_fields_keep_an_oversized_imported_chart_width_when_the_height_changes
reopens a workbook with a 12,000-wide chart, opens Format Chart Area's
Size section, checks the Width field shows 12000 and types 201 as the
height: the width stays 12,000, the height is 201 and the journaled
chart.set carries no width. Without the fix the field shows
"Width 4000".
34 KiB
Target-app parity: GridCraft vs Microsoft Excel
Last reviewed: 2026-10-11 · Last updated: 2026-11-02 · Change: minor (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 paritymeasures; 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,.lprojfolders 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 incrates/functions/src/*.rsplusSPECIAL_FUNCTIONSincrates/calc/src/eval.rs(evaluator special forms), minus the test-onlyADD2: 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 incrates/engine/src/cmd/*.rs, recomputed from source by script and identical to the committedparity-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 incrates/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 and Limits reports; Load/Save Model, Reset All and Solver Options; no Sensitivity 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 benchyet). - Whether Excel opens our XLSX output without repair, across features.
Revision history
| Date | Change | Summary |
|---|---|---|
| 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 |