Bug
The gateway enumerates active Kanban boards and calls dispatch_once() independently for each board with the same max_in_progress value. Each board has a separate SQLite database, so _dispatch_once_locked() counts only that board's running rows.
Pinned revision reproduced: bc6d86b15c1d3136ee6e56275ffb1d3ff282f943 (Hermes Agent v0.20.0 / 2026.8.3).
Reproduction
- Create two disposable active boards.
- Put at least nine ready tasks on each.
- Configure
max_in_progress = 9.
- Run the same per-board dispatch loop used by the gateway.
Expected: at most nine workers across the gateway service.
Actual: nine workers spawn from each board, eighteen aggregate.
Impact
The documented/configured "global" limit cannot be used as a service-wide process or cgroup safety boundary. Worker subprocesses share the gateway's systemd cgroup, so active-board count multiplies the possible population and can produce reclaim/OOM/restart loops.
Suggested direction
Track service-wide running/spawning counts across all active boards during one gateway tick and pass only remaining global headroom to each board. Add a two-board exact-runtime regression test and account for concurrent gateway ticks/dispatchers atomically.
Bug
The gateway enumerates active Kanban boards and calls
dispatch_once()independently for each board with the samemax_in_progressvalue. Each board has a separate SQLite database, so_dispatch_once_locked()counts only that board's running rows.Pinned revision reproduced:
bc6d86b15c1d3136ee6e56275ffb1d3ff282f943(Hermes Agent v0.20.0 / 2026.8.3).Reproduction
max_in_progress = 9.Expected: at most nine workers across the gateway service.
Actual: nine workers spawn from each board, eighteen aggregate.
Impact
The documented/configured "global" limit cannot be used as a service-wide process or cgroup safety boundary. Worker subprocesses share the gateway's systemd cgroup, so active-board count multiplies the possible population and can produce reclaim/OOM/restart loops.
Suggested direction
Track service-wide running/spawning counts across all active boards during one gateway tick and pass only remaining global headroom to each board. Add a two-board exact-runtime regression test and account for concurrent gateway ticks/dispatchers atomically.