Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Builds are **unsigned**, so SmartScreen and Gatekeeper warn on first launch (the
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Compare** | Two files or pasted text, split or inline, word-level highlights, in-view search, and a live re-diff when a file changes on disk. |
| **Understand structure** | JSON, YAML and XML compared as _data_: reordering keys or reformatting stops counting, and unchanged keys collapse away. |
| **Excel** | `.xlsx` workbooks as aligned grids — sheet tabs and cell-level highlights, with inserted rows and columns that don't cascade into false changes. Dates read as dates, hidden sheets and rows are marked, and formulas are compared as well as their results, so a total pasted over the formula behind it is caught rather than shown as unchanged. Set a tolerance — one of the presets or a threshold of your own, percentage or raw — and rounding noise stops counting; export the whole change list as a CSV. |
| **Excel** | `.xlsx` workbooks as aligned grids — sheet tabs and cell-level highlights, with inserted rows and columns that don't cascade into false changes. Dates read as dates, hidden sheets and rows are marked, and formulas are compared as well as their results, so a total pasted over the formula behind it is caught rather than shown as unchanged. Headers are found under a title row rather than assumed to be row 1, and rows can be paired by the columns that name them — one column or several — so the same export sorted differently reads as the one figure that moved instead of as a rewrite. Set a tolerance — one of the presets or a threshold of your own, percentage or raw — and rounding noise stops counting; export the whole change list as a CSV. |
| **CSV** | `.csv` and `.tsv` compare as text or, one toggle away, as the same grid — rows aligned by their first column, quoted fields kept whole. |
| **Huge files** | Past 32 MB a file is indexed by line instead of loaded, and the rows you're looking at are read from disk as you scroll — a multi-gigabyte log opens in seconds. Marked as streamed, with the few actions that need the whole text saying so rather than half-working. |
| **Keep** | Saved diffs: encrypted, tagged, optionally auto-expiring. Drag a row onto another to arrange the list yourself; starred rows stay above the rest. Your open tabs come back on the next launch, and the strip can be told to close the oldest comparison to make room for a new one. |
Expand Down Expand Up @@ -105,7 +105,7 @@ flowchart LR
<table>
<tr>
<td width="50%" valign="top">
<img src="docs/screenshots/spreadsheet-diff.png" alt="Two multi-sheet Excel workbooks compared as aligned grids: sheet tabs with per-sheet change counts, a tolerance control and a change-register export, changed cells boxed, and an added row and an inserted column each shown as a striped gap on the side without them">
<img src="docs/screenshots/spreadsheet-diff.png" alt="Two multi-sheet Excel workbooks compared as aligned grids: sheet tabs with per-sheet change counts, a tolerance control, a row-matching control and a change-register export, changed cells boxed, and an added row and an inserted column each shown as a striped gap on the side without them">
<p align="center"><em>Excel workbooks as aligned grids.</em></p>
</td>
<td width="50%" valign="top">
Expand Down
24 changes: 9 additions & 15 deletions docs/brand/roadmap.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 9 additions & 1 deletion docs/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,15 @@ where the concept lives in this repo.
- **Shared strings** — an `.xlsx` de-duplicated text table (`sharedStrings.xml`)
that cells reference by index.
- **LCS** — _Longest Common Subsequence_, the classic diff algorithm; used to
align spreadsheet rows and to build the copy-as-patch output.
align spreadsheet rows by default and to build the copy-as-patch output.
- **Key column** — a column whose value names a row, so the two sides pair by
identity rather than by position or whole-row contents; several together make
a **composite key** (an account plus a cost centre). Chosen per sheet in the
grid's Match-rows panel and applied by `utils/matchRowsByKey.js`. It is what
lets the same export, sorted differently, read as the figures that moved.
- **Header row** — the row whose labels name the columns. Found by scanning the
first few rows (`headerPairing`), because an exported pack opens with a title
and a date before it; without one, columns pair by position.
- **Monaco** — the VS Code editor component, used for the text diff view.
- **Mermaid** — the text-to-diagram library used to render `mermaid` snippets.

Expand Down
44 changes: 25 additions & 19 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Roadmap

<img src="brand/roadmap.svg" width="100%"
alt="Roadmap board — four tracks. Spreadsheet · finance: row identity by key columns, header row offset, amounts read as amounts, delta and net variance, reading a big diff, caps that announce themselves. Diagrams: sequence · gantt · pie, click a change to pan to it. Comparing more: folder compare, image pairs, three-way merge — a decision first. Signing: macOS Developer ID, Windows deferred.">
alt="Roadmap board — four tracks. Spreadsheet · finance: amounts read as amounts, delta and net variance, reading a big diff, caps that announce themselves. Diagrams: sequence · gantt · pie, click a change to pan to it. Comparing more: folder compare, image pairs, three-way merge — a decision first. Signing: macOS Developer ID, Windows deferred.">

<sup>Board is `docs/brand/roadmap.svg` — hand-authored, edit it alongside the
sections below.</sup>
Expand All @@ -12,7 +12,9 @@ sections below.</sup>

**Built** — formulas captured and normalised to R1C1 (`r1c1.js`), number formats
(`numfmt.js`), materiality tolerance, change register, hidden state + error
cells, columns paired by header, `.csv`/`.tsv` through the same grid.
cells, columns paired by header — found under a title row, not assumed to be
row 1 — rows paired by the columns that name them, `.csv`/`.tsv` through the
same grid.

```mermaid
flowchart TB
Expand All @@ -27,9 +29,9 @@ flowchart TB
sh --> ad["adapters/xlsxAdapter.js<br>adapters/csvAdapter.js — delimited text"]
subgraph rend["renderer"]
direction TB
ad --> ac["utils/alignColumns.js — pair columns by header"]
ad --> ac["utils/alignColumns.js — headerPairing<br>scans past a title row"]
ac --> dw["utils/spreadsheetDiff.js — diffWorkbooks<br>utils/sheetCells.js — cell identity"]
dw --> al["utils/alignRows.js — rows + tolerance"]
dw --> al["utils/alignRows.js — signatures + tolerance<br>utils/matchRowsByKey.js — key columns"]
al --> g["SpreadsheetGrid.vue"]
al --> cr["utils/changeRegister.js --> diff:exportFile"]
end
Expand All @@ -44,30 +46,31 @@ trial balance, a GL export, a board pack — hits the gaps below.
```mermaid
flowchart LR
subgraph now["now"]
direction TB
a["1 · row identity<br>key columns · re-sorted rows"]
b["2 · header row offset"]
end
subgraph next["next"]
direction TB
c["3 · amounts read as amounts"]
d["4 · Δ and net variance"]
end
subgraph later["later"]
subgraph next["next"]
direction TB
e["5 · reading a big diff"]
f["6 · caps that announce themselves"]
end
now --> next --> later
now --> next
```

- **1 · row identity** — `opts.keyColumn` exists (`spreadsheetDiff.js:78`) with
no UI, takes one column, and rows pair by LCS over row signatures: the same
export sorted differently reads as 100% changed. Key-based matching,
composite keys, duplicate-key detection
- **2 · header row offset** — `alignColumns.js:16` reads `rows[0]`. A title row
above the header fails `usable()` and drops silently to positional pairing,
which is the failure it was written to prevent
**1 · row identity** and **2 · header row offset** are done.

- `matchRowsByKey.js` pairs rows by one column or several, wherever they sit, so
a re-sorted export reads as the figures that moved. Duplicate keys pair in
order of occurrence and are COUNTED, never hidden — the panel says so
- `headerPairing` scans for the first row that reads as a header (capped at 10)
instead of reading `rows[0]` and dropping to positional pairing; the band
names the row it used when it was not the first
- The hovered row is marked in BOTH grids — they are two `<table>`s, so `:hover`
in one cannot reach the row aligned with it in the other

**Open.**

- **3 · amounts read as amounts** — `numfmt.js` renders date, time and percent;
everything else falls through to the raw float, so a P&L shows `1234567.891`
and never `(1,234)`. A currency or rounding change is invisible today
Expand All @@ -79,7 +82,7 @@ flowchart LR
formulas sharing a prefix compare EQUAL; `maxMetaCells` (`sheet.js:137`) drops
formula and format comparison past 100k cells; `csvAdapter` sets `truncated`
and nothing renders it. A cap that hides is worse than a cap
- **Tolerance** takes a threshold of your own now (`useSpreadsheetDiff.js:7`,
- **Tolerance** takes a threshold of your own now (`useToleranceChoice.js`,
percentage or raw), but it is still global and still `abs` OR `pct`
(`alignRows.js:39-40`); materiality is "under €100 AND under 0.5%", per
column. Date serials are now exempt (`meta.dt` — a percentage of 45870 is
Expand Down Expand Up @@ -140,6 +143,9 @@ flowchart LR
u --> v["DiagramDiffViewer.vue<br>+ change rail"]
```

- A `.mmd` pair opens AS a picture — every load path takes the view from the
files, and a restored snapshot that recorded none does too rather than
falling back to text (`viewChrome.js` `restoredSemanticView`)
- Status is encoded twice — colour AND stroke pattern — and the three tokens are
held to a contrast floor and a pairwise ΔE floor on all 20 themes by
`check-theme-depth.mjs`
Expand Down
Binary file modified docs/screenshots/spreadsheet-diff.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading