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
Check · Review · Land · Live done — Landed and live in production.
/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
/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.migratestill stands in for the file in tests.selfSwapState(enabled)returns{ enabled, migrateReq, blocked }.blockedholdsswapBlocked()'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, andnullwhen 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 throughmigrateReq(), so swaps behave as before. listCapacity(src/actions/capacity.ts): carriesselfSwap, which is admin-only like the rest of the result.- /capacity page: a new
Self-swapcard with one row (id="self-swap"). It showsreadyorblocked, the reason, whetherFORGE_SELF_SWAPis set, and the value read fromnet.ipv4.tcp_migrate_req. - MCP
capacity: its doc string documentsselfSwap: { enabled, migrateReq, blocked }. No new tool, andtest/mcp-size.test.tspasses 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 onselfSwapStateonly, 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
The page and tool work as described, but two things on the list are missed.
- 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. - 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 withselfSwap: false(or call the page and tool in a second app) and assert thatblockedand the row name it. Also assert that a non-admin gets noselfSwapfrom the tool and a 404 from the page. That is the admin-only claim, and nothing tests it. - Design: the status
ready/blockedis a baremonospan inside the row title. Use the named status component or badge from docs/DESIGN.md, not hand-rolled text. Also drop the<br />inmetaand the duplicateactivityicon (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.
/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): carriesselfSwap, 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 abadge, success forreadyand attn forblocked. The detail line gives the reason, whetherFORGE_SELF_SWAPis set, and the value read fromnet.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, andlistCapacityfor anyone who calls the screen directly). It shows ready or blocked,FORGE_SELF_SWAP set/offandtcp_migrate_req <value>, with the reason wrapped underneath. The cursor stops at the guards, soenever reaches this row. - MCP
capacity: its doc string documentsselfSwap. No new tool, andtest/mcp-size.test.tspasses 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.tscovers, 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.tscovers 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
/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: whetherFORGE_SELF_SWAP=1is set.migrateReq: the kernel'stcp_migrate_reqsetting, read as1,0orunreadable.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 bothnpmTopRepoLastHour/getRepoByIdfrom main andselfSwapStatefrom this branch.listCapacityreturnsegress: egressHour(app.db)(main's version) next toselfSwap.src/http/mcp/tools/capacity.ts: the tool's description listsegress.npmBytesLastHourandnpmTopRepoLastHourfrom main, then theselfSwapfields 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. 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.
/capacity and the MCP
capacitytool now say whether this forge can swap itself, and if not, why. So you can check whether a hosted child hastcp_migrate_req=1(#8378) by opening its /capacity. You no longer need cluster access or a refused landing to find out.src/release/swap.ts): adds two plain reads.migrateReq()returns"1","0"or"unreadable";handover.migratestill stands in for the file in tests.selfSwapState(enabled)returns{ enabled, migrateReq, blocked }.blockedholdsswapBlocked()'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, andnullwhen 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 throughmigrateReq(), so swaps behave as before.listCapacity(src/actions/capacity.ts): carriesselfSwap, which is admin-only like the rest of the result.Self-swapcard with one row (id="self-swap"). It showsreadyorblocked, the reason, whetherFORGE_SELF_SWAPis set, and the value read fromnet.ipv4.tcp_migrate_req.capacity: its doc string documentsselfSwap: { enabled, migrateReq, blocked }. No new tool, andtest/mcp-size.test.tspasses 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.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 onselfSwapStateonly, 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 MCPcapacitywith no arguments and readselfSwap.Checks:
bun scripts/gate.ts,bun x tsc --noEmitandbun scripts/design-lint.tsare clean.scripts/fast.tspicked 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