Problem
GATEWAY_MAX_CHECK_READS is a single GLOBAL per-request store-read budget for the whole fleet. The fan-out surfaces (ListObjects/CheckSet/Expand) scale it off their candidate/node caps, but a SINGLE Check over a pathologically wide union/tupleToUserset model is bounded by the flat global value.
That means one tenant with an unusually wide-but-legitimate model can force the global ceiling to be raised for everyone, weakening the abuse backstop for every other tenant. Conversely, lowering it to contain an abusive tenant penalizes well-behaved ones.
Proposal
Add a per-project (and ideally per-tenant) override for the read budget — a real feature with its own configuration surface (admin API / project config), validation (reuse the minMaxCheckReads floor), and precedence rules (override > global default). The engine already takes the budget per-operation, so the wiring is to resolve the override alongside the model in the resolver and pass it through.
Until then
The global knob plus the authz_eval_backstop_total{reason="budget"} alert (load-bearing, must be provisioned day-one) is the operational mitigation, documented in the README read-budget runbook. This issue is linked from that note.
Context: review-gate advisory on #50 / PR #62.
Problem
GATEWAY_MAX_CHECK_READSis a single GLOBAL per-request store-read budget for the whole fleet. The fan-out surfaces (ListObjects/CheckSet/Expand) scale it off their candidate/node caps, but a SINGLECheckover a pathologically wideunion/tupleToUsersetmodel is bounded by the flat global value.That means one tenant with an unusually wide-but-legitimate model can force the global ceiling to be raised for everyone, weakening the abuse backstop for every other tenant. Conversely, lowering it to contain an abusive tenant penalizes well-behaved ones.
Proposal
Add a per-project (and ideally per-tenant) override for the read budget — a real feature with its own configuration surface (admin API / project config), validation (reuse the
minMaxCheckReadsfloor), and precedence rules (override > global default). The engine already takes the budget per-operation, so the wiring is to resolve the override alongside the model in the resolver and pass it through.Until then
The global knob plus the
authz_eval_backstop_total{reason="budget"}alert (load-bearing, must be provisioned day-one) is the operational mitigation, documented in the README read-budget runbook. This issue is linked from that note.Context: review-gate advisory on #50 / PR #62.