Files
gridcraft/ROADMAP.md
T
Pranav f6a0556b9e Objects: one selection for every floating object, eight resize handles, and objects that follow edits (#470)
* 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".
2026-11-02 09:30:13 +01:00

43 KiB
Raw Blame History

GridCraft roadmap

Stage: alpha · next: beta, ~25 points of "ready for real work" and ~160–240 h away

Last reviewed: 2026-11-01 · Last updated: 2026-11-02 · Change: minor (floating objects: one selection, eight resize handles, keyboard delete; earlier: Chart data tables: live source values beneath column, bar, line, area and compatible combo charts; legend keys and borders; XLSX round-trip and print/PDF; earlier: Formulas › Function Library as labelled buttons with category menus; Recently Used and Insert Function categories; XLSX workbook-view selection, bounded tab ratios and sheet-edit regressions; readiness estimates unchanged; earlier: CSV and text open detects each column's date order, so day-first dates are not silently swapped) · Target: Microsoft Excel (Microsoft 365)

GridCraft aims at full Microsoft Excel parity, and at being better in places: faster, open (XLSX is the native format), fully scriptable by agents (MCP, control channel, CLI), and on the web. This page is the summary. The detail is in:

Headline numbers

Number Value Kind
2026-10-14 Editing a cell with text that would read back as a number, boolean, date or formula (entered with a leading apostrophe) shows the apostrophe in the editor and formula bar, so Enter unchanged keeps it text (#1362)
Feature breadth (weighted) ~75% estimated, anchored on two measurements: ribbon catalog 276 / 292 (94.5%), worksheet functions 513 / 523 (98.1%; 504 working, 96.4%)
Ready for real work ~50% estimated from written weights (51.6); target-app-parity.md
Mainstream practitioner ~50% estimated: typical analyst/finance user, weekly features, × 0.90 interaction × 0.92 stability × 0.88 file exchange; method
Essentials user ~63% estimated: core features only, × 0.92 launch/stability × 0.95 clarity × 0.90 opening sent files; method
Remaining to beta ~160–240 Opus 5.5 agent-hours estimated; itemized in roadmap.md
Remaining to full parity ~700–1,100 Opus 5.5 agent-hours estimated; sum of the dimension rows below
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 resize and polish (6–10 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).

Why alpha: all six core workflows in the alpha gate pass end to end on macOS with save and reopen, and the core workflow works end to end (open an XLSX, enter formulas and data, format, sort and filter, chart, pivot, print to PDF, save XLSX), but users still hit blocking gaps on real files: 100 MB workbooks don't open (#175), there's no .xls (#121), Arabic and Devanagari text isn't shaped (Chinese text still reported in #142), charts lose their type and options on round trip, and nobody has yet confirmed that Excel opens our output without a repair prompt across a real corpus. Beta needs those closed (see beta gates).

The 2026-10-07 numbers (catalog 89%, "feature depth ~65%", "~215 h to full parity") were re-measured. Catalog and function counts held or rose; the depth and hours moved because of new evidence: 82 issues filed by users and contributors in the repo's first five days, and scope the old estimate left out (localization, legacy .xls, Power Query and the data model, collaboration, mobile, AI).

By dimension

Dimension Ready for real work Hours to parity Doc
Features (13 areas, table below) ~59% (breadth ~75%) 300–485 target-app-parity.md
UI/UX fidelity ~55% 50–80 ui-parity.md
File formats ~50% 80–120 file-format-parity.md
Performance ~35% 35–55 target-app-parity.md
Stability ~60% 15–25 gaps.md
Localization ~10% (ribbon in 6 languages) 100–165 localization-parity.md
Hardware (multi-core calc, GPU, pen, multi-window) ~40% 25–40 hardware-parity.md
Platforms ~80% (no iOS/Android; ahead on Linux, BSD, RISC-V) 30–60 target-app-parity.md
Ecosystem / add-ins ~10% (VBA out of scope; own scripts, MCP, CLI) 25–40 target-app-parity.md
AI features ~15% (agent control strong; no in-app assistant) 30–50 target-app-parity.md
Total ~50% ~700–1,100

Features

Area Breadth Ready Hours Doc
Formula language and calculation ~92% ~72% 20–30 target-app-parity.md
Worksheet functions 96.6% measured ~82% 16–26 function-parity.md
Editing, navigation, clipboard, fill ~90% ~70% 15–25 ui-parity.md
Cell formatting, styles, conditional formatting ~95% ~80% 8–14 target-app-parity.md
Sort, filter, tables, validation, outline ~82% ~70% 10–16 target-app-parity.md
PivotTables ~65% ~45% 25–40 target-app-parity.md
Charts and sparklines ~50% ~30% 40–60 chart-parity.md
Page layout, print, PDF ~80% ~55% 12–20 target-app-parity.md
What-if and analysis (Goal Seek, Solver, ToolPak, Forecast) ~50% ~40% 22–35 target-app-parity.md
Get & Transform, external data, data model ~15% ~10% 60–100 target-app-parity.md
Insert objects (pictures, shapes, ink, SmartArt, equations) ~55% ~45% 25–40 target-app-parity.md
Review, comments, protection, collaboration ~55% ~40% 35–55 target-app-parity.md
Automation (recorded scripts; typed macros with a recorder, a Macros dialog and a step editor; no VBA) ~30% ~20% 12–20 target-app-parity.md

Languages

The ribbon is translated into Japanese, Simplified Chinese, Korean, Brazilian Portuguese, Russian and German (266–268 labels each, ~12% of ~2,200 strings; merged 10-10 in #31, #104, #82, German added 10-11), the interface follows the system language, and CJK, Thai and Hebrew text falls back to system fonts (#38). Japanese (10-17) and Brazilian Portuguese also translate the dialog titles and labels, message boxes, Backstage/File-view items, template names and native menus: 943 strings each, ~43%. The remaining dialogs, menus and messages are English; formulas and number formats are en-US only. Localized German formulas and numbers are in PR #163. Detail: localization-parity.md.

Language Code Status UI strings
English en full (source language) 100%
Simplified Chinese zh-Hans menus only ~12%
Spanish es none 0%
Hindi hi none 0%
Arabic ar none (no RTL layout, no shaping) 0%
French fr none 0%
Portuguese pt-BR menus, File view, dialogs ~43%
Indonesian id none 0%
Japanese ja menus, File view, dialogs, messages ~43%
German de menus only ~12%
Korean ko menus only ~12%
Vietnamese vi none 0%

Other shipped languages: 3 (Russian and German, menus only, ~12%; Dutch, menus, File view and dialog titles, ~24%).

Upcoming

Ranked; estimates in Opus 5.5 agent-hours. Detail and the full beta-gate list in docs/roadmap.md.

  1. Land the open PR queue (50 open PRs on 2026-10-10, many fixing listed gaps: recalc and spill correctness, chart kind round-trip, CJK font fallback, macOS Finder open, German and Chinese UI). Review and merge: 8–15 h.
  2. XLSX fidelity on a real-world corpus, with Excel opening our output without repair: 25–35 h.
  3. Large workbooks and recalc speed: 100 MB XLSX, 1M rows, multi-threaded recalc: 40–60 h.
  4. Charts depth: kinds and options round-trip, axes, trendlines, error bars: 25–35 h.
  5. Text in every script (CJK, Thai, Arabic, Devanagari) in cells and PDF: 12–20 h.
  6. Legacy .xls import and password-protected workbooks: 20–30 h.
  7. Localization: extend the catalog past the ribbon, then the twelve languages: 100–165 h.

Progress log

Date What landed
2026-11-02 Floating objects: charts, pictures, shapes and slicers share one selection with a frame of eight resize handles (each moves only its own edges, also on right-to-left sheets); Delete or Backspace deletes the selected object and Escape drops the selection; slicers follow row and column edits and sorts like the other objects; chart series follow cut-moves and sheet renames and deletes; a copied sheet gives its objects fresh ids; ui.inspect reports selectedObject and ui.object.select selects any object (#190, #213)
2026-11-01 Chart data tables are available from Chart Design › Add Chart Element and Format Chart Area. Tables follow live source values and number formats, keep blank cells blank, offer legend keys and border settings, and survive XLSX save/reopen; the shared renderer includes them in print and PDF. Readiness estimates unchanged.
2026-11-01 XLSX keeps the first visible workbook window's active sheet and display settings together, falling back to the first view when all are hidden. Tab ratios are normalized to 0–1000 on import and export; invalid numeric text uses 600. Synthetic round trips cover isolated attributes, missing views, and active tabs after sheet deletion/reordering; firstSheet remains separate #2264 work (#3057).
2026-10-31 Esc in File › Info, Print or Options first leaves the text field; the next Esc returns to the sheet (#3035)
2026-10-31 CSV and text open detects each column's date order: a value that reads only day first (31/05/2026) makes the column day first, a value that reads only month first (12/31/2026) makes it month first, an all-ambiguous column keeps month first with a warning, and a column with both kinds stays text with a warning (#2765)
2026-10-31 Recently Used lists the functions most recently entered in a formula from any source (ribbon, control channel, MCP, scripts), kept with the preferences and returned by formulas.recentlyUsed; the Insert Function dialog takes Excel's title and a working category list (Most Recently Used, All, each category)
2026-10-31 Formulas › Function Library as a big Insert Function button, the AutoSum split button and three columns of labelled small buttons, each category book in its own colour; category menus end with Insert Function… on that category; More Functions cascades into the remaining categories; Home › Editing shares the AutoSum menu; the MR key tip opens Recently Used
2026-10-25 AutoSum over a selection does what Excel does: a selected row gets one total to its right (in its last cell if that is empty), not a one-cell total under each cell; a block whose last column is empty gets each row's total there, one whose last row is empty each column's, and with both the corner gets the total of the block; otherwise totals go under each column as before
2026-10-24 Macro interface (macros.md): an Automate › Macros group (Record Macro, which turns into Stop Recording, Use Relative References, Run Macro with recent macros); "Recording · N steps" with Stop in the status bar; a Record Macro dialog (checked name, free Ctrl+Shift shortcut, description); the Macros dialog lists macros beside Automate scripts and a VBA project, with Run, Step Into, Edit, Create, Delete and Options; Ctrl+Shift+letter macro shortcuts; questions that offer Run, Overwrite, Shift Down or Shift Right; a step editor with a breakpoint gutter, drag to reorder, a command picker, reference boxes that switch between relative tokens and absolute references, Inputs and Output tabs, a debug bar (Check, Run, Step, Continue, Run to Here, Stop with keep or undo) and grid overlays for inputs, writes, conflicts and the current step
2026-10-24 Go To lists the named ranges of every sheet (Sheet2!Name for a name scoped to another sheet; hidden names, constants and formulas left out) and the references entered before, a double-click goes to an entry, and the Reference box takes several names or references separated by commas (Price, Type, B14:C22,F19:G30)
2026-10-24 Status bar: a right-click opens a menu that sets which selection statistics show (Average, Count and Sum by default; Numerical Count, Minimum and Maximum are new), kept with the preferences (view.statusBar)
2026-10-24 Ctrl+Shift+U (Control+Shift+U on a Mac) expands and collapses the formula bar, on the grid and while editing (view.expandFormulaBar); on Windows and Linux it used to underline
2026-10-24 Fill handle: from a date, the right-drag menu and the Auto Fill Options button offer Fill Days, Fill Weekdays (Saturday and Sunday skipped), Fill Months and Fill Years
2026-10-24 PivotTables: Enable show details (pivot.options enableShowDetails); turned off, Show Details and double-clicking a value cell list no records, and XLSX files keep the setting (enableDrill)
2026-10-24 PivotTables: right-clicking a value, subtotal or grand total cell offers Show Details in the cell menu, which lists the cell's source records on a new sheet as double-clicking does
2026-10-24 Sheet tabs: dragging the handle between the tabs and the horizontal scrollbar gives the tabs more or less of the bar, as in Excel; each open workbook keeps its own share
2026-10-24 Charts: 100% Stacked Area (insert.chart {type: "area", subtype: "stacked100"}), drawn as each value's share of its category's total; XLSX percentStacked area charts open as 100% stacked instead of stacked
2026-10-23 Accounting negatives in text: $(1,234), $ (5) and (5)% read as negative numbers when typed, coerced by arithmetic or passed to VALUE, like Excel 365; (-5), ((5)), $5% and dates or times in parentheses stay text
2026-10-23 Calc: INDEX(A1:C3,2) (one index on a reference of several rows and columns) is #REF! as in Excel, instead of the whole row; INDEX(A1:C3,2,) still gives the row
2026-10-22 Formula hardening: digits too many for a finite number are text, so "1 <400 digits>/<400 digits>" no longer coerces to NaN; a NaN column index in VLOOKUP, HLOOKUP and the D-functions is #VALUE! instead of an index underflow; REGEXREPLACE stops building a result as soon as it can only be too long (a worst case went from 1 GB to 7 MB) (#2163, #2162)
2026-10-22 View › New Window and Arrange All on the ribbon. Arrange All tiles, stacks side by side or top to bottom, or cascades the native windows over the main window's monitor, the active one first. Two windows on one workbook show different sheets without copying the workbook or marking it changed; Save records the sheet of the window used last. A dialog stays in the window it was opened in
2026-10-22 On the desktop every workbook window is a native window of its own: New, Open and New Window open one, each keeps its own cell draft, dialog and ribbon, and the macOS menu bar acts on the window focused last. Closing one of several windows on a workbook doesn't ask; closing a workbook's last window, or quitting, asks about unsaved changes in that window. The last window closed quits on Windows and Linux; macOS keeps running with the menu bar. First craft-libs craft-window use (window list and viewport driver)
2026-10-22 View › New Window opens a second window on the same workbook (it used to open a copy whose Save overwrote the original): each window has its own selection, active sheet and scroll, titles read "Book1:1" / "Book1:2", and Switch Windows, Hide, Unhide and Close act per window. The control channel, CLI send and MCP tools take an optional window or doc id and default to the active window; window.list (MCP list_windows) lists the windows
2026-10-22 Typing in a cell and then choosing File › New no longer strands the first workbook: the entry is committed into its own workbook before any File or window command (a refused entry stays open and stops the command), View › Switch Windows and the macOS Window menu list the open workbooks with unsaved markers, view.switchWindows {doc} switches by a stable workbook id, and the macOS Quit item asks about unsaved workbooks
2026-10-21 Page Setup paper sizes match Japanese Excel: B4/B5/B6 are the JIS sizes (ISO B4/B5/B6 stay reachable by name), so a Japanese B5 worksheet prints at 182×257 mm; Japanese Postcard (100×148 mm), Double Postcard (148×200 mm), Envelope #3/#4 (120×235/90×205 mm), Kaku #2/#3 (240×332/216×277 mm) and A6 are added, both sizes reach the PDF page (file.exportPdf/file.print MediaBox) and the size survives an XLSX round-trip; the Page Layout Size menu lists them. B4/B5 used to be the ISO sizes, which is changed here
2026-10-20 Japanese interface catalog covers every key the Brazilian Portuguese catalog translates: the 398-label shared core plus 545 dialog, message, Backstage and menu strings (943 total, ~43% of ~2,200). A test parses pt.rs's source, so the two catalogs stay in step
2026-10-20 Interface translated into Dutch (518 labels: ribbon, context menus, File view, dialog titles, Options); nl, nl-NL, nl-BE locale tags resolve to Dutch
2026-10-19 Long flat operator chains (=A1+A2+…) up to Excel's 8,192-character limit (4,096 operands): entering, filling, inserting rows, undo, Evaluate Formula and XLSX save no longer overflow the stack; chains past 64 operands are saved as plain formulas, not dynamic arrays; Spanish formula entry accepts chains past 256 operands (#916)
2026-10-19 Linux: "Use system setting" for the theme keeps following the desktop when the XDG Desktop Portal stops answering: each read gives up after 2 s and the next poll reconnects, where one unanswered call stalled the watcher for the rest of the session
2026-10-16 Memory: undo steps share a sheet's picture bytes and the workbook's VBA project instead of copying them: 50 edits on a sheet with a 20 MB picture keep 22 MB instead of 992 MB
2026-10-16 Memory: floating pictures are decoded at about the size they are drawn, with limits, into a cache bounded by bytes and dropped with their workbook, instead of at full size into one that never let go; two open workbooks no longer show each other's picture. 12 large pictures scrolled through keep 40 MB of textures instead of 258 MB, and none once the workbook closes
2026-10-16 The web app keeps its preferences between visits (#1562): theme (dark mode), interface size, language, editing options and the rest of what the desktop app saves in ui.json and prefs.json are kept in the browser's localStorage, written as soon as they change
2026-10-16 Memory: the interface and script fallback fonts are read once per run and shared with egui instead of copied into it: an empty workbook settles at 158 MB instead of 258 MB on macOS
2026-10-15 File › Options › Formulas: Maximum Iterations and Maximum Change fields for iterative calculation, disabled while it is off, with Excel's limits (1 to 32767, 0 or more)
2026-10-15 Function help follows the interface language: argument hints, autocomplete, Insert Function (search and readable categories) and the Formulas-tab menus read per-language tables of descriptions and argument names; Spanish keeps its 10 functions in the new format
2026-10-15 Row auto-fit counts a cell's line breaks only when the cell wraps, as Excel does: a file whose unwrapped cells hold multi-line text no longer opens with tall rows (typing a break still turns wrap on and grows the row)
2026-10-14 Lookups (MATCH, XMATCH, VLOOKUP, HLOOKUP, XLOOKUP, LOOKUP) compare numbers exactly like Excel, so a computed key such as =0.1+0.2 no longer finds 0.3; = and COUNTIF/SUMIF keep their 15-digit comparison
2026-10-14 Functions: EOMONTH, EDATE, WORKDAY, NETWORKDAYS, YEARFRAC, WEEKNUM, the bond and coupon functions, DISC, BIN2DEC, IM* and the other Analysis ToolPak functions give #VALUE! for a reference to more than one cell in a value argument, as Excel 365 does, instead of spilling; array constants and computed arrays still lift
2026-10-14 Protect Sheet on a protected sheet: Home › Format, its keytips (HOP, RPS) and the tab menu now read Unprotect Sheet… and unprotect (straight away without a password); a protected sheet that forbids selecting locked (or unlocked) cells is enforced for clicks, arrows and Go To, and the Protect Sheet dialog has the select options (#1346)
2026-10-14 .xls (Excel 97-2003) files open with their formatting: fonts, solid and pattern fills, borders (with diagonals), alignment (rotation, indent, wrap, shrink), locked and hidden cells, the workbook's custom colour palette, its Normal font and its user-defined cell styles
2026-10-14 XLSX: formulas opened with dynamic-array metadata (cm) keep it on save, with xl/metadata.xml. Before, a formula returning one value lost it (11 of 40 corpus files that have the part lost it entirely), and Excel recalculated some of them with implicit intersection (SUMPRODUCT(IFERROR(...)) changed value)
2026-10-14 Recalculation: a dynamic array's anchor given a new formula that reads its old spill area (A1 was =SEQUENCE(3), becomes =SUM(A2:A3)+1 or =SEQUENCE(1,A2+1)) sees that area empty instead of the old values
2026-10-14 Recalculation: when two arrays of one recalculation want the same empty cells, the formulas that read the one laid out second (at its anchor or over the cells it would have spilled into) read #SPILL! and empty cells instead of its values
2026-10-14 Border keytips: each Alt, H, B letter applies the preset Excel's Borders menu gives it (H,B,O bottom, H,B,B bottom double, H,B,N no border, H,B,A all borders and the rest); they all drew a bottom border before. H,B,M opens Format Cells on the Border tab
2026-10-13 Formula-entry Command/Ctrl-click inserts another reference with the locale's argument separator; Shift-click extends from a stable, sheet-aware anchor. Pointer tests cover repeated clicks, reversed ranges, ordinary replacement, typed separators, Spanish syntax, sheet switches and keyboard continuation. Readiness estimates unchanged.
2026-10-13 formulas.evaluate (gridcraft-cli eval, MCP evaluate_formula) refuses what entering the formula in a cell refuses, with the reason (=SUM(1;2): "expected , or )"), instead of #NAME? for any formula that doesn't parse
2026-10-13 Colour menus: Fill Color, Font Color and the Format Cells pickers end with Recent Colors (the last ten custom colours) and More Colors… (hue/saturation area, RGB, hex box, preview, OK/Cancel) (#928)
2026-10-13 Multi-level category axes: a category range two or more columns wide beside a column of values (year beside month, Excel's multiLvlStrRef) draws its innermost labels across the plot and the outer levels in rows under them with group separators (columns beside the labels in bar charts), instead of flattening the two columns into twice as many categories; saving writes the reference back as multiLvlStrRef with Excel's level caches, so the axis survives a round trip
2026-10-13 Charts: a huge trendline forecast no longer collapses the chart: on a category axis it adds at most four times the data in empty slots (at least 32), the line is sampled over the plot only, and forecasts read from XLSX or set by command are clamped, NaN and infinity becoming 0 (#1148)
2026-10-13 XLSX export writes a picture used on several sheets once, as one xl/media part every drawing points to (it wrote a copy per drawing: a 16-sheet workbook with one 112 KB logo grew from 0.4 to 1.9 MB) (#985)
2026-10-13 XLSX: [Content_Types].xml, _rels/.rels, the workbook rels and xl/workbook.xml are the first zip entries (document properties last), so libmagic and PHP finfo detect the file type even with large properties (#1090)
2026-10-13 Conditional formatting: a rule gathers range statistics only when it reads them (top/bottom, above average, duplicates, scales, bars, icons) and borrows them instead of copying them per cell, so the per-frame lookup of an expression or cell-value rule no longer visits its whole range (#1098, part 1)
2026-10-12 Next/previous sheet navigation stops at the first/last visible worksheet instead of activating a hidden boundary sheet; the current selection is retained
2026-10-21 Macro engine (macros.md): typed, declarative macros saved in the workbook (a JSON field; hidden names in xlsx); declared inputs checked with messages that name the cells; tokens (Input.col(2), Row, Output, Name:Total, {{…}} in formulas); one undo step with full rollback; a footprint dry run with ask, fail, overwrite, shift down or shift right; a policy that keeps macros away from files and the app, with approval for macros in opened files; Repeat, If and Stop steps; a debugger; a relative recorder; macro.* commands beside the unchanged Automate scripts
2026-10-12 Security: the --control server requires an auth token (random, kept in a 0600 file or chosen with GRIDCRAFT_CONTROL_TOKEN) on each connection's first line and closes bad connections (#777)
2026-10-12 Rows auto-fit oversized fonts: opening a file and whole-row/column formatting grow non-custom rows to their tallest font (#833)
2026-10-12 Number formats: parsing a format code is linear in its length (long runs of [, , or / no longer take quadratic time), and an unclosed [ is a literal when splitting sections as well as when tokenizing (#810)
2026-10-12 Number formats: a fraction denominator with 65,536 zeros no longer crashes; format codes are capped at 255 characters like Excel (longer codes display as General, TEXT gives #VALUE!) (#807)
2026-10-12 Security: cell hyperlinks open only http, https and mailto, after a confirmation; other schemes (file:, smb:, UNC, custom handlers) are refused (#777, part 1)
2026-10-12 Deleting several Ctrl-selected rows or columns removes them all in one undo step (#758)
2026-10-12 XLSX chart sheets are kept on open and save: the sheet, its drawing and chart (with style and colours) are written back unchanged in their place among the worksheets, and left out when the sheet they plot is deleted or renamed or a worksheet took their name (#727)
2026-10-12 CSV and tab-separated export is capped at 512 MiB: a sheet whose used range would expand to more (two cells far apart, such as A1 and XFD1048576, are 16 GiB of commas) is refused with the rows, columns and limit, before anything is allocated or written (#528)
2026-10-12 PDF writer hardening: text width cannot overflow, all-zero dash arrays and negative or NaN stroke widths are sanitised, non-finite sizes and positions draw nothing (#812)
2026-10-12 PDF export writes the document title and author as UTF-16BE when they are not ASCII, so viewers show accents, currency signs and non-Latin text correctly (#813)
2026-10-12 TEXT() over a range and chart labels parse each number format code once instead of once per value (#806)
2026-10-12 SUBTOTAL(109) over hidden rows recalculates after Row Height, AutoFit Row Height and Ungroup reveal rows (found by the command-sequence fuzz)
2026-10-12 Page Layout view: drag the margin edges on the rulers to set the page margins (resize cursor, live preview, value tooltip, one undo step, Esc cancels) (#792)
2026-10-12 Forecast Sheet gets Forecast Start: begin the forecast inside the history to compare it with the actuals (#785)
2026-10-12 Ink strokes save as unfilled DrawingML paths and reopen as editable ink with their points, colour and width; icons in #551 remain a follow-up
2026-10-12 The selection outline stays visible when extended to the last row (Ctrl+Shift+Down): its sides are cut to the viewport instead of stroking a 20-million-point rectangle (#687)
2026-10-12 File › Print selects a system printer, copies, duplex and grayscale, submits PDF jobs through craft-print on a worker and shows spooler errors; browser printing and PDF export remain available
2026-10-11 UI building blocks: theme tokens with a WCAG contrast test over both themes (icons and reference colours follow dark mode); ribbon scroll arrows and a large split button (Formulas › AutoSum opens its menu); the formula bar grows from one to five lines, then scrolls; a code editor widget with Python and LaTeX colouring
2026-10-11 Command-sequence fuzzing: random command sequences checked against undo/redo, XLSX round-trip and full recalculation; fixes for the table, legacy-array, spill, AutoSum, Watch Window and sheet-copy bugs it found
2026-10-11 Password-protected workbooks open: GridCraft asks for the password and decrypts Agile and Standard encryption (#11)
2026-10-11 Text boxes keep their formatting: run size, bold, italic, typeface, text colour and outline, alignment, vertical anchor and "no outline" (#377)
2026-10-11 Desktop printing opens the print PDF in the system viewer; Save As offers CSV, web page and PDF; macOS File › Properties opens File › Info (#370, #343)
2026-10-11 Windows: DirectX 12 shaders compile with FXC, so a missing or stray dxcompiler.dll no longer stops the app at start (#339, #354)
2026-10-11 Merged cells draw their whole outline: right and bottom edges come from the last column's and last row's cells (#376)
2026-10-11 Shrink to fit draws too-wide text and numbers in a smaller font inside the cell or merged area (#375)
2026-10-11 Shift+Space and Ctrl+Space select the row / column without starting an edit; Control+Space on Mac (#338)
2026-10-11 Workbooks reopen at their saved scroll position (topLeftCell, also with frozen panes) and save the current one back (#378)
2026-10-11 Protect Sheet passwords use Excel-compatible hashes and round-trip in XLSX sheetProtection (imported passwords verify instead of being dropped)
2026-10-11 Review › Protect Workbook opens a dialog with an optional password (Excel-compatible hash, kept in XLSX workbookProtection); unprotecting verifies it (#345)
2026-10-11 Formula bar, name box and dialogs fall back to the cell font: Hebrew (and any script cells can show) no longer turns into boxes there (#349)
2026-10-11 Headers and footers: first-page and odd/even variants are read, kept, printed and edited in Page Layout view; Insert › Header & Footer edits the header in place (#344)
2026-10-11 Legacy Excel 97-2003 .xls (BIFF8) import with formulas, number formats, merges, sizes and names (#121)
2026-10-11 XLSX pass-through: custom XML, external links, connections, query tables, printer settings, form/ActiveX controls and OLE objects are kept on save (#330, #324)
2026-10-11 Data › Forecast › Forecast Sheet: a new sheet with the history, FORECAST.ETS forecast, confidence bounds, statistics and a chart (#322)
2026-10-11 Startup no longer panics on a system font egui can't parse: fonts are validated and skipped (#226)
2026-10-11 Ctrl+drag on the fill handle swaps copying and extending a series (#264)
2026-10-11 Odd-period bond functions ODDFPRICE, ODDFYIELD, ODDLPRICE, ODDLYIELD: Financial 55 / 55 (#275)
2026-10-11 PERCENTOF and EUROCONVERT worksheet functions (#279)
2026-10-11 BAHTTEXT: amounts in Thai words with Baht and Satang (#291)
2026-10-11 TRIMRANGE: ranges and arrays without blank outer rows and columns (#296)
2026-10-11 Selected charts, pictures and shapes can be deleted from the keyboard (#213)
2026-10-11 Ribbon translated into German (266 labels; de, de-DE, de-AT, de-CH locale tags resolve to German)
2026-10-11 View › Interface size: a saved 75–200 % scale for the whole window (#230)
2026-10-11 View › Formula Bar and Zoom 100% reachable from the CLI and MCP (#289)
2026-10-11 Freeze panes by dragging the freeze handles on the header edges (#195)
2026-10-11 XLSX: threaded comments (replies, resolved, timestamps) and note visibility survive a save (#300)
2026-10-11 Cell checkboxes: Insert › Checkbox on the ribbon, Excel's Delete and value rules, XLSX round trip as Excel cell controls (#196)
2026-10-11 Review › Allow Edit Ranges with Excel-compatible password hashes, kept in XLSX (#307)
2026-10-11 PivotTable calculated fields (pivot.calculatedField), evaluated on sums like Excel, with XLSX round-trip (#304)
2026-10-11 PivotCharts (insert.pivotChart): charts bound to a PivotTable's report, following refreshes and layout changes (#311)
2026-10-11 FORECAST.ETS, FORECAST.ETS.CONFINT, FORECAST.ETS.SEASONALITY, FORECAST.ETS.STAT: AAA exponential smoothing forecasts (#314)
2026-10-11 File tab Backstage view (Home, New, Open, Info, Save As, Print preview, Export, Options) and file.options (#174)
2026-10-10 Ribbon translated into Japanese, Chinese, Korean, Brazilian Portuguese and Russian with system-language default (#31, #104, #82); CJK/Thai/Hebrew font fallback (#38); clear messages for encrypted and .xls files (#17); smooth line charts (#62). Progress docs restructured; full re-measure (this page). Initial ribbon key tips (#43), in-place text box editing (#84), copy as HTML table (#36). ODS and XLSB data import (#100, #101); recalc linear in the number of range formulas (#66); RISC-V Linux build; Flatpak repository on Pages; web cell-commit trap fixed
2026-10-09 Community fixes: spill range operator A1#, sheet-scoped names, protection refuses locked-cell edits, Insert/Delete Cells adjust references, DATE(1900,2,29), SUMIF sizing, ROUND at 15 digits, _xlpm. LAMBDA parameters in XLSX, vertical scrollbar, system appearance, border previews; v0.4.0
2026-10-08 v0.2.0 and v0.3.0 releases; Flatpak, AppImage zsync, branded DMG; desktop log file; DirectX 12 default on Windows
2026-10-07 About window with contributor and model credits; macOS release runner
2026-10-06 M0–M13 first pass: engine, 478 functions, XLSX/CSV, egui UI, charts, PivotTables with XLSX round-trip, PDF and printing, what-if, spelling, Draw, task panes, MCP, CLI, web build, release packaging
2026-10-05 Repository created

Revision history

Date Change Summary
2026-11-02 minor Progress log: one selection and eight resize handles for every floating object
2026-11-01 minor Chart data tables are available from Chart Design › Add Chart Element and Format Chart Area. Tables follow live source values and number formats, keep blank cells blank, offer legend keys and border settings, and survive XLSX save/reopen; the shared renderer includes them in print and PDF. Readiness estimates unchanged.
2026-11-01 trivial Workbook views: selected window settings stay together, tab ratios are bounded, and regressions cover isolated settings and sheet edits; readiness estimates unchanged (#3057)
2026-10-31 minor File-page text fields keep the view open when Esc cancels an edit (#3035)
2026-10-31 minor Progress log: Recently Used and Insert Function categories
2026-10-31 minor Progress log: Function Library
2026-10-25 minor Progress log: AutoSum over a selected row, and a selection's empty last row and column
2026-10-24 minor Macro interface on the Automate tab; progress log row
2026-10-24 minor Macro engine and macro.* commands; catalog 275 / 291 → 276 / 292 (View › Macros › Record Macro); progress log row
2026-10-23 minor Progress log: accounting negatives in number text
2026-10-23 minor Progress log: INDEX with one index on a 2-D reference is #REF!
2026-10-22 trivial Progress log: formula hardening (#2163, #2162)
2026-10-22 minor Progress log: Arrange All; two windows on one workbook without copying it
2026-10-22 minor Progress log: a native window per workbook window
2026-10-22 minor Progress log: New Window shares the workbook; window ids for scripts and MCP
2026-10-22 minor Progress log: drafts stay in their workbook, Switch Windows, macOS Quit asks to save
2026-10-21 minor Page Setup paper sizes: JIS B4/B5/B6 (ISO by name), Japanese postcards and envelopes, A6; PDF page size follows, XLSX round-trips
2026-10-20 minor Dutch (nl) listed under other shipped languages; progress log row
2026-10-19 minor Progress log: long flat operator chains (#916)
2026-10-19 trivial Progress log: desktop theme portal read timeout
2026-10-16 minor Progress log: undo steps share picture and macro bytes
2026-10-16 minor Progress log: floating pictures' textures bounded and kept per workbook
2026-10-16 trivial Progress log: web preferences kept between visits (#1562)
2026-10-16 minor Progress log: interface fonts held once instead of twice
2026-10-14 minor Progress log: .xls import reads cell formatting
2026-10-14 minor Progress log: lookups compare numbers exactly
2026-10-14 minor Progress log: Analysis ToolPak value arguments reject multi-cell references
2026-10-14 minor XLSX dynamic-array cm metadata kept on save; progress log row
2026-10-14 minor Progress log: spill anchor reading its old spill area
2026-10-14 minor Progress log: formulas reading an array that loses a spill conflict
2026-10-13 trivial Progress log: More Colors… and Recent Colors in the colour menus (#928)
2026-10-13 minor Multi-level category axes (read, drawn, written); progress log row
2026-10-13 trivial Progress log: shared pictures written once on XLSX export (#985)
2026-10-13 minor Progress log: conditional-format lookups no longer scan the range for rules without statistics (#1098)
2026-10-12 minor Progress log: hidden-sheet navigation at workbook boundaries
2026-10-12 minor The control server requires an auth token and closes bad connections (#777); progress log row
2026-10-12 minor Rows auto-fit oversized fonts on open and whole-row/column formatting (#833); progress log row
2026-10-12 minor Progress log: multi-area row/column delete (#758)
2026-10-12 trivial Progress log: XLSX chart sheets kept on save (#727)
2026-10-12 trivial Progress log: CSV export size cap (#528)
2026-10-12 minor Progress log: margins dragged on the Page Layout rulers (#792)
2026-10-12 minor Ink preservation across XLSX save/reopen (ink portion of #551)
2026-10-12 minor Desktop File > Print now discovers printers and submits PDF jobs through pinned craft-print with printer choice, copies, duplex and grayscale; browser printing and PDF export remain available. Remaining print parity includes page ranges and driver-specific tray/options UI; physical printer fidelity needs hardware validation.
2026-10-11 minor UI building blocks; progress log row
2026-10-11 minor Password-encrypted workbooks open (#11); progress log row
2026-10-11 minor Forecast Sheet (#322); progress log row
2026-10-11 minor Worksheet functions 505 / 523 (ODD* bond functions); progress log row
2026-10-11 minor Worksheet functions 503 / 523 (PERCENTOF, EUROCONVERT); progress log row
2026-10-11 minor Worksheet functions 502 / 523 (BAHTTEXT); progress log row
2026-10-11 minor Worksheet functions 502 / 523 (TRIMRANGE); progress log row
2026-10-11 minor Selected objects can be deleted from the keyboard (#213)
2026-10-11 minor Catalog 258 → 260 / 290: View › Formula Bar and Zoom 100% (#289)
2026-10-11 minor Progress log: XLSX threaded comments round trip (#300)
2026-10-11 minor Catalog 258 → 259 / 290: Allow Edit Ranges (#307)
2026-10-11 minor Worksheet functions 505 / 523 (FORECAST.ETS family); progress log row
2026-10-11 minor Czech (cs) listed under other shipped languages: ribbon only, ~12%
2026-10-10 minor Readiness-by-audience table with hours to ~95% per audience; full number unchanged (additive weighted sum)
2026-10-10 minor Added Mainstream practitioner (~50%) and Essentials user (~63%); languages updated for the 10-10 merges (ribbon in ja, zh, ko, pt-BR, ru); localization 5%→10%; full number re-checked (51.6, unchanged)
2026-10-10 minor Checked against the alpha gate (six core workflows pass): stays alpha
2026-10-10 major Re-measured against Excel for Mac 16.113.4: stage alpha, breadth ~75%, ready ~50%, ~160–240 h to beta, ~700–1,100 h to full parity; progress docs restructured; detail moved to docs/
2026-10-07 major First estimates: catalog 89%, functions ~93%, depth ~65%, ~35 h to alpha, ~215 h to full parity