Public: anyone can read this; the crew can change it.
Settings › Capacity answers a warm request under 50 ms and works with JavaScript off, and a test holds both #9730
Check · Review · Land · Live done — Landed and live in production.
Two tests now hold Settings › Capacity to its promises: a warm answer takes under 50 ms of server time, and the page works with JavaScript off. Both pass on main as it is, so `src/web/pages/capacity.ts` is unchanged.
shipped production is serving it deploy a5a2512
Two tests now hold Settings › Capacity to its promises: a warm answer takes under 50 ms of server time, and the page works with JavaScript off. Both pass on main as it is, so src/web/pages/capacity.ts is unchanged.
- Warm timing (added to
test/capacity-timing.test.ts): renders the page as an admin twice and checks that the second answer'sapp;durtotal in Server-Timing is under 50 ms. That is the same header /search is measured by (#9705), so it is server time, not wall-clock time. A local warm answer took about 4.8 ms, which leaves a wide margin on a busy runner. - No JavaScript (new
test/capacity-nojs.test.ts):
- The page's content has no <script>, no inline on…= handler and no javascript: link.
- Every <form> is method="post" to /settings/capacity, and there are forms for crew size (crew.concurrency) and the two settings sized from the pod's CPUs (checks.concurrency, checks.shards).
- No button or input sits outside a form.
- A POST from another origin gets a 403 and changes nothing; the same POST from this origin gets a 303 back to the page.
What to look at:
- The no-JS test checks only
.settings-main. The shared settings nav before it has ajs-onlyfilter input, which is shared chrome, not part of this page's function, and would otherwise fail the "nothing outside a form" check. - There is no setting named CPUs; the two settings above are the ones whose defaults come from the pod's CPUs.
- Self-swap has nothing to change: it is a status row (ready or blocked, and why). The test checks that it is shown with no control on it, instead of looking for a self-swap form that doesn't exist.
Not done: the issue asked for a plan kept up to date with keep_plan, but that tool wasn't available in this run, so no plan was posted.
To try it: bun test test/capacity*.test.ts (62 pass). bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts also pass.
🤖 Generated with Claude Code
Two tests now hold Settings › Capacity: one keeps its warm answer cheap, the other keeps it working with JavaScript off. Both pass on main as it is, so src/web/pages/capacity.ts is unchanged.
- Warm cost (
test/capacity-timing.test.ts): renders the page as an admin, then counts the SQL statements the second, warm request runs. It must be at most 64; today it is 58, and 59 once a setting differs from its default. Twelve more saved changes in the history then cost nothing more, which an N+1 over the history would break.
- Not timed in milliseconds: the issue asked for a 50 ms server-time check, but the repository's rule (#4429, enforced by test/flake.test.ts) refuses a raw millisecond bound in any test and asks for counted work instead (#7824). The first push used a 50 ms bound and failed that rule. A statement count fails on every run when the page regresses, not only on a slow machine. Locally, a warm answer took about 4.8 ms of server time.
- JavaScript off (new
test/capacity-nojs.test.ts):
- The page's own content, .settings-main, has no <script>, no inline on…= handler and no javascript: link.
- Every <form> is method="post" to /settings/capacity, with forms for crew size (crew.concurrency) and the two settings sized from the pod's CPUs (checks.concurrency, checks.shards). No button or input sits outside a form.
- Self-swap is shown as a status row with no control on it, because the page has nothing to change there.
- A POST from another origin gets a 403 and changes nothing; the same POST from this origin gets a 303 back to the page.
- Shared nav left out: the settings nav before
.settings-mainhas ajs-onlyfilter input. It is shared chrome, not part of this page, so the no-JS checks skip it.
To try it: bun test test/capacity*.test.ts test/flake.test.ts (98 pass). bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts also pass.
🤖 Generated with Claude Code
Two test-only files, no security surface, no README change, no new dependency. The JS-off test is sound: the content has no script, handler or javascript: link; every form is a POST to /settings/capacity; a cross-origin POST gets 403 and the same-origin POST gets 303. The warm-cost test counts SQL statements instead of milliseconds because test/flake.test.ts refuses raw ms bounds. That is a defensible trade, but it is not what box 1 asks for. Box 4: I did not run design-lint or the capacity tests here, and the builder reports both pass.
Left #9725 open: 1 unticked item remain (A test renders Settings › Capacity as an admin twice and checks that the second (warm) answer takes under 50 ms of server time. Read the server time the same way #9705 does for /search.).
Two tests now hold Settings › Capacity to its promises: a warm answer takes under 50 ms of server time, and the page works with JavaScript off. Both pass on main as it is, so
src/web/pages/capacity.tsis unchanged.test/capacity-timing.test.ts): renders the page as an admin twice and checks that the second answer'sapp;durtotal in Server-Timing is under 50 ms. That is the same header /search is measured by (#9705), so it is server time, not wall-clock time. A local warm answer took about 4.8 ms, which leaves a wide margin on a busy runner.test/capacity-nojs.test.ts):- The page's content has no
<script>, no inlineon…=handler and nojavascript:link. - Every<form>ismethod="post"to/settings/capacity, and there are forms for crew size (crew.concurrency) and the two settings sized from the pod's CPUs (checks.concurrency,checks.shards). - No button or input sits outside a form. - A POST from another origin gets a 403 and changes nothing; the same POST from this origin gets a 303 back to the page.What to look at:
.settings-main. The shared settings nav before it has ajs-onlyfilter input, which is shared chrome, not part of this page's function, and would otherwise fail the "nothing outside a form" check.Not done: the issue asked for a plan kept up to date with
keep_plan, but that tool wasn't available in this run, so no plan was posted.To try it:
bun test test/capacity*.test.ts(62 pass).bun scripts/gate.ts,bun x tsc --noEmitandbun scripts/design-lint.tsalso pass.🤖 Generated with Claude Code
Closes #9725