fix(ci): collapse dual lint gates into one ratcheting budget - #1059
Merged
RUKAYAT-CODER merged 2 commits intoAug 27, 2026
Merged
Conversation
Remove the second ESLint gate from syntax.yml so exactly one workflow gates on lint. The remaining lint gate in ci.yml now reads its warning ceiling from a single lint-budget.json instead of a hardcoded 250, and a new lint:budget check fails both when warnings exceed the budget and when the committed budget is looser than the measured count, so the ceiling can only decrease. lint:budget:record measures and tightens the budget after a cleanup.
|
@snowrugar-beep Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Contributor
|
Thank you for contributing to the project. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1017
Closes #1016
Closes #1018
Closes #1019
Collapses the two conflicting ESLint gates into exactly one, backed by a single ratcheting warning budget in
lint-budget.json. The CILintstep now reads its ceiling from that file instead of a hardcoded 250, andsyntax.ymlloses its duplicate--max-warnings=0ESLint step (it keeps the type check). A newnpm run lint:budgetcheck fails both when warnings exceed the budget and when the committed budget is looser than the measured count, so the ceiling can only decrease;npm run lint:budget:recordmeasures and tightens it after a cleanup. The single most important design decision is to store the budget in a committed file that CI reads, making it one source of truth that a ratchet drives strictly downward.Why
ci.ymlallowed 250 lint warnings whilesyntax.ymlallowed zero — two gates on the same tool with thresholds 250 apart, so one was always theatre. The 250 cap was hardcoded in the workflow, had no ratchet, and the duplicate gate made the real policy unknowable. This change removes the contradiction, expresses the policy once, and ties it to a measured, decreasing budget.What was built
.github/workflows/syntax.yml— removed the duplicateESLint check (no-fix)step (--max-warnings=0). The workflow is now type-check only, so exactly one workflow gates on lint..github/workflows/ci.yml— theLintstep now derives its ceiling fromlint-budget.json(--max-warnings=$(node -p "require('./lint-budget.json').maxWarnings")) instead of hardcoding 250, and a newEnforce lint budget ratchetstep runsnpm run lint:budget.lint-budget.json(new) — single source of truth:{ "maxWarnings": 250 }. The initial value matches the previous hardcoded ceiling so the first run is behavior-identical; the ratchet replaces it with a measured count.scripts/lint-budget.js(new) — does not reinvent ESLint; it shells out to the existingnpx eslint, parses the JSON output, and countsseverity === 1messages.checkfails when warnings exceed the budget or when the budget is looser than the measured count (forcingrecord);recordrefuses to raise the budget and writes the measured count back. Config errors surface as exit 2.package.json— addedlint:budgetandlint:budget:record.CONTRIBUTING.md— documented the budget file, both commands, and the ratchet rule.Files modified: 4; new files: 2 (
lint-budget.json,scripts/lint-budget.js).Acceptance criteria coverage
syntax.yml; onlyci.ymlruns lint)scripts/lint-budget.js, which measures the live warning count; the committed 250 is the pre-existing ceiling and the ratchet check fails until a measured value is recorded vianpm run lint:budget:record)recordrefuses to raise the budget;checkfails when the committed budget is looser than the measured count)Deliberately deferred
npm run lint:budget/ CI run forceslint:budget:recordto capture the true count, which is the honest way to establish the number without fabricating it. This also inherently means the lint gate will keep failing until the recorded budget matches reality — consistent with the issue's premise that neither gate passes today. No code change is required afterward beyond onerecordcommit.Test plan
node --check scripts/lint-budget.js— JS syntax OKlint-budget.jsonparses (node -e "require('./lint-budget.json')") — OKnpm run lint:budget— not executed locally (per program instructions to skip build/lint/test execution on this host; requiresnode_moduleswhich is not installed here). The script's behavior is unit-readable: JSON parse of ESLint output, severity-1 count, two failure branches.npm run lint:budgetshould report over/under budget count, andnpm run lint:budget:recordshould write the measured count tolint-budget.json.Env vars / Notes
No environment variables introduced. The budget file
lint-budget.jsonis the only config surface and must be committed with every tightening.