diff --git a/AGENTS.md b/AGENTS.md index a7d7256eeb4..d0269b7f628 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -97,6 +97,7 @@ Follow these coding conventions for new/updated code (a three-line fix in a lega - Annotate every variable with `: Final` (LIT010). Unpacking and walrus targets cannot carry the annotation, so they are implicitly final. Don't rebind them. Never rebind or mutate function parameters (LIT011); `self`/`cls` attribute stores are the exception. If rebinding or in-place mutation is truly unavoidable, suppress with `# rebind-ok: ` - Qualify every TypedDict field with `ReadOnly[...]` (LIT012), which nests freely with `Required` / `NotRequired` / `Annotated` in any order. If making the key writable is truly unavoidable, suppress with `# writable-ok: ` - Comprehensions take at most one `for` clause and one `if` clause (LIT014); split stacked clauses into a helper generator, a named intermediate, or a plain loop. Suppress with `# comprehension-ok: ` only when unavoidable + - Every pydantic model must be frozen (LIT015), set via `model_config = ConfigDict(frozen=True)`, a dict-literal `model_config`, an inner `class Config`, or the class keywords. Subclasses inherit it unless they override it. If making the model mutable is truly unavoidable, suppress with `# frozen-ok: ` on the `class` line - Use dependency injection - Fully typed; no `Any` or coarse types like `dict[str, Any]` or just `dict`. Every function parameter must be strongly typed - Use tagged unions + match diff --git a/scripts/type_discipline_gate.py b/scripts/type_discipline_gate.py index 3293f32d565..fda6bb5def0 100644 --- a/scripts/type_discipline_gate.py +++ b/scripts/type_discipline_gate.py @@ -17,7 +17,8 @@ LIT012 (TypedDict field without a `ReadOnly[...]` qualifier; suppress with `# writable-ok: `), and LIT014 (comprehension with more than one `for` or `if` clause; suppress with `# comprehension-ok: ` on a spanned line, which belongs to the innermost violating comprehension spanning it and -to any single-line violating comprehension on that line) carry limits at +to any single-line violating comprehension on that line), and LIT015 +(pydantic model not frozen; suppress with `# frozen-ok: `) carry limits at or above their current count to ratchet down; LIT005 (`*-ok` suppression without a reason) is frozen at limit 0 so any net-new reasonless suppression trips the gate; LIT013 (`*-ok` suppression diff --git a/type-discipline-budget.json b/type-discipline-budget.json index 11bc9722d81..40752398386 100644 --- a/type-discipline-budget.json +++ b/type-discipline-budget.json @@ -37,5 +37,8 @@ }, "LIT014": { "limit": 369 + }, + "LIT015": { + "limit": 230 } }