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

/capacity and MCP `capacity` say whether this forge can swap itself, and why not: tcp_migrate_req, SSH held, or FORGE_SELF_SWAP off #8403

Merged opened this

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

Merged

/capacity and the MCP `capacity` tool now say whether this forge can swap itself, and if not, why. So you can check whether a hosted child has `tcp_migrate_req=1` (#8378) by opening its /capacity. You no longer need cluster access or a refused landing to find out.

shipped production is serving it deploy 40e21c3

opened this

/capacity and the MCP capacity tool now say whether this forge can swap itself, and if not, why. So you can check whether a hosted child has tcp_migrate_req=1 (#8378) by opening its /capacity. You no longer need cluster access or a refused landing to find out.

  • Swap module (src/release/swap.ts): adds two plain reads. migrateReq() returns "1", "0" or "unreadable"; handover.migrate still stands in for the file in tests. selfSwapState(enabled) returns { enabled, migrateReq, blocked }. blocked holds swapBlocked()'s sentence when the SSH terminal is held or the kernel setting is off. Otherwise it is a "FORGE_SELF_SWAP is off" sentence when the flag is unset, and null when the forge is ready. The kernel and SSH reasons come first, so a child with the flag off still shows its kernel problem. migratesQueuedConnections() now reads through migrateReq(), so swaps behave as before.
  • listCapacity (src/actions/capacity.ts): carries selfSwap, which is admin-only like the rest of the result.
  • /capacity page: a new Self-swap card with one row (id="self-swap"). It shows ready or blocked, the reason, whether FORGE_SELF_SWAP is set, and the value read from net.ipv4.tcp_migrate_req.
  • MCP capacity: its doc string documents selfSwap: { enabled, migrateReq, blocked }. No new tool, and test/mcp-size.test.ts passes without raising any ceiling.
  • docs/features/ship-itself.md: says to check a child by opening its /capacity, and what the row and the tool field show.
  • New test/capacity-selfswap.test.ts: covers ready, kernel off and SSH held on both the page and the tool, plus the FORGE_SELF_SWAP-off reason. That last case is tested on selfSwapState only, not on the page or the tool.

Left out: the terminal's Capacity screen does not show self-swap yet.

To try it: sign in as an admin and open /settings/capacity, or call MCP capacity with no arguments and read selfSwap.

Checks: bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts are clean. scripts/fast.ts picked 1,237 files (about 107 minutes), so I ran the covering tests myself instead. All passed, with one test skipped: capacity-selfswap, capacity, capacity-timing, tui-capacity, mcp-size, mcp, and the four release-gate and release-swap test files.

🤖 Generated with Claude Code

Closes #8383

commented

/capacity and the MCP capacity tool now say whether this forge can swap itself, and if not, why. So you can check whether a hosted child has tcp_migrate_req=1 (#8378) by opening its /capacity. You no longer need cluster access or a refused landing to find out.

  • Swap module (src/release/swap.ts): adds two plain reads. migrateReq() returns "1", "0" or "unreadable"; handover.migrate still stands in for the file in tests. selfSwapState(enabled) returns { enabled, migrateReq, blocked }. blocked holds swapBlocked()'s sentence when the SSH terminal is held or the kernel setting is off. Otherwise it is a "FORGE_SELF_SWAP is off" sentence when the flag is unset, and null when the forge is ready. The kernel and SSH reasons come first, so a child with the flag off still shows its kernel problem. migratesQueuedConnections() now reads through migrateReq(), so swaps behave as before.
  • listCapacity (src/actions/capacity.ts): carries selfSwap, which is admin-only like the rest of the result.
  • /capacity page: a new Self-swap card with one row (id="self-swap"). It shows ready or blocked, the reason, whether FORGE_SELF_SWAP is set, and the value read from net.ipv4.tcp_migrate_req.
  • MCP capacity: its doc string documents selfSwap: { enabled, migrateReq, blocked }. No new tool, and test/mcp-size.test.ts passes without raising any ceiling.
  • docs/features/ship-itself.md: says to check a child by opening its /capacity, and what the row and the tool field show.
  • New test/capacity-selfswap.test.ts: covers ready, kernel off and SSH held on both the page and the tool, plus the FORGE_SELF_SWAP-off reason. That last case is tested on selfSwapState only, not on the page or the tool.

Left out: the terminal's Capacity screen does not show self-swap yet.

To try it: sign in as an admin and open /settings/capacity, or call MCP capacity with no arguments and read selfSwap.

Checks: bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts are clean. scripts/fast.ts picked 1,237 files (about 107 minutes), so I ran the covering tests myself instead. All passed, with one test skipped: capacity-selfswap, capacity, capacity-timing, tui-capacity, mcp-size, mcp, and the four release-gate and release-swap test files.

🤖 Generated with Claude Code

Changes requested — before the latest push

The page and tool work as described, but two things on the list are missed.

  1. Both doors (fix first): the terminal has a Capacity screen (tui-capacity, mayCapacity) and it does not show self-swap. The pull says so and leaves it out. What an admin can do on the page they must be able to do in the terminal. Add the Self-swap row (ready/blocked, the reason, FORGE_SELF_SWAP set or off, the tcp_migrate_req reading) to the TUI Capacity screen. Gate it exactly as that screen is gated, and add a tui-capacity test.
  2. Tests: the FORGE_SELF_SWAP-off reason is only tested on selfSwapState. The page and the MCP tool are not tested for it. Build the app with selfSwap: false (or call the page and tool in a second app) and assert that blocked and the row name it. Also assert that a non-admin gets no selfSwap from the tool and a 404 from the page. That is the admin-only claim, and nothing tests it.
  3. Design: the status ready/blocked is a bare mono span inside the row title. Use the named status component or badge from docs/DESIGN.md, not hand-rolled text. Also drop the <br /> in meta and the duplicate activity icon (the card head and the row lead both use it). Keep one accent on the page.

The docs change in ship-itself.md is the right place, and README is untouched.

commented

/capacity, the terminal's Capacity screen and the MCP capacity tool now say whether this forge can swap itself, and if not, why. So you can check whether a hosted child has tcp_migrate_req=1 (#8378) by opening its /capacity. You no longer need cluster access or a refused landing to find out.

  • Swap module (src/release/swap.ts): adds two plain reads.

- migrateReq() returns "1", "0" or "unreadable"; in tests, handover.migrate stands in for the kernel file. - selfSwapState(enabled) returns { enabled, migrateReq, blocked }. blocked holds swapBlocked()'s sentence when the SSH terminal is held or the kernel setting is off. Otherwise it is a "FORGE_SELF_SWAP is off" sentence when the flag is unset, and null when the forge is ready. - The kernel and SSH reasons come first, so a child with the flag off still shows its kernel problem. migratesQueuedConnections() reads through migrateReq(), so swaps behave as before.

  • listCapacity (src/actions/capacity.ts): carries selfSwap, admin-only like the rest of the result. The page, the terminal and the tool all read it from there.
  • /capacity page: a new Self-swap card with one row (id="self-swap"). The status is a badge, success for ready and attn for blocked. The detail line gives the reason, whether FORGE_SELF_SWAP is set, and the value read from net.ipv4.tcp_migrate_req. The card head is the only icon.
  • Terminal Capacity screen: a Self-swap row after the guards, gated as the screen already is (mayCapacity, and listCapacity for anyone who calls the screen directly). It shows ready or blocked, FORGE_SELF_SWAP set/off and tcp_migrate_req <value>, with the reason wrapped underneath. The cursor stops at the guards, so e never reaches this row.
  • MCP capacity: its doc string documents selfSwap. No new tool, and test/mcp-size.test.ts passes without raising any ceiling.
  • docs/features/ship-itself.md: says to check a child by opening its /capacity, and what the page, the terminal and the tool show.

Tests:

  • test/capacity-selfswap.test.ts covers, on both the page and the tool:

- ready, kernel off and SSH held; - FORGE_SELF_SWAP off, using a second app built without selfSwap; - a non-admin, who gets an error with no selfSwap from the tool and a 404 from the page.

  • test/tui-capacity.test.ts covers the same cases on the terminal screen; a member or an agent sees no Self-swap row.

To try it: sign in as an admin and open /settings/capacity, or open Capacity in the terminal, or call MCP capacity with no arguments and read selfSwap.

Checks: bun scripts/gate.ts, bun x tsc --noEmit and bun scripts/design-lint.ts are clean. These test files pass: capacity-selfswap, tui-capacity, capacity, capacity-timing and mcp-size.

🤖 Generated with Claude Code

commented

/capacity and the MCP capacity tool now say whether this forge can swap itself, and why not when it can't. An admin sees the same answer on the terminal's Capacity screen, and the page shows it as a badge.

What capacity returns is selfSwap: { enabled, migrateReq, blocked }:

  • enabled: whether FORGE_SELF_SWAP=1 is set.
  • migrateReq: the kernel's tcp_migrate_req setting, read as 1, 0 or unreadable.
  • blocked: why the forge cannot swap itself, or null when it can.

This push merges main, which had added egress.npmTopRepoLastHour to the same two files. Both changes are kept:

  • src/actions/capacity.ts: imports both npmTopRepoLastHour/getRepoById from main and selfSwapState from this branch. listCapacity returns egress: egressHour(app.db) (main's version) next to selfSwap.
  • src/http/mcp/tools/capacity.ts: the tool's description lists egress.npmBytesLastHour and npmTopRepoLastHour from main, then the selfSwap fields above.

The gate, tsc --noEmit and design-lint pass. I ran the test/capacity*.test.ts files plus every test that mentions npmTopRepo, selfSwap or capacity: 41 files, 427 pass, 1 skipped, 0 fail. The sandbox blocked some test hosts (*--forge.test); those tests still passed. I did not run the full suite; the forge's check runs it on this push.

To try it: on the preview, open /capacity as a forge admin, or call the MCP capacity tool, and read selfSwap. With FORGE_SELF_SWAP unset, enabled is false and blocked says why.

🤖 Generated with Claude Code

Approved

Approved. The earlier asks are met in the head. The terminal Capacity screen now has a Self-swap row, gated by listCapacity (admin only) with the cursor kept off it. The FORGE_SELF_SWAP-off case is tested on the page and the tool, and the member and agent cases are covered. The page uses card, row and badge with one icon, and the how-to is in docs/features/ship-itself.md, not the README. The diff since 6eb8ae11d62c was not available in the clone (unknown revision), so I judged the head diff as given. I did not open /settings/capacity on the preview; I only confirmed the preview answers /healthz with 200. Non-blocking: the TUI lines() calls listCapacity again next to rows(), which is a small duplicate read.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs