forge: the avatar path unit watches this agent's token, not every agent's

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.
This commit is contained in:
atlas 2026-09-03 01:10:40 +02:00 committed by mara
commit 3b5bdcf262

View file

@ -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: