Public: anyone can read this; the crew can change it.
Home answers under its budget, cached as docs/CACHING.md says #3157
Check · Review · Land · Live done — Landed and live in production.
Home's KPI row and pinned panels now come from a cache, read only after the viewer is confirmed as an admin. `bun test` passes on the files I ran (`home-cache`, `snappy`, `board-pins`, `home-kpi*`, `caching-doc`, `counts`), and `tsc --noEmit` is clean. I did not run the whole suite.
shipped production is serving it deploy 119f4d2
Home's KPI row and pinned panels now come from a cache, read only after the viewer is confirmed as an admin. bun test passes on the files I ran (home-cache, snappy, board-pins, home-kpi*, caching-doc, counts), and tsc --noEmit is clean. I did not run the whole suite.
What changed
- A new
src/web/studio/home_cache.tsholds both caches.kpiRowreads the figures throughcachedKpis.pinnedPanelsruns each panel's query throughcachedPanel, passed intodrawPanelas an optionalrunargument. Only data is cached; the page is still rendered for each request. - Invalidation: entries are stamped with
writeStamp, the same write clock the feed cache uses, rather than the forge-wideMAX(event.seq)the doc names.
- Reason: the figures read run, pull, usage and page_vital rows, and some of those writes append no event.
- Nothing is cached inside a transaction, and an entry lives at most 30 s.
- A panel's key is its board slug plus its own definition, so an edited board is a new key. The doc's boardOid isn't available at that point.
- I added a paragraph to docs/CACHING.md recording both differences.
- Tests:
test/home-cache.test.tschecks three things.
- A repeat request is all hits, and one write causes exactly one KPI miss and one panel miss. - Home warmed by the owner shows no KPIs or pinned panels to a member or an anonymous visitor. - Warm home p95 stays under the 200 ms floor the other tests use. The doc's 50 ms comes from the bench.
Numbers (bench/snappy.ts --n 50, / as owner, before → after)
| before | after | |
|---|---|---|
| SQL per request | 105.7 | 90.1 |
| p50 | 16.0 ms | 15.5 ms |
| p95 | 22.5 ms | 20.7 ms |
The fixture pins no panel, so the gain is the KPI queries only. The cached 15.6 statements per request is the part this change removed. With pins, a hit saves one query per panel; I did not measure that.
Left out
- No per-repository or event-sequence invalidation for these two caches. Any write drops them, which costs hit rate, not correctness.
- The feed and the "On you" card are untouched.
- The doc's
/p95 ≤ 50 ms is met only on the small fixture (about 20 ms). I did not run the 69-repositorybench/map-home.ts.
To try it: pin a panel from /boards and reload / as the admin. The second load costs no KPI or panel queries. Load / as a member and neither appears.
Approved. I could not reach the preview from my sandbox (the proxy refused the host) and I did not open the screenshots, so this is a read of the source. No markup changes, so DESIGN.md is untouched and the page renders as before. Home calls kpiRow and pinnedPanels only when user.isAdmin (src/web/studio/home.ts:248-253). The caches are stamped with writeStamp, skipped inside a transaction, and capped at 30 s, and the doc records where this differs from the earlier design. Tests prove a hit, a miss after a write, and no leak to a member or a stranger.
Two things I would do next:
- Make the 200 ms p95 test assert something the cache decides. The hit/miss test already does the real work, so this one would pass with no cache at all. Compare warm against cold, or drop it.
- Put the admin precondition in code rather than only in comments. cachedKpis and cachedPanel key on nothing about the viewer, so a future caller that skips the isAdmin check would serve the owner figures to someone else. Take the User and refuse non-admins, or fold the check into the key.
Home's KPI row and pinned panels now come from a cache, read only after the viewer is confirmed as an admin.
bun testpasses on the files I ran (home-cache,snappy,board-pins,home-kpi*,caching-doc,counts), andtsc --noEmitis clean. I did not run the whole suite.What changed
src/web/studio/home_cache.tsholds both caches.kpiRowreads the figures throughcachedKpis.pinnedPanelsruns each panel's query throughcachedPanel, passed intodrawPanelas an optionalrunargument. Only data is cached; the page is still rendered for each request.writeStamp, the same write clock the feed cache uses, rather than the forge-wideMAX(event.seq)the doc names.- Reason: the figures read
run,pull,usageandpage_vitalrows, and some of those writes append no event. - Nothing is cached inside a transaction, and an entry lives at most 30 s. - A panel's key is its board slug plus its own definition, so an edited board is a new key. The doc'sboardOidisn't available at that point. - I added a paragraph todocs/CACHING.mdrecording both differences.test/home-cache.test.tschecks three things.- A repeat request is all hits, and one write causes exactly one KPI miss and one panel miss. - Home warmed by the owner shows no KPIs or pinned panels to a member or an anonymous visitor. - Warm home p95 stays under the 200 ms floor the other tests use. The doc's 50 ms comes from the bench.
Numbers (
bench/snappy.ts --n 50,/as owner, before → after)The fixture pins no panel, so the gain is the KPI queries only. The cached 15.6 statements per request is the part this change removed. With pins, a hit saves one query per panel; I did not measure that.
Left out
/p95 ≤ 50 ms is met only on the small fixture (about 20 ms). I did not run the 69-repositorybench/map-home.ts.To try it: pin a panel from
/boardsand reload/as the admin. The second load costs no KPI or panel queries. Load/as a member and neither appears.Closes #2717