Declaring a budget
Every endpoint names the number of queries it may run and the largest result set it may materialise. The numbers are deliberately small: a list endpoint gets one query for the page and one for its relationships, not one per row.
Measuring
The test suite enables the query log, calls the endpoint with a representative fixture, and fails when either budget is exceeded. The failure message prints the queries that ran, so the fix is visible without reproducing the test locally.
Enforcing in production
The same budget is registered as a request listener. A breach is logged with the endpoint and the query count, and the response is still served: the budget is a design guard, not a runtime kill switch. The alert is what makes the next regression visible.
Why not a query cache
Caching would have hidden the problem rather than fixing it. A cache turns a slow query into a stale answer and makes the next engineer debug two systems instead of one.