Skip to content

Commit cb0a7c0

Browse files
scotwellsclaude
andcommitted
docs(quota): quota enforcement enhancement (#171)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 89126ef commit cb0a7c0

1 file changed

Lines changed: 253 additions & 0 deletions

File tree

  • docs/compute/development/enhancements/quota-enforcement
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
---
2+
status: provisional
3+
stage: alpha
4+
latest-milestone: "v0.x"
5+
---
6+
7+
<!--
8+
TODO (datum-cloud/enhancements process — not yet done):
9+
- Open a tracking issue in datum-cloud/enhancements and link it here. The doc's
10+
final location (area directory + short title) is decided in that issue.
11+
- If this lands in the enhancements repo, place it under the compute area, e.g.
12+
`enhancements/compute/quota-enforcement/README.md`.
13+
- Assign the PR to sponsoring approvers before moving status -> implementable.
14+
15+
Status note: management-plane enforcement is already IMPLEMENTED; the edge and
16+
flat single-tenant designs are PROPOSED. Overall status is kept `provisional`
17+
until the proposed portion is approved.
18+
-->
19+
20+
# Quota Enforcement Across Compute Deployments
21+
22+
- [Summary](#summary)
23+
- [Motivation](#motivation)
24+
- [Goals](#goals)
25+
- [Non-Goals](#non-goals)
26+
- [Proposal](#proposal)
27+
- [User Stories](#user-stories)
28+
- [Notes/Constraints/Caveats](#notesconstraintscaveats)
29+
- [Risks and Mitigations](#risks-and-mitigations)
30+
- [Design Details](#design-details)
31+
- [Where claims live decides how grants are observed](#where-claims-live-decides-how-grants-are-observed)
32+
- [Claims route to the owning ledger](#claims-route-to-the-owning-ledger)
33+
- [Flat single-tenant identity](#flat-single-tenant-identity)
34+
- [Access prerequisites](#access-prerequisites)
35+
- [Production Readiness Review Questionnaire](#production-readiness-review-questionnaire)
36+
- [Feature Enablement and Rollback](#feature-enablement-and-rollback)
37+
- [Monitoring Requirements](#monitoring-requirements)
38+
- [Dependencies](#dependencies)
39+
- [Scalability](#scalability)
40+
- [Troubleshooting](#troubleshooting)
41+
- [Implementation History](#implementation-history)
42+
- [Drawbacks](#drawbacks)
43+
- [Alternatives](#alternatives)
44+
- [Infrastructure Needed](#infrastructure-needed)
45+
46+
## Summary
47+
48+
Customers should be able to run quota-enforced Instances on **any** Datum deployment —
49+
the central management plane, an edge cell, or a flat single-tenant cluster. Today they
50+
can't: enabling quota anywhere but the management plane either silently never evaluates
51+
(claims recorded where the quota system never reads them) or crashes compute-manager
52+
outright. This enhancement makes enforcement work in all three deployments, so an
53+
Instance is gated on a real quota grant wherever it runs. The single organizing idea is
54+
that a quota claim is created in — and read from — the control plane that owns the
55+
project's quota ledger, and how a grant is observed follows from where that ledger sits.
56+
57+
## Motivation
58+
59+
Quota is how the platform bounds what customers can consume. If it only works in the
60+
central management plane, then every deployment closer to the customer — edge cells and
61+
single-tenant clusters — either runs ungated or can't run compute-manager at all. The
62+
crash on edge cells is a hard blocker to standing compute up there. Making enforcement
63+
portable across deployments is what lets quota-bearing products ship beyond the
64+
management plane.
65+
66+
### Goals
67+
68+
- Enforce quota on Instances in all three deployments: management plane, edge cell, flat
69+
single-tenant.
70+
- compute-manager starts and stays healthy with quota enabled in every deployment (no
71+
startup crash).
72+
- An Instance is gated until its quota is actually granted, and ungated promptly once it
73+
is.
74+
75+
### Non-Goals
76+
77+
- WorkloadDeployment-level quota (this covers Instance-level claims only).
78+
- A live claim watch at the edge (deferred — see [Alternatives](#alternatives)).
79+
- Cleanup or migration of claims written to the wrong cluster before the shipped fix.
80+
- Changes to the quota evaluator itself; this enhancement produces claims and observes
81+
grants, it does not decide them.
82+
83+
## Proposal
84+
85+
The deployments differ in exactly one way that matters: **where an Instance's
86+
ResourceClaim lives**, and from that, how a grant is observed.
87+
88+
| Deployment | Where ResourceClaims live | How quota is enforced |
89+
|---|---|---|
90+
| **Management plane** | Per-project Milo control planes the manager already engages | Live watch on those claims (shipped) |
91+
| **Edge cell** | Remote Milo — one control plane per project, not on the cell | Claim written to the owning project; grant observed via the always-on backoff reconcile — no live watch |
92+
| **Flat single-tenant** | Co-located on the one cluster | Live watch on the local claims |
93+
94+
In every case a claim is created in, and read from, the control plane that owns the
95+
project's quota ledger — write and read must be the same ledger, or grants are never
96+
seen. Enforcement has an always-on backoff floor (a pending Instance's reconcile re-runs
97+
on a backing-off schedule and re-checks its claim); at the edge that floor is the sole
98+
liveness mechanism, and everywhere else it backstops the live watch.
99+
100+
### User Stories
101+
102+
- As an operator, I stand up compute-manager on an edge cell with quota enabled; it
103+
starts cleanly, and customer Instances there are gated on grants from their projects'
104+
quota ledgers back in the platform.
105+
- As an operator, I run a flat single-tenant cluster with quota co-located; Instances are
106+
gated on grants from the local ledger, with the cluster's single project named in
107+
configuration.
108+
109+
### Notes/Constraints/Caveats
110+
111+
- **Flat single-tenant identity.** A flat deployment may not run the platform layer that
112+
derives a claim's project from namespace-ownership labels, so it names its single
113+
project explicitly in configuration and attributes every claim to it.
114+
- **Cell-wide Instance name uniqueness (flat mode).** See the known limitation under
115+
[Drawbacks](#drawbacks) — in flat mode Instance names must be unique across the whole
116+
cell.
117+
118+
### Risks and Mitigations
119+
120+
- **Edge grant latency.** With no live edge watch, a grant is observed on the backoff
121+
schedule (seconds, backing off), not instantly. Accepted as the tradeoff of deferring
122+
the edge watch; correctness is unaffected (an Instance stays gated until granted).
123+
- **Missing edge access to the remote ledger.** If a cell can't reach its projects'
124+
ledgers, its Instances stay gated until access is fixed — correct (never a bypass), but
125+
it blocks scheduling and shows up as recurring reconcile errors rather than one obvious
126+
failure.
127+
- **Flat-mode name collision.** Same-named Instances in different namespaces contend for
128+
one claim; mitigated by the cell-wide-uniqueness rule until claim identity is
129+
namespace-qualified.
130+
131+
## Design Details
132+
133+
### Where claims live decides how grants are observed
134+
135+
A **live** claim watch runs only where the claims sit on a cluster the manager already
136+
engages — the management plane's per-project control planes, and a flat single-tenant
137+
cluster's local API. An edge cell's claims are remote and split per project, so it runs
138+
no live watch. That also removes the startup crash: the edge's local cluster does not
139+
serve the quota API and should never have been asked to watch that kind. The rule is
140+
simply: watch claims live only where a cluster the manager already engages serves the
141+
quota API; determining this must fail loud rather than silently resolve to "off."
142+
143+
### Claims route to the owning ledger
144+
145+
Creating, reading, and deleting an Instance's claim targets the control plane that owns
146+
the project's quota ledger — the project control plane for management plane and edge, the
147+
local cluster for flat single-tenant. At the edge this routing doubles as the liveness
148+
mechanism: each backoff reconcile creates-or-reads the remote claim and checks whether it
149+
has been granted.
150+
151+
### Flat single-tenant identity
152+
153+
Because a flat deployment may lack the platform namespace-ownership layer, it takes its
154+
project identity from configuration and attributes every claim to that one project. If
155+
local quota is enabled without a configured project, the deployment refuses to start
156+
rather than emit claims the evaluator can't attribute.
157+
158+
### Access prerequisites
159+
160+
Each deployment needs only the access for the operations it performs, granted
161+
platform-side (not from this repository):
162+
163+
- **Edge cell:** create/read/delete on the remote per-project claims — but no list/watch,
164+
since it runs no live watch, and no project-discovery permission.
165+
- **Flat single-tenant:** access to the co-located quota API on its own cluster.
166+
- **Management plane:** the existing provider-cluster watch is unchanged.
167+
168+
## Production Readiness Review Questionnaire
169+
170+
<!-- Trimmed to the subsections relevant at alpha, following the precedent of other
171+
compute enhancements. Beta-targeted subsections (rollout/upgrade/rollback planning) are
172+
deferred. -->
173+
174+
### Feature Enablement and Rollback
175+
176+
- [ ] Feature gate
177+
- [x] Other
178+
- Enablement is by deployment configuration, not a global gate: a deployment enforces
179+
quota when it is configured with access to a quota ledger (and, for flat
180+
single-tenant, a configured project). No configuration means quota is not enforced.
181+
- Enabling/disabling requires no control-plane downtime; it takes effect on
182+
compute-manager restart with the changed configuration.
183+
- Rollback is removing the quota configuration; enforcement stops and Instances are no
184+
longer gated on grants.
185+
186+
### Monitoring Requirements
187+
188+
- [x] API .status
189+
- The Instance's quota-granted status condition tells an operator whether an Instance is
190+
gated or granted. An Instance stuck ungated indicates quota is pending or a ledger it
191+
can't reach.
192+
193+
### Dependencies
194+
195+
- Milo quota evaluator and the per-project (or local) quota ledgers it serves — the
196+
authority that grants or denies claims. If unavailable, claims are not granted and
197+
Instances stay gated (no bypass).
198+
- Platform-side access grants (see [Access prerequisites](#access-prerequisites)).
199+
200+
**Open verification item.** It is not yet confirmed that Milo's quota evaluator actually
201+
grants a flat single-tenant claim attributed to the configured project — i.e. that the
202+
project is entitled in a co-located ledger. This is platform-side behavior, testable only
203+
in a running deployment, and must be verified before relying on flat single-tenant
204+
enforcement.
205+
206+
### Scalability
207+
208+
- The edge path adds no live watch, so it introduces no per-project watch fan-out; its
209+
only added calls are the per-Instance claim create/read on the backoff schedule.
210+
211+
### Troubleshooting
212+
213+
- **Instances stuck ungated on an edge cell:** confirm the cell's create/read access to
214+
its projects' remote ledgers, and that those projects are entitled so claims are
215+
granted rather than left pending.
216+
- **Instances stuck ungated in flat single-tenant:** confirm a project is configured and
217+
that the local evaluator grants claims attributed to it (see the open verification item
218+
under [Dependencies](#dependencies)).
219+
220+
## Implementation History
221+
222+
- Management-plane claim routing and the live watch on project control planes:
223+
**implemented** (verified 2026-05-26).
224+
- Edge cell (no live watch, backoff-only) and flat single-tenant (co-located watch,
225+
configured project): **proposed** here; edge fixes the startup crash.
226+
227+
## Drawbacks
228+
229+
- Edge enforcement observes grants on the backoff schedule, not instantly — a latency
230+
cost relative to a live watch.
231+
- Flat single-tenant carries an operator constraint until claim identity is
232+
namespace-qualified: **Instance names must be unique across the whole cell**, because a
233+
claim's identity derives from its Instance's name and all of a project's claims share
234+
one space, so two same-named Instances in different namespaces would collide on one
235+
claim.
236+
237+
## Alternatives
238+
239+
- **A live edge watch via a per-project-control-plane forwarder***deferred*. It means
240+
one watch per project control plane a cell serves (fan-out that grows with projects),
241+
and the always-on backoff already delivers grants within seconds, so the machinery
242+
isn't worth it now. Revisit if edge grant latency ever becomes a product concern.
243+
- **A single unified multi-cluster provider spanning the cell and the remote ledger**
244+
rejected; it destabilizes the cell's control path by breaking the single-cluster
245+
assumption its controllers rely on.
246+
- **Installing the quota API locally on edge cells** — rejected; the edge should read the
247+
authoritative ledger, not host it.
248+
249+
## Infrastructure Needed
250+
251+
- Platform-side access grants in the project (or local) control planes, per
252+
[Access prerequisites](#access-prerequisites). These cannot be granted from the compute
253+
repository and should be tracked via the enhancement's tracking issue.

0 commit comments

Comments
 (0)