Skip to content

[Phase 2] standards/agent-rate-limits.json config + standard doc (single source of truth) #638

Closed

Description

@don-petry

Story

As a platform engineer,
I want add standards/agent-rate-limits.json as the machine-readable single source of truth for per-agent-type limits, with a standards/agent-rate-limits.md companion and a JSON contract test,
so that every gate and workflow reads limits from one signed-off file instead of hardcoding them in scripts.

Acceptance Criteria

  1. standards/agent-rate-limits.json exists and mirrors the shape of standards/pr-limits.json: a _schema_version, inline _note fields recording the human sign-off + rationale, a per-agent-type map of controls, and exempt-actor / exempt-label lists.
  2. Per the ADR taxonomy, each in-scope agent type carries max_concurrent_runs, max_runtime_minutes, cooldown_minutes, daily_run_budget, and a circuit_breaker (consecutive_failure_threshold + pause/backoff duration); plus an org_wide token_budget block with the 5-hour-window threshold (default 90%) and a Claude-priority flag.
  3. The config is inert on merge: values are documented as requiring human sign-off before any gate enforces them (mirroring the pr-limits sign-off gate), and no workflow reads it yet.
  4. A bats contract test asserts the file is parseable JSON, required keys are present, numeric limits are positive integers, and the token threshold is within range — mirroring the pr-limits config contract.
  5. standards/agent-rate-limits.md documents each control and cites the ADR as the decision record and, like pr-limits.md, does NOT restate the changeable numeric values in prose (it points readers at the JSON).
  6. The AGENTS.md standards table gains a row linking the new standard, keeping standards discoverable.
  7. The per-agent daily_run_budget is documented in agent-rate-limits.md as the concrete per-agent cost bound, so the epic's cost cap is traceable to a specific config key.

Tasks / Subtasks

Dev Notes

  • Mirror standards/pr-limits.json (petry-projects/.github) in spirit: it carries status: signed-off, a top-level _note with the human sign-off date + epic/gate reference, a _schema_version, an org_wide block, an (intentionally empty) per_source_caps map, and exempt_actors / exempt_labels. Reuse the exempt_actors set (dependabot[bot], @petry-projects/org-leads break-glass, etc.) so the same actors bypass rate limits.
  • The pr-limits standard doc deliberately does NOT restate the numeric cap in prose ('a changeable value stated in prose is a second place to forget to update'); the reader runs jq over the JSON. Follow that convention exactly in agent-rate-limits.md.
  • Per AGENTS.md: 'all standards and rulesets belong in .github/standards/'; the standards table at the top of AGENTS.md is the discovery index — add a row like the existing 'PR limits' row.
  • Tests: the repo uses bats under tests/ (e.g. canary_rollout.bats, test_bootstrap_new_repo.bats); TDD is mandatory per AGENTS.md (tests in the same PR). The config contract test mirrors how pr-limits.json validity is asserted.
  • Do NOT activate values: like the pr-limits config's sign-off gate (epic Enable GitHub pull request limits to cut automation-PR noise #505 gate [Phase 3 gate] Human sign-off: final PR-limit caps + exempt list + rollout scope #566), the numbers require human sign-off. The config is a data file; the gate library (Phase 3) and wiring (Phases 4-5) consume it later.

Project Structure Notes

New files land under standards/ in the target public repo, next to pr-limits.json / pr-limits.md. Test lands under tests/ per the repo bats convention.

References

  • standards/pr-limits.json (petry-projects/.github — config shape and single-source-of-truth pattern to mirror)
  • standards/pr-limits.md (petry-projects/.github — companion-doc convention: never restate numbers)
  • AGENTS.md

Likely target surface

  • standards/agent-rate-limits.json (new — machine-readable per-agent limits)
  • standards/agent-rate-limits.md (new — companion standard doc)
  • tests/test_agent_rate_limits_config.bats (new — JSON contract test)
  • AGENTS.md

Story prepared by the BMAD Scrum Master (Bob) for epic #636. Status: ready-for-dev.


⚠️ Post-ADR clarification (added 2026-08-30, after PR #995 merged — read before implementing)

The Phase 1 ADR (docs/initiatives/agent-rate-limits-adr.md, merged in f720a092) settled a contradiction that was open when this story was written. The ADR as merged is authoritative; where this story's wording predates it, follow the ADR.

  1. The 5-hour session window and the 7-day weekly_all window are FIXED windows, not rolling/sliding ones. Each carries an authoritative resets_at. Within a window, percent is monotonically non-decreasing; the only event that lowers it is the reset. Do not describe either window as "rolling" in the JSON _note fields or in agent-rate-limits.md. (The per-minute anthropic-ratelimit-* token bucket is continuously replenished — that one is genuinely not a fixed window, and is a different mechanism.)

  2. There is NO percentage resume mark. Do not add one. An earlier ADR draft proposed a half-open resume at 80% utilization; that was removed, not re-tuned, because under a fixed window a downward percentage dip cannot occur, making the mark unreachable by construction. Do not emit a resume_pct, resume_threshold, hysteresis, or equivalent key in the org_wide.token_budget block. AC Add multi-agent isolation strategy using git worktrees #2 asks for the 90% threshold and the Claude-priority flag — that is the complete set.

  3. The two breakers close on different events, so do not model them with one shared resume key:

    • session (5-hour): closes only at resets_at.
    • weekly_all (7-day): closes at resets_at or when percent < 100 - (reserve_pct_per_day * days_until_reset) stops holding — which can happen earlier because the glide-path threshold rises as days_until_reset shrinks. The threshold moves; utilization never falls. If a reserve_pct_per_day key is included, default it to 2 and mark it inert pending sign-off like every other value.
  4. weekly_scoped (per-model exhaustion) is never pause-worthy — only session and weekly_all are. If the config enumerates limit kinds, encode that distinction rather than leaving it to the consumer.

  5. AC Add coding standards & principles section to AGENTS.md #3's "inert on merge" still stands in full: no workflow reads this file in this PR.

Activity

  1. don-petry commented on Aug 30, 2026

    @don-petry
    ContributorAuthor

    Dev-Lead Implementation Plan

    Issue: #638 — [Phase 2] standards/agent-rate-limits.json config + standard doc (single source of truth)

    Scope

    Add standards/agent-rate-limits.json as the machine-readable single source of truth for per-agent-type rate limits + circuit breakers (mirroring pr-limits.json), an inert-pending-sign-off org_wide.token_budget block, a companion standards/agent-rate-limits.md that never restates the numbers, a bats contract test, and a discovery-index row in AGENTS.md — with no consumer wiring (AC #3).

    Implementation Checklist

    • standards/agent-rate-limits.json — status: provisional, top-level _note (human sign-off pending, epic Agentic Activity Circuit Breakers & Org-Wide Rate-Limiting Standard #636 gate, cites ADR), _schema_version, per-agent-type controls map (dev-lead, compliance-audit, feature-ideation, initiative-driver) with max_concurrent_runs, max_runtime_minutes, cooldown_minutes, daily_run_budget, circuit_breaker{consecutive_failure_threshold, backoff_minutes}; org_wide.token_budget (fixed 5h session + 7d weekly_all windows, pause_threshold_pct default 90, reserve_pct_per_day 2 inert, claude_priority: true, pause_worthy_kinds = session+weekly_all, weekly_scoped non-pausing); reuse exempt_actors/exempt_labels from pr-limits
    • standards/agent-rate-limits.md — companion doc citing the ADR as decision record, documents each control WITHOUT restating numbers (jq-the-JSON convention), names daily_run_budget as the concrete per-agent cost bound (AC docs: document branch protection rules, rulesets, and auto-merge policy #7)
    • AGENTS.md — add an "Agent rate limits" row to the standards discovery table
    • .github/workflows/agent-rate-limits-tests.yml — CI runner mirroring pr-limits-tests.yml so the contract test is actually enforced (AGENTS.md CI-gate mandate)

    Tests to Write

    • tests/test_agent_rate_limits_config.bats — parseable JSON; required top-level keys; each agent's numeric limits are positive integers; circuit_breaker keys present/positive; org_wide.token_budget.pause_threshold_pct within (0,100]; claude_priority boolean; weekly_scoped marked non-pause-worthy; NO resume_pct/hysteresis key exists (per post-ADR clarification); exempt lists mirror pr-limits (dependabot[bot], security)

    Post-ADR guardrails honored

    Fixed windows (not "rolling"); no percentage resume mark / resume_pct; weekly_scoped never pause-worthy; reserve_pct_per_day default 2 inert; config inert on merge (no workflow reads it).

    Test Command

    bats --print-output-on-failure tests/test_agent_rate_limits_config.bats

  2. don-petry commented on Aug 30, 2026

    @don-petry
    ContributorAuthor

    Dev-Lead: Implementation Complete

    Plan Execution

    Post-ADR clarifications honored

    Fixed windows (never called "rolling" in the token-budget block); no percentage resume mark / resume_pct / hysteresis key (guarded by a test); weekly_scoped never pause-worthy; reserve_pct_per_day default 2 kept inert; config inert on merge (no workflow reads it).

    Test Results

    $ bats --print-output-on-failure tests/test_agent_rate_limits_config.bats
    1..26
    ok 1 config file exists
    ...
    ok 16 the session threshold default is 90 (ADR §7 / AC #2)
    ok 17 claude_priority flag is boolean true (AC #2)
    ok 19 weekly_scoped (per-model) is NOT pause-worthy (ADR §2.5 / post-ADR #4)
    ok 21 there is NO percentage resume mark anywhere (post-ADR clarification #2)
    ok 22 the token-budget windows are never described as 'rolling' (post-ADR #1)
    ok 26 security is present in the exempt-label list
    
    # Full tests/ suite: all green (canary_rollout, persona_mention, bootstrap,
    # seed-template, and the new agent-rate-limits contract test).
    # Required lint: bash .dev-lead/scripts/dev-lead-lint.sh -> all checks passed.
    # markdownlint-cli2 on the new/edited markdown -> 0 issues.
    

    Files Changed

    • standards/agent-rate-limits.json (new): per-agent limits + circuit breakers + org-wide token-budget breaker; single source of truth, provisional/inert.
    • standards/agent-rate-limits.md (new): companion standard, cites the ADR, points readers at the JSON instead of restating values.
    • tests/test_agent_rate_limits_config.bats (new): JSON contract test (parseable, keys, positive-integer limits, threshold range, pause-worthy distinction, no-resume-mark / no-"rolling" guards).
    • .github/workflows/agent-rate-limits-tests.yml (new): CI gate for the config + test.
    • AGENTS.md: added the "Agent rate limits" discovery-index row.

    Notes

    • One addition beyond the literal task list: .github/workflows/agent-rate-limits-tests.yml. AC Add workflow, environment, and orchestration guidance #4 asks to "mirror the pr-limits config contract," which includes CI enforcement (pr-limits-tests.yml); AGENTS.md mandates gating bats in CI, and the repo treats an unenforced test as a defect (see the canary-rollout-tests.yml header). The workflow is a verbatim-style mirror of pr-limits-tests.yml (read-only, path-scoped, SHA-pinned). Trivial to drop if out of scope.
    • Cooldown for weekly-cron agents (compliance-audit, feature-ideation) is encoded as 0 (= n/a) rather than a faked positive value; the test asserts cooldown is a non-negative int and the other three limits are strictly positive.
    • No behavior is wired: this is the Phase-2 data file only. The gate library (Phase 3) and wiring (Phases 4–5) consume it after human sign-off.
  3. added a commit that references this issue on Aug 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions