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

Crew runs at once defaults to what the pod's memory holds, as children.max does, so a big machine needs no override #2550

Merged opened this

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

Merged

The default for "Crew runs at once" (`crew.concurrency`) now follows the pod's memory, the way `children.max` does. A big machine gets its share without an override, so the sentinel stops flagging one that is set on purpose.

shipped production is serving it deploy ddc329f

opened this

The default for "Crew runs at once" (crew.concurrency) now follows the pod's memory, the way children.max does. A big machine gets its share without an override, so the sentinel stops flagging one that is set on purpose.

  • src/core/capacity.ts: the new crewForMemory(bytes) gives one run per 3 GiB above the forge's own 2 GiB, at least 2 and at most 16. So 4 GiB → 2, 32 GiB → 10, 64 GiB → 16. capacityDefault("crew.concurrency") uses it with memoryLimitBytes(). A valid FORGE_CREW_CONCURRENCY still wins, and a stored value overrides both.
  • Capacity page: the help line now reads "Empty: one per 3 GiB of memory above the forge's own 2 GiB, from the pod's limit, at least 2 and at most 16."
  • src/main.ts: the crew service now boots with this default. It used to boot with a hard-coded 2, and noteBooted records the boot value as the default in force, so without this change the boot value would still have shown as 2. A hosted child forge still boots at 1.
  • Sentinel: settingsAway in src/crew/sentinel.ts already compares with capacityDefault, so its code is unchanged and it now uses the memory default.
  • Docs: the defaults listed in README.md and docs/APPS.md now give the formula.

Tests

  • The new test/capacity-crew.test.ts covers:

- the three cases from the issue, plus the floor and an unreadable value; - the help text; - the environment winning, and an out-of-range value being ignored; - a stored value overriding the default and clearing back to it; - the sentinel ignoring a stored value equal to the memory default and flagging one that differs.

  • I changed one existing test because it was wrong after this change: test/capacity.test.ts expected the crew's previous value in the change log to be "2". That value now depends on the machine, so the test expects capacityDefault("crew.concurrency").
  • The type check and the capacity tests pass. One test in test/capacity.test.ts (shard reset) fails on main as well in this sandbox, because the shell sets FORGE_CHECK_SHARDS=4. With that variable unset, the whole file passes.

Not done

  • /admin/limits still shows CAPACITY[...].fallback (2) as the crew's default, because settings/limits.ts reads the static fallback for both concurrency limits. Changing that would touch the checks limit as well, so I left it.

To try it: open Settings → Capacity with no stored crew value and no FORGE_CREW_CONCURRENCY, and the default shown is the pod's memory share. On a 32 GiB pod that is 10, so the vxrail's stored 10 no longer counts as away from its default.

🤖 Generated with Claude Code

Closes #2548

commented

The default for "Crew runs at once" (crew.concurrency) now follows the pod's memory, the way children.max does. A big machine gets its share without an override, so the sentinel stops flagging one that is set on purpose.

  • src/core/capacity.ts: the new crewForMemory(bytes) gives one run per 3 GiB above the forge's own 2 GiB, at least 2 and at most 16. So 4 GiB → 2, 32 GiB → 10, 64 GiB → 16. capacityDefault("crew.concurrency") uses it with memoryLimitBytes(). A valid FORGE_CREW_CONCURRENCY still wins, and a stored value overrides both.
  • Capacity page: the help line now reads "Empty: one per 3 GiB of memory above the forge's own 2 GiB, from the pod's limit, at least 2 and at most 16."
  • src/main.ts: the crew service now boots with this default. It used to boot with a hard-coded 2, and noteBooted records the boot value as the default in force, so without this change the boot value would still have shown as 2. A hosted child forge still boots at 1.
  • Sentinel: settingsAway in src/crew/sentinel.ts already compares with capacityDefault, so its code is unchanged and it now uses the memory default.
  • Docs: the defaults listed in README.md and docs/APPS.md now give the formula.

Tests

  • The new test/capacity-crew.test.ts covers:

- the three cases from the issue, plus the floor and an unreadable value; - the help text; - the environment winning, and an out-of-range value being ignored; - a stored value overriding the default and clearing back to it; - the sentinel ignoring a stored value equal to the memory default and flagging one that differs.

  • I changed one existing test because it was wrong after this change: test/capacity.test.ts expected the crew's previous value in the change log to be "2". That value now depends on the machine, so the test expects capacityDefault("crew.concurrency").
  • The type check and the capacity tests pass. One test in test/capacity.test.ts (shard reset) fails on main as well in this sandbox, because the shell sets FORGE_CHECK_SHARDS=4. With that variable unset, the whole file passes.

Not done

  • /admin/limits still shows CAPACITY[...].fallback (2) as the crew's default, because settings/limits.ts reads the static fallback for both concurrency limits. Changing that would touch the checks limit as well, so I left it.

To try it: open Settings → Capacity with no stored crew value and no FORGE_CREW_CONCURRENCY, and the default shown is the pod's memory share. On a 32 GiB pod that is 10, so the vxrail's stored 10 no longer counts as away from its default.

🤖 Generated with Claude Code

commented

The default for "Crew runs at once" (crew.concurrency) now follows the pod's memory, the way children.max does, so a big machine needs no override and the sentinel stops flagging one that is set on purpose.

  • src/core/capacity.ts: the new crewForMemory(bytes) gives one run per 3 GiB above the forge's own 2 GiB, at least 2 and at most 16. So 4 GiB → 2, 32 GiB → 10, 64 GiB → 16. capacityDefault("crew.concurrency") uses it with memoryLimitBytes(). A valid FORGE_CREW_CONCURRENCY still wins, and a stored value overrides both.
  • Capacity page: the help line now reads "Empty: one per 3 GiB of memory above the forge's own 2 GiB, from the pod's limit, at least 2 and at most 16."
  • src/main.ts: the crew service now boots with this default. It used to boot with a hard-coded 2, and noteBooted records the boot value as the default in force, so without this change the boot value would still have shown as 2. A hosted child forge still boots at 1.
  • Sentinel: settingsAway in src/crew/sentinel.ts already compares with capacityDefault, so its code is unchanged and it now uses the memory default.
  • Docs: the defaults listed in README.md and docs/APPS.md now give the formula.

Flaky restore test (the failed check). "repositories come back in the manifest's order when later reads land first" failed because of a race in src/snapshot/restore.ts, not a slow machine. Restore clones up to CLONES (4) repositories at once and threw from whichever clone failed first, so which repository the error named depended on timing. Now, after a failure no new clones start, the ones already running finish, and the error names the earliest failed bundle in manifest order.

Tests

  • The new test/capacity-crew.test.ts covers:

- the three cases from the issue, plus the floor and an unreadable value; - the help text; - the environment winning, and an out-of-range value being ignored; - a stored value overriding the default and clearing back to it; - the sentinel ignoring a stored value equal to the memory default and flagging one that differs.

  • test/snapshot-restore-clones.test.ts gains a test where the last bundle's clone fails first. It fails without the restore fix and passes with it.
  • I changed one existing test because it was wrong after this change: test/capacity.test.ts expected the crew's previous value in the change log to be "2". That value now depends on the machine, so the test expects capacityDefault("crew.concurrency").
  • The type check, the capacity tests and the snapshot-restore tests pass; the restore-parallel test passed on three more runs. One test in test/capacity.test.ts (shard reset) fails on main as well when run locally, because the shell sets FORGE_CHECK_SHARDS=4. With that variable unset, the whole file passes.

Not done

  • /admin/limits still shows CAPACITY[...].fallback (2) as the crew's default, because settings/limits.ts reads the static fallback for both concurrency limits. Changing that would touch the checks limit as well, so I left it.

To try it: open Settings → Capacity with no stored crew value and no FORGE_CREW_CONCURRENCY, and the default shown is the pod's memory share. On a 32 GiB pod that is 10, so the vxrail's stored 10 no longer counts as away from its default.

🤖 Generated with Claude Code

Approved

Approved. crewForMemory mirrors childrenForMemory, env still wins, a stored value overrides, main.ts now boots the crew on the same default so noteBooted agrees with the Capacity page, and the sentinel needed no change. Tests would fail without each behaviour. The restore ordering fix is disclosed and has a test that fails without it. I could not reach the preview from my sandbox (network denied), so I judged the source only. Next, in order: (1) /admin/limits still shows the static fallback 2 as the crew default while Capacity shows the memory share, so one machine says two numbers; make settings/limits.ts read capacityDefault for crew.concurrency (and open an issue if you keep it out of this pull). (2) The README and APPS.md line gives the formula but not that a hosted child boots at 1; add it so the doc is true for both.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs