From 3b5bdcf26287579ece27892e27b70e4fd8e881be Mon Sep 17 00:00:00 2001 From: atlas Date: Thu, 3 Sep 2026 01:10:40 +0200 Subject: [PATCH] forge: the avatar path unit watches this agent's token, not every agent's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The service reads `$HYPERHIVE_STATE_DIR/forge-token` — its own. The path unit that retriggers it globbed `/agents/*/state/forge-token`, and every agent's state dir is visible from inside every container, so a sibling's token appearing re-fired this agent's sync. Enough of them arrive together to trip systemd's start rate limit, so the unit ends `start-limit-hit` after the upload has already succeeded: a red [FAILED] on every container on every boot, for work that worked. Measured on this container at tonight's 23:54 boot, before the change: five `avatar uploaded (HTTP 204)` inside one second, then `Start request repeated too quickly`. After it lands, that boot line should read one upload and no limit. The path is spelled the way the same file already spells it for tea-login, 223 lines up — `userName` was in scope the whole time. --- nix/agent-modules/forge.nix | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/nix/agent-modules/forge.nix b/nix/agent-modules/forge.nix index d83cc1f1..81fb5dd9 100644 --- a/nix/agent-modules/forge.nix +++ b/nix/agent-modules/forge.nix @@ -252,10 +252,18 @@ in # Without this path unit, RemainAfterExit=true would prevent systemd # from ever re-running the service. See # docs/agent-lifecycle/persistence.md::forge-avatar-sync. + # ⚠️ This agent's own token, not a glob over `/agents/*/`. Every agent's + # state dir is visible from inside every container, so a wildcard here + # watches paths this unit has no business reacting to: each sibling's + # token appearing re-fires *this* agent's sync, and enough of them + # arriving at once trips systemd's start rate limit — leaving a red + # `[FAILED]` on every boot after the upload has already succeeded. + # The service reads `$HYPERHIVE_STATE_DIR/forge-token`; this is the same + # file, spelled the way `tea-login` above already spells it. systemd.paths.forge-avatar-sync = lib.mkIf (config.hyperhive.icon != null) { description = "trigger forge-avatar-sync when forge-token appears"; wantedBy = [ "multi-user.target" ]; - pathConfig.PathExistsGlob = "/agents/*/state/forge-token"; + pathConfig.PathExists = "/agents/${userName}/state/forge-token"; }; # One-shot: hyperhive.icon → Forgejo profile avatar. Shape contract: