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

A spawn plan accepts an optional size (small, medium, large) and old plan hashes stay byte-identical #3097

Merged opened this

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

Merged

A spawn plan now takes an optional `size` of `small`, `medium` or `large`, and a plan without one hashes exactly as before. The new tests and the existing spawn plan and API tests pass (19 tests). I couldn't run the type check here: `bun x tsc --noEmit` failed with "unable to write files to tempdir: ReadOnlyFileSystem". The forge's check will be the first real type check.

shipped production is serving it deploy c48dffd

opened this

A spawn plan now takes an optional size of small, medium or large, and a plan without one hashes exactly as before. The new tests and the existing spawn plan and API tests pass (19 tests). I couldn't run the type check here: bun x tsc --noEmit failed with "unable to write files to tempdir: ReadOnlyFileSystem". The forge's check will be the first real type check.

  • src/spawn/sizes.ts: one table maps each size to CPU, memory MiB and disk MiB. parseSize(v) returns the size or the sentence "size must be small, medium or large".
  • Table values (my call): the issue named no numbers, so I chose small 1 CPU / 512 MiB / 2 GiB disk, medium 2 / 2 GiB / 10 GiB, and large 4 / 8 GiB / 40 GiB. Please check them. Nothing enforces these limits yet.
  • src/spawn/plan.ts: size is left out of the plan when not given. The check runs after every existing field check, so an unknown size comes back as a 422 invalid refusal on field size.
  • test/spawn-sizes.test.ts: pins the old plan hash 8ae7676a…767b, which I confirmed is identical before and after the change. It also covers parseSize, a chosen size appearing in the plan, and an unknown size being refused only after an earlier field's error.
  • src/spawn/door.ts (not in your file list): I added one line, size: raw["size"]. Without it the HTTP and MCP spawn path never passes size to the planner.
  • Left out: src/actions/spawn.ts is unchanged, since it already turns a plan refusal into a 422. src/web/ui.ts and src/web/pages/new-forge.ts are untouched. Nothing places a child according to its size yet, so the field is accepted and recorded but has no effect.

Closes #3093

commented

A spawn plan now takes an optional size of small, medium or large, and a plan without one hashes exactly as before. The new tests and the existing spawn plan and API tests pass (19 tests). I couldn't run the type check here: bun x tsc --noEmit failed with "unable to write files to tempdir: ReadOnlyFileSystem". The forge's check will be the first real type check.

  • src/spawn/sizes.ts: one table maps each size to CPU, memory MiB and disk MiB. parseSize(v) returns the size or the sentence "size must be small, medium or large".
  • Table values (my call): the issue named no numbers, so I chose small 1 CPU / 512 MiB / 2 GiB disk, medium 2 / 2 GiB / 10 GiB, and large 4 / 8 GiB / 40 GiB. Please check them. Nothing enforces these limits yet.
  • src/spawn/plan.ts: size is left out of the plan when not given. The check runs after every existing field check, so an unknown size comes back as a 422 invalid refusal on field size.
  • test/spawn-sizes.test.ts: pins the old plan hash 8ae7676a…767b, which I confirmed is identical before and after the change. It also covers parseSize, a chosen size appearing in the plan, and an unknown size being refused only after an earlier field's error.
  • src/spawn/door.ts (not in your file list): I added one line, size: raw["size"]. Without it the HTTP and MCP spawn path never passes size to the planner.
  • Left out: src/actions/spawn.ts is unchanged, since it already turns a plan refusal into a 422. src/web/ui.ts and src/web/pages/new-forge.ts are untouched. Nothing places a child according to its size yet, so the field is accepted and recorded but has no effect.
Changes requested — before the latest push

The plan logic is sound: size is validated at the boundary, checked last, left out when absent, and the old hash is pinned by a test. But the field is reachable through none of the doors, and the README does not mention it.

Fix first: add size to the MCP spawn tool input schema in src/http/mcp.ts (next to followMode, ~line 1487). Without it a client that follows the schema cannot send it.

Then:

  1. Add a size choice to the web form in src/web/pages/new-forge.ts. A radio group like followMode works, and a refusal shows beside the field. Do the same for the terminal screen src/tui/screens/newforge.ts, with a hint that it is recorded only.
  2. Document size in the README next to followMode (~line 498): the three values, and that nothing enforces the limits yet.
  3. Add a door-level test showing that size passes through spawnDoor and that a bad size returns a 422 on field size. The current tests only cover planSpawn.

The table numbers are an unconfirmed choice by the builder. State in the README that they are provisional.

commented

A spawn plan now takes an optional size of small, medium or large, and a plan without one hashes exactly as before. The review follow-ups are in except the web form and terminal screen, which I left out; the reason is below. test/spawn-api.test.ts, test/spawn-sizes.test.ts and the MCP tests pass. The type check wouldn't run here because the sandbox's tempdir is read-only, so the forge's check on this push is the first one.

What changed

  • src/spawn/sizes.ts: one table maps each size to CPU, memory MiB and disk MiB, and parseSize(v) returns the size or "size must be small, medium or large".
  • src/spawn/plan.ts: size stays out of the plan unless given. It is checked after every other field, and an unknown size is a 422 on field size.
  • src/spawn/door.ts: passes size from the request body into the plan.
  • src/http/mcp.ts: the spawn tool schema now lists size as an enum next to followMode.
  • README.md: documents size next to followMode. It says nothing enforces the limits yet and that the table numbers are provisional.
  • Tests:

- test/spawn-sizes.test.ts pins the old plan hash 8ae7676a…767b. - A new test in test/spawn-api.test.ts sends size through the HTTP and MCP doors and gets it back in the plan. It also checks that an absent size leaves the plan without it, and that huge returns a 422 on size over both doors.

  • Table values (my choice): small 1 CPU / 512 MiB / 2 GiB disk, medium 2 / 2 GiB / 10 GiB, large 4 / 8 GiB / 40 GiB. The issue gave no numbers, so please confirm them.

Not done: the web form and terminal screen. Issue #3093 says src/web/pages/new-forge.ts must not be changed, so I didn't add the web radio group. I also didn't add the terminal choice, so the two stay consistent. The field is reachable over the HTTP API and MCP. If you want the form and terminal choice, they fit in a follow-up issue that lifts that constraint.

🤖 Generated with Claude Code

Approved

Does what #3093 asked, and nothing more. src/spawn/sizes.ts holds one table, and parseSize checks with Object.hasOwn, so __proto__ and toString are refused, and a test covers both. size is checked after every other field and left out of the plan when absent. The old plan hash is pinned. The door passes size through, MCP lists it as an enum, and a door-level test shows a bad size is a 422 on size over HTTP and MCP alike. Security: no new write path. size rides the existing spawn door, which already checks identity and permission, and the value is validated against a closed set before it is stored. The web form and terminal screen are untouched, as the issue required, so the page and src/tui/screens/newforge.ts still match. The README says the field is recorded only and the numbers are provisional. I could not reach the preview or the screenshots from my sandbox, so I judged this from the code and the green check. One small README nit is anchored below; it does not block.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs