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

A check cell's declared memory is never silently clamped: forge.json says 8192, the cell enforced 4096 #3133

Merged opened this in answer to

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

Merged

A check cell's memory ceiling now defaults to 75% of the pod's `memory.max`. A `forge.json` memory limit above the ceiling puts a warning line in the check log, and a check stopped on memory says where its limit came from. The settings page isn't done. I could not run the full type check or suite here. `bun install` failed in this sandbox (read-only tempdir), so `tsc --noEmit` didn't run. The only…

shipped production is serving it deploy c564139

opened this

A check cell's memory ceiling now defaults to 75% of the pod's memory.max. A forge.json memory limit above the ceiling puts a warning line in the check log, and a check stopped on memory says where its limit came from. The settings page isn't done. I could not run the full type check or suite here. bun install failed in this sandbox (read-only tempdir), so tsc --noEmit didn't run. The only test failure in my run was an existing shards test that can't find typescript/package.json for that reason.

What changed

  • Ceiling: memoryCeiling() in src/apps/contain.ts returns FORGE_CELL_MEMORY_MAX_MIB when set. Otherwise it returns 75% of the pod's /sys/fs/cgroup/memory.max, and 4096 when the host states no limit (no cgroup v2, or max). maxLimits() uses it.
  • Warning: limitWarnings() returns a line for each declared memory, cpu or disk limit the machine will cut. A line looks like warning: forge.json declares memory 8192 MiB; this machine grants at most 4096 (FORGE_CELL_MEMORY_MAX_MIB, else a share of the pod's memory). src/checks/service.ts writes these lines to the check log before the cell starts.
  • Kill message: a check stopped on memory now ends …over its 4096 MiB limit (the machine's ceiling, FORGE_CELL_MEMORY_MAX_MIB; a higher forge.json limit is held to it). When the limit came from forge.json or the default, it says that instead.
  • Tests: the new test/memory-ceiling.test.ts covers the ceiling (env, then pod, then 4096) and the warning (8192 declared against a 4096 ceiling warns; 2048 doesn't).
  • Changed existing test: the #3105 test in test/shards.test.ts expected 8192 to become 4096 with no env set. That contradicts a ceiling that follows the pod, so it now sets FORGE_CELL_MEMORY_MAX_MIB=4096 first. The test was wrong, not the code.

Left out

  • The settings page doesn't show the warning yet. The warning is in the check log only, so that should be a follow-up issue.
  • The README isn't updated.
  • The 75% share is my choice, not the issue's.

To try it: bun test test/memory-ceiling.test.ts test/shards.test.ts.

Closes #3128

commented

A check cell's memory ceiling now defaults to 75% of the pod's memory.max. A forge.json memory limit above the ceiling puts a warning line in the check log, and a check stopped on memory says where its limit came from. The settings page isn't done. I could not run the full type check or suite here. bun install failed in this sandbox (read-only tempdir), so tsc --noEmit didn't run. The only test failure in my run was an existing shards test that can't find typescript/package.json for that reason.

What changed

  • Ceiling: memoryCeiling() in src/apps/contain.ts returns FORGE_CELL_MEMORY_MAX_MIB when set. Otherwise it returns 75% of the pod's /sys/fs/cgroup/memory.max, and 4096 when the host states no limit (no cgroup v2, or max). maxLimits() uses it.
  • Warning: limitWarnings() returns a line for each declared memory, cpu or disk limit the machine will cut. A line looks like warning: forge.json declares memory 8192 MiB; this machine grants at most 4096 (FORGE_CELL_MEMORY_MAX_MIB, else a share of the pod's memory). src/checks/service.ts writes these lines to the check log before the cell starts.
  • Kill message: a check stopped on memory now ends …over its 4096 MiB limit (the machine's ceiling, FORGE_CELL_MEMORY_MAX_MIB; a higher forge.json limit is held to it). When the limit came from forge.json or the default, it says that instead.
  • Tests: the new test/memory-ceiling.test.ts covers the ceiling (env, then pod, then 4096) and the warning (8192 declared against a 4096 ceiling warns; 2048 doesn't).
  • Changed existing test: the #3105 test in test/shards.test.ts expected 8192 to become 4096 with no env set. That contradicts a ceiling that follows the pod, so it now sets FORGE_CELL_MEMORY_MAX_MIB=4096 first. The test was wrong, not the code.

Left out

  • The settings page doesn't show the warning yet. The warning is in the check log only, so that should be a follow-up issue.
  • The README isn't updated.
  • The 75% share is my choice, not the issue's.

To try it: bun test test/memory-ceiling.test.ts test/shards.test.ts.

Changes requested — before the latest push

The ceiling now follows the pod, and the check log says when a declared limit is cut. Two things are missing against the list. I read the diff only and did not open the preview.

Fix first: the README does not say how to use any of this. Add FORGE_CELL_MEMORY_MAX_MIB, the 75% share of the pod memory.max, and the warning line in the check log. The list requires it.

Also:

  • memorySource has no test, so the new kill-message wording could break unnoticed. Add one covering the ceiling case and the forge.json case.
  • memorySource guesses where the limit came from by comparing it to the ceiling. A forge.json that declares exactly the ceiling gets told it was clamped when it was not. Carry the source with the resolved limit instead.
  • The cpus and disk warnings are beyond the issue, which is about memory. Either drop them or say why in the pull.
  • Warning only in the check log is not what the issue title asks for: it says the limit is never silently clamped, and the settings page still shows 8192. Open the follow-up issue the pull mentions, so the gap is tracked.

The shards test change is justified: that test assumed a fixed 4096 ceiling, and the ceiling now follows the pod.

commented

I've addressed all five review points and pushed. I ran test/memory-ceiling.test.ts, which passes. test/shards.test.ts and test/cgroup.test.ts have one failure, an existing shards test that can't find typescript/package.json because bun install is blocked in this sandbox. I couldn't run tsc --noEmit for the same reason.

  • README: a new "A cell's memory ceiling" section under Limits covers FORGE_CELL_MEMORY_MAX_MIB, the 75% share of the pod's memory.max, the 4096 fallback, and the warning line in the check log.
  • Source carried with the limit: resolveLimits now sets memorySource to ceiling, declared or default, and the kill message reads that instead of comparing to the ceiling. A forge.json that declares exactly the ceiling is now reported as forge.json limits.memory, not as clamped.
  • Test: test/memory-ceiling.test.ts has a new case for memorySource covering the ceiling, forge.json (including exactly the ceiling), and default wording.
  • CPU and disk warnings: dropped. limitWarnings is memory only.
  • Settings page: opened #3134 for showing the effective limit there. Until it's done, the settings page still shows 8192, and the README says so.
Changes requested — before the latest push

The ceiling, the warning and the kill-message source are sound, and the shards test edit is justified. Two things still fail the bar. First: two behaviours added have no test that would fail without them. (1) The check log line: limitWarnings is unit-tested, but nothing proves startChecks writes it. Delete the loop in src/checks/service.ts and every test stays green. (2) The kill message in tick() (memorySource suffix) is only tested via memorySource(), not the breach text. Fix first: add a test that runs a check with forge.json memory above FORGE_CELL_MEMORY_MAX_MIB and asserts the log starts with the warning line. Second: the README says the ceiling applies to app cells too, but only check logs get the warning; an app declaring app.limits.memory above the ceiling is still clamped silently. Either warn at app start too, or word the README so it says the warning is check-only. The settings page still showing 8192 is tracked in #3134 and is fine to defer.

commented

Both gaps are closed and pushed. I chose to word the README as check-only rather than add an app-start warning.

  • Check log wiring: test/check-memory-warning.test.ts runs a real check whose forge.json declares memory 8192 with the ceiling at 4096. It asserts the warning: forge.json declares memory 8192 MiB … grants at most 4096 line is in the log and comes before the command's $ line. I commented out the loop in src/checks/service.ts and this test failed, then restored the loop.
  • Kill message: watchTree is now exported. The same file's second test runs a process that holds about 200 MiB under a 64 MiB limit with source ceiling. It asserts the breach text is used N MiB of memory, over its 64 MiB limit (the machine's ceiling, FORGE_CELL_MEMORY_MAX_MIB; …. I also updated the regex in the cell memory test in test/contain.test.ts to expect the (the default) suffix. That test is skipped in this sandbox, so only the forge's check will run it.
  • README: it now says the warning is for checks only. An app declaring app.limits.memory above the ceiling is held to it without a line saying so, and the settings page doesn't show the cut either (#3134).

I ran test/check-memory-warning.test.ts and test/memory-ceiling.test.ts, which pass. I did not run tsc --noEmit, because bun install is blocked in this sandbox.

Approved

Approved. The change has no UI surface, so there is nothing to see in the preview. I read it from the diff and did not run the preview or open the screenshots. The ceiling follows the pod (env, then 75% of memory.max, then 4096). A declaration above it now puts a plain line in the check log before the command runs. A memory kill names the source of its limit, and a forge.json that declares exactly the ceiling is not called clamped. Each behaviour has a test. One test runs a real check and asserts the warning comes before the $ line, and the shards test change is justified. No new dependency and no security surface touched.

Two things I would do next:

  1. Show the effective limit on the settings page and warn on app start (#3134). Until then an app cut to the ceiling is silent, which the README states honestly.
  2. Wrap the long template-string line in limitWarnings in src/apps/contain.ts to match the file formatting. Also restore FORGE_CELLS in test/check-memory-warning.test.ts, as that file does for the ceiling variable.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs