feat(core): metered network pause-or-throttle toggle - #17
Merged
Merged
Conversation
Contributor
Coverage
Gate: passed - no coverage regression (epsilon 0.1 pp). |
pmaxhogan
enabled auto-merge (squash)
June 25, 2026 18:39
Make `skip_on_metered` configurable to either PAUSE (the V1 behaviour) or THROTTLE - keep syncing on a metered network at a reduced bandwidth cap (V2, DESIGN s17). Pacer: the optional bandwidth bucket becomes runtime-swappable via a new `Pacer::set_bandwidth_cap` (a default no-op on the trait, so the six NoopPacer impls need no change; AimdPacer overrides it). The bucket + its effective rate live behind one `Mutex<ByteGate>`; `permit_bytes` clones the bucket Arc out under a brief lock so the async acquire never holds the lock across an await, and a concurrent cap swap is safe. set_bandwidth_cap is idempotent. Install / lift / idempotency are tested. Orchestrator: holds the executor's pacer (shared via a new `with_pacer` builder, no-op default like `with_command_runner`). When the gates are open it applies the effective cap for the current network: on a metered network in Throttle mode the metered cap, otherwise the base cap. The metered gate no longer pauses in Throttle mode. A pure `effective_bandwidth_cap_mbps` + two gate tests (throttle caps + does not pause; pause still pauses + skips the cap) cover it. Settings: `metered_mode` (pause|throttle) + `metered_bandwidth_cap_mbps` threaded through the SPEC s22 `global` group; assembly shares the pacer. UI: a metered mode selector (shown when "limit on metered" is on) + a throttle bandwidth cap input, with i18n and a component test. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01WvXMHHbYGddVPpmQR2XmK1
pmaxhogan
force-pushed
the
claude/feat-metered-throttle
branch
from
June 25, 2026 18:41
e6f4b9a to
c7a3a41
Compare
pmaxhogan
added a commit
that referenced
this pull request
Jun 26, 2026
… V2+" list (C4) DESIGN s17 still listed schedule windows, pre/post shell hooks, and metered-network throttle as deferred, and the schedule-windows entry asserted "V1 does NOT ship this" - all three shipped in 0.2.0 (#12/#16/#17), plus CLI local-state inspection (#13). Annotate each "(SHIPPED 0.2.0)" + add a header note; keep the historical design text. Also note metered detection is Windows-only (conservative default on macOS/Linux). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012CyiRqk2DVwmJjEu5gcD1m
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Makes the metered-network behaviour configurable to pause (V1 default) or throttle — keep syncing on a metered network at a reduced bandwidth cap (V2, DESIGN s17). This is the toggle you asked for on the metered feature.
Design (the careful part — the pacer is safety-critical)
The pacer's optional bandwidth bucket becomes runtime-swappable via a new
Pacer::set_bandwidth_cap:NoopPacerimpls need no change; onlyAimdPaceroverrides it.Mutex<ByteGate>.permit_bytesclones the bucketArcout under a brief lock, then runs the asyncacquirewithout holding the lock across the await — so a concurrent cap swap is safe and there's no deadlock.set_bandwidth_capis idempotent (no rebuild when the rate is unchanged), so it's safe to call every cycle. The daily-quota re-init rebuilds from the current rate, keeping the two consistent.The orchestrator shares the executor's pacer (a
with_pacerbuilder, no-op default likewith_command_runner). When the gates are open it applies the effective cap for the current network — metered cap in Throttle mode, base cap otherwise — and the metered gate no longer pauses in Throttle mode.Changes
Pacer::set_bandwidth_cap+AimdPacerByteGate;MeteredModeenum + config fields; orchestratorwith_pacer+apply_bandwidth_cap+ gate change + pureeffective_bandwidth_cap_mbps.metered_mode+metered_bandwidth_cap_mbpsthreaded through theglobalgroup.Tests / gates (all green locally)
driven-core: 229 tests incl. pacer install/lift/idempotency + orchestrator throttle-caps / pause-still-pauses tests. clippy clean.driven-app: 212 tests. clippy clean.🤖 Generated with Claude Code
Generated by Claude Code