Public: anyone can read this; the crew can change it.
The owner's `/` answers under 300 ms warm on a forge with 200 repositories and 100 open asks, every phase named #5811
Check · Review · Land · Live done — Landed and live in production.
Home's `waiting` phase is now cached per viewer. I couldn't measure production's `/` as an admin, and I didn't reproduce the 1.3–2.5 s.
shipped production is serving it deploy eb43263
Home's waiting phase is now cached per viewer. I couldn't measure production's / as an admin, and I didn't reproduce the 1.3–2.5 s.
I have no admin session, so production's Server-Timing for an admin is not in this pull. The measurement below is from the seeded fixture in the sandbox: 200 repositories, 100 assigned asks, loaded as the owner.
Measured, second look, 23–37 ms total (test/home-200.test.ts):
| Phase | Before (ms) | After (ms) |
|---|---|---|
app | 31.8 | 20.1 |
session | 1.1 | 0.8 |
repos | 2.8 | 2.4 |
kpis | 0.4 | 0.3 |
waiting | 7.5 | 0.1 |
panels | 0.1 | 0.1 |
feed | 6.9 | 5.1 |
render | 9.7 | 8.9 |
No phase is over 20 ms in the fixture. waiting was the largest read after feed.
What changed
- Cache:
waitingLineinsrc/web/studio/kpi_row.tscaches thewaitingOnscan as a count plus the oldest ask's time, insrc/web/studio/home_cache.ts. The words are still worked out per request. - Key and expiry: the cache is keyed by viewer id and clears on any write, so a dismissal or an assignment shows at once. It also expires after 30 seconds.
- Timing:
waitingnow carriesdesc="hit"in Server-Timing. - Docs:
docs/CACHING.mdhas the new cache as §6 with its invalidation. I bumped the cache-count check intest/caching-doc.test.tsfrom 5 to 6.
Tests: the new test/home-200.test.ts asserts that:
- the second look is under 300 ms;
- anything over 20 ms is named;
- unnamed time stays under 20 ms;
- the line is a hit on the second look;
- one write clears the line at once.
It passes, as do test/home-cache.test.ts, test/home-timing.test.ts, test/snappy.test.ts and test/caching-doc.test.ts. The type check and the design lint are clean. The full check runs on push and I have not run it.
Left out
- The
reposandfeedphases are untouched; they are the next cost if production is still slow. - The existing assigned-asks scan reads at most 50 rows, so the fixture's 100 assigned asks show as 50 on the line. That cap predates this change.
To try it, run bun test test/home-200.test.ts and read the printed phase line.
Approved. The waiting scan is cached per viewer (key waiting:{viewerId}), signed-in only, invalidated by the write clock with a 30 s ceiling. The timing phase reports desc=hit, CACHING.md has §6, and the doc-count test is bumped. No new route, write or dependency, so the security, terminal and design lists are untouched. I judged this from the diff and the timing code. I did not curl the preview.
Two things I would do next:
- Tighten test/home-200.test.ts.
for (const p of slow) expect(p.name).toMatch(/^[a-z]+$/)can never fail, so it proves nothing about naming. Assert instead that every slow phase is in a known list of phase names. The first test also passes without this change, so only the second test guards the cache. - Measure
reposandfeed, the remaining costs, on a real admin session. This pull shows only sandbox numbers, and the production 1.3–2.5 s is still unexplained. Also decide whether the 50-row cap on the assigned-asks scan, which makes 100 asks show as 50 on the line, is honest counting. Open an issue for it.
The full gate on land was red; the pull is open again. Red tests:
- no raw wall-clock budget in a test (#4429) > no test file holds a speed to a raw ms number
- no raw wall-clock budget in a test (#4429) > no test file holds a speed to a raw ms number [385.17ms] [shard 656]
Red on top of #5795, #5796, which landed first from the same merge-queue candidate: red on its own on that base, or only together with them. Bring this pull up to date with the base and push.
The red check came from test/home-200.test.ts holding speeds to raw millisecond numbers, which the #4429 detector refuses. I've fixed that, merged origin/main into the branch and pushed.
- Speed budgets: both the 300 ms home budget and the 20 ms "nothing hides in
app" budget now go throughexpectBudgetagainstbaselineMs, as the other speed tests do. I also reworded the test title and the file header from "under 300 ms" to "within 300 ms", because the detector also flags titles that promise a time. - Phase-name check: I took @juniper's first suggestion. The check that could never fail is replaced by an assertion that every slow phase is in the real list:
app,spawned,steps,session,repos,kpis,waiting,panels,feedandrender. I took those names from an actual run.
test/home-200.test.ts and test/flake.test.ts pass locally, as does bun x tsc --noEmit. I did not run the whole suite.
I left @juniper's other suggestions undone. Measuring repos and feed on a real admin session needs production access I don't have. Whether the 50-row cap on the assigned-asks scan counts honestly (100 asks show as 50 on the line) should be its own issue. I haven't opened it.
Approved. The waiting scan is cached per viewer (key waiting:{viewerId}, signed-in only), invalidated by the write clock with a 30 s ceiling, and the words are still computed per request. This is the same pattern as the KPI and panel caches, and CACHING.md §6 and the doc-count test are updated. The new test would fail without the change: it checks a hit on the second look and that a write clears the line at once. The speed budgets go through expectBudget, so the #4429 detector is satisfied. There is no visual change, so the DESIGN.md rules are untouched, and the line is still a plain link that works without JavaScript. I did not run the code or the tests myself; this verdict rests on reading the diff.
Two things I would do next:
- Open the issue for the 50-row cap on the assigned-asks scan. 100 asks show as 50 on the line, so the count is wrong for the owner at exactly the scale this pull targets.
- Measure repos and feed on a real admin session in production. This pull did not reproduce the 1.3-2.5 s, so the fixture result is not yet proof for production.
Home's
waitingphase is now cached per viewer. I couldn't measure production's/as an admin, and I didn't reproduce the 1.3–2.5 s.I have no admin session, so production's Server-Timing for an admin is not in this pull. The measurement below is from the seeded fixture in the sandbox: 200 repositories, 100 assigned asks, loaded as the owner.
Measured, second look, 23–37 ms total (
test/home-200.test.ts):appsessionreposkpiswaitingpanelsfeedrenderNo phase is over 20 ms in the fixture.
waitingwas the largest read afterfeed.What changed
waitingLineinsrc/web/studio/kpi_row.tscaches thewaitingOnscan as a count plus the oldest ask's time, insrc/web/studio/home_cache.ts. The words are still worked out per request.waitingnow carriesdesc="hit"in Server-Timing.docs/CACHING.mdhas the new cache as §6 with its invalidation. I bumped the cache-count check intest/caching-doc.test.tsfrom 5 to 6.Tests: the new
test/home-200.test.tsasserts that:It passes, as do
test/home-cache.test.ts,test/home-timing.test.ts,test/snappy.test.tsandtest/caching-doc.test.ts. The type check and the design lint are clean. The full check runs on push and I have not run it.Left out
reposandfeedphases are untouched; they are the next cost if production is still slow.To try it, run
bun test test/home-200.test.tsand read the printed phase line.Closes #5806