feat(quota): meter notes on platform-scoped subjects against their author - #793
Closed
kevwilliams wants to merge 1 commit into
Closed
kevwilliams wants to merge 1 commit into
kevwilliams wants to merge 1 commit into
Conversation
…thor Notes on contacts, users and organizations belong to no project, so #792 stopped them claiming project quota. That left them unmetered entirely. Meter them against the note's author instead. spec.creatorRef is set by the mutating webhook from the authenticated user, so it can't be spoofed into another user's quota, and the quota plugin validates after mutating webhooks run, so it is always populated by the time the claim template renders. Adds a notes-per-user registration on a new resource type. It cannot reuse notes.miloapis.com/notes: the registration cache is keyed by resource type alone, so two registrations on one type would silently clobber each other. The project and user claim policies carry complementary constraints and partition note subjects between them; a unit test asserts that invariant against the shipped config so a future subject kind can't fall through either policy or match both. Requires a matching GrantCreationPolicy in the datum repo. Without a grant the bucket limit is 0 and notes are denied, so that must land first. The chainsaw tests supply the grant directly.
Merged
3 tasks
kevwilliams
added a commit
to datum-cloud/datum
that referenced
this pull request
Sep 17, 2026
…ts (#291) ## Summary Grants each user an allowance for notes on platform-scoped subjects — contacts, users and organizations. Those notes belong to no project, so milo meters them against the note's author instead of a project. Pairs with milo-os/milo#793, and **this one has to land first**: bucket limits come only from active grants and start at 0, so shipping the milo side without this grant would deny contact notes outright. ## Why no parentContext The existing project policy sets `parentContext` because a note on a project-scoped subject is created in that project's control plane, so its claim lands there and the grant has to follow. These notes are different — they're created in the core control plane, where Users also live, so the grant belongs there and the policy writes locally. That's also the branch that sets an owner reference on the trigger, so a user's grant is garbage-collected with the user. The project-scoped policies don't get that. ## The one thing needing a decision **The 1000 default is a starting point, not a researched number.** It's meant to be generous enough not to bite real usage while making the notes countable — the point of this work is that they stop being invisible, not that the limit binds. Project notes are 100, but that's per project; this is per person across every contact they touch, so the same number would be much tighter in practice. Happy to change it to whatever product thinks is right. ## Test plan - [x] `kustomize build config/services/notes.miloapis.com` renders both grant policies - [x] All top-level kustomizations still build - [ ] Not exercised against a cluster. The milo-side chainsaw tests supply an equivalent grant directly, so the mechanism is covered there; this PR is the production wiring of it.
4 tasks
Contributor
Author
|
We decided this is not needed right now in #792 |
3 tasks
kevwilliams
added a commit
to datum-cloud/datum
that referenced
this pull request
Sep 19, 2026
Reverts #291. ## Why #291 granted every user an allowance for `notes.miloapis.com/user-notes`, to meter notes on contacts against their author. The milo side that defined and claimed that resource type (milo-os/milo#793) has been closed — notes on contacts are only ever created by platform users, so there's nothing to meter. That leaves this policy minting a `ResourceGrant` per user for a resource type that no longer exists anywhere, growing with every new user. ## Blast radius None. Nothing claims `user-notes` now that milo-os/milo#793 is closed, and a grant for a resource type with no claims is inert. The project-scoped notes grant (100 per project) is untouched and still doing real work. Contact notes keep working — milo-os/milo#792 is what fixed those, and it does so by not creating a claim at all, so it needs no grant. ## Test plan - [x] `kustomize build config/services/notes.miloapis.com` renders only the project grant policy - [x] All top-level kustomizations still build - [x] No remaining references to `user-notes` in config
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.
Follow-up to #792 (stacked on it — review that one first).
Summary
#792 stopped notes on contacts, users and organizations from claiming project quota, which unblocked them but left them unmetered. This meters them against the note's author instead, so staff notes are counted and limits become possible later.
notes-per-userregistration, consumeriam.miloapis.com/Userspec.creatorRefcreatorRefis set by the mutating webhook from the authenticated user, so it can't be spoofed into someone else's quota, and the quota plugin validates after mutating webhooks run, so it's always populated by the time the claim template renders.Two things worth knowing
It needs a new resource type, not a second registration on
notes.miloapis.com/notes. The registration cache is keyed by resource type alone with no duplicate guard, so two registrations on one type would silently clobber each other.GrantCreationPolicyfornotes.miloapis.com/user-notesexists in datum would deny contact notes again — re-breaking exactly what #792 fixed. The chainsaw tests supply the grant directly, so CI here passes either way; production would not. Please don't merge until the datum policy is in place.The datum policy should omit
parentContext— notes on contacts are created in the core control plane where Users also live, so the grant is written locally, and that's the branch that sets an owner reference, so a user's grant is garbage-collected with the user.Test plan
user-noteskustomize build config/servicesrenders all three new objectstask test:unitpassestest/quota/user-notes-quotachainsaw test — not run locally, no cluster. Asserts a contact note creates a claim consuming the author's quota, that it's granted, and that no project-scoped claim is created.test/crm/note-contact-lifecyclegains a grant fixture, since its notes now consume author quota. Also unverified locally.