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:
@@ -39,6 +39,13 @@ the app icon (experimental).**
|
||||
longer than its own interval no longer accumulates an unbounded backlog that
|
||||
then runs back-to-back indefinitely. The job details pane now shows the
|
||||
queued-run count (", N queued") whenever it is non-zero.
|
||||
- The History tab no longer grows without bound: it keeps the newest 1000
|
||||
records and drops the oldest, the way a job's own activity list is capped.
|
||||
Column widths are also folded in one record at a time instead of being
|
||||
re-measured across every row on every event, so recording a run no longer
|
||||
gets slower the longer the app has been running. Measured on 5000 accumulated
|
||||
records, one History redraw went from **15.8 ms to 0.9 ms**; at the new cap
|
||||
the width rescan alone accounted for 1.5 ms of every redraw.
|
||||
|
||||
**Jobs:**
|
||||
|
||||
|
||||
@@ -65,6 +65,14 @@ change to their shape has to stay compatible on its own.
|
||||
- **History tab is session-only.** `JobRuntime.Logs` exists only in memory for the
|
||||
current process. Log files on disk feed aggregate statistics via `SeedStats`
|
||||
only. See [ARCHITECTURE.md](ARCHITECTURE.md).
|
||||
- **History is capped and its columns only widen.** The tab keeps the newest
|
||||
`maxHistoryRows` records and drops the oldest, the way `maxJobLogs` caps a
|
||||
job's own activity list — an app left in the tray records thousands of runs a
|
||||
day, each carrying the run's full captured output. Column widths are folded in
|
||||
one record at a time instead of rescanned from every row, so a column never
|
||||
narrows when a record ages out: the rows on screen were laid out against the
|
||||
wider value. A theme change is the one case that rescans, because every stored
|
||||
width was measured at the old text size.
|
||||
- Several tests share a coverage profile with another test on purpose, and a few
|
||||
functions sit at 0% on purpose. Both lists live in
|
||||
[TESTS.md](TESTS.md) — check them before reporting a test as redundant or a
|
||||
|
||||
@@ -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. |
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user