refactor(combo): move handleRoundRobinCombo into roundRobinCombo.ts (#12811)

Validado numa worktree combinada com as 16 PRs desta leva sobre `release/v3.8.51`: typecheck:core limpo, check-file-size e check-changelog-integrity OK, complexity 2788/3218 e cognitive 1261/1437, ESLint 0 erros nos 152 arquivos alterados, 771 testes unitários focados, 49 de integração e a suíte vitest:ui completa (2149) verdes.

**Sobre a reconstrução da branch.** Esta PR continha os 7 commits do #12746 mais os 3 do round-robin. O dono escolheu mergear os dois em sequência em vez de fechar um como subsumido, então depois que o squash do #12746 entrou eu reconstruí esta branch: cherry-pick de `05059880`, `54168238` e `ddd6bcbf` sobre o tip novo, e force-push. Autoria preservada — os três commits continuam seus (`Minxi Hou <houminxi@gmail.com>`), verificado com `git log --format=%an` antes do push. A PR foi de +4167/−3187 em 14 arquivos para +1281/−1182 em 5, que é o delta real do round-robin.

O `05059880` ("guard round-robin extract before the lift") é o commit que faz esse tipo de extract ser revisável: sem um teste que fixe o contrato antes do movimento, mover 1198 linhas é indistinguível de reescrever 1198 linhas.

Revalidei sobre o tip reconstruído: `round-robin-combo`, `combo-attempt-loop`, `execute-target-attempt`, `execute-target-gates` e `combo-loop-safety-timer-leak-11804` — 24/24 — com typecheck:core limpo e o cap de arquivo OK.
This commit is contained in:
Bob.Hou
2026-09-07 08:09:51 -04:00
committed by GitHub
parent 6b587d0046
commit ce49d969ca
5 changed files with 1281 additions and 1182 deletions

View File

@@ -0,0 +1 @@
- **refactor(combo):** move `handleRoundRobinCombo` (and `resolveTargetTokenLimit`) into `open-sse/services/combo/roundRobinCombo.ts`. `combo.ts` drops from 2164 to 1014 lines (`split("\n").length`); the leaf is 1199 (under the 1200 new-file cap). The round-robin call site uses a dynamic `import()` so `releaseStickyPinOnFailure` / `clearStaleLKGP` can stay exported from `combo.ts` without a static cycle. Skip / sticky / semaphore / safety-timer behavior is unchanged.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -48,10 +48,9 @@ test("attempt budget lives on state.globalAttempts, not extra.globalAttempts box
test("handleComboChatInner does not leave unused delay locals or unused failureTracker import", async () => {
const comboSrc = readFileSync(resolve(here, "../../../open-sse/services/combo.ts"), "utf8");
const inner = comboSrc.slice(
comboSrc.indexOf("async function handleComboChatInner"),
comboSrc.indexOf("async function handleRoundRobinCombo")
);
const innerStart = comboSrc.indexOf("async function handleComboChatInner");
const rrStart = comboSrc.indexOf("async function handleRoundRobinCombo");
const inner = comboSrc.slice(innerStart, rrStart === -1 ? comboSrc.length : rrStart);
assert.doesNotMatch(inner, /const retryDelayMs = resolveDelayMs/);
assert.doesNotMatch(inner, /const fallbackDelayMs = resolveDelayMs/);
assert.doesNotMatch(comboSrc, /clearComboFailureTracking/);

View File

@@ -0,0 +1,52 @@
/**
* Source guards for the round-robin extract (PR-1).
* handleRoundRobinCombo + resolveTargetTokenLimit must live in
* roundRobinCombo.ts, not in the combo.ts import sandwich.
*/
import assert from "node:assert/strict";
import { existsSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { describe, it } from "node:test";
import { fileURLToPath } from "node:url";
const root = join(dirname(fileURLToPath(import.meta.url)), "../../..");
const comboSrc = readFileSync(join(root, "open-sse/services/combo.ts"), "utf8");
const rrPath = join(root, "open-sse/services/combo/roundRobinCombo.ts");
describe("round-robin extract guards", () => {
it("defines handleRoundRobinCombo in roundRobinCombo.ts, not combo.ts", () => {
assert.equal(existsSync(rrPath), true, "roundRobinCombo.ts must exist");
const rr = readFileSync(rrPath, "utf8");
assert.match(rr, /export async function handleRoundRobinCombo/);
assert.equal(
/^(export )?async function handleRoundRobinCombo/m.test(comboSrc),
false,
"combo.ts must not define handleRoundRobinCombo after the lift"
);
});
it("moved resolveTargetTokenLimit out of the import sandwich", () => {
const rr = readFileSync(rrPath, "utf8");
assert.match(rr, /function resolveTargetTokenLimit/);
assert.equal(
comboSrc.includes("function resolveTargetTokenLimit"),
false,
"combo.ts must not keep resolveTargetTokenLimit between import blocks"
);
});
it("clears rrLoopSafetyTimer in a finally on the extracted file", () => {
const rr = readFileSync(rrPath, "utf8");
assert.match(rr, /rrLoopSafetyTimer = setTimeout\(/);
assert.match(rr, /finally\s*\{[^}]*clearTimeout\(rrLoopSafetyTimer\)/s);
});
it("calls releaseStickyPinOnFailure (injection: deleting the call goes red)", () => {
const rr = readFileSync(rrPath, "utf8");
assert.match(
rr,
/releaseStickyPinOnFailure\(/,
"#6692 quality/exhaustion path must still release the sticky pin"
);
});
});