Skip to content

refactor(lint): collapse type/lint budgets to a single per-rule limit - #31883

Merged
yassin-berriai merged 4 commits into
litellm_internal_stagingfrom
litellm_bump-basedpyright-budgets-50pct-9a8c
Jul 1, 2026
Merged

refactor(lint): collapse type/lint budgets to a single per-rule limit#31883
yassin-berriai merged 4 commits into
litellm_internal_stagingfrom
litellm_bump-basedpyright-budgets-50pct-9a8c

Conversation

@mateo-berri

@mateo-berri mateo-berri commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Relevant issues

The per-rule ceilings in the type and lint budgets sit at roughly 10% headroom over the recorded count, and multiple in-flight PRs are already tripping them even when they add only a handful of diagnostics. This first widens that headroom, then reworks how the budgets are represented and ratcheted so the mechanism is simpler to reason about

There are three steps, one per commit. First, every rule in basedpyright-code-budget.json gets its slack raised to at least 50% of baseline (never lowering a rule that already had more), so there is ample room for a long while. Second, the three non-frontend budget files (ruff-strict, type-discipline, basedpyright-code) drop the baseline + slack split in favour of a single limit equal to the old sum; nothing consumed the split beyond that sum, and the original baselines live in git history if anyone wants them. Third, make pre-commit and make lint-budget-update get an explicit staged-vs-working-tree contract

make lint-budget-update no longer re-captures raw counts. It lowers each rule's limit by the number of violations this branch cleared since its branch point (the merge-base with the base branch), so the granted headroom shrinks by exactly what was fixed and a limit is never raised. CI stays red for a rule only under the same two conditions as today: the codebase total is over the limit and this change is above the branch-point count (it introduced at least one net violation), so an unrelated PR is never blamed for pre-existing drift

On parity: make pre-commit chooses which checks to run from the staged index but runs the linters over the working tree, so unstaged edits and untracked files skew a green/red away from a commit of only the staged changes. There is no safe way to lint the index in place, so the script now warns when unstaged or untracked changes are present, and CLAUDE.md documents that you must stage everything first for both make pre-commit and make lint-budget-update to predict CI correctly

Pre-Submission checklist

  • I have added meaningful tests
  • My PR passes all CI/CD checks (e.g., lint, format, unit tests)
  • My PR's scope is as isolated as possible; it only solves 1 specific problem
  • I have requested a Greptile review by commenting @greptileai and received a Confidence Score of at least 4/5 before requesting a maintainer review

Screenshots / Proof of Fix

This is lint tooling, so the proof is the scripts running against the migrated budgets exactly as a developer and CI invoke them

The gates read the new limit schema and pass:

$ uv run python scripts/ruff_strict_gate.py --base origin/litellm_internal_staging
OK: every strict rule is within its codebase ceiling (base origin/litellm_internal_staging)
$ uv run python scripts/type_discipline_gate.py --base origin/litellm_internal_staging
OK: every LIT rule is within its codebase ceiling (base origin/litellm_internal_staging)

--update ratchets a limit down by exactly what the branch fixed since its branch point. Suppressing one real cast() (a genuine LIT006 fix) and re-running dropped that rule's limit by one, and by nothing else:

$ uv run python scripts/type_discipline_gate.py --update
Ratcheted LIT-rule limits down by 1 violations this branch fixed
# LIT006 limit before: 1113   after: 1112

With no branch fixes it is a no-op and never raises a limit:

$ uv run python scripts/ruff_strict_gate.py --update
Ratcheted strict-rule limits down by 0 violations this branch fixed
# ruff-strict-budget.json unchanged

The non-gating ratchet guard reads either schema, so across this migration it correctly reports the ruff and type-discipline limits as unchanged and flags only the basedpyright ceilings that genuinely rose from the 50% headroom bump (expected, and merged over by a human since the guard is advisory):

$ uv run python scripts/budget_ratchet_check.py --base origin/litellm_internal_staging
FAIL: budget limit(s) loosened vs base origin/litellm_internal_staging ...
  basedpyright-code-budget.json  reportUnknownMemberType: limit raised 29537 -> 40556
  ... (basedpyright rules only; ruff + type-discipline show none)

The pre-commit parity guard warns on unstaged/untracked changes and stays silent once everything is staged:

$ bash scripts/pre_commit_lint.sh    # with unstaged changes present
pre-commit: NOTE - unstaged/untracked changes are included in these checks but
  won't be in a commit of only your staged changes, so this result may differ from
  CI. Stage everything you intend to commit (git add) for an accurate prediction:
    ...
$ git add -A && bash scripts/pre_commit_lint.sh   # everything staged
# (no note)

Unit tests for all three gates and the ratchet guard, including the new ratchet-by-fixes arithmetic and the legacy-schema fallback:

$ uv run python -m pytest tests/test_litellm/test_type_check_gate.py tests/test_litellm/test_ruff_strict_gate.py tests/test_litellm/test_type_discipline_gate.py tests/test_litellm/test_budget_ratchet_check.py -q
46 passed

Type

🧹 Refactoring
🚄 Infrastructure

Changes

basedpyright-code-budget.json, ruff-strict-budget.json and type-discipline-budget.json now carry a single limit per rule. scripts/type_check_gate.py, scripts/ruff_strict_gate.py and scripts/type_discipline_gate.py read limit, and their --update ratchets it down by what the branch fixed vs its branch point (extracted into a small tested ratcheted_budget helper). scripts/budget_ratchet_check.py compares limits and tolerates the legacy baseline + slack schema on the base side. The Makefile help and targets are reworded, lint-budget-update now also ratchets the type-discipline budget, and the update targets fetch the base ref since they resolve the merge-base. scripts/pre_commit_lint.sh warns on unstaged/untracked changes, and CLAUDE.md documents the stage-first requirement

Slack Thread

Open in Web Open in Cursor 

The per-rule ceilings in basedpyright-code-budget.json sat at roughly 10% slack over baseline, which several in-flight PRs are already bumping into. Raise the slack on every rule to at least 50% of its baseline so there is ample headroom for a long while, while never lowering any rule that already had more generous slack (e.g. reportReturnType stays at 100).

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
@CLAassistant

CLAassistant commented Jul 1, 2026

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ mateo-berri
❌ cursoragent
You have signed the CLA already but the status is still pending? Let us recheck it.

@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

cursoragent and others added 2 commits July 1, 2026 14:26
The three non-frontend budget files (ruff-strict, type-discipline, basedpyright-code) tracked a per-rule baseline and slack whose sum was the ceiling. Nothing consumed the split beyond that sum, so this replaces both keys with a single limit equal to the old baseline + slack; the original baselines live in git history if anyone needs them.

The gate scripts and the ratchet guard now read limit directly. lint-budget-update no longer re-captures raw counts; it ratchets each rule's limit down by the number of violations this branch cleared since its branch point (the merge-base), so the granted headroom shrinks by exactly what was fixed and a limit never rises. The ratchet guard reads either schema so it still compares correctly across the migration boundary.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
…et-update

make pre-commit selects which checks to run from the staged index but runs the linters over the working tree, so unstaged edits to tracked files and untracked files skew a green/red away from what a commit of only the staged changes would produce. There is no safe in-place way to lint the index, so the script now warns when unstaged or untracked changes are present, and CLAUDE.md documents that you must stage everything first for both make pre-commit and make lint-budget-update to predict CI correctly.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
@cursor cursor Bot changed the title chore(lint): raise basedpyright per-rule slack to 50% of baseline refactor(lint): collapse type/lint budgets to a single per-rule limit Jul 1, 2026
@mateo-berri
mateo-berri marked this pull request as ready for review July 1, 2026 14:43
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai


Generated by Claude Code

@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR collapses the baseline + slack two-field schema in all three non-frontend budget files into a single limit, reworks --update across all gate scripts to ratchet limits down by exactly what the branch fixed since its merge-base (never raising them), and wires type-discipline-budget.json into make lint-budget-update for the first time.

  • Schema migration: ruff-strict-budget.json, type-discipline-budget.json, and basedpyright-code-budget.json now carry one limit per rule; gate scripts read spec["limit"] directly; budget_ratchet_check.py retains a _ceiling() helper that understands both schemas so base-side comparisons work across the migration.
  • Ratchet logic: --update no longer re-captures raw counts. The new ratcheted_budget helper computes new_limit = max(0, old_limit − max(0, base_count − current_count)), so only verified fixes shrink a ceiling and nothing ever loosens one; all three gate scripts and their test suites cover this arithmetic.
  • pre_commit_lint.sh parity warning: A new block detects unstaged or untracked changes and warns to stderr that the linters run over the working tree, so the result may diverge from CI, which only sees the committed snapshot.

Confidence Score: 5/5

Purely tooling-internal changes with no production code paths touched; all gate scripts and the ratchet guard continue to protect CI from regressions.

The change touches only lint tooling, budget JSON files, and their tests. The core ratchet arithmetic is straightforward and directly tested in all three gate suites. budget_ratchet_check.py correctly bridges the schema migration on the base side via _ceiling(). The previously noted concern about spec["limit"] lacking a legacy fallback in is_vacuous_run and ratcheted_budget is a pre-existing flag from the earlier review thread and carries no new risk after the budget files are fully migrated here.

No files require special attention.

Important Files Changed

Filename Overview
scripts/type_check_gate.py Migrated from baseline+slack to single limit; added ratcheted_budget helper; --update now lowers limits by branch fixes vs merge-base instead of re-capturing raw counts
scripts/ruff_strict_gate.py Same limit schema migration and ratcheted_budget logic as type_check_gate.py; --update now passes base_ref through from args.base
scripts/type_discipline_gate.py Migrated to single limit schema and gained ratcheted_budget; --update wired to base_ref; now included in lint-budget-update via Makefile
scripts/budget_ratchet_check.py Dropped independent baseline tracking; added _ceiling() helper that reads both new limit and legacy baseline+slack, keeping base-side comparisons safe across the migration
scripts/pre_commit_lint.sh Added unstaged/untracked detection block; warns to stderr when working tree diverges from staged index so the pre-commit result may not match CI
Makefile lint-budget-update now includes lint-type-discipline-budget-update; update targets gain lint-fetch-base dependency; help text updated
CLAUDE.md Added type-discipline-budget.json to the lint-budget-update guidance and documented the stage-first requirement for both pre-commit and budget update
tests/test_litellm/test_type_check_gate.py Updated fixtures to new limit schema; added three new tests covering ratcheted_budget: fixes lower limits, growth holds flat, and zero-clamping
tests/test_litellm/test_budget_ratchet_check.py Updated to new schema; added test confirming legacy baseline+slack format is still read correctly on the base side of a comparison
tests/test_litellm/test_ruff_strict_gate.py Updated fixtures; added test for ratcheted_budget confirming fixes reduce limits and growth leaves them flat
tests/test_litellm/test_type_discipline_gate.py Updated fixtures; added test for ratcheted_budget with fix-lowers/growth-holds behaviour

Reviews (3): Last reviewed commit: "docs(lint): list type-discipline budget ..." | Re-trigger Greptile

empty run would clear every ceiling and pass silently."""
return not counts and any(spec["baseline"] for spec in budget.values())
empty run would clear every limit and pass silently."""
return not counts and any(spec["limit"] for spec in budget.values())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 is_vacuous_run now directly accesses spec["limit"], but budget_ratchet_check.py uses a dedicated _ceiling() helper that also handles the legacy baseline + slack schema. If cmd_check were ever called with an incompletely-migrated budget (e.g. after a merge conflict that reintroduced one old-format rule), this will KeyError instead of catching the vacuous run — the safety net silently disappears.

Suggested change
return not counts and any(spec["limit"] for spec in budget.values())
return not counts and any(
spec.get("limit") or (spec.get("baseline", 0) + spec.get("slack", 0))
for spec in budget.values()
)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Declining this one deliberately. The proposed fallback would be dead code guarding a state that no normal commit, branch, or PR reaches, and the repo guidelines rule out error handling for impossible scenarios.

The merge-conflict framing doesn't actually make it reachable in a way this change would catch. If a botched conflict resolution left one rule in the old baseline + slack form, the file is simply corrupt, and evaluate() (cap = spec["limit"]) and the expected = sum(spec["limit"] ...) line right below this one would KeyError on that same rule anyway. Patching only is_vacuous_run doesn't restore a safety net; it just moves the loud failure a few lines down while pretending the file is well-formed. A KeyError naming the missing limit key is the correct, visible failure for a corrupt budget, not something to paper over.

budget_ratchet_check.py needs _ceiling() for a real reason: it reads the base-ref copy of the JSON via git show <ref>:<path>, which genuinely can predate the migration during this transition. type_check_gate.py never reads a base-ref copy; it derives base counts by running basedpyright over the base worktree, so it can't encounter the old schema. The asymmetry is intentional, not an oversight.


Generated by Claude Code

Comment thread CLAUDE.md Outdated
@mateo-berri

Copy link
Copy Markdown
Contributor Author

Thanks for the review. On the two points:

  1. CLAUDE.md omitting type-discipline-budget.json from the make lint-budget-update instruction: fixed in 24f9877, the instruction now lists all three budget files

  2. is_vacuous_run in type_check_gate.py lacking the legacy-schema fallback that _ceiling has in budget_ratchet_check.py: this one is a non-issue. is_vacuous_run only ever reads the working-tree budget via budget = json.loads(BUDGET_PATH.read_text()) in cmd_check, and the working tree always carries the new limit schema because the budget file and the script that reads it migrate together in this PR. The legacy baseline + slack fallback exists in budget_ratchet_check.py for one reason only: that guard diffs the budget file against its own copy at the merge-base (git show <ref>:<path> in _load_base), and that base-side copy can predate the migration. type_check_gate.py never reads a base-ref copy of the JSON; it only ever computes base counts by running basedpyright over the base worktree, so it cannot encounter the old schema and a fallback there would be dead code


Generated by Claude Code

@greptile-apps

greptile-apps Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Collapses the baseline + slack two-field budget schema into a single limit per rule across all three non-frontend budget files, and reworks --update in each gate script to ratchet limits down by the number of violations the branch fixed since its merge-base rather than re-capturing raw counts.

  • All three gate scripts (ruff_strict_gate.py, type_discipline_gate.py, type_check_gate.py) now read spec["limit"] directly; each gains a ratcheted_budget helper that subtracts only what the branch cleared (clamped so limits never rise), and budget_ratchet_check.py adds a _ceiling() shim to stay compatible with old-schema base refs during the transition.
  • make lint-budget-update is extended to include type-discipline alongside ruff-strict and basedpyright, and all three update targets now declare lint-fetch-base as a prerequisite so merge-base resolution has the remote ref available.
  • scripts/pre_commit_lint.sh gains a warning when unstaged or untracked changes are present, and CLAUDE.md documents the stage-first requirement for both make pre-commit and make lint-budget-update.

Confidence Score: 4/5

Pure tooling refactor with no production code changes; the gate logic is mechanically equivalent to the prior schema and is well-covered by 46 unit tests.

The ratchet arithmetic, schema migration, and pre-commit warning are all correct and well-tested. The only gaps are that the gate scripts access spec["limit"] directly without a legacy-schema fallback (unlike budget_ratchet_check.py), and CLAUDE.md omits type-discipline-budget.json from the budget-update guidance paragraph. Neither affects runtime correctness while the repository is in its post-migration state.

CLAUDE.md (guidance paragraph names only two of the three budget files now updated by make lint-budget-update); scripts/type_check_gate.py (is_vacuous_run and ratcheted_budget lack the legacy-schema fallback present in budget_ratchet_check.py).

Important Files Changed

Filename Overview
scripts/type_check_gate.py Migrated from baseline+slack to a single limit field; added ratcheted_budget helper; --update now lowers limits by what the branch fixed vs merge-base. is_vacuous_run uses spec["limit"] directly with no legacy-schema fallback (unlike budget_ratchet_check.py).
scripts/ruff_strict_gate.py Migrated ceiling from baseline+slack to limit; ratcheted_budget helper added; cmd_update now computes branch-point delta and passes base_ref correctly.
scripts/type_discipline_gate.py Migrated to single limit schema; ratcheted_budget helper added; cmd_update now takes base_ref and ratchets by branch fixes. Consistent with ruff_strict_gate.py.
scripts/budget_ratchet_check.py Simplified regression detection to a single limit comparison; _ceiling() correctly handles both new limit schema and legacy baseline+slack for cross-migration diffs. Dropped the separate baseline-raise check, which is no longer needed.
scripts/pre_commit_lint.sh Added unstaged/untracked file warning that lists affected files on stderr without blocking the check. Logic is correct: git diff --name-only + git ls-files --others --exclude-standard.
Makefile lint-budget-update now includes type-discipline; update targets gain lint-fetch-base dependency so merge-base resolution works; new lint-type-discipline-budget-update target added and declared PHONY.
CLAUDE.md Documents the stage-first requirement for pre-commit and lint-budget-update, but the budget-update guidance still only names ruff-strict and basedpyright budgets, omitting type-discipline-budget.json which is now also updated.
tests/test_litellm/test_type_check_gate.py Tests updated to new limit schema; added ratcheted_budget tests covering fix-driven decrease, growth holdflat, and zero-clamp cases. Good coverage of new semantics.
tests/test_litellm/test_budget_ratchet_check.py Tests updated for new schema; legacy baseline+slack compatibility test added; dropped tests for the now-removed baseline-raise check. Coverage matches the new contract.
type-discipline-budget.json Collapsed baseline+slack into a single limit equal to the old sum for all eight LIT rules. Values are mechanically equivalent to the prior schema.

Comments Outside Diff (1)

  1. scripts/type_check_gate.py, line 147-154 (link)

    P2 is_vacuous_run accesses spec["limit"] without a legacy fallback

    budget_ratchet_check.py explicitly supports both the old baseline + slack schema and the new limit schema via _ceiling() to handle the case where the base side of a diff predates the migration. is_vacuous_run here does not have that fallback: spec["limit"] raises KeyError on any old-schema spec. In normal flow after this PR lands, all budget files carry the new schema, so this cannot fire. But if a future revert of the budget JSON (without a corresponding script revert) happens, the gate would crash instead of failing gracefully. The inconsistency between how budget_ratchet_check.py and the gate scripts handle mixed-schema data is worth a comment, even if the practical risk today is low.

Reviews (2): Last reviewed commit: "docs(lint): list type-discipline budget ..." | Re-trigger Greptile

Comment thread CLAUDE.md
@mateo-berri

Copy link
Copy Markdown
Contributor Author

@greptileai


Generated by Claude Code

@mateo-berri

Copy link
Copy Markdown
Contributor Author

On the one remaining P2 (is_vacuous_run / ratcheted_budget reading spec["limit"] without a legacy baseline + slack fallback): I'm declining this deliberately, and it should not hold the score.

The review itself grants that it cannot fire: "In normal flow after this PR lands, all budget files carry the new schema, so this cannot fire." The only scenario it constructs is a future revert of basedpyright-code-budget.json to the old schema without a matching revert of type_check_gate.py. That is a self-inconsistent repository state that no normal commit, branch, or PR produces, because the JSON and the script that reads it live in the same tree and move together.

budget_ratchet_check.py needs _ceiling() for a concrete, reachable reason: it diffs the working-tree budget against its own copy at the merge-base via git show <ref>:<path>, and that base-side blob genuinely can predate the migration during this transition. type_check_gate.py never reads a base-ref copy of the JSON; it derives base counts by running basedpyright over the base worktree, so it structurally cannot meet an old-schema spec. Adding the fallback there would be dead code guarding an impossible state, which the repo's own guidelines rule out ("No error handling for impossible scenarios"). And in the contrived reverted-JSON case, a loud KeyError naming the missing limit key is the better failure than silently interpreting a stale baseline + slack as if it were current.

Given the deducting item is acknowledged as unable to fire and the fix would be dead code the guidelines forbid, I'd ask that this not stand as a blocker.


Generated by Claude Code

@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run


Generated by Claude Code

1 similar comment
@mateo-berri

Copy link
Copy Markdown
Contributor Author

bugbot run


Generated by Claude Code

@cursor cursor Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 24f9877. Configure here.

@yassin-berriai
yassin-berriai merged commit e141596 into litellm_internal_staging Jul 1, 2026
122 of 123 checks passed
@yassin-berriai
yassin-berriai deleted the litellm_bump-basedpyright-budgets-50pct-9a8c branch July 1, 2026 15:12
duanhongyi pushed a commit to duanhongyi/litellm that referenced this pull request Jul 2, 2026
…BerriAI#31883)

* chore(lint): raise basedpyright per-rule slack to 50% of baseline

The per-rule ceilings in basedpyright-code-budget.json sat at roughly 10% slack over baseline, which several in-flight PRs are already bumping into. Raise the slack on every rule to at least 50% of its baseline so there is ample headroom for a long while, while never lowering any rule that already had more generous slack (e.g. reportReturnType stays at 100).

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>

* refactor(lint): collapse type/lint budgets to a single per-rule limit

The three non-frontend budget files (ruff-strict, type-discipline, basedpyright-code) tracked a per-rule baseline and slack whose sum was the ceiling. Nothing consumed the split beyond that sum, so this replaces both keys with a single limit equal to the old baseline + slack; the original baselines live in git history if anyone needs them.

The gate scripts and the ratchet guard now read limit directly. lint-budget-update no longer re-captures raw counts; it ratchets each rule's limit down by the number of violations this branch cleared since its branch point (the merge-base), so the granted headroom shrinks by exactly what was fixed and a limit never rises. The ratchet guard reads either schema so it still compares correctly across the migration boundary.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>

* chore(lint): surface staged-vs-working parity for pre-commit and budget-update

make pre-commit selects which checks to run from the staged index but runs the linters over the working tree, so unstaged edits to tracked files and untracked files skew a green/red away from what a commit of only the staged changes would produce. There is no safe in-place way to lint the index, so the script now warns when unstaged or untracked changes are present, and CLAUDE.md documents that you must stage everything first for both make pre-commit and make lint-budget-update to predict CI correctly.

Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>

* docs(lint): list type-discipline budget in lint-budget-update instruction

---------

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Mateo Wang <mateo-berri@users.noreply.github.com>
yuneng-berri added a commit that referenced this pull request Jul 10, 2026
…dashboard

Add backend-lint-metrics.json with the real reportAny (implicit Any) and
reportExplicitAny (explicit Any) counts across the tree. The basedpyright budget's
limit stopped tracking the real count after its limit collapse in #31883, so a trend
dashboard reading that file went stale; this reports the real numbers instead.

scripts/lint_metrics.py regenerates it, reusing type_check_gate's counting so the
numbers match what CI measures, and a weekly workflow opens a PR when they drift.
Report-only: nothing gates on the file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants