Commit Graph

7 Commits

Author SHA1 Message Date
Edouard Vanbelle ef7143da43 fix(front-test): change the i18n load test
return from Claude:

    The bench measures nothing reliable at this scale. afterMs=13.21 vs beforeMs=12.56 is ~650ns
    per lookup for both paths; at that granularity a single GC pause or scheduler hiccup easily
    swamps the actual gain, and the "after" path happens to run first (cold caches), so it gets
    penalised on unlucky runs. Your local station happens to warm up before the noise lands; CI
    shared-runners often don't.

    Fix: run each path a few times and take the minimum (min is noise-proof — noise only slows
    things down, never speeds them up):
2026-07-19 17:39:35 +02:00
Claude c930f865b0 perf: round 14 — faces narrow projection, auth per-request allocs, CalDAV emit buffers, frontend set churn
Benchmark-gated (benches/ROUND14.md); every change ships a BEFORE/AFTER
benchmark with an equivalence gate and is rolled back on regression (the
rule is encoded as a GATE FAIL exit / threshold expect).

Backend
- Q1 faces_for_file → narrow face_boxes_for_file(id, person_id, bbox) with the
  caller filter pushed into SQL: drops the 2 KiB embedding BYTEA + 6 unused
  columns per face. 15-face lightbox open 0.312→0.219 ms, 32 KB→840 B/req.
- A1 cookie auth uses the borrow-only extract_cookie_str (already backs CSRF)
  instead of extract_cookie_value's owned String: -1 alloc/cookie request.
- A2 compute_relevance ASCII case-fold fast path vs name.to_lowercase() per
  result row (Unicode fallback preserved): 1.40x, 12→3 allocs/page.
- A3 sub pre-parsed to Uuid at decode time (TokenClaims.sub_id) vs re-parsing
  the 36-char claim on every request incl. cache hits: 22.7→0.7 ns.
- A4 auth + NextCloud middlewares borrow request.headers() instead of taking
  axum's HeaderMap extractor (a full map clone): 2→0 allocs/authed request.
- A5 CalDAV getlastmodified via the stack rfc2822_utc (byte-identical to
  chrono) vs a per-event to_rfc2822() heap String: 5→0 allocs.
- A6 CalDAV per-event href + quoted etag written into reused page buffers vs a
  fresh format! pair per event: 3.48x, 240→6 allocs/40-event page.

Frontend
- F1 t() shares one frozen EMPTY_PARAMS for the no-interpolation call forms vs
  a throwaway {} per call: -1 alloc/call.
- F2 favorites favoriteIds is a persistent SvelteSet with per-page add (clear
  on reset) vs a brand-new set over the whole accumulated list each page:
  22.3x over a 40-page drain (O(N^2)→O(N)).

Verified: cargo check --all-targets, cargo clippy -D warnings, both bench
packs (GATE PASS), frontend npm run check + vitest (4/4). ROUND14.md also
records the investigated-but-deferred backlog (music N+1, contact vcard
over-fetch, CachedBlobBackend syscalls, ResourceList.sections builder, etc.).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PymgCdK78NzUF3oRAQCJfN
2026-07-19 10:22:12 +00:00
Claude 61c9470981 perf(frontend): round 6 — coalesced progressive listing, in-place SvelteSet, batch fan-out, t() value cache
Four SPA hot-path fixes, each shipping with a vitest benchmark gate
(verbatim BEFORE replica + equivalence + perf assertion) so CI
re-verifies the win on every run:

- fetchFolderListing invoked onPage after EVERY 200-row page with the
  whole accumulated listing, and the files view re-sorts everything per
  emission — O(N²/page) main-thread work on large folders. Page one and
  the final page always emit; intermediates coalesce to one per 150 ms.
  25×200 load: 30.9 → 4.0 ms (7.8x), 65 000 → 5 200 sorted elements.

- selected/favoriteIds/sharedIds (files) and favoriteIds (recent) were
  $state<Set>s copied whole on every toggle. Now one SvelteSet each,
  mutated in place (the useSelection pattern): 1 000 toggles @ N=5 000
  771.9 → 1.9 ms (399x); one-toggle fan-out across 40 mounted rows
  40 → 3 re-runs when refining a select-all.

- batchDelete/moveInto awaited one request per item serially and
  probed listing.folders.find per id (O(N·M)). Now an id index built
  once + mapLimit(6) fan-out, failure semantics preserved: 100-item
  delete @ 5 ms RTT 525 → 89 ms (5.9x), 38 825 → 500 probes.

- t() re-split its dotted key and walked the nested dict on every call,
  and interpolate regex-scanned strings without placeholders. Resolved
  values now memoize per (dict, key) in a WeakMap + a {{ guard:
  20k mixed calls 22.7 → 8.6 ms (2.63x).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017aJu9ghvuT8WqC31ZEGTBA
2026-07-18 00:54:38 +00:00
Edouard Vanbelle 3108fed228 fix(front): clean localStorage on user change
- fix issue with selected drive and user logout/login via another user
    (was raising a "404 not found")
    - normalize all localStorage to "oxi-" prefix
    - add a specific frontend/AGENTS.md for frontend part (stop increasing the global AGENTS.md)
2026-07-07 21:37:00 +02:00
Claude a8709b447a perf(i18n): load the English fallback lazily, off the startup critical path
`initI18n` runs in the client `init()` hook and blocks the first render. For
every non-English user it awaited TWO locale dictionaries back to back — the
active locale AND `en` (the fallback) — so first paint waited on two sequential
round-trips + JSON parses.

Now it awaits only the active locale, then warms `en` in the background
(non-blocking). `t()` only consults `dicts.en` for keys the active locale is
missing, and most call sites already pass an inline English fallback, so the
deferred `en` doesn't change what users see; when it arrives `dicts.en` is
reactive, so any key that fell through re-renders. English users are unchanged
(no second fetch was ever needed).

Net: non-English startup drops from two blocking locale fetches to one, halving
the i18n payload on the critical path (the server already serves these JSONs
brotli/gzip-compressed via the global CompressionLayer, so the wire cost was
already small — this removes the extra round-trip + parse from first paint).

Validated: new unit test (initI18n resolves while the en fetch is still pending,
en is kicked off in the background, and a key missing from the active locale
falls back once en lands) → 47 frontend tests green; npm run check; prod build.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M8Vb9QHmLZnEMzHz7MrFy6
2026-06-19 16:27:58 +00:00
Bradley Nelson 89e14f8f9e visual continunity 2026-06-17 22:07:18 -06:00
Bradley Nelson daa3010458 init new frontend 2026-06-17 17:06:30 -06:00