Performance budgets that survive a redesign

Most sites are fast on launch day and slow a year later. Somebody adds a chat widget, a marketing team uploads a four-megabyte banner, and a few months on the home page weighs more than the first Doom game. We stopped fighting this with advice and started fighting it with numbers.
The budget file
Every project has a small file in its repository that sets the limits:
{
"home": { "html": "30kb", "css": "40kb", "js": "60kb", "images": "400kb" },
"product": { "html": "30kb", "css": "40kb", "js": "80kb", "images": "700kb" },
"lcp": "2.0s",
"cls": "0.05"
}
The build fails if a page goes over. That is it. Nobody has to remember the rule, and a person who wants to add something heavy has to remove something else first or argue for a larger budget in a pull request.
Where the numbers come from
We measure the pages on a mid-range Android phone on a throttled connection, and set the budget slightly above what we get at launch. We review it with the client every quarter. Sometimes it goes up, usually because they have a good reason, and sometimes it goes down.
What it changed
In the last two years, the median page weight of our new sites dropped from 1.4 MB to 380 KB. The budgets also changed how we design. When every image costs something, you stop using five photographs where one will do, and the page gets better.