Conversation
…n (uncommitted work rescued from task/435 worktree) Agentflare-Agent: claude-code_2-1-228_harness Agentflare-Branch: wip/resource-gate
…supervisor.rs tests to stay under LOC gate Agentflare-Agent: claude-code_2-1-228_harness Agentflare-Branch: task/435 Agentflare-Item: 435
Adds `agentflare-resource-gate`, a new crate providing a process-wide, continuously-sampled host-pressure tier that gates autonomous dispatch independently of the existing per-agent `auth_db` cooldown check. **What it does:** - `signals.rs` — samples global CPU usage via a *fresh* `sysinfo::System` per call (regression guard against a Sentry-reported panic when a long-lived `System` outlives a runtime core-count change), plus a lightweight server/container/headless heuristic (`AGENTFLARE_DEPLOYMENT` env override, k8s, `/.dockerenv`, no-display-on-Linux). - `policy.rs` — pure `decide(signals, cfg) -> Policy` with tiers `Aggressive` (server/always-on) → `Normal` → `Throttled` → `Paused`, in a documented evaluation order (user override → server mode → CPU severity → CPU busy threshold), thresholds clamped so a malformed config can't silently disable or force-throttle dispatch. - `gate.rs` — a `OnceLock`-backed singleton: `init_global()` starts a 30s background sampler (idempotent, safe to call more than once), and `current_policy()` is a cheap cached read defaulting to `Normal` if never initialized. - `pool_size.rs` — the pre-existing `dashboard::concurrency` worker-pool sizing logic, relocated here as it's the same "how much can this host handle" concern (`work_max_concurrency`'s CPU+memory-aware sizing). **Integration:** `supervisor::run_discovery_tick` and `self_repair_or_gate` now take a `host_policy: Policy` parameter and skip dispatch (counting the item as `waiting`, not vanishing it) when `host_policy.blocks_dispatch()` — independent of, and alongside, the existing `is_cooling_down` agent check. `dashboard/server.rs::run` calls `init_global()` once at daemon startup and threads the live policy into both dispatch call sites. **Scope decisions:** - Battery/AC probing (present in the openhuman reference design) is deliberately deferred — agentflare's autonomous `work` runs mostly on always-on dev boxes/servers, and pulling in `starship-battery` adds a real macOS FFI dependency chain for a signal unlikely to matter. Documented in `signals.rs` as a `Policy`/`Signals` field addable later with no API break. - The per-worker concurrency semaphore described in the item's "proposed shape" (hard-cap concurrent dispatch under `Throttled`/`Paused`) is not implemented — out of scope for the "Done when" bar, which only requires `current_policy()` existing and consulted by both dispatch paths plus a CPU-pressure test proving it blocks dispatch. Left as a natural follow-up. - `src/supervisor.rs`'s 3 new `host_gate_tests` were split into `src/supervisor_host_gate_tests.rs` (via `#[path]`) purely to stay under the repo's 1500-line LOC gate — no logic change. - `crates/agentflare-jobs/src/supervisor.rs` had picked up an unrelated `task/440` dead-code fix borrowed for local clippy testing (its own diff said "will be reverted") — reverted back to master's version; that fix belongs to `task/440`, not this item. **Verification:** `cargo test -p agentflare --bin agentflare supervisor::` — 22/22 passed including the 3 new host-gate tests. `cargo test -p agentflare-resource-gate` — 23/23 passed. `cargo clippy -p agentflare -p agentflare-resource-gate --all-targets -- -A unsafe_code -A clippy::pedantic` — zero warnings. A full `--workspace -D warnings` clippy run is blocked by the pre-existing (master, Windows-only) `agentflare-jobs` dead-code/unused-import issue that `task/440` already fixes separately — intentionally left untouched rather than folding an unrelated fix into this PR. This branch also recovers uncommitted work-in-progress that was sitting in this item's worktree from an earlier, incomplete session (never committed, discovered during an unrelated branch/worktree cleanup pass) — the crate and integration above are that work, finished and verified. Agentflare-Agent: claude-code_2-1-228_harness Agentflare-Branch: task/435 Agentflare-Item: 435
|
Warning Review limit reachedYou’ve reached a temporary PR review limit under our Fair Usage Limits Policy. Next review available in: 8 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (5)
📝 WalkthroughWalkthroughThe PR adds the ChangesHost Resource Gate
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant DashboardServer
participant ResourceGate
participant Supervisor
participant WorkQueue
DashboardServer->>ResourceGate: current_policy()
ResourceGate-->>DashboardServer: Policy
DashboardServer->>Supervisor: run_discovery_tick(..., Policy)
Supervisor->>WorkQueue: enqueue work when policy allows
Supervisor-->>DashboardServer: report dispatched or waiting items
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/agentflare-resource-gate/src/config.rs`:
- Around line 25-35: Validate the threshold ordering in GateConfig::from_env by
restoring the default threshold pair when cpu_busy_threshold_pct >=
cpu_severe_pct, rather than relying only on individual range clamping. Add the
same guard in policy::decide because GateConfig fields are public, preserving
the intended Normal, Throttled, and Paused tiers. Add tests covering inverted
and equal thresholds.
In `@src/supervisor.rs`:
- Around line 534-538: Update the self-repair review flow around the dispatch
result and run_review_sweep so cooldown and host-policy deferrals return a
distinct deferred outcome rather than false/skipped. Add
ReviewSweepResult.waiting, increment it for retryable deferrals including
host_policy.blocks_dispatch(), and update the dashboard log to report waiting;
add throttled and paused self-repair tests covering these cases.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 415efb6f-56e8-4408-bc61-2c6825d1fa86
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (12)
Cargo.tomlcrates/agentflare-resource-gate/Cargo.tomlcrates/agentflare-resource-gate/src/config.rscrates/agentflare-resource-gate/src/gate.rscrates/agentflare-resource-gate/src/lib.rscrates/agentflare-resource-gate/src/policy.rscrates/agentflare-resource-gate/src/pool_size.rscrates/agentflare-resource-gate/src/signals.rssrc/dashboard/mod.rssrc/dashboard/server.rssrc/supervisor.rssrc/supervisor_host_gate_tests.rs
💤 Files with no reviewable changes (1)
- src/dashboard/mod.rs
work/supervisor on CPU/battery pressure…ed CPU thresholds, defer instead of skip Three fixes on top of the resource-gate work: - The host-gate test module used a #[path] override with a '..' traversal (src/supervisor/tests/../../). Windows resolved it lexically, but Linux walks the real path and those intermediate directories don't exist, so fmt/clippy/build all failed in CI. Moved the file to the location Rust's default module resolution already looks for and dropped #[path] entirely. - policy::decide clamped cpu_busy_threshold_pct and cpu_severe_pct to 0..100 independently, which still admits an inverted pair (busy >= severe). That collapses the tier ladder -- every reading above severe pauses before it can be judged merely busy, making Throttled unreachable. GateConfig's fields are public, so the ordering guard has to live in decide() rather than only in from_env(). Falls back to the shared default pair. - self_repair_or_gate returned a bool, so a cooldown or host-pressure block was counted as 'skipped' -- which reads to an operator as a decision that won't be revisited, when in fact the next sweep retries it. Replaced with a SelfRepairOutcome enum and added ReviewSweepResult.waiting, mirroring DiscoveryTickResult.waiting from item #82. Agentflare-Agent: claude-code_2-1-228_agent Agentflare-Branch: task/435 Agentflare-Item: 435
…, not just in decide() CodeRabbit's config.rs finding asked for the ordering guard in GateConfig::from_env as well, which the previous commit only added to policy::decide. That was the weaker half: env vars are the actual user-facing input path, so from_env could hand back a config whose threshold pair disagreed with what the gate would really enforce -- misleading to anything else reading those fields (a log line, a future dashboard tile), even though decide() recovered internally. Extracted the clamp-and-order logic into GateConfig::normalized() so there is one implementation, applied at the env boundary and re-applied (idempotently) in decide() -- still needed there because the fields are public and a hand-built GateConfig never passes through from_env. Agentflare-Agent: claude-code_2-1-228_agent Agentflare-Branch: task/435 Agentflare-Item: 435
Host resource gate for autonomous dispatch (item #435)
Adds
agentflare-resource-gate, a new crate providing a process-wide,continuously-sampled host-pressure tier that gates autonomous dispatch
independently of the existing per-agent
auth_dbcooldown check.What it does:
signals.rs— samples global CPU usage via a freshsysinfo::Systempercall (regression guard against a Sentry-reported panic when a long-lived
Systemoutlives a runtime core-count change), plus a lightweightserver/container/headless heuristic (
AGENTFLARE_DEPLOYMENTenv override,k8s,
/.dockerenv, no-display-on-Linux).policy.rs— puredecide(signals, cfg) -> Policywith tiersAggressive(server/always-on) →Normal→Throttled→Paused, in adocumented evaluation order (user override → server mode → CPU severity →
CPU busy threshold), thresholds clamped so a malformed config can't
silently disable or force-throttle dispatch.
gate.rs— aOnceLock-backed singleton:init_global()starts a 30sbackground sampler (idempotent, safe to call more than once), and
current_policy()is a cheap cached read defaulting toNormalif neverinitialized.
pool_size.rs— the pre-existingdashboard::concurrencyworker-poolsizing logic, relocated here as it's the same "how much can this host
handle" concern (
work_max_concurrency's CPU+memory-aware sizing).Integration:
supervisor::run_discovery_tickandself_repair_or_gatenow take a
host_policy: Policyparameter and skip dispatch (counting theitem as
waiting, not vanishing it) whenhost_policy.blocks_dispatch()—independent of, and alongside, the existing
is_cooling_downagent check.dashboard/server.rs::runcallsinit_global()once at daemon startup andthreads the live policy into both dispatch call sites.
Scope decisions:
deliberately deferred — agentflare's autonomous
workruns mostly onalways-on dev boxes/servers, and pulling in
starship-batteryadds a realmacOS FFI dependency chain for a signal unlikely to matter. Documented in
signals.rsas aPolicy/Signalsfield addable later with no API break.shape" (hard-cap concurrent dispatch under
Throttled/Paused) is notimplemented — out of scope for the "Done when" bar, which only requires
current_policy()existing and consulted by both dispatch paths plus aCPU-pressure test proving it blocks dispatch. Left as a natural follow-up.
src/supervisor.rs's 3 newhost_gate_testswere split intosrc/supervisor_host_gate_tests.rs(via#[path]) purely to stay underthe repo's 1500-line LOC gate — no logic change.
crates/agentflare-jobs/src/supervisor.rshad picked up an unrelatedtask/440dead-code fix borrowed for local clippy testing (its own diffsaid "will be reverted") — reverted back to master's version; that fix
belongs to
task/440, not this item.Verification:
cargo test -p agentflare --bin agentflare supervisor::—22/22 passed including the 3 new host-gate tests.
cargo test -p agentflare-resource-gate— 23/23 passed.cargo clippy -p agentflare -p agentflare-resource-gate --all-targets -- -A unsafe_code -A clippy::pedantic— zero warnings. A full--workspace -D warningsclippyrun is blocked by the pre-existing (master, Windows-only)
agentflare-jobsdead-code/unused-import issue that
task/440already fixes separately —intentionally left untouched rather than folding an unrelated fix into this
PR.
This branch also recovers uncommitted work-in-progress that was sitting in
this item's worktree from an earlier, incomplete session (never committed,
discovered during an unrelated branch/worktree cleanup pass) — the crate
and integration above are that work, finished and verified.
Summary by CodeRabbit
New Features
Bug Fixes