Commit Graph
3 Commits
Author SHA1 Message Date
Thomas Camlong 37dead1690 docs(perf): verify the off-screen changes, and record two instruments that lied
The off-screen work was committed unmeasured; this closes that debt. Measured on two
containers restored from identical data:

  image requests   138, 135  ->  22, 22   (-84%)
  image bytes        12.27 MiB -> 0.03 MiB
  layout objects  11611, 7836  ->  3694, 3705  (-53%)

A 99.8% drop in image bytes is not believable, so it was checked instead of reported. Two
checks were bad instruments before one worked:

  - Counting decoded images via getBoundingClientRect() reported 80/80 loaded in BOTH arms.
    Reading geometry forces layout, which forces content-visibility subtrees to render, which
    triggers the very image loads being tested for. The instrument caused the result.
  - Screenshots came back byte-identical in both arms, because this environment shows an
    onboarding overlay and media-requests renders blank with unreachable integrations. Good
    evidence of no visual difference; useless as evidence that images render.
  - Counting img.complete && naturalWidth > 0 reads no geometry and gave the answer: 80/80
    decoded in both arms, 138 responses before against 25 after.

So nothing is visually broken. The 80 imgs are integration icons sharing URLs, deduplicated to
~25 unique fetches in both arms; the ~113 avoided requests are other widgets' off-screen
artwork, chiefly media-requests' full-size per-card backdrops, which is also where the 12 MiB
came from.

Stated limit: media-requests renders blank in this environment, so its visible-card behaviour
after the change is unverified. Media-releases is verified at 80/80 decoded.
2026-08-11 10:20:33 +02:00
Thomas Camlong d2e86895f4 docs(perf): rewrite the client doc with the measured overlay results
Replaces the earlier version with what was actually measured, and closes out all 54
findings from the widget audit rather than leaving categories open:

  overlay-per-row (12)      5 fixed; 7 are functional tooltips with real labels
  index-key (11)            all safe - static text splits, or stateless rows from
                            user-configured JSONPath data with no stable id
  nested-component (2)      both fixed
  inline-style-per-row (29) left alone; a fresh object per row only defeats memoisation
                            if the child is memoised, and these are not

Measured, deterministic per-widget counts:

  mediaReleases      340 comp / 8387 fib  ->  170 / 8057
  calendar           171 comp / 1195 fib  ->   75 /  907
  beszelSystemTable   36 comp / 1286 fib  ->   18 / 1230

Records two metrics that turned out unusable - Chrome's board-level JSEventListeners read
7905 to 17114 across six runs of identical code, and its Nodes counter includes detached
nodes - and one claim withdrawn: the media-releases tooltip fix measured zero, the win for
that widget came entirely from the shared OverflowBadge fix.
2026-08-11 10:11:08 +02:00
Thomas Camlong c73b139dbd docs(perf): split the findings into per-subject markdown files
PHASE2-FINDINGS.md had grown past 1,200 lines mixing server memory, client rendering,
methodology and a long list of rejected experiments, which made it unusable as a
reference. Split under docs/perf/:

  README.md              headline results and the change-by-change ratio table
  SERVER-MEMORY.md       what the container's RAM is made of, layer by layer
  CLIENT-PERFORMANCE.md  dashboard cost in Chrome: DOM, fibers, images, paint
  REJECTED.md            ideas implemented, measured and abandoned, with numbers
  METHODOLOGY.md         the tools, and the measurement traps that gave wrong answers

PHASE2-FINDINGS.md is now an index so existing links keep working.

METHODOLOGY.md is the part worth keeping: every wrong number in this investigation came
from an instrument rather than the application, and each trap is written down - snapshots
cannot explain peaks, V8 truncates snapshot strings to ~1 KiB, snapshot objects are not
live handles, measuring without a forced GC measures V8's growth, taking a CDP snapshot
added 134 MiB to the process being measured, per-component React attribution silently
returns nothing on a production build, a fixed port can measure a leftover container, and
a server-side change that moves a client-side metric means the workload changed.
2026-08-10 19:08:20 +02:00