Measured on 2026-10-26: /apps takes 240–260 ms (shelf;dur≈234) and /trevato takes 195–235 ms (apps;dur≈208). Both build their rows with shelfRows in src/web/studio/shelf.ts. productionFactsForRepos calls envsFor once per app, and the other reads are batched.
Done when:
[ ] Server-Timing for shelf (on /apps) and apps (on /:owner) is split into records, runs, production, pulls and rows, so the slow part is named.
[ ] The production status of every shown app is read in one batch, or from a cache keyed by the serving state. Nothing per app touches disk or a process during render.
[ ] A test with 40 apps asserts that shelfRows finishes under 40 ms and that its rows are byte-identical to before the change.
Files: src/web/studio/shelf.ts, src/apps/serving.ts (if the batch read lives there), test/shelf-speed.test.ts.
Measured on 2026-10-26:
/appstakes 240–260 ms (shelf;dur≈234) and/trevatotakes 195–235 ms (apps;dur≈208). Both build their rows withshelfRowsin src/web/studio/shelf.ts.productionFactsForReposcallsenvsForonce per app, and the other reads are batched.Done when:
shelf(on /apps) andapps(on /:owner) is split intorecords,runs,production,pullsandrows, so the slow part is named.shelfRowsfinishes under 40 ms and that its rows are byte-identical to before the change.Files: src/web/studio/shelf.ts, src/apps/serving.ts (if the batch read lives there), test/shelf-speed.test.ts.