Repository navigation
feat(ci): automate ratchet shrink-banking so caps stop outliving their files (#8584) - #8612
Merged
diegosouzapw merged 2 commits intoJul 27, 2026
Conversation
This was referenced Jul 25, 2026
…per-inference#8584) The quality ratchet is only half automatic, and it is the wrong half. Raising a cap is a manual JSON edit that takes ten seconds and is the fastest way to unblock a red PR. Lowering one requires someone to run `--update` and commit the result — and no workflow does: grepping `.github/workflows/` for `--update` finds only wiki-sync.yml (unrelated) and ci.yml's check-quality-ratchet.mjs --require-tighten (a different script against a different metric). Measured on release/v3.8.49 at 4053e23: 18 frozen files already at or under the 800-line new-file cap, the worst at 132x (src/shared/validation/schemas.ts, 19 lines carrying a 2,523 cap); the complexity ceiling walked 1794 -> 2169 across ~37 rebaseline notes with exactly one decrease (-1); "tighten via --update next cycle" written 31 times and honoured once in six weeks. A cap that outlives the code that earned it converts every completed decomposition into a growth allowance for whoever edits that file next. New job `bank-ratchet-shrinks` in nightly-release-green.yml measures the active release branch, runs the two shrink-only `--update` paths, and opens ONE always-current PR with the result. Schedule/dispatch only, deliberately not on push: banking has no latency requirement, while a per-merge run would rebuild the PR branch during merge campaigns and pay for a full ESLint walk each time. Detection stays on push (release-green); only banking is batched. The job never pushes to release/* — a human merges, so a bad measurement cannot land unreviewed. scripts/quality/verify-ratchet-bank.mjs is the hard guarantee that the automation can only ever write downward. It diffs the post-`--update` tree against HEAD and aborts the job before a commit exists — opening no PR — unless every change is a frozen/testFrozen entry lowered or removed, `count` lowered, or cognitiveComplexity.value lowered. Raising a number, adding an entry, changing cap/testCap, or deleting/rewriting a `_rebaseline_*` note all fail. A bot that could raise a cap would be strictly worse than the status quo. Verified both directions against the real baselines: --update + verifier reports 77 lowered / 14 removed / nothing raised, exit 0; hand-raising chatCore.ts to 9999 and cap to 1200 is rejected with exit 1. 22 unit tests cover each way the automation could go wrong. No product code changes.
MumuTW
force-pushed
the
chore/auto-bank-ratchet-shrinks
branch
from
July 26, 2026 09:51
2aa6bab to
8bef1c9
Compare
diegosouzapw
merged commit Jul 27, 2026
b676c5f
into
cheaper-inference:release/v3.8.49
15 checks passed
diegosouzapw
added a commit
that referenced
this pull request
Jul 27, 2026
…stryker drift
file-size: nine frozen entries could not absorb the combined result of the
31-PR train. Two distinct causes, kept apart in the baseline note on purpose:
(1) GENUINE irreducible growth at existing chokepoints —
providerLimits/auth (#8632), rateLimitManager (#8616),
models-catalog-route.test (#8610).
(2) COLLISION with #8585, which banked shrinks measured on the pre-train
release tip while 30 sibling PRs in the SAME train grew those files
again — chat/accountFallback (#8628), chatCore (#8613),
videoGeneration (#8581), imageGeneration.
Ceilings re-pinned to the post-merge tip. #8612 (also in this train) automates
shrink-banking so this self-inflicted drift stops recurring.
stryker: three covering unit tests were missing from tap.testFiles —
isLocalStreamLifecycleError-abort-shape (circuitBreaker.ts, a shared base-red
that was reddening Fast Quality Gates on every open PR),
noauth-autocombo-lockout-7623 (accountFallback.ts) and
kimi-quota-reset-recovery (auth.ts), the latter two landed with this train.
Merged
HouMinXi
pushed a commit
to HouMinXi/OmniRoute
that referenced
this pull request
Aug 2, 2026
…r files (cheaper-inference#8584) (cheaper-inference#8612) * feat(ci): automate ratchet shrink-banking on the release branch (cheaper-inference#8584) The quality ratchet is only half automatic, and it is the wrong half. Raising a cap is a manual JSON edit that takes ten seconds and is the fastest way to unblock a red PR. Lowering one requires someone to run `--update` and commit the result — and no workflow does: grepping `.github/workflows/` for `--update` finds only wiki-sync.yml (unrelated) and ci.yml's check-quality-ratchet.mjs --require-tighten (a different script against a different metric). Measured on release/v3.8.49 at d408a20: 18 frozen files already at or under the 800-line new-file cap, the worst at 132x (src/shared/validation/schemas.ts, 19 lines carrying a 2,523 cap); the complexity ceiling walked 1794 -> 2169 across ~37 rebaseline notes with exactly one decrease (-1); "tighten via --update next cycle" written 31 times and honoured once in six weeks. A cap that outlives the code that earned it converts every completed decomposition into a growth allowance for whoever edits that file next. New job `bank-ratchet-shrinks` in nightly-release-green.yml measures the active release branch, runs the two shrink-only `--update` paths, and opens ONE always-current PR with the result. Schedule/dispatch only, deliberately not on push: banking has no latency requirement, while a per-merge run would rebuild the PR branch during merge campaigns and pay for a full ESLint walk each time. Detection stays on push (release-green); only banking is batched. The job never pushes to release/* — a human merges, so a bad measurement cannot land unreviewed. scripts/quality/verify-ratchet-bank.mjs is the hard guarantee that the automation can only ever write downward. It diffs the post-`--update` tree against HEAD and aborts the job before a commit exists — opening no PR — unless every change is a frozen/testFrozen entry lowered or removed, `count` lowered, or cognitiveComplexity.value lowered. Raising a number, adding an entry, changing cap/testCap, or deleting/rewriting a `_rebaseline_*` note all fail. A bot that could raise a cap would be strictly worse than the status quo. Verified both directions against the real baselines: --update + verifier reports 77 lowered / 14 removed / nothing raised, exit 0; hand-raising chatCore.ts to 9999 and cap to 1200 is rejected with exit 1. 22 unit tests cover each way the automation could go wrong. No product code changes. * chore(skills): sync cli-backup-sync SKILL.md after rebase onto tip
HouMinXi
pushed a commit
to HouMinXi/OmniRoute
that referenced
this pull request
Aug 2, 2026
…stryker drift
file-size: nine frozen entries could not absorb the combined result of the
31-PR train. Two distinct causes, kept apart in the baseline note on purpose:
(1) GENUINE irreducible growth at existing chokepoints —
providerLimits/auth (cheaper-inference#8632), rateLimitManager (cheaper-inference#8616),
models-catalog-route.test (cheaper-inference#8610).
(2) COLLISION with cheaper-inference#8585, which banked shrinks measured on the pre-train
release tip while 30 sibling PRs in the SAME train grew those files
again — chat/accountFallback (cheaper-inference#8628), chatCore (cheaper-inference#8613),
videoGeneration (cheaper-inference#8581), imageGeneration.
Ceilings re-pinned to the post-merge tip. cheaper-inference#8612 (also in this train) automates
shrink-banking so this self-inflicted drift stops recurring.
stryker: three covering unit tests were missing from tap.testFiles —
isLocalStreamLifecycleError-abort-shape (circuitBreaker.ts, a shared base-red
that was reddening Fast Quality Gates on every open PR),
noauth-autocombo-lockout-7623 (accountFallback.ts) and
kimi-quota-reset-recovery (auth.ts), the latter two landed with this train.
MumuTW
added a commit
to MumuTW/OmniRoute
that referenced
this pull request
Aug 27, 2026
…ting every nightly bank `verifyFrozenMap` compared `_rebaseline_*` note values with `after[key] !== prev`. That is a referential comparison: correct for the string notes it was written against, wrong for the object-valued one that landed on 2026-08-11, where the merge-storm rebaseline folded four file->LOC pairs under a single note key. Two structurally identical objects off two `JSON.parse` calls are never `===`, so the verifier reported that note "rewritten" on a tree nobody had touched. Effect: `node scripts/quality/verify-ratchet-bank.mjs` exited 1 on pristine release/v3.8.51, and the `bank-ratchet-shrinks` job in nightly-release-green.yml (cheaper-inference#8612) aborts on any non-zero exit. The automation added precisely to stop caps outliving their shrinks (cheaper-inference#8584) has therefore banked nothing since 2026-08-11. Fix uses the module's own `jsonEqual()` helper, so notes are still compared verbatim -- a genuinely edited note, string or object, is still rejected. Both new tests fail without the one-line change and pass with it. Claude-Session: https://claude.ai/code/session_01WXi3P7fMBXdVyZdnEeDYwq
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…r files (cheaper-inference#8584) (cheaper-inference#8612) * feat(ci): automate ratchet shrink-banking on the release branch (cheaper-inference#8584) The quality ratchet is only half automatic, and it is the wrong half. Raising a cap is a manual JSON edit that takes ten seconds and is the fastest way to unblock a red PR. Lowering one requires someone to run `--update` and commit the result — and no workflow does: grepping `.github/workflows/` for `--update` finds only wiki-sync.yml (unrelated) and ci.yml's check-quality-ratchet.mjs --require-tighten (a different script against a different metric). Measured on release/v3.8.49 at 54b4bf1: 18 frozen files already at or under the 800-line new-file cap, the worst at 132x (src/shared/validation/schemas.ts, 19 lines carrying a 2,523 cap); the complexity ceiling walked 1794 -> 2169 across ~37 rebaseline notes with exactly one decrease (-1); "tighten via --update next cycle" written 31 times and honoured once in six weeks. A cap that outlives the code that earned it converts every completed decomposition into a growth allowance for whoever edits that file next. New job `bank-ratchet-shrinks` in nightly-release-green.yml measures the active release branch, runs the two shrink-only `--update` paths, and opens ONE always-current PR with the result. Schedule/dispatch only, deliberately not on push: banking has no latency requirement, while a per-merge run would rebuild the PR branch during merge campaigns and pay for a full ESLint walk each time. Detection stays on push (release-green); only banking is batched. The job never pushes to release/* — a human merges, so a bad measurement cannot land unreviewed. scripts/quality/verify-ratchet-bank.mjs is the hard guarantee that the automation can only ever write downward. It diffs the post-`--update` tree against HEAD and aborts the job before a commit exists — opening no PR — unless every change is a frozen/testFrozen entry lowered or removed, `count` lowered, or cognitiveComplexity.value lowered. Raising a number, adding an entry, changing cap/testCap, or deleting/rewriting a `_rebaseline_*` note all fail. A bot that could raise a cap would be strictly worse than the status quo. Verified both directions against the real baselines: --update + verifier reports 77 lowered / 14 removed / nothing raised, exit 0; hand-raising chatCore.ts to 9999 and cap to 1200 is rejected with exit 1. 22 unit tests cover each way the automation could go wrong. No product code changes. * chore(skills): sync cli-backup-sync SKILL.md after rebase onto tip
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…stryker drift
file-size: nine frozen entries could not absorb the combined result of the
31-PR train. Two distinct causes, kept apart in the baseline note on purpose:
(1) GENUINE irreducible growth at existing chokepoints —
providerLimits/auth (cheaper-inference#8632), rateLimitManager (cheaper-inference#8616),
models-catalog-route.test (cheaper-inference#8610).
(2) COLLISION with cheaper-inference#8585, which banked shrinks measured on the pre-train
release tip while 30 sibling PRs in the SAME train grew those files
again — chat/accountFallback (cheaper-inference#8628), chatCore (cheaper-inference#8613),
videoGeneration (cheaper-inference#8581), imageGeneration.
Ceilings re-pinned to the post-merge tip. cheaper-inference#8612 (also in this train) automates
shrink-banking so this self-inflicted drift stops recurring.
stryker: three covering unit tests were missing from tap.testFiles —
isLocalStreamLifecycleError-abort-shape (circuitBreaker.ts, a shared base-red
that was reddening Fast Quality Gates on every open PR),
noauth-autocombo-lockout-7623 (accountFallback.ts) and
kimi-quota-reset-recovery (auth.ts), the latter two landed with this train.
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.
Implements proposal 2 of #8584. Companion to #8585 (the one-off banking run) and #8589 (the
--updategap fix) — but this is the one that makes the other two stop decaying.The problem, restated in one line
The ratchet is only half automatic, and it is the wrong half.
--update, commit, get it reviewedGrep
.github/workflows/for--update:wiki-sync.yml(unrelated) andci.yml'scheck-quality-ratchet.mjs --require-tighten(a different script, a different metric). Neithercheck:file-size --updatenorcheck:complexity-ratchets --updateis run by anything.Measured on
release/v3.8.49at4053e2314: 18 frozen files already at or under the 800-line new-file cap, worst at 132× (src/shared/validation/schemas.ts, 19 lines carrying a 2,523 cap); the complexity ceiling walked1794 → 2169across ~37 rebaseline notes with exactly one decrease (−1);"tighten via --update next cycle"written 31 times, honoured once in six weeks.The consequence is not "caps drift up". It is that a cap outlives the code that earned it, so every completed decomposition silently becomes a growth allowance for whoever edits that file next.
What this adds
New job
bank-ratchet-shrinksinnightly-release-green.yml— that workflow already measures the active release branch, so this reuses its lane, its branch resolution, and its injection guard.Schedule + dispatch only, deliberately not
push. Banking has no latency requirement — a shrink banked within 8h is fine — while a per-merge run would rebuild the PR branch repeatedly during merge campaigns and pay for a full ESLint walk each time. Detection stays on push (release-green, unchanged); only banking is batched.It never pushes to
release/*. A human merges the PR, so a bad measurement cannot land unreviewed. That is also why it opens one force-updated PR rather than one per run.The safety verifier is the actual argument
A bot that could raise a cap would be strictly worse than the status quo. So the job writes nothing unattended without
scripts/quality/verify-ratchet-bank.mjsclearing it first. The verifier diffs the post---updatetree againstHEADand aborts the job before a commit exists — opening no PR — unless every single change is one of:frozen/testFrozennumeric entry lowered or removedcomplexity-baseline.json→countloweredquality-baseline.json→metrics.cognitiveComplexity.valueloweredEverything else fails: raising a number, adding an entry, changing
cap/testCap, or deleting/rewriting a_rebaseline_*note. That last one matters more than it looks — the notes are the audit trail for why each ceiling exists, and they are stored inside the samefrozenobject as the file entries (which is why the gate prints182 arquivos congeladosfor 127 real files). A naive "rewrite the JSON" bot would eat them.Verified both directions against the real baselines
Forward —
--updatethen verify, on the actual release tip:Negative control — hand-raise one entry and the cap, exactly what the verifier exists to stop:
The baseline edits were reverted — this PR contains no baseline changes and no product code changes. Banking the current 91 is #8585's job; this is the machinery that keeps doing it.
tests/unit/verify-ratchet-bank.test.ts— 22 tests, one per way the automation could go wrong (raise, add, delete a note, rewrite a note, movecap, move an unrelated metric while the tracked one legitimately dropped, …). All pass.Notes for review
docs/architecture/QUALITY_GATES.mdshows ~29 deleted lines that are not mine.lint-stagedrunsprettier --writeon*.md, and two pre-existing tables in that file were not prettier-clean atHEAD, so any commit touching the file reformats them. The change is whitespace-only. Say the word and I will add the file to.prettierignoreinstead (there is precedent —docs/reference/ENVIRONMENT.mdis excluded for exactly this reason).--updatecurrently cannot remove an entry whose value already equals the frozen value and sits under the cap; fix(quality): let --update remove baseline entries that already fit the cap #8589 adds that third bucket. The lane inherits whatever--updatecan do.--updateis shrink-only by construction, independently of this PR:check-file-size.mjswrites only fromimprovements, andcheck-complexity-ratchets.mjsonly when.improved. The verifier is defence in depth, not the only guard.--updateinvocations run underset +eon purpose: they exit non-zero while the branch is over baseline, which is precisely when there is nothing to bank. Their exit code is not the signal; the verifier is.Closes the mechanism half of #8584. Proposal 3 (replacing the 93 dead
#3501references with a live decomposition tracker) is not in this PR.