perf: cap the History list and fold column widths incrementally

History was appended to on every recorded run and never trimmed, and every
event re-sorted the whole slice and re-measured the Job, Detail and Log
columns across every row. The per-run cost therefore grew with the number of
rows, in exactly the mode the app is designed for: left in the tray for days.

The session History now keeps the newest maxHistoryRows (1000) records, the
way maxJobLogs caps a job's own activity list, and drops the oldest from the
front, zeroing the tail so a dropped record's full captured output is not
kept alive by the backing array. Column widths move into a historyLog value
that folds each new record into the current maxima instead of rescanning.
Widths only grow within a theme, so a column never narrows when a record ages
out; a theme change is the one case that still rescans, because every stored
width was measured at the old text size.

Measured with a throwaway benchmark over 5000 accumulated records: one
refresh went from 15.8 ms to 0.9 ms. At the new cap the full width rescan
alone costs 1.5 ms, so both halves of the fix carry weight.

Plan item 6 of docs/PROJECT_REVIEW_PLAN.md (finding 3.1).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-06 17:15:46 +03:00
parent 263717874c
commit 98c820e3bd
6 changed files with 231 additions and 30 deletions
+4
View File
@@ -494,6 +494,10 @@ column-width behaviour of the assembled table.
| `TestHistoryCellTemplateIsPlainText` | Verifies the cell template already carries the zero `TextStyle`, since the per-cell assignment that used to reset it is gone. |
| `TestTextColumnWidthClamps` | Covers the three shapes of `textColumnWidth`: below the minimum, in range, and capped at the maximum. |
| `TestHistoryColumnsFitTheirContent` | Verifies every column is at least as wide as its widest known or present value, at the default text size and at a scaled theme. |
| `TestHistoryLogCapsRecords` | Regression guard for the unbounded History list: the log keeps the newest `maxHistoryRows` records, drops the oldest from the front, and trims a list handed in already over the cap. |
| `TestHistoryLogWidthsMatchAFullScan` | Verifies the incremental column widths equal a full rescan while every measured record is still present — the cheaper path must not clip what the old one showed. |
| `TestHistoryLogWidthsDoNotShrinkWhenRecordsAgeOut` | Verifies a column keeps its width after the record that set it is dropped by the cap, since the rows on screen were laid out against it. |
| `TestHistoryLogRescansOnThemeChange` | Verifies a theme change falls back to a full rescan, the one case the incremental fold cannot handle because every stored width was measured at the old text size. |
---