Swarm elapsed thresholds

The swarm measures idle and waiting periods from the event that started them. A slower controller pass no longer multiplies those periods by the number of minutes between passes. Actions still run during a pass: a deadline becoming due does not start another pass or interrupt one already running.

Defaults and observation windows

These durations preserve the previous behavior at a one minute cadence. The first observation counts as one, so a third observation spans two minutes and a twentieth observation spans nineteen minutes.

Decision Start event Duration or rule
Idle nudge threshold First eligible idle observation 2 minutes; equivalent to 3 observations at one minute intervals
Idle retirement First eligible idle observation 19 minutes; equivalent to 20 observations at one minute intervals
Idle with a claim health finding First eligible idle observation The existing AGENTIHOOKS_HEALTH_IDLE_TICKS threshold, default 3, reads elapsed one minute observations
Waiting on input First observation of the current prompt input_ticks derives from time spent on that prompt; existing consumers keep their thresholds
Failed retirement health finding First failed retirement attempt 2 minutes of continuing failed attempts
Dispatch seat bottleneck trigger First report naming the current bottleneck 2 minutes across reports naming the same bottleneck; the latest report must also be no more than 15 minutes old
Autoscale pending raise First decision requesting the uninterrupted raise 2 minutes before lifting the hold; subsequent increases remain limited to two seats per pass
Ledger slow probe First slow pass Still requires two consecutive slow passes; this change does not replace that streak with a timer
Early end health finding First pass that ends early on a missing pass value AGENTIHOOKS_HEALTH_EARLY_ENDS, default 3, counts consecutive passes ending early on the same value; a full pass clears it

The elapsed comparison allows 30 seconds of scheduling slack. A two minute limit can therefore be reached after 90 seconds. At exact one minute and three minute cadences, the following observations result:

Time since first idle observation One minute passes Three minute passes
0 minutes First observation First observation
2 minutes Idle nudge threshold reached No pass
3 minutes Already past nudge threshold Idle nudge threshold reached on this pass
19 minutes Idle retirement due No pass
21 minutes Already past retirement threshold Idle retirement due on this pass

These are eligibility times while all other checks permit the action. The stale heartbeat nudge has a separate ten minute silence window; it is not a two minute reminder. An agent due for idle retirement gets no stale nudge.

Configuration and inspection

No new duration setting is required. Existing settings keep their names. AGENTIHOOKS_HEALTH_IDLE_TICKS still accepts a count, but compares it with elapsed one minute observations rather than the number of controller passes. For example, 6 represents five minutes since the first idle observation, subject to scheduling slack and the next pass:

AGENTIHOOKS_HEALTH_IDLE_TICKS=6 agentihooks swarm example-swarm status --json

This changes only that invocation. Put the variable in the controller’s launch environment to configure its scheduled health passes. It does not change the fixed idle retirement or nudge durations.

For an existing agentihooks controller run installation, a three minute controller interval uses its existing environment setting:

AGENTIHOOKS_CONTROLLER_TICK_SECONDS=180 agentihooks controller run

Use this setting on the controller only. The host-scheduled swarm tick command refuses it because that scheduler runs every minute. Controller lease duration also follows the controller interval; these elapsed observation windows do not change that separate lease behavior.

Inspect the current findings and capacity decision in the same deployment environment as the running controller:

agentihooks swarm example-swarm status --json
agentihooks swarm example-swarm autoscale --json

autoscale is read only: repeated inspection does not advance a stored raise. A changed target preserves the start of an uninterrupted pending raise. An interrupted raise clears it; the next raise starts a new hold. Capacity drops still apply immediately. The two seat limit remains per pass, so slower passes can still slow the climb after the initial hold.

Holds and stored state

An active declared wait, operator activity, an outage or recovery, a ledger hold, or owned automated cleanup can hold idle decisions. Held time does not add to the stored idle observation count. The next eligible observation continues from the count retained before the hold. The master is exempt from idle retirement.

Waiting on the same input prompt retains its start time. A different prompt starts a new interval; leaving the prompt clears that input wait.

Idle and input event starts are stored separately from agent rows in Redis, with a one day TTL. Dispatch streaks and pending raises keep their start in their existing records. Existing strict row readers remain compatible. Legacy idle counts, dispatch streaks and pending raises without a start timestamp are anchored using the previous one minute assumption. This preserves progress but cannot reconstruct the historical cadence. Counts such as idle_ticks and input_ticks can jump between passes because they describe elapsed time.

The ledger probe remains an exception: two slow passes three minutes apart produce the alert at the second pass. Faster or slower sampling still affects when those two observations exist. Prompt backlog counts changes in prompt values, rather than controller passes, and is unchanged.

Troubleshooting and evidence

Symptom Check and action
A decision arrives after its nominal duration Compare the first observation with the actual pass times and check holds. No action runs between passes.
Idle counts increase by more than one Expected with a slower cadence: counts represent one minute observations spanned by elapsed time.
A health setting on a status command does not change later findings Configure the running controller’s environment; a command’s environment applies only to that invocation.
Autoscale still climbs slowly after the hold Check the two seats per pass limit, quota, ready demand and host room in the reason.
Ledger slow alert does not appear after one slow sample It requires a second consecutive slow pass.

Pull request 9274 records the implementation and cadence proofs. Its green focused run reports 13634 passing tests, and its mutation preflight passed. The elapsed cadence tests cover idle nudge and retirement at three minute intervals, input waits, idle health and the ledger probe. These runs establish regression behavior, not a production rollout.