# Supervisor Q198 S1 (row 257, #1762): parsers for the host pressure inputs in design D4 (`docs/plans/2026-10-21_q198-system-manager.md`), and a pure evaluator that turns timestamped samples into a hold or release decision. Nothing here samples the host, runs a process or timer, or enforces anything. The live sampler, the Console view and admission are S2 and S3. ```sh node --test packages/supervisor/tests/ ``` ## Parsers Each parser takes file text the caller already read. Text that isn't the shape the kernel writes throws a `SupervisorError` with `kind: "parse"`; a sampler treats that as a missing signal. | Export | Input | Returns | |---|---|---| | `parseLoadavg` | `/proc/loadavg` | `{ load1, load5, load15 }` | | `parseMeminfo` | `/proc/meminfo` | `{ memTotal, memAvailable, swapTotal, swapFree }` in bytes | | `parsePsi(text, resource)` | `/proc/pressure/{cpu,memory,io}` or a cgroup `*.pressure` | `{ some, full }`, each `{ avg10, avg60, avg300, total }`; `full` is null only for cpu | | `parseCpuList` | `/sys/devices/system/cpu/online`, `cpuset.cpus.effective` | how many CPUs the list names | | `parseCpuMax` | `cpu.max` | the quota in CPUs, or null for `max` | | `parseMemoryMax` | `memory.max` | bytes, or null for `max` | | `parseMemoryCurrent` | `memory.current` | bytes | | `parseMemoryEvents` | `memory.events` | `{ oom, oomKill }` | | `parseVmstat` | `/proc/vmstat` | `{ pswpin, pswpout, oomKill }`; `oomKill` is the host-only OOM counter, null when absent | `effectiveCpus({ online, cpuset, cpuMax })` is the smallest of the host count, the cpuset and the quota at every cgroup level given; a fractional quota stays fractional. `effectiveMemory({ meminfo, levels })` takes cgroup levels as `{ max, current }` text. The limit is the smallest of `MemTotal` and every numeric `memory.max`. Available memory is the smallest of `MemAvailable` and `max - current` at each limited level. `memory.current` counts page cache, so this errs toward holding. With no cgroup input both functions use the host's figures. ## Evaluator `evaluate(state, sample, rules, { reconciled })` returns `{ state, decision }`. It starts from `initialState()`, which is held: no signal has been seen yet. Time is the sample's `at` in milliseconds. The evaluator never reads the clock. A sample has these signals: `load { at, load1, cpus }`, `memory { at, available, limit }`, `psi { at, cpuSome, memoryFull, ioFull }` (avg10 percentages), `oom { at, kills }` and `disk { at, free }`. | Signal | Hold | Release | |---|---|---| | `load1 / cpus` | ≥ 0.80 on 3 consecutive samples | ≤ 0.55 | | available memory | < max(15% of limit, 1 GiB), on one sample | > max(25% of limit, 2 GiB) | | PSI avg10 | cpu some ≥ 20, memory full ≥ 2 or io full ≥ 10, on 3 consecutive samples | cpu some < 10, memory full < 0.5 and io full < 3 | | critical | OOM kill counter rises, memory < 5% of limit, or disk free < 1 GiB | the caller passes `reconciled`, then the normal release | - **Release** needs every applicable release condition on every sample for 30 s. A dead-band sample (between hold and release) or a new hold restarts the window. - **Missing or stale:** a required signal that is missing, malformed, more than 6 s older than the sample, or later than it holds at once with `health-unknown`. `load`, `memory`, `oom` and `disk` are always required. PSI becomes required once a sample has carried it. A host without PSI skips the PSI rows, and one that loses it holds. - **Consecutive counts** reset after a gap of more than 6 s between samples. The PSI count runs across resources: any PSI hold condition on 3 consecutive samples holds. - **OOM:** the first OOM sample is the baseline. A counter that falls (a recreated cgroup) resets the baseline with the note `oom-counter-reset`. - **Critical** never ends on thresholds alone. `reconciled` only counts once no critical condition remains, and the 30 s release still follows. The evaluator never sets it and never touches a kill switch. - **A clock that goes backwards** holds with `health-unknown` and the note `clock-backwards`. `decision` is `{ mode, reasons, unknown, critical, releaseAt, notes }`. - `mode` is `open`, `held` or `critical`. - `reasons` are `health-unknown`, `load-high`, `memory-low`, `psi-cpu`, `psi-memory`, `psi-io`, `hysteresis`, `release-pending` or the critical codes `critical-oom`, `critical-memory` and `critical-disk`. - `releaseAt` is set while a release is pending. `DEFAULT_RULES` is the D4 table, frozen. `resolveRules(overrides)` merges overrides key by key. It refuses with `kind: "rules"` on an unknown key, a non-number or a contradictory pair, for example: - a release threshold at or past its hold; - a release floor at or below its hold floor; - a critical memory fraction at or above the hold fraction; - a stale limit at or below the sample interval. Provider scope (429, quota, Retry-After) is not here; it belongs to S3 and S5.