mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 12:22:14 +03:00
* test(sse): repair two base-red gates on release/v3.8.49 `release/v3.8.49` is red at its own HEAD (36f8fd10) — `Quality Gates` and `Release-Green (continuous)` both fail — so every PR opened against it inherits four failing checks regardless of content. Two of those causes had no owner: #8480/#8481/#8482 cover the compression ladder, the antigravity catalog, and the resilience/translator regressions respectively, none of them these. 1. `chatcore-client-usage-buffer.test.ts` — 5/5 failing. #8331/#8356 (e8719783e) inserted an `options` parameter between `clientResponseFormat` and `deps` on `applyClientUsageBuffer()`. The five call sites here still passed `deps` in the fourth position, so the injected spies landed in the `options` slot and the real implementations ran — every `calls.*.length` assertion saw 0. The `Parameters<typeof applyClientUsageBuffer>[3]` cast in `makeDeps()` masked the type error, which is why it reached the branch. Call sites updated to `(resp, body, format, {}, deps)` and the cast repointed to `[4]`. Two cases added for the parameter that caused this, since nothing at this layer exercised it: `preserveContextBudgetInVisibleUsage` re-folds `context_budget_*` into the visible fields for the Claude-Code path, and the default path keeps the real unbuffered #8331 numbers. 2. `claude-to-openai-think-close-5123.test.ts` — 4 unsuppressed `@typescript-eslint/no-explicit-any` errors, failing `npm run lint`. Its suppression entry allows `count: 2` but the file had grown to four `(chunk: any)` callbacks. Rather than raise the frozen count, the cause is fixed: `collectChunks()` returns `StreamChunk[]` instead of `unknown[]`, narrowing once at the boundary so all four callbacks need no annotation. The suppression entry is then stale and removed, which ratchets the file to zero. Test-only plus one allowlist deletion; no production code. Verified on a clean worktree of the base commit: `npm run lint` clean (was 4 errors), `chatcore-client-usage-buffer` 7/7 (was 0/5), `claude-to-openai-think-close-5123` 3/3. * chore(ci): rebaseline five inherited file-size overages on release/v3.8.49 `check:file-size` fails on release/v3.8.49 at its own HEAD (36f8fd10), which is what turns `Fast Quality Gates` red for every PR against this base: tokenHealthCheck.ts 832 -> 841 chat.ts 1865 -> 1866 auth.ts 2475 -> 2486 accountFallback.ts 1941 -> 1960 combo.ts 3630 -> 3642 None of these files is touched by this PR. The growth was inherited from already merged PRs that did not bump their entries, so there is no offending branch left to fix — the same situation the baseline already records under `_rebaseline_2026_07_02_5798_release_green`, and the procedure it documents is to raise the frozen values with a justification note. Raised to the current base values only. The files stay frozen and cannot grow further; an in-flight PR that adds lines to them bumps its own entry as usual (#8482 touches accountFallback.ts and combo.ts and will need that). * chore(ci): register 11 covering unit tests in stryker tap.testFiles `check:mutation-test-coverage --strict` fails on release/v3.8.49 at its own HEAD: 11 unit tests that cover mutated modules are absent from `stryker.conf.json` `tap.testFiles`, so their mutant kills do not count. The gate does not self-heal — it names the exact files to add. open-sse/services/accountFallback.ts + 8247-accountfallback-model-unhealthy, 8248-accountfallback-nvidia-degraded, model-lockout-exact-cooldown-cap, repro-antigravity-404-family-cooldown-hijack src/sse/services/auth.ts + 7993-noauth-proxy-routing, 8200-perplexity-web-401-cooldown, sse-auth-antigravity-credits src/server/authz/routeGuard.ts + authz/route-guard-vnc-session-local-only open-sse/utils/error.ts + error-sensitive-redaction open-sse/utils/publicCreds.ts + adobe-firefly src/shared/utils/circuitBreaker.ts + 8332-combo-vision-fallback None is a file this PR touches, and the gate reports the identical 11 on a worktree carrying none of these base-red fixes. Additions only (11 insertions, 0 deletions); the array stays sorted. This widens what the mutation run accounts for rather than relaxing anything. * chore(ci): re-measure accountFallback.ts file-size cap against the current base tip The entry frozen in this PR (1960) was the value at 36f8fd10; the base has since advanced to1cafd328cand the file is 1966 there, so check:file-size would still have been red on the merge commit. Re-measured to 1966. Same inherited drift the note already documents: check:file-size does not run on the PR->release fast path, so growth accrues unmeasured between release rebaselines. The other four entries still match the current tip (tokenHealthCheck 841, chat 1866, auth 2486, combo frozen 3642 >= 3640). --------- Co-authored-by: backryun <busan011@ormbiz.co.kr>
134 lines
5.5 KiB
TypeScript
134 lines
5.5 KiB
TypeScript
// Characterization of applyClientUsageBuffer — the non-streaming usage buffer/estimate block
|
|
// extracted from handleChatCore (chatCore god-file decomposition, #3501). Deps are injected so the
|
|
// buffer-vs-estimate branch and the in-place mutation of translatedResponse.usage are observable.
|
|
// Locks: usage present → buffer+filter; usage absent → estimate from content length; empty content
|
|
// (length 2 from JSON.stringify("")) still estimates; the mutation target is translatedResponse.
|
|
import { test } from "node:test";
|
|
import assert from "node:assert/strict";
|
|
|
|
const { applyClientUsageBuffer } = await import(
|
|
"../../open-sse/handlers/chatCore/clientUsageBuffer.ts"
|
|
);
|
|
|
|
function makeDeps(overrides: Record<string, unknown> = {}) {
|
|
const calls = { buffer: [] as unknown[], estimate: [] as unknown[], filter: [] as unknown[] };
|
|
const deps = {
|
|
addBufferToUsage: (u: unknown) => {
|
|
calls.buffer.push(u);
|
|
return { ...(u as object), _buffered: true };
|
|
},
|
|
estimateUsage: (...a: unknown[]) => {
|
|
calls.estimate.push(a);
|
|
return { _estimated: true };
|
|
},
|
|
filterUsageForFormat: (u: unknown, _fmt: unknown) => {
|
|
calls.filter.push(u);
|
|
return { ...(u as object), _filtered: true };
|
|
},
|
|
...overrides,
|
|
} as Parameters<typeof applyClientUsageBuffer>[4];
|
|
return { deps, calls };
|
|
}
|
|
|
|
test("usage present → buffer then filter, mutates in place", () => {
|
|
const { deps, calls } = makeDeps();
|
|
const resp: Record<string, unknown> = { usage: { prompt_tokens: 5 } };
|
|
applyClientUsageBuffer(resp, { messages: [] }, "openai", {}, deps);
|
|
assert.equal(calls.buffer.length, 1);
|
|
assert.equal(calls.estimate.length, 0);
|
|
assert.equal((resp.usage as Record<string, unknown>)._buffered, true);
|
|
assert.equal((resp.usage as Record<string, unknown>)._filtered, true);
|
|
});
|
|
|
|
test("all-zero usage stub → estimate (not constant buffer-only 2000)", () => {
|
|
const { deps, calls } = makeDeps();
|
|
const resp: Record<string, unknown> = {
|
|
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
|
choices: [{ message: { content: "PONG" } }],
|
|
};
|
|
applyClientUsageBuffer(resp, { messages: [{ role: "user", content: "hi" }] }, "openai", {}, deps);
|
|
assert.equal(calls.buffer.length, 0, "must not buffer zeros into USAGE_TOKEN_BUFFER");
|
|
assert.equal(calls.estimate.length, 1);
|
|
assert.equal((resp.usage as Record<string, unknown>)._estimated, true);
|
|
});
|
|
|
|
test("no usage but content present → estimate then filter", () => {
|
|
const { deps, calls } = makeDeps();
|
|
const resp: Record<string, unknown> = {
|
|
choices: [{ message: { content: "hello world" } }],
|
|
};
|
|
applyClientUsageBuffer(resp, { messages: [] }, "openai", {}, deps);
|
|
assert.equal(calls.buffer.length, 0);
|
|
assert.equal(calls.estimate.length, 1);
|
|
assert.equal((resp.usage as Record<string, unknown>)._estimated, true);
|
|
assert.equal((resp.usage as Record<string, unknown>)._filtered, true);
|
|
// estimateUsage receives (body, contentLength, format)
|
|
const args = calls.estimate[0] as unknown[];
|
|
assert.equal(args[2], "openai");
|
|
assert.equal(typeof args[1], "number");
|
|
});
|
|
|
|
test("empty content → JSON.stringify('') length 2 > 0 still estimates", () => {
|
|
const { deps, calls } = makeDeps();
|
|
const resp: Record<string, unknown> = {};
|
|
applyClientUsageBuffer(resp, {}, "claude", {}, deps);
|
|
// content "" → JSON.stringify("") = '""' length 2 → contentLength 2 > 0
|
|
assert.equal(calls.estimate.length, 1);
|
|
const args = calls.estimate[0] as unknown[];
|
|
assert.equal(args[1], 2);
|
|
});
|
|
|
|
test("content length is computed from choices[0].message.content", () => {
|
|
const { deps, calls } = makeDeps();
|
|
const resp: Record<string, unknown> = {
|
|
choices: [{ message: { content: "abc" } }],
|
|
};
|
|
applyClientUsageBuffer(resp, {}, "openai", {}, deps);
|
|
// JSON.stringify("abc") = '"abc"' → length 5
|
|
const args = calls.estimate[0] as unknown[];
|
|
assert.equal(args[1], 5);
|
|
});
|
|
|
|
// #8331/#8356 added the `options` parameter between `clientResponseFormat` and `deps`,
|
|
// which is what silently broke the five call sites above (the injected spies landed in
|
|
// the `options` slot, so the real implementations ran and no spy was ever recorded).
|
|
// Cover the option itself so the new parameter is exercised, not just tolerated.
|
|
|
|
test("preserveContextBudgetInVisibleUsage folds context_budget_* back into visible fields", () => {
|
|
const { deps, calls } = makeDeps({
|
|
addBufferToUsage: (u: unknown) => ({
|
|
...(u as object),
|
|
context_budget_prompt_tokens: 2005,
|
|
context_budget_input_tokens: 2005,
|
|
context_budget_total_tokens: 2010,
|
|
}),
|
|
});
|
|
const resp: Record<string, unknown> = {
|
|
usage: { prompt_tokens: 5, input_tokens: 5, total_tokens: 10 },
|
|
};
|
|
|
|
applyClientUsageBuffer(resp, { messages: [] }, "openai", {
|
|
preserveContextBudgetInVisibleUsage: true,
|
|
}, deps);
|
|
|
|
const filtered = calls.filter[0] as Record<string, unknown>;
|
|
assert.equal(filtered.prompt_tokens, 2005, "Claude-Code path re-folds the buffered value");
|
|
assert.equal(filtered.input_tokens, 2005);
|
|
assert.equal(filtered.total_tokens, 2010);
|
|
});
|
|
|
|
test("without the option the visible usage keeps the real unbuffered #8331 numbers", () => {
|
|
const { deps, calls } = makeDeps({
|
|
addBufferToUsage: (u: unknown) => ({
|
|
...(u as object),
|
|
context_budget_prompt_tokens: 2005,
|
|
}),
|
|
});
|
|
const resp: Record<string, unknown> = { usage: { prompt_tokens: 5 } };
|
|
|
|
applyClientUsageBuffer(resp, { messages: [] }, "openai", {}, deps);
|
|
|
|
const filtered = calls.filter[0] as Record<string, unknown>;
|
|
assert.equal(filtered.prompt_tokens, 5, "default path must not inflate client-visible metering");
|
|
});
|