From 4198fdd1ea16f0cde7c5ee2cb7d9d677c9562327 Mon Sep 17 00:00:00 2001 From: MumuTW <42820974+MumuTW@users.noreply.github.com> Date: Sat, 25 Jul 2026 23:48:10 +0800 Subject: [PATCH 1/4] fix(quality): let --update remove baseline entries that already fit the cap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `check:file-size --update` could only ever delete an entry from inside the improvement branch (`loc < frozen[file]`). An entry sitting at EXACTLY its frozen value while already within the 800-line new-file cap therefore never qualified for removal, however far under the cap it was — it stayed in the baseline permanently. Three real cases on release/v3.8.49 @ 4053e2314 survived a full `--update` run for this reason: src/app/(dashboard)/dashboard/providers/[id]/ProviderDetailPageClient.tsx 798 src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderModels.ts 155 src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderSettings.ts 264 `evaluateFileSizes` now reports a third bucket, `redundant` — in `frozen`, not a violation, not an improvement, and `loc <= cap` — and the `--update` path deletes those entries alongside the shrinks. Same treatment for the testFrozen/testCap half, which had the identical gap. The non-update gate path is untouched: `redundant` entries were already passing and still pass, so no PR's result changes. Only `--update` behaves differently. TDD: 7 new failing tests first (16 total in tests/unit/check-file-size.test.ts, 9 pre-existing all still passing), then the fix, then 16/16 green. End-to-end on the real baseline, `--update` now reports "74 arquivo(s) encolheram, 3 entrada(s) redundante(s) removida(s)" and removes 17 entries instead of 14, with 0 caps raised. That baseline diff is deliberately NOT in this commit — banking the data belongs to #8585. Refs #8584 --- scripts/check/check-file-size.mjs | 53 ++++++++++++++++++++------ tests/unit/check-file-size.test.ts | 60 ++++++++++++++++++++++++++++++ 2 files changed, 101 insertions(+), 12 deletions(-) diff --git a/scripts/check/check-file-size.mjs b/scripts/check/check-file-size.mjs index 7704c27b15d5..3a3cc3a2d0b0 100644 --- a/scripts/check/check-file-size.mjs +++ b/scripts/check/check-file-size.mjs @@ -5,7 +5,10 @@ // - arquivo congelado: só pode ENCOLHER (nunca crescer); // - arquivo NOVO (fora do baseline): não pode passar do CAP. // Assim o próximo arquivo de 12.760 linhas é impossível, e os 91 atuais só melhoram. -// --update ratcheta o baseline para baixo (encolhimentos + remove quem caiu < cap). +// --update ratcheta o baseline para baixo: encolhimentos + remove toda entrada que +// já cabe no cap, inclusive quem NÃO encolheu nesta rodada (loc === frozen[file]). +// Antes a remoção só acontecia dentro do ramo de encolhimento, então uma entrada +// igual ao próprio teto ficava presa no baseline para sempre — ver #8584. import fs from "node:fs"; import path from "node:path"; import { pathToFileURL } from "node:url"; @@ -27,21 +30,30 @@ const SKIP_DIRS = new Set(["node_modules", "dist-electron", ".next", ".build", " /** * Avalia LOC atuais contra o baseline congelado. - * @returns {{violations: string[], improvements: [string, number][]}} + * + * `redundant` (#8584): entrada que NAO precisa mais existir — o arquivo esta + * exatamente no valor congelado E ja cabe no cap de arquivo novo. Antes, a + * remocao do baseline so acontecia dentro do ramo de `improvements` + * (loc < frozen), entao uma entrada igual ao proprio teto nunca saia da lista, + * por mais abaixo do cap que estivesse (3 casos reais no v3.8.49). + * + * @returns {{violations: string[], improvements: [string, number][], redundant: string[]}} */ export function evaluateFileSizes(currentLocByFile, frozen, cap) { const violations = []; const improvements = []; + const redundant = []; for (const [file, loc] of Object.entries(currentLocByFile)) { if (file in frozen) { if (loc > frozen[file]) violations.push(`${file}: ${loc} > congelado ${frozen[file]} (não pode crescer)`); else if (loc < frozen[file]) improvements.push([file, loc]); + else if (loc <= cap) redundant.push(file); } else if (loc > cap) { violations.push(`${file}: ${loc} > cap ${cap} (arquivo novo acima do limite)`); } } - return { violations, improvements }; + return { violations, improvements, redundant }; } function countLines(file) { @@ -105,40 +117,57 @@ function main() { const cap = baseline.cap; const frozen = baseline.frozen || {}; const current = collectLoc(); - const { violations, improvements } = evaluateFileSizes(current, frozen, cap); + const { violations, improvements, redundant } = evaluateFileSizes(current, frozen, cap); // Test-file gate (Layer 1 anti-reinflation): same shrink-only + new-≤cap semantics, // reusing evaluateFileSizes against the testFrozen baseline + testCap. const testCap = baseline.testCap; const testFrozen = baseline.testFrozen || {}; const currentTests = collectTestLoc(); - const { violations: testViolations, improvements: testImprovements } = - typeof testCap === "number" - ? evaluateFileSizes(currentTests, testFrozen, testCap) - : { violations: [], improvements: [] }; + const { + violations: testViolations, + improvements: testImprovements, + redundant: testRedundant, + } = typeof testCap === "number" + ? evaluateFileSizes(currentTests, testFrozen, testCap) + : { violations: [], improvements: [], redundant: [] }; if (UPDATE) { let changed = false; - if (violations.length === 0 && improvements.length) { + if (violations.length === 0 && (improvements.length || redundant.length)) { for (const [file, loc] of improvements) { if (loc <= cap) delete frozen[file]; // caiu para dentro do cap → sai do baseline else frozen[file] = loc; // continua grande mas encolheu → trava no novo valor } + // #8584: entradas que já cabem no cap sem terem encolhido nesta rodada + // (loc === frozen[file]) também saem — antes ficavam presas para sempre. + for (const file of redundant) delete frozen[file]; baseline.frozen = Object.fromEntries(Object.entries(frozen).sort()); changed = true; - console.log(`[file-size] baseline ratcheado: ${improvements.length} arquivo(s) encolheram`); + console.log( + `[file-size] baseline ratcheado: ${improvements.length} arquivo(s) encolheram` + + (redundant.length ? `, ${redundant.length} entrada(s) redundante(s) removida(s)` : "") + ); } - if (typeof testCap === "number" && testViolations.length === 0 && testImprovements.length) { + if ( + typeof testCap === "number" && + testViolations.length === 0 && + (testImprovements.length || testRedundant.length) + ) { for (const [file, loc] of testImprovements) { if (loc <= testCap) delete testFrozen[file]; // caiu para dentro do testCap → sai do baseline else testFrozen[file] = loc; // continua grande mas encolheu → trava no novo valor } + for (const file of testRedundant) delete testFrozen[file]; baseline.testFrozen = Object.fromEntries(Object.entries(testFrozen).sort()); changed = true; console.log( - `[test-file-size] baseline ratcheado: ${testImprovements.length} arquivo(s) de teste encolheram` + `[test-file-size] baseline ratcheado: ${testImprovements.length} arquivo(s) de teste encolheram` + + (testRedundant.length + ? `, ${testRedundant.length} entrada(s) redundante(s) removida(s)` + : "") ); } if (changed) fs.writeFileSync(BASELINE_PATH, JSON.stringify(baseline, null, 2) + "\n"); diff --git a/tests/unit/check-file-size.test.ts b/tests/unit/check-file-size.test.ts index 89823adffdc5..c4d0315a2f94 100644 --- a/tests/unit/check-file-size.test.ts +++ b/tests/unit/check-file-size.test.ts @@ -70,3 +70,63 @@ test("frozen test file that shrank is an improvement, not a violation", () => { assert.deepEqual(r.violations, []); assert.deepEqual(r.improvements, [["tests/unit/combo-routing-engine.test.ts", 3000]]); }); + +// --- Redundant entries (#8584): an entry that no longer needs to exist --- +// `--update` could only ever delete an entry from inside the improvement branch +// (loc < frozen), so a file sitting at EXACTLY its frozen value while already +// within the new-file cap could never leave the baseline, however far under the +// cap it was. Those entries are reported separately as `redundant`. + +test("frozen file sitting at its baseline but already within the cap is redundant", () => { + const r = evaluateFileSizes({ "a.ts": 500 }, { "a.ts": 500 }, cap); + assert.deepEqual(r.violations, []); + assert.deepEqual(r.improvements, []); + assert.deepEqual(r.redundant, ["a.ts"]); +}); + +test("frozen file sitting at its baseline but still over the cap is NOT redundant", () => { + const r = evaluateFileSizes({ "a.ts": 1000 }, { "a.ts": 1000 }, cap); + assert.deepEqual(r.violations, []); + assert.deepEqual(r.improvements, []); + assert.deepEqual(r.redundant, []); +}); + +test("frozen file exactly at the cap is redundant (cap is inclusive)", () => { + const r = evaluateFileSizes({ "a.ts": 800 }, { "a.ts": 800 }, cap); + assert.deepEqual(r.redundant, ["a.ts"]); +}); + +test("a file that shrank stays an improvement and is not double-counted as redundant", () => { + const r = evaluateFileSizes({ "a.ts": 500 }, { "a.ts": 1000 }, cap); + assert.deepEqual(r.improvements, [["a.ts", 500]]); + assert.deepEqual(r.redundant, []); +}); + +test("a frozen file that grew is a violation and never redundant", () => { + const r = evaluateFileSizes({ "a.ts": 1001 }, { "a.ts": 1000 }, cap); + assert.equal(r.violations.length, 1); + assert.deepEqual(r.redundant, []); +}); + +test("the real residual entries from #8584 are reported as redundant", () => { + // Measured on release/v3.8.49 @ 4053e2314: each sits at exactly its frozen + // value and far below the 800 cap, yet survived a full `--update` run. + const frozen = { + "src/app/(dashboard)/dashboard/providers/[id]/ProviderDetailPageClient.tsx": 798, + "src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderModels.ts": 155, + "src/app/(dashboard)/dashboard/providers/[id]/hooks/useProviderSettings.ts": 264, + }; + const r = evaluateFileSizes({ ...frozen }, frozen, cap); + assert.deepEqual(r.violations, []); + assert.deepEqual(r.improvements, []); + assert.deepEqual(r.redundant.sort(), Object.keys(frozen).sort()); +}); + +test("redundant applies to the test-file path too", () => { + const r = evaluateFileSizes( + { "tests/unit/small.test.ts": 300 }, + { "tests/unit/small.test.ts": 300 }, + testCap + ); + assert.deepEqual(r.redundant, ["tests/unit/small.test.ts"]); +}); From b2312f852a7251e04b0ef5d5b918afd80e3b968b Mon Sep 17 00:00:00 2001 From: MumuTW <42820974+MumuTW@users.noreply.github.com> Date: Sun, 26 Jul 2026 17:39:48 +0800 Subject: [PATCH 2/4] docs(changelog): add fragment for #8589 file-size --update at-cap removal --- changelog.d/fixes/8589-file-size-update-remove-at-cap.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/fixes/8589-file-size-update-remove-at-cap.md diff --git a/changelog.d/fixes/8589-file-size-update-remove-at-cap.md b/changelog.d/fixes/8589-file-size-update-remove-at-cap.md new file mode 100644 index 000000000000..26118ff27d17 --- /dev/null +++ b/changelog.d/fixes/8589-file-size-update-remove-at-cap.md @@ -0,0 +1 @@ +- **fix(quality):** `check:file-size --update` now removes baseline entries that already fit the new-file cap even when LOC equals the frozen value (`redundant` path) — closes the #8584 gap where at-cap entries were stuck forever ([#8589](https://github.com/diegosouzapw/OmniRoute/pull/8589)) — thanks @MumuTW From 937660da405d5827a4863e9f6acc4f69ca990280 Mon Sep 17 00:00:00 2001 From: MumuTW <42820974+MumuTW@users.noreply.github.com> Date: Sun, 26 Jul 2026 17:50:19 +0800 Subject: [PATCH 3/4] chore(skills): sync cli-backup-sync SKILL.md with catalog Same tip fix as #8657 so Merge integrity is green without waiting for that PR to land. Regenerated via generate-agent-skills --apply. --- skills/cli-backup-sync/SKILL.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/skills/cli-backup-sync/SKILL.md b/skills/cli-backup-sync/SKILL.md index 7a030bc1e65e..9dff9daba2c2 100644 --- a/skills/cli-backup-sync/SKILL.md +++ b/skills/cli-backup-sync/SKILL.md @@ -2,6 +2,7 @@ name: cli-backup-sync description: Backup and restore OmniRoute data from the CLI. Trigger incremental snapshots, sync to cloud storage, manage backup schedules, and restore from archive files. --- + ## Overview @@ -75,15 +76,6 @@ omniroute backup disable ### `backup status` -**Flags:** - -- `--name ` -- `--cloud` -- `--encrypt` -- `--key-file ` -- `--exclude ` -- `--retention ` - **Example:** ```bash From 75b9382fbe7a2512145f8bab6b8613b058581a98 Mon Sep 17 00:00:00 2001 From: MumuTW <42820974+MumuTW@users.noreply.github.com> Date: Sun, 26 Jul 2026 17:53:26 +0800 Subject: [PATCH 4/4] chore(skills): regenerate cli-backup-sync without prettier drift --- skills/cli-backup-sync/SKILL.md | 1 - 1 file changed, 1 deletion(-) diff --git a/skills/cli-backup-sync/SKILL.md b/skills/cli-backup-sync/SKILL.md index 9dff9daba2c2..e1dccfed63b0 100644 --- a/skills/cli-backup-sync/SKILL.md +++ b/skills/cli-backup-sync/SKILL.md @@ -2,7 +2,6 @@ name: cli-backup-sync description: Backup and restore OmniRoute data from the CLI. Trigger incremental snapshots, sync to cloud storage, manage backup schedules, and restore from archive files. --- - ## Overview