Files
minabot/docs/performance.md
2026-09-08 16:35:45 +02:00

4.6 KiB

Performance improvements

The September 2026 audit produced twelve changes, implemented in separate backend, frontend, and worker worktrees and verified together before release.

Changes

Area Improvement
Database reads Fetch the latest day snapshots, tasks, and effective revisions for the requested dates. Carry-enabled counts look back to the necessary prior reset or log.
Synchronization Skip already-materialized habits and unchanged marker writes; expire tasks using an index of open occurrences.
Catch-up Materialize bounded batches with bulk task inserts, yield between batches, and serialize same-account operations until their data is ready.
Calendar payloads compact=true omits task lists and repeated requirements. Dated editing endpoints retain full detail.
Calendar caching Cache account-scoped ranges using persisted per-habit change versions; fetch visible months first and extend on demand. Historical edits and local midnight invalidate the appropriate data.
React rendering Preserve unchanged habit objects and callbacks; memoize calendar data and geometry.
Initial JavaScript Split the showcase and optional forms, editors, settings, and sharing interfaces into lazy-loaded modules.
Browser fonts Serve complete WOFF2 fonts separately with conditional caching; retain the original TTF files for native image rendering.
Image rendering Share a bounded queue across server renderers, deduplicate identical in-flight requests within their owner, and release completed canvas surfaces.
Backups Run SQLite snapshots, verification, durability, and replication in a subprocess, preserving startup health and overlap prevention.
Reminders Check delivery-slot eligibility before evaluating habits; revalidate preferences and progress immediately before sending.
Avatars Bound cached images/downloads, reuse concurrent downloads, and briefly cache failures.

Local measurements

These are synthetic measurements on a development Mac, not production capacity estimates. Absolute timings vary with hardware and load.

Scenario Before After
Dashboard service work, ten task habits with five years of history 169.81 ms 2.76 ms
Unchanged synchronization, ten habits 34 queries / 10 row changes 4 queries / 0 row changes
Combined year calendar, ten habits with ten tasks each 10,693,864 JSON bytes 1,267,884 compact JSON bytes
Catching up a year, ten habits with ten tasks each ~1.17 s without yielding ~1.11 s total; 112 timer ticks, largest gap 11.75 ms
Initial calendars, ten new manual habits 1,947,301 JSON characters 476,954 JSON characters
Unchanged focus refresh, same ten habits 11 requests / 10 calendar requests 1 request / 0 calendar requests
Switching identical habit filters 920 Date.parse calls 0
Initial JavaScript, including static dependencies 716,094 bytes 286,641 bytes
Initial JavaScript, locally gzip-compressed 199,622 bytes 99,192 bytes
Main stylesheet 273,268 bytes 85,733 bytes
Main stylesheet, locally gzip-compressed 106,410 bytes 13,636 bytes
Fifty already-delivered reminder checks 210 ms / 1,000 day evaluations 14 ms / 0 day evaluations
Three renders with the same avatar URL 3 downloads 1 download
Sixteen identical concurrent image renders: timer delay 68 ms 1.1 ms
~98 MiB replicated backup: main-thread timer delay 421 ms 1.9 ms

Calendar byte/character counts describe serialized JSON, not compressed wire traffic. JavaScript/CSS gzip sizes are local compression estimates. Image RSS measurements concern transient native allocations, not memory leaks.

Operation and verification

The application remains one Bun process with SQLite/WAL and one set of Discord delivery workers. The backup subprocess owns a separate connection. Render admission defaults to two active jobs, sixteen total pending jobs, and two jobs per account; an overloaded renderer returns a retryable busy response.

Migrations add a persisted calendar revision and a partial index for open task occurrences. Existing historical requirements, carryover rules, privacy boundaries, rate-limit handling, and confirmed-deleted-message replacement remain covered by regression tests.

Run bun run typecheck, bun test, and bun run test:smoke. The smoke test uses a disposable production database. Browser verification should cover lazy route and dialog loading, count/task saves, historical corrections, calendar ranges, both themes, narrow layouts, and separately served fonts. Timing tests should measure event-loop availability as well as total job duration.