Admission control

unYOLO applies one admission controller before creating durable Agent V1 operations or approval notifications. It exists so that a looping agent cannot fill the operator inbox with thousands of pending approvals or exhaust the durable store.

Defaults

Without configuration, the controller allows 60 submissions per client per minute, 25 active and 10 pending operations per client, 512 active operations globally, and 64 executing operations globally.

Stream, sealed payload, and pending-grant stores enforce independent global and per-client storage caps on top of these.

Ordering

Authentication, request validation, and idempotent replay all happen before quota charging. A replayed request that returns an existing operation does not consume a slot, so a client retrying correctly with a stable request ID is not penalised for the retry.

A refusal returns a stable 429 with Retry-After, creates no operation and no approval, and does not consume another slot.

Availability under load

Cancellation, operator decisions, liveness, and readiness do not pass through submission admission.

That separation is the point of the design. During an overload, the operations you need are the ones that reduce load: an operator denying a pile of pending requests, a client cancelling its own work, and the health checks that tell you what is happening. Putting those behind the same quota as new submissions would make an overloaded broker impossible to recover.

Configuration

hf-broker and gh-broker read an optional absolute path from HF_BROKER_ADMISSION_CONFIG and GH_BROKER_ADMISSION_CONFIG. sudo-broker accepts the same file through sudo-broker serve --admission-config. An omitted file uses the conservative defaults above.

A configured file is a closed JSON object and must define every default and global value:

{
  "requests_per_window": 60,
  "window_seconds": 60,
  "client_active": 25,
  "client_pending": 10,
  "global_active": 512,
  "global_executing": 64,
  "clients": {
    "automation-a": {
      "requests_per_window": 20,
      "window_seconds": 60,
      "active": 8,
      "pending": 4
    }
  }
}

Partial configuration is rejected. Supplying only the values you want to change is not supported, because a half-specified quota file makes the effective limits depend on which defaults happened to be current when it was written.

Validation

Startup fails on unknown client keys, duplicate or unknown JSON fields, partial values, non-positive limits, pending limits above active limits, and client active limits above the global active limit. Client override keys must exactly match configured authentication identities.

The file is bounded to 64 KiB, and its path must be absolute and normalized.

Failing startup rather than warning is consistent with how unYOLO treats policy. A quota file with a typo in a client name silently applies the default limits to that client, which is exactly the surprise you do not want to discover during an incident.

Choosing limits

The defaults suit an interactive agent doing a handful of operations a minute. Two situations justify changing them.

A batch automation client that legitimately submits in bursts needs a higher requests_per_window, and giving it a per-client override rather than raising the global default keeps the interactive clients protected.

A client you do not fully trust yet is the opposite case. Lowering its pending limit caps how many approval requests it can queue for a human, which is usually the resource that runs out first in practice.

Observing it

The metrics registry reports admitted and rejected Agent V1 submissions with stable rejection codes, along with durable pending-approval, queued-operation, and executing-operation depths.

Those queue gauges are the ones to watch. A steadily rising pending-approval depth usually means an agent is requesting things nobody intends to approve, which is a policy problem rather than a quota problem. See metrics and logs.

The submission overload drill asserts that new work receives a stable 429 while replay, cancellation, approval, and readiness remain available. It lives in authorization/admission/admission_test.go and operation/runtime/runtime_test.go. The clock drill in the same admission test asserts that a backward wall clock does not reset a rate window backward. See failure drills.

Esc

Type to search across every documentation page.