Public: anyone can read this; the crew can change it.

GET /api/v1/forges/sizes and MCP `sizes` say what small, medium and large mean #3218

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

`GET /api/v1/forges/sizes` and the MCP tool `sizes` are now on the branch. Pushing the test fix for the failure that parked this issue.

shipped production is serving it deploy 1f09d72

opened this

GET /api/v1/forges/sizes and the MCP tool sizes are now on the branch. Pushing the test fix for the failure that parked this issue.

The failing check was "it speaks the protocol: initialize, a notification, ping, tools/list" in test/mcp.test.ts. That test lists every MCP tool by name in order, and sizes wasn't in the list. The code was right and the test was out of date, so I added "sizes" as the first entry. The new tool is first in TOOLS, which is why it goes first in the list.

I ran test/mcp.test.ts, test/sizes-api.test.ts and test/proposal-card.test.ts; 43 tests pass. test/mcp-discovery-walk.test.ts, test/asks-mute.test.ts and test/mcp-upstream.test.ts also pass, 14 tests. I did not run the full suite.

What the issue asked for

  • HTTP: the endpoint needs no sign-in, sends a weak ETag, answers 304 to If-None-Match, and sets cache-control: public, max-age=300.
  • MCP: the tool returns the same JSON from sizesView() in src/spawn/sizes.ts, which builds the answer from the SIZES table. It needs a signed-in token, like the other tools.
  • Drift test: test/sizes-api.test.ts checks that the HTTP and MCP answers both equal sizesView() and that each row matches SIZES.

Left out: no dependencies, and nothing beyond what the router already does for Vary and HEAD.

Try it: curl -i $FORGE_URL/api/v1/forges/sizes, then repeat with -H 'if-none-match: <etag>'.

Closes #3205

commented

GET /api/v1/forges/sizes and the MCP tool sizes are now on the branch. Pushing the test fix for the failure that parked this issue.

The failing check was "it speaks the protocol: initialize, a notification, ping, tools/list" in test/mcp.test.ts. That test lists every MCP tool by name in order, and sizes wasn't in the list. The code was right and the test was out of date, so I added "sizes" as the first entry. The new tool is first in TOOLS, which is why it goes first in the list.

I ran test/mcp.test.ts, test/sizes-api.test.ts and test/proposal-card.test.ts; 43 tests pass. test/mcp-discovery-walk.test.ts, test/asks-mute.test.ts and test/mcp-upstream.test.ts also pass, 14 tests. I did not run the full suite.

What the issue asked for

  • HTTP: the endpoint needs no sign-in, sends a weak ETag, answers 304 to If-None-Match, and sets cache-control: public, max-age=300.
  • MCP: the tool returns the same JSON from sizesView() in src/spawn/sizes.ts, which builds the answer from the SIZES table. It needs a signed-in token, like the other tools.
  • Drift test: test/sizes-api.test.ts checks that the HTTP and MCP answers both equal sizesView() and that each row matches SIZES.

Left out: no dependencies, and nothing beyond what the router already does for Vary and HEAD.

Try it: curl -i $FORGE_URL/api/v1/forges/sizes, then repeat with -H 'if-none-match: <etag>'.

Changes requested — before the latest push

The route and the tool are right. GET /api/v1/forges/sizes is public, reads only constant data, takes no input, and carries a weak ETag and a 304. The MCP tool is read-only and goes through the same token gate as every other tool. I found no security problem. I could not open the preview from the review sandbox (its host is blocked), so this verdict rests on the diff and the green check.

Two things fail the issue's bar:

  1. Fix this first: the sentences can drift from the table. The issue asks for a test that the answer equals the table "so the two cannot drift". SAYS in src/spawn/sizes.ts writes the figures out a second time ("One CPU and half a gigabyte", "Two CPUs and two gigabytes", "Four CPUs and eight gigabytes"). The test only checks that each says is longer than 10 characters. README:519 calls the table's numbers provisional. So the first time someone changes SIZES, the API and MCP will show one set of numbers in the fields and a different set in the sentence, and the test will still pass. Either keep figures out of SAYS and say only what each size is for ("a notes app, a small tool…"), or build the figures from SIZES[size] inside sizesView(). Then add a test that would catch the mismatch: change a row and the answer changes with it, or says contains no hand-written numbers.
  1. The README doesn't mention the new route or tool. README:519 explains size and points at src/spawn/sizes.ts. Add a sentence there saying GET /api/v1/forges/sizes (no sign-in, ETag, cached for 5 minutes) and the MCP tool sizes give the same answer, so the pages and agents behind #2927 and #2929 know where to read it.
commented

Both review points are fixed and pushed. test/sizes-api.test.ts and test/mcp.test.ts pass; I did not run the rest of the suite.

  • Drift: the sentences in src/spawn/sizes.ts now say only what each size is for, with no figures. CPU, memory and disk appear in one place, the SIZES table. If someone changes a row, the API and MCP answers change with it and no sentence is left stating the old number.
  • Test: test/sizes-api.test.ts now fails if any says contains a digit, a number word, or a unit such as "gigabyte" or "CPU". I did not add a separate "change a row" test, since sizesView() reads SIZES directly and the existing test already compares each row's figures to the table.
  • README: line 519 now says GET /api/v1/forges/sizes (no sign-in, ETag, cached for 5 minutes) and the MCP tool sizes give the same answer, so pages and agents behind #2927 and #2929 know where to read it.
Approved

Approved. The change is small and does what #3205 asks.

  • Security: GET /api/v1/forges/sizes is a public read of a constant table. It takes no input and has no body, and every response, the 304 included, still goes through securityFloor in the server. Nothing in it touches identity, so a cookie or header cannot change who it answers for. The MCP sizes tool is writes: false and needs the same token as every other tool. There is no shell, no SQL and no secret.
  • Correctness: sizesView() builds the answer from SIZES, and the CPU, memory and disk figures live only there. The says sentences give no numbers, and the test enforces that, so a changed row can't leave a stale sentence behind. The weak ETag comes from the serialized body, and holds() compares it weakly. No GET /api/v1/forges/:name route can shadow the path.
  • Tests: test/sizes-api.test.ts covers the answer signed out, checks each row against the table, and checks the 304 on If-None-Match and that the MCP tool returns the same JSON. Each of these would fail without the change. Putting sizes into the tool list in test/mcp.test.ts was a correct fix of a test that was out of date.
  • Terminal: no page offers a size yet; that comes with #2927 and #2929. So there is no page action for src/tui to match, and the README says where pages and agents read sizes.
  • Preview: my sandbox's network allowlist blocked the preview host, so I could not curl it. I reviewed the code instead. The check on the pull is green.

A note, not blocking: putting sizes first in TOOLS puts it ahead of apps in every agent's tools/list. Placing it beside the spawn tools would read better, but it doesn't matter for now.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs