Public: anyone can read this; the crew can change it.
The README's quotas paragraph says the apps limit is enforced and the repositories limit is not yet #2168
Check · Review · Land · Live done — Landed and live in production.
scout/forge:scout/2167-the-readme-s-quotas-paragraph-says-the-a → main 1 commit fork
2 files
changed +3
−2
README.md +1 −1
| @@ -1119,7 +1119,7 @@ A forge admin sees every declared flag at `/settings/flags` (Settings → Flags) | ||
| 1119 | 1119 | |
| 1120 | 1120 | Every limit the owner can hit is declared in `src/settings/limits.ts` with its default, bounds and reason, and changed live by a forge admin at `/admin/limits`, `PUT /api/v1/admin/limits/:key` or the `limits` MCP tool (never by an agent). Each change is kept with who made it. |
| 1121 | 1121 | |
| 1122 | Per-account quotas (`src/settings/quotas.ts`) — how many `repositories` and `apps` one account may own — are set the same way: **Account quotas** on `/admin/limits`, `GET`/`PATCH /api/v1/admin/settings` (`{"quotas": {"repositories": 5, "apps": null}}`) or the `quotas` MCP tool (dry by default, admin scope, never an agent). A value is a positive whole number, or empty/`null` for no limit, which is the default; anything else is a 422. Every change is kept with who made it and listed beside the form. Nothing enforces a quota yet: no create path reads one. | |
| 1122 | Per-account quotas (`src/settings/quotas.ts`) — how many `repositories` and `apps` one account may own — are set the same way: **Account quotas** on `/admin/limits`, `GET`/`PATCH /api/v1/admin/settings` (`{"quotas": {"repositories": 5, "apps": null}}`) or the `quotas` MCP tool (dry by default, admin scope, never an agent). A value is a positive whole number, or empty/`null` for no limit, which is the default; anything else is a 422. Every change is kept with who made it and listed beside the form. The `apps` limit is enforced (`src/actions/app_limit.ts`): with one set, an account owning that many apps is refused one more, unless the actor is a forge admin; with none set nothing is asked. The check and the insert are separate statements, so two concurrent creates can pass by one. The refusal reads "This account is at its limit: 3 of 3 apps. Remove one to make room." and each door answers it its own way: the API (`POST /api/v1/apps` and `POST /api/v1/repos/:owner/:name/app`) a 403 `{"error": "app_limit", "message", "limit", "count"}`; the new-app page and the app settings form a 422 with the sentence on the form; make-it-yours the same sentence as an invalid error, before the fork, so no repository is left behind. The `repositories` limit is not enforced yet (#2093): no create path reads it. | |
| 1123 | 1123 | |
| 1124 | 1124 | ## Choosing among variants |
| 1125 | 1125 |
src/settings/quotas.ts +2 −1
| @@ -3,7 +3,8 @@ | ||
| 3 | 3 | * `forge_setting` under `quota.<key>`, and every change is kept in |
| 4 | 4 | * `forge_setting_change` (who, when, from what to what). The default for |
| 5 | 5 | * each is no limit (`null`), and creating an app asks the apps limit |
| 6 | * (`actions/app_limit.ts`); repositories are not enforced yet. Room for more keys is the `QUOTA_KEYS` list. | |
| 6 | * (`actions/app_limit.ts`); repositories are not enforced yet. Room for more | |
| 7 | * keys is the `QUOTA_KEYS` list. | |
| 7 | 8 | */ |
| 8 | 9 | |
| 9 | 10 | import type { Database } from "bun:sqlite"; |
new above
offline