Commit Graph
4 Commits
Author SHA1 Message Date
Thomas Camlong 2ebfe659b2 revert(perf): drop the dockerode and docker-modem pnpm patches
Both patches came out of this work and both are removed at the maintainer's
request. The finding was real - ssh2's WASM heap costs +14.0 MiB RSS on require,
and @grpc/grpc-js another 14.6 MiB across 61 files, neither of which a
socket-based Docker install ever uses - but patching a dependency means every
future dockerode or docker-modem bump fails until someone regenerates the patch,
and that recurring cost is not worth roughly 25 MiB.

The finding stays on record in SERVER-MEMORY.md because the fix belongs upstream:
both packages require a module at file scope while using it in exactly one
already-guarded branch, so a PR to each would fix it for every consumer with no
patch to maintain here.

The two remaining patches, @types/node-unifi and trpc-to-openapi, predate this
work and are untouched. allowUnusedPatches was already set on dev and is left
alone. Lockfile regenerated: patchedDependencies now lists only those two.

Also sharpens the Cache Components entry. The SqliteError was simply an unmigrated
build database, which is fixable - but feeding the build a database would be the
wrong fix, because serverSetting is per-installation data on the user's volume and
a shell prerendered against the build machine's database would bake one install's
settings into every other install's first paint. The error was Next.js correctly
reporting a request-time read sitting in the shell path.
2026-08-14 11:16:55 +02:00
Thomas Camlong 083a926719 docs(perf): give every one of the 50 widgets a verdict
Completes the sweep: 11 fixed, 8 triaged, 10 read and found clean, 21 verified
bounded. Each verdict records the evidence behind it, because "I read this" and
"its list cannot get long" are different strengths of claim and should not look
alike in a table.

The four widgets the ranking flagged as most likely to hide something all came
back clean, and three were already bounded before I looked - traefik slices to
what its width shows, umami to its own limit option, beszel-alerts to
options.maxHistoryItems. system-resources looked worst of all with 14 unmemoised
maps, until it turned out none of the six chart components it feeds is memoised
either, so a stable array identity would preserve nothing.
2026-08-11 16:33:33 +02:00
Thomas Camlong 8f94ea47e3 docs(perf): add a handoff with the unverified item, the remaining lever, and the clean-PR set
Records where this stopped so it can be picked up cleanly:

  1. c526dd2b7 (media-requests content-visibility) is typechecked but NOT measured - the
     only performance claim on this branch not A/B'd before commit. Verify with
     measure-board-paint.mts, three repeats; revert if image requests do not fall.
  2. The one lever with headroom left is the tRPC router's eager integration imports - a
     16.10 MiB subtree of 460 files reached by every API route, which pays twice because
     both the ~41 MiB of retained source and the ~38 MiB of V8 compiler zones scale with
     how much JavaScript the server compiles. Every allocator and V8-flag avenue is closed.
  3. Deferred with prizes attached: ASCII-escaping bundles (9.45 MiB, needs its own PR),
     lazy mysql2/pg (21.4 MiB, structurally blocked), beszelSystemStats chart SVG.
  4. The proposed set for the clean PR, six changes producing -26% peak anon and -52% at
     idle for +18% CPU - with the gRPC patch flagged as hygiene rather than a measured win,
     and the +30% board-load figure flagged as not established.
2026-08-10 19:12:28 +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