Compare commits

...

2 Commits

Author SHA1 Message Date
adevwithpurpose
cfd15aef16 Merge remote-tracking branch 'origin/release/v3.8.50' into fix/release-v3.8.50-basereds 2026-08-18 12:02:00 -03:00
Xiangzhe
131aebcde5 fix(compression): gate de estágio não derruba o pipeline com engine sem metadata
`assertValidEngine()` valida id, apply, compress, getConfigSchema e
validateConfig — não exige `metadata`. Uma engine registrada sem esse campo é,
portanto, um registro legal. Mas `canRunAtCompressionStage` lia
`engine.metadata.executionStages` sem guarda, então essa engine legal derrubava o
pipeline inteiro com `TypeError: Cannot read properties of undefined` em vez de
falhar aberto, que é o contrato da compressão.

Metadata ausente é o mesmo caso de "não declarou executionStages" e passa a cair
no mesmo fallback documentado: só pre-translation.

Isso destravava também `tests/unit/compression/pipeline-circuit-breaker.test.ts`,
que registra uma engine de teste sem metadata e vinha 8/9 na base — agora 9/9. O
teste novo torna o contrato explícito, em vez de deixá-lo dependendo de uma
reprodução incidental noutro arquivo.
2026-08-18 07:56:56 -03:00
2 changed files with 77 additions and 1 deletions

View File

@@ -800,7 +800,11 @@ function canRunAtCompressionStage(
stage: CompressionStage | undefined
): boolean {
const effectiveStage = stage ?? "pre-translation";
const stages = engine.metadata.executionStages;
// `assertValidEngine` não exige `metadata`, então uma engine registrada sem
// esse campo é legal — e sem a guarda derrubava o pipeline inteiro com
// TypeError em vez de falhar aberto. Metadata ausente é o mesmo caso de "não
// declarou estágio" e cai no mesmo fallback: só pre-translation.
const stages = engine.metadata?.executionStages;
return stages ? stages.includes(effectiveStage) : effectiveStage === "pre-translation";
}

View File

@@ -0,0 +1,72 @@
/**
* Gate de estágio × engine sem `metadata`.
*
* `assertValidEngine()` (engines/registry.ts) valida `id`, `apply`, `compress`,
* `getConfigSchema` e `validateConfig` — NÃO exige `metadata`. Uma engine sem
* esse campo é, portanto, um registro legal. Mas `canRunAtCompressionStage`
* lia `engine.metadata.executionStages` sem guarda, então essa engine legal
* derrubava o pipeline inteiro com `TypeError: Cannot read properties of
* undefined` — em vez de falhar aberto, que é o contrato da compressão.
*
* O fallback documentado para quem não declara `executionStages` é "só
* pre-translation". Metadata ausente é o mesmo caso de "não declarou", e tem de
* cair no mesmo fallback.
*/
import { describe, it, beforeEach, afterEach } from "node:test";
import assert from "node:assert/strict";
import {
registerCompressionEngine,
unregisterCompressionEngine,
} from "../../../open-sse/services/compression/engines/registry.ts";
import { applyStackedCompression } from "../../../open-sse/services/compression/strategySelector.ts";
import type { CompressionEngine } from "../../../open-sse/services/compression/engines/types.ts";
const ENGINE_ID = "metadata-less-test-engine";
const body = () => ({ messages: [{ role: "user", content: "hello world" }] });
describe("stage gate — engine sem metadata", () => {
beforeEach(() => {
// Registro deliberadamente sem `metadata`: é o que assertValidEngine aceita.
registerCompressionEngine({
id: ENGINE_ID,
name: "metadata-less test engine",
targets: ["messages"],
stackable: true,
apply(input: Record<string, unknown>) {
return { body: input, compressed: false, stats: null };
},
compress() {
return { text: "", stats: null };
},
getConfigSchema() {
return [];
},
validateConfig() {
return { valid: true, errors: [] };
},
} as unknown as CompressionEngine);
});
afterEach(() => unregisterCompressionEngine(ENGINE_ID));
it("não derruba o pipeline no estágio pré-tradução (default)", () => {
const r = applyStackedCompression(body(), [{ engine: ENGINE_ID }]);
assert.equal(r.compressed, false);
assert.deepEqual(r.body, body());
});
it("não derruba o pipeline no estágio pós-tradução — pula pelo fallback", () => {
const r = applyStackedCompression(body(), [{ engine: ENGINE_ID }], {
compressionStage: "post-translation",
});
assert.equal(r.compressed, false);
assert.deepEqual(r.body, body());
// Fallback documentado: quem não declara estágio só roda pre-translation.
assert.ok(
r.stats?.validationWarnings?.some((w) => w.includes(ENGINE_ID) && w.includes("skipped")),
`esperado aviso de skip por estágio, veio ${JSON.stringify(r.stats?.validationWarnings)}`
);
});
});