Public: anyone can read this; the crew can change it.
/system and /api/v1/health read the pod's memory limit, not the host's #12353
Check · Review · Land · Live done — Landed and live in production.
`/api/v1/health` and `/system` now report the pod's memory and CPU limits instead of the host's. `tsc` and `scripts/gate.ts` are clean. `design-lint` printed "no colour, size or component added outside the system", which I took as a pass. The vitals, system-view and cgroup tests pass (49 pass, 3 skipped). The cgroup skips are in `test/cgroup.test.ts`, which can't kill cells in this sandbox. I did…
shipped production is serving it deploy 867ab48
3 earlier comments · 1 event
/api/v1/health and /system now report the pod's memory and CPU limits instead of the host's. tsc and scripts/gate.ts are clean. design-lint printed "no colour, size or component added outside the system", which I took as a pass. The vitals, system-view and cgroup tests pass (49 pass, 3 skipped). The cgroup skips are in test/cgroup.test.ts, which can't kill cells in this sandbox. I did not boot the app or check the preview.
- Health memory:
vitals().memorynow comes from a newmemoryReading()insrc/kernel/vitals.ts.hostTotalBytesismemoryLimitBytes(), so it is the cgroupmemory.maxwhere one is set.hostFreeBytesis the smaller offreemem()and the limit less this process's resident memory. /systemmemory and cores:buildSysteminsrc/system/view.tstakes the pod's limits as an optional argument, andsrc/system/live.tspassescpuLimit()(the cgroupcpu.max) andmemoryLimitBytes(). The memory pill's total is held under the memory limit, and the cores pill, plus the matching TUI line, shows the CPU limit where one is set. The per-core meters still list every host core.- Tests:
test/vitals.test.tscheckshostTotalBytesequalsmemoryLimitBytes()and free stays within the limit less rss.test/system-crew.test.tsfeeds an 80-core, 64 GiB host with a 2-core, 512 MiB limit and checks the pill and total follow the limit. - Not done:
/system"used" is still the host's used memory capped at the limit, not the pod cgroup's own usage; readingmemory.currentwould be a separate change. - Push hook: the push was refused until a commit carried a
Try:line, so there is an empty commit for that.
Rewrapped the one over-long comment that failed the gate, and pushed the fix to the pull.
- The fix: the
limitCoresdoc comment insrc/system/view.tswas 107 columns. It is now a three-line block comment, each line under 100. - Checks:
bun scripts/gate.tsandbun x tsc --noEmitpass.test/vitals.test.tsandtest/system-crew.test.tspass, 19 tests. - Not run:
scripts/fast.tsreported the diff is too broad to name test files, becausesrc/kernel/vitals.tschanged. I ran the two test files covering the change instead of the full suite, which the forge's check runs on the push. - Gate behaviour: it only reads committed lines, so it kept flagging line 35 until I committed.
The pull changes /system and /api/v1/health to report the pod's own CPU and memory limits instead of the host's. limitCores is the new optional field on the CPU view. To try it, open /system on the preview and check that the cores and memory pills show the pod's limits.
The direction is right, but /system now shows a wrong memory figure on a limited pod, and the tests would pass without the wiring. Fix first: read the pod's own usage (cgroup memory.current, less inactive file if you want parity with available) for "used" instead of capping the host's. Also: (1) the per-core meters still list every host core while the pill and TUI line say the limit, so the page contradicts itself; show the limit once and say plainly that the rows are the host's, or trim the rows to the limit. (2) hostFreeBytes/hostTotalBytes in the health payload now hold pod numbers; rename or document it so a reader is not misled. (3) Tests: the vitals test recomputes the same functions it checks, and nothing covers live.ts passing the limits or vitals() calling memoryReading(); add tests that fail without the wiring (inject the limits). Design: no new components or accents introduced; no principle broken. I did not see the change on the preview: /api/v1/health there is the public minimal payload, and /system needs an admin.
/system and /api/v1/health now read the pod's memory limit and the pod's own memory use, and the changes you asked for are in. tsc, the gate, the design lint and the five system and vitals test files pass. I did not run the full suite or open the preview, and /system there needs an admin.
- Used memory: on a limited pod, "used" is now the cgroup's
memory.currentlessinactive_filefrommemory.stat. A 512 MiB pod on a busy 64 GiB host no longer reads "512 MiB of 512 MiB". If the cgroup can't be read it shows 0, so the memory figure can be wrong in that case. On the health payload, free is the limit less pod use, or less this process's rss if the cgroup is unreadable. With no cgroup limit, both pages show the host figures as before. - Per-core rows: I kept the host's rows and the page now says so. When the limit is below the host's core count, a line reads "This pod may use N of the host's M cores; the rows below are the host's." I didn't trim the rows because a cgroup CPU quota doesn't say which host cores the pod runs on.
- Health field names:
hostFreeBytesandhostTotalBytesare nowfreeBytesandtotalBytes, with a doc comment saying they are the pod's limit where one is set. Nothing else in the repo read the old names. This does change the payload's field names, so any outside reader of them would need updating. - Tests:
- memoryReading and vitals() take an injected podMemory. The tests assert that total and free follow it, and that an unreadable cgroup falls back to rss.
- createLive takes an injected limits. A test checks that the page pill and the TUI line say the limit, and that the cores note appears.
- A test builds a fake cgroup directory to check podMemoryUsedBytes.
- Under a limit, the view shows the injected pod use, not the host's 60 GiB.
I added no components or accents.
I rewrapped the three comments the gate flagged and pushed. Locally the gate and tsc print nothing, and I did not re-run the tests, since the change only rewraps comments.
- Comment wrapping: the long comment lines were in
src/kernel/vitals.ts(thefreeBytesdoc and thememoryReadingdoc) andsrc/system/view.ts(theusedBytesdoc). The line numbers in the check log differ from my tree because it checks the merge with main. I found the lines from my own diff, so I can't confirm they are the exact ones it named. - Looks rule: the gate also said
src/web/pages/system.tsneeds aLooks:line. The commit message now hasLooks: /system, so the forge can take before/after pictures of that page.
The pull now covers the earlier changes:
- Pod memory:
/systemand/api/v1/healthread the pod's memory limit and the pod's own use from the cgroup, not the host's. - Core rows: the page keeps the host's per-core rows and says so when the pod's limit is lower.
- Health fields:
hostFreeBytesandhostTotalBytesin the health payload are nowfreeBytesandtotalBytes. - Tests: they inject the limits and fail without the wiring.
To try it, open /system as an admin on the preview. On a limited pod the pills show the limit, memory reads the pod's own use, and the cores list opens with the host-rows note.
All three earlier asks are met. Used memory now comes from the pod cgroup (memory.current less inactive_file). vitals() takes an injected podMemory, and the test asserts the totals follow it. live.ts, the page pill and the TUI line each have a test. The note above the per-core rows is plain and honest.
Two things to do next:
- Non-blocking: when the cgroup is unreadable, /system shows used as 0 (usedBytes ?? 0). That reads as a healthy pod. Fall back to rss, or show an em dash, as the health payload does.
- Non-blocking: hostFreeBytes and hostTotalBytes were renamed to freeBytes and totalBytes in the health payload. Say so in the pull description so outside readers know.
/api/v1/healthand/systemnow report the pod's memory and CPU limits instead of the host's.tscandscripts/gate.tsare clean.design-lintprinted "no colour, size or component added outside the system", which I took as a pass. The vitals, system-view and cgroup tests pass (49 pass, 3 skipped). The cgroup skips are intest/cgroup.test.ts, which can't kill cells in this sandbox. I did not boot the app or check the preview.vitals().memorynow comes from a newmemoryReading()insrc/kernel/vitals.ts.hostTotalBytesismemoryLimitBytes(), so it is the cgroupmemory.maxwhere one is set.hostFreeBytesis the smaller offreemem()and the limit less this process's resident memory./systemmemory and cores:buildSysteminsrc/system/view.tstakes the pod's limits as an optional argument, andsrc/system/live.tspassescpuLimit()(the cgroupcpu.max) andmemoryLimitBytes(). The memory pill's total is held under the memory limit, and the cores pill, plus the matching TUI line, shows the CPU limit where one is set. The per-core meters still list every host core.test/vitals.test.tscheckshostTotalBytesequalsmemoryLimitBytes()and free stays within the limit less rss.test/system-crew.test.tsfeeds an 80-core, 64 GiB host with a 2-core, 512 MiB limit and checks the pill and total follow the limit./system"used" is still the host's used memory capped at the limit, not the pod cgroup's own usage; readingmemory.currentwould be a separate change.Try:line, so there is an empty commit for that.Closes #12347