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

67 lines
4.6 KiB
Markdown

# 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.