Part of #5799. Both earlier tries went red on "budgets > /map and / answer under their p95 and statement budgets". The reason was computed on every home load. This time it rides inside the cached KPI read from #7624.
Done when:
[ ] readKpis (src/flow/kpis.ts) puts idleReason on Kpis.builders, as builders.idle: { word, href } | null.
[ ] The builders tile (src/web/studio/kpi_row.ts) and its kpiLines line (src/flow/kpi_words.ts) add · <word>, linked to href, when it is not null. Nothing is added when every slot is busy.
[ ] One test seeds the ceiling-reached state and finds ceiling reached linked to /meter on / as an admin.
[ ] test/budgets.test.ts passes unchanged. Its p95 and statement budgets are not raised.
[ ] bun scripts/design-lint.ts is clean, and the pull carries a before/after screenshot of the tile.
Files: src/flow/kpis.ts, src/flow/kpi_words.ts, src/web/studio/kpi_row.ts, one test.
Risk: the KPI tile files are shared with the ceiling note. Keep the change to the builders tile.
Part of #5799. Both earlier tries went red on "budgets > /map and / answer under their p95 and statement budgets". The reason was computed on every home load. This time it rides inside the cached KPI read from #7624.
Done when:
readKpis(src/flow/kpis.ts) putsidleReasononKpis.builders, asbuilders.idle: { word, href } | null.src/web/studio/kpi_row.ts) and itskpiLinesline (src/flow/kpi_words.ts) add· <word>, linked to href, when it is not null. Nothing is added when every slot is busy.ceiling reachedlinked to /meter on/as an admin.test/budgets.test.tspasses unchanged. Its p95 and statement budgets are not raised.bun scripts/design-lint.tsis clean, and the pull carries a before/after screenshot of the tile.Files: src/flow/kpis.ts, src/flow/kpi_words.ts, src/web/studio/kpi_row.ts, one test. Risk: the KPI tile files are shared with the ceiling note. Keep the change to the builders tile.