Parent: #1936
Problem
contributorOpenPrCap/contributorOpenIssueCap live on the per-repo repository_settings row, and the enforcement query only lists open items scoped to the SAME repo. A self-hosted install that gates multiple repos (a common topology — e.g. one operator running 3 repos on one self-host instance) has no aggregate view: an actor spreading low-volume spam/farming PRs across several gated repos in the same install never trips any single repo's cap, even though their fleet-wide open-item count is high.
This is a simpler, more immediately buildable version of the already-tracked cross-instance federation work (#1970 — opt-in federated intelligence across separate self-hosted instances, which needs real cross-instance privacy/trust design). This is cross-REPO-within-one-install: no federation, no cross-instance privacy design needed — just an aggregate query against the same database every repo on that install already shares.
Requirements
- Add an optional, install-level
globalContributorOpenItemCap (env var or a maintainer-only settings row — not per-repo, since it aggregates ACROSS repos), off by default.
- When set, check the actor's total open PR/issue count across ALL repos this install gates, in addition to (not instead of) the existing per-repo cap, in the same short-circuit block as the existing
contributorCapMatch.
- Must not require any new cross-instance networking/API — purely a same-database aggregate query.
- The existing
autoCloseExemptLogins shared exemption list (already reusable across features per its own design) should apply here too.
Deliverables
- The
globalContributorOpenItemCap setting (install-scoped, not per-repo — needs its own config surface, likely an env var or a singleton settings row mirroring global_contributor_blacklist's existing tenant-free-singleton pattern).
- An aggregate open-item-count query spanning all repos this install tracks.
- Wiring into the existing
contributorCapMatch short-circuit in src/settings/agent-actions.ts, reusing itemKind/closeKind: "contributor_cap" rather than inventing a new kind.
- Tests: an actor over the install-wide cap but under every individual repo's cap is still caught; the existing per-repo cap continues to work unchanged; off-by-default confirmed.
Acceptance criteria
- With
globalContributorOpenItemCap configured, an actor whose SUM of open items across every repo on the install exceeds the cap is caught, even if no single repo's own cap is tripped.
- Off by default — zero behavior change for a single-repo install or one that hasn't opted in.
- Reuses the existing
contributor_cap closeKind and close-message shape, not a new disposition type.
Expected outcome
A self-host operator running multiple repos on one instance gets a real fleet-wide view of contributor abuse, closing the gap where spreading low-volume farming across repos currently evades every per-repo cap.
Parent: #1936
Problem
contributorOpenPrCap/contributorOpenIssueCaplive on the per-reporepository_settingsrow, and the enforcement query only lists open items scoped to the SAME repo. A self-hosted install that gates multiple repos (a common topology — e.g. one operator running 3 repos on one self-host instance) has no aggregate view: an actor spreading low-volume spam/farming PRs across several gated repos in the same install never trips any single repo's cap, even though their fleet-wide open-item count is high.This is a simpler, more immediately buildable version of the already-tracked cross-instance federation work (#1970 — opt-in federated intelligence across separate self-hosted instances, which needs real cross-instance privacy/trust design). This is cross-REPO-within-one-install: no federation, no cross-instance privacy design needed — just an aggregate query against the same database every repo on that install already shares.
Requirements
globalContributorOpenItemCap(env var or a maintainer-only settings row — not per-repo, since it aggregates ACROSS repos), off by default.contributorCapMatch.autoCloseExemptLoginsshared exemption list (already reusable across features per its own design) should apply here too.Deliverables
globalContributorOpenItemCapsetting (install-scoped, not per-repo — needs its own config surface, likely an env var or a singleton settings row mirroringglobal_contributor_blacklist's existing tenant-free-singleton pattern).contributorCapMatchshort-circuit insrc/settings/agent-actions.ts, reusingitemKind/closeKind: "contributor_cap"rather than inventing a new kind.Acceptance criteria
globalContributorOpenItemCapconfigured, an actor whose SUM of open items across every repo on the install exceeds the cap is caught, even if no single repo's own cap is tripped.contributor_capcloseKind and close-message shape, not a new disposition type.Expected outcome
A self-host operator running multiple repos on one instance gets a real fleet-wide view of contributor abuse, closing the gap where spreading low-volume farming across repos currently evades every per-repo cap.