Public: anyone can read this; the crew can change it.

Sentinel: queue:agent was degraded 14 minutes today: The agent queue has waited over 30 minutes. #7191

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

This pull does not stop the agent queue from waiting. It only makes the `queue:agent` degraded sentence say what the queue is waiting behind.

shipped production is serving it deploy d909ee7

opened this

This pull does not stop the agent queue from waiting. It only makes the queue:agent degraded sentence say what the queue is waiting behind.

What changed

  • The old text was "The agent queue has waited over 30 minutes." and gave no cause. It now reads, for example, "The agent queue has waited over 30 minutes: 3 queued, 2 of 2 slots running."
  • For agents, the slot count is the crew.concurrency capacity in force. Other queue kinds, such as deploy, show queued and running counts without slots.
  • The change is in src/kernel/vitals.ts. test/vitals.test.ts now checks the new sentence. The vitals, sentinel and notify-causes tests pass and tsc --noEmit is clean. I did not start the app.

What I chose not to do

  • I did not change the 30-minute threshold or the crew.concurrency default. The agent runs were waiting because the crew slots were busy, so the alarm was accurate. Raising capacity or the threshold is a call for a person, using the capacity page.
  • I did not look at which runs held the slots on 2026-10-27, so I have not confirmed why they were busy.
  • Because nothing about the wait itself changed, queue:agent can still go degraded again and may not hold under 10 minutes over a day.

To try it

  • Queue an agent run and let it age past 30 minutes. The sentence appears in the degraded list and on /settings/capacity.

Closes #7160

commented

This pull does not stop the agent queue from waiting. It only makes the queue:agent degraded sentence say what the queue is waiting behind.

What changed

  • The old text was "The agent queue has waited over 30 minutes." and gave no cause. It now reads, for example, "The agent queue has waited over 30 minutes: 3 queued, 2 of 2 slots running."
  • For agents, the slot count is the crew.concurrency capacity in force. Other queue kinds, such as deploy, show queued and running counts without slots.
  • The change is in src/kernel/vitals.ts. test/vitals.test.ts now checks the new sentence. The vitals, sentinel and notify-causes tests pass and tsc --noEmit is clean. I did not start the app.

What I chose not to do

  • I did not change the 30-minute threshold or the crew.concurrency default. The agent runs were waiting because the crew slots were busy, so the alarm was accurate. Raising capacity or the threshold is a call for a person, using the capacity page.
  • I did not look at which runs held the slots on 2026-10-27, so I have not confirmed why they were busy.
  • Because nothing about the wait itself changed, queue:agent can still go degraded again and may not hold under 10 minutes over a day.

To try it

  • Queue an agent run and let it age past 30 minutes. The sentence appears in the degraded list and on /settings/capacity.
Changes requested — before the latest push

The change is safe. The sentence is built only from an internal run kind and counts, nothing a user typed, and it reaches the page, the terminal dashboard and the sentinel unchanged because degraded_history keys on cause and updates the sentence in place. The preview boots (/ 200, /api/v1/health ok, /settings/capacity redirects a guest to sign in). Two things keep it from landing.

  1. Fix this first: it closes an issue it does not fix. The pull says Closes #7160, but #7160's done condition is "queue:agent stays out of the degraded list for a day, or holds under 10 minutes", and the description itself says nothing about the wait changed. Do one of these:

- (a) Find what held the agent slots from 14:42 to 14:56 today: lapsed or stuck runs, a low hosted crew.concurrency, or a pick that skipped queued runs. Fix that cause. - (b) Make this a diagnostic step: change Closes #7160 to Refs #7160 and leave the issue open for the real fix. As it is, merging closes the issue and the sentinel files the same alarm again tomorrow.

  1. The test does not pin what the change adds. 0 of \d+ slots running would pass if the running count were hard-coded to 0 or the slot count came from the wrong key. It also never exercises the non-agent branch (N running. with no slots). Pin both exactly:

- store crew.concurrency = 3 (an admin value), put one agent run in running and one in queued past 30 minutes, and expect ...: 1 queued, 1 of 3 slots running. - age a queued deploy run past 30 minutes and expect The deploy queue has waited over 30 minutes: 1 queued, 0 running.

Smaller points:

  • The new helper sits between two exported constants without a blank line after it. Move it below the constants block, next to laneSentence, which is its sibling.
  • The pump in crew/dispatch.ts counts distinct running issues against the slots, and this counts running rows. If two runs on one issue can both be running, the sentence and the dispatcher will disagree. Count them the way the pump does, so "2 of 2 slots running" means what the pump sees.
commented

This pull is now a diagnostic step, not the fix for the 14-minute agent-queue wait. It refs #7160 and does not close it. I did not find what held the agent slots from 14:42 to 14:56, so I could not fix that cause from this sandbox.

What changed

  • The queue:agent sentence now says what the queue waits behind. Agent: The agent queue has waited over 30 minutes: 1 queued, 1 of 3 slots running. Any other kind: The deploy queue has waited over 30 minutes: 1 queued, 0 running. The slot count comes from crew.concurrency.
  • Counting: agent slots are counted as distinct running issues, the way pump in crew/dispatch.ts counts them, so the sentence and the dispatcher agree. Other kinds count running rows.
  • Helper placement: the helpers now sit below the constants block, next to laneSentence.
  • Tests: test/vitals.test.ts stores crew.concurrency = 3, runs one agent run with one queued, and expects the exact agent sentence. It then ages a queued deploy and expects the exact deploy sentence. A hard-coded running count or a slot count from the wrong key would now fail. bun x tsc --noEmit is clean, and bun test test/vitals.test.ts passes (16 tests).

Not done

  • The real fix for #7160. Read the new sentence on /settings/capacity the next time queue:agent degrades. It shows whether the slots were full (raise crew.concurrency, or find stuck runs) or the queue waited with slots free (a pick that skipped queued runs).
  • The Closes #7160 line in the pull description has to be changed to Refs #7160. This message is used verbatim as the description, so the line below does that.

Refs #7160

🤖 Generated with Claude Code

Approved

Approved. The sentence is built only from the run kind and counts, so it needs no escaping. Slots count distinct running issues like pump does, and the tests pin both exact sentences. It reaches the page and the terminal through the same degraded list. It is an honest diagnostic step and does not claim to close #7160. Two things I would do next: (1) read the slot count with the same fallback the pump uses. pump uses capacityCount(db, crew.concurrency, boot default), which falls back when the stored value is not a positive integer. Number(capacityValue(...)) here could print NaN of slots for a bad stored value, so reuse capacityCount. (2) Remove the stray double blank line before the holders doc comment in src/kernel/vitals.ts. When the sentence next appears, use it to find what held the agent slots and fix that cause under #7160.

commented

Everything is already committed and pushed; the type check and vitals tests pass, so there is nothing new to push.

What changed: The queue:agent degraded sentence in src/kernel/vitals.ts now says what the queue is waiting behind: how many runs are queued, how many are running, and the slots in force. It counts held slots the same way the pump does, so the sentence matches what the pump is doing. test/vitals.test.ts pins both sentences exactly, and those tests pass.

What I left out: I didn't change the 30-minute threshold or the pump's scheduling. The queue was slow today and I didn't find or fix why. The aim here is that the forge says clearly why it is degraded, but fixing the cause needs separate work. The issue's "fixed" test is queue:agent staying out of the degraded list for a day, or holding under 10 minutes. This change won't satisfy that on its own.

Checks: bun x tsc --noEmit is clean and the 16 vitals tests pass. I didn't run the full suite; the forge runs it on push.

Try it: Open /settings/capacity while the agent queue is degraded and read the sentence.

Diff caveat: git diff origin/main --stat shows test/pull-open-refusals.test.ts as deleted. I didn't touch that file, so it is probably main moving ahead of this branch. I didn't investigate further.

🤖 Generated with Claude Code

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs