From 33aa2bdbc80b9124ffd6810252be96f2482528d1 Mon Sep 17 00:00:00 2001 From: atlas Date: Sun, 13 Sep 2026 13:05:17 +0200 Subject: [PATCH] subagent daemon: scope an OOM kill to the session that lost the draw MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit systemd's default OOMPolicy=stop tears the whole unit down the moment the kernel kills any process in its cgroup, so a single over-large subagent takes the daemon and every sibling session with it — measured on a live agent, both units show OOMPolicy=stop today, which is exactly the "every live subagent session was cut mid-turn" symptom. That blast radius is also what would make the preceding commit a bad trade: deliberately putting this unit first in the OOM queue is only an improvement if losing one subagent isn't losing all of them. OOMPolicy= continue scopes the loss to the process the kernel actually chose, and leaves the daemon alive to report the kill instead of vanishing and being restarted with an empty session map. Refs #4316 --- nix/agent-modules/mcp.nix | 8 ++++++++ nix/module-eval.nix | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/nix/agent-modules/mcp.nix b/nix/agent-modules/mcp.nix index d5e9f5a6..151bbd00 100644 --- a/nix/agent-modules/mcp.nix +++ b/nix/agent-modules/mcp.nix @@ -375,6 +375,14 @@ in # inherits the value from the daemon, so the ordering covers the # whole subtree and not just this process. OOMScoreAdjust = 500; + # systemd's default is `stop`, which tears the whole unit down as + # soon as the kernel kills *any* process in its cgroup — so one + # over-large subagent takes the daemon and every sibling session + # with it, which is the blast radius that makes an OOM here + # expensive. `continue` scopes the loss to the process the kernel + # actually chose and leaves the daemon serving, which is also what + # lets it report the kill rather than vanish and be restarted. + OOMPolicy = "continue"; User = userName; Group = userName; } diff --git a/nix/module-eval.nix b/nix/module-eval.nix index ace26482..25208745 100644 --- a/nix/module-eval.nix +++ b/nix/module-eval.nix @@ -1402,6 +1402,16 @@ let in sub > 0 && own < 0 && sub > own; } + { + # The pair the case above only makes sense with: preferring this unit + # as the victim is an improvement only if losing one subagent isn't + # losing all of them. systemd's default `stop` would take the daemon + # and every sibling session down with whichever process the kernel + # chose, which is the blast radius that made the preference a bad + # trade in the first place. + name = "one subagent losing the OOM draw does not stop the daemon"; + ok = (agentSubagentDaemon agentUncapped).serviceConfig.OOMPolicy == "continue"; + } { # The doctrine three glue files state, as a property a rewrite has to # keep: a client is defined by holding a certificate the store accepts,