π€ automated
Found dogfooding #1640/#1644/#1645 on main (chain write-up: #1204 (comment)).
What happened. Concurrent agents: 3, three entries on the queue, no agent running on the project β the Agents panel said "No agents working right now", the last run on the project had been DONE for ten minutes. The drain's Run now reported:
tf-1334-dogfood: started 2 agents: draining the queue entry "[Add a root `.gitignore` β¦"; draining the queue entry "[Add a `package.json` β¦"
Two of three. The third entry sat on the queue.
Why two. The fan-out is picks = open.slice(0, concurrency - activeAgents) (auto-pm.ts:922), so activeAgents read 1 at 01:20:55. activeAgentCount (daemon-runtime.ts:840) is live pids on the project plus the starting set:
for (const [key, pid] of activeAgents) { if (keyBelongsTo(key, targetProjectId) && isPidAlive(pid)) live++ }
return live + [...starting].filter(key => keyBelongsTo(key, targetProjectId)).length
The pid half is re-checked against the OS, so a dead process cannot hold a slot. The starting half is not: a key that is added on spawn and never removed β a spawn path that throws between the two, or a refused start that skips the cleanup β costs the project one slot for the rest of the daemon's life, invisibly. Not diagnosed which it was; by 01:27 no process of the earlier runs was alive, and the daemon does not log the count.
Timeline on that project: 01:03 three planners via the sweep (all DONE by 01:06, locks released); 01:06 one triage via the card's plain start (DONE 01:10); 01:20 the drain click β count 1.
Fix shape. Either log the breakdown on every stand-down/fan-out decision (live=N starting=M), so the next occurrence names itself β or make starting self-healing the way activeAgents is (a key older than the spawn timeout is dropped). Both are small; the first is what would have made this an answer instead of a question.
Repro. Not reliable yet. Three sweep-started runs, one card-started run, then a drain click on a project the panel shows idle.
π€ automated
Found dogfooding #1640/#1644/#1645 on
main(chain write-up: #1204 (comment)).What happened.
Concurrent agents: 3, three entries on the queue, no agent running on the project β the Agents panel said "No agents working right now", the last run on the project had been DONE for ten minutes. The drain's Run now reported:Two of three. The third entry sat on the queue.
Why two. The fan-out is
picks = open.slice(0, concurrency - activeAgents)(auto-pm.ts:922), soactiveAgentsread 1 at 01:20:55.activeAgentCount(daemon-runtime.ts:840) is live pids on the project plus thestartingset:The pid half is re-checked against the OS, so a dead process cannot hold a slot. The
startinghalf is not: a key that is added on spawn and never removed β a spawn path that throws between the two, or a refused start that skips the cleanup β costs the project one slot for the rest of the daemon's life, invisibly. Not diagnosed which it was; by 01:27 no process of the earlier runs was alive, and the daemon does not log the count.Timeline on that project: 01:03 three planners via the sweep (all DONE by 01:06, locks released); 01:06 one triage via the card's plain start (DONE 01:10); 01:20 the drain click β count 1.
Fix shape. Either log the breakdown on every stand-down/fan-out decision (
live=N starting=M), so the next occurrence names itself β or makestartingself-healing the wayactiveAgentsis (a key older than the spawn timeout is dropped). Both are small; the first is what would have made this an answer instead of a question.Repro. Not reliable yet. Three sweep-started runs, one card-started run, then a drain click on a project the panel shows idle.