mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-18 21:22:28 +03:00
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.
This commit is contained in:
@@ -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";
|
||||
}
|
||||
|
||||
|
||||
72
tests/unit/compression/engine-stage-gate-metadata.test.ts
Normal file
72
tests/unit/compression/engine-stage-gate-metadata.test.ts
Normal 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)}`
|
||||
);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user