Files
OmniRoute/tests/unit/ui/omniglyphContextPage.test.tsx
Diego Rodrigues de Sa e Souza 04af8b1517 feat(compression): adota omniglyph 1.4.0, perfis semânticos e contabilidade com evidência (#10647)
* feat(compression): target-wire OmniGlyph stage and transport fidelity gate

Roda o OmniGlyph depois da tradução para o wire real do provedor, em vez do
corpo de origem. Um cliente OpenAI roteado para Claude deixava de comprimir com
skip:source_format_not_claude porque o corpo ainda estava em formato OpenAI
quando a engine era avaliada.

- dispatch nativo por wire: Anthropic Messages, OpenAI Chat Completions e
  OpenAI Responses (input[] preservado, sem achatar para messages[]);
- estágio target-wire pós-translateRequest, com guarda contra dupla compressão
  no caminho Claude→OpenAI;
- preserveSystemPrompt do OmniRoute mapeado para compressSystem: false;
- imageTransportPolicy: fidelidade de bytes/dimensões separada de supportsVision;
  só Anthropic/Claude tem recibo byte-preserving, o resto é fail-closed;
- contagem de tokens de data URL PNG no wire OpenAI (marcador ;base64,);
- README e i18n en/pt-BR com claims escopados ao caminho medido.

* feat(compression): adota omniglyph 1.4.0 e tira o gate de modelo da env do host

O 1.4.0 introduziu escopos de segurança e passou a resolvê-los dentro de
isOmniGlyphSupportedModel() lendo process.env.OMNIGLYPH_PROFILE. Somado ao
OMNIGLYPH_MODELS que já existia, duas variáveis do ambiente do host decidiam em
silêncio o gate de TODO request do OmniRoute: passthrough desligaria a engine
inteira e OMNIGLYPH_MODELS admitiria modelos sem recibo medido, enquanto a UI
segue prometendo "Claude Fable 5 na rota direta medida".

O adapter passa a usar isOmniGlyphSupportedModelForScope() com escopo explícito
e fixa o escopo mais restrito como teto: a env só pode ESTREITAR a allowlist,
nunca alargar. Os dois wires compartilham a mesma lista no pacote desde o
1.4.0, então uma checagem cobre Anthropic e GPT.

- omniglyph ^1.3.1 -> ^1.4.0 (lock em 1.4.0);
- testes de regressão para os dois caminhos de sequestro por env;
- teste de contrato dos exports novos (escopo, perfis, accounting).

O 1.4.0 também traz, sem mudança de código aqui: correção do glyph K que era
lido como H, remoção do backtracking polinomial no secret-guard, overrides do
pnpm em pnpm-workspace.yaml e as transitivas vulneráveis resolvidas.

* feat(compression): expõe os perfis semânticos do omniglyph nos três wires

O 1.4.0 trouxe perfis nomeados (coding-safe, balanced, aggressive,
passthrough), mas só transformAnthropicMessages() os resolve sozinho: os
transformadores OpenAI recebem TransformOptions cru e ignorariam o campo. Um
perfil escolhido pelo operador valeria no wire Claude e sumiria no OpenAI. O
adapter passa a mesclar o perfil com mergeCompressionProfileOptions() antes de
chamar Chat Completions e Responses.

O default segue aggressive — a política que os recibos publicados mediram.
Medido nesta base: com coding-safe/balanced, uma sessão sem histórico acumulado
para em below_min_chars e a engine não faz nada, porque os dois fixam
minCompressChars no máximo e desligam system/tools/tool-results. Como a engine é
opt-in, um default assim entregaria "ligado, 0% de ganho".

O perfil é TETO, não piso: mergeCompressionProfileOptions não deixa um override
do chamador reabrir uma lane lossy que o perfil fechou. Coberto por teste, por
ser contra-intuitivo.

Também fecha um caminho em que o OmniRoute violaria a própria política: o wire
OpenAI do pacote não tem compressSystem — honra apenas compressTools,
gptHistory, minCompressChars e reflow, e sempre troca a instrução por um
ponteiro para a imagem. Com preserveSystemPrompt ligado, imagear assim queimaria
o prefixo quente que a decisão cache-aware está protegendo, sem nada no corpo
devolvido denunciando. A engine agora pula com
skip:system_preservation_unsupported_on_wire.

* feat(compression): contabilidade física do omniglyph com grau de evidência

O adapter descartava o TransformInfo inteiro, então a UI mostrava um número de
economia sem dizer de onde ele vinha — contagem do provider, estimativa ou só
diferença de bytes. O 1.4.0 expõe normalizeAccounting(), que classifica essa
evidência e resolve a semântica de cache por família: Anthropic reporta input,
cache-create e cache-read em buckets DISJUNTOS, enquanto OpenAI e xAI reportam
cached como SUBCONJUNTO do input. Somar à mão dá double-count silencioso.

O novo omniglyphTelemetry.ts não filtra por denylist — MONTA um objeto novo,
campo a campo, só com número e enum. TransformInfo mistura contadores
inofensivos com material que não pode ser persistido: bytes PNG,
imageSourceText(s), recoverable[].text, os sha8 de system/CLAUDE.md/primeira
mensagem, nomes de tags observadas e o bloco env (cwd, branch, versões). Copiar
o objeto inteiro transformaria telemetria de compressão em vazamento de prompt.
O teste de negação prova que segredo, caminho do operador, texto do system e
base64 não aparecem, e varre a allowlist exigindo que toda string seja de um
enum conhecido.

- provider threaded do chatCore e do bridge Codex WS até a engine; ausente vira
  `unknown`, que faz o upstream recusar adivinhar buckets de cache;
- contabilidade propagada para o engineBreakdown do passo (o agregado do
  pipeline soma todas as engines e não serviria);
- skip não emite contabilidade: zeros ali seriam indistinguíveis de "a engine
  nem rodou".

* feat(compression): perfil do omniglyph configurável, persistido e documentado

Fecha o caminho do operador: o perfil já existia no adapter, mas só como
default de código. Agora atravessa schema Zod, normalizador do banco, API de
settings e a página dedicada do engine.

- OmniglyphConfig tipado + omniglyphConfigSchema (z.enum dos quatro perfis);
- normalizeOmniglyphConfig: nome desconhecido vindo do storage cai para o
  default em vez de virar "roda com a política padrão";
- seletor na página do engine, com PATCH próprio — o perfil vive fora do mapa
  `engines`, e mandá-lo junto reescreveria o mapa inteiro (o store persiste o
  mapa como uma linha JSON só);
- i18n en/pt-BR descrevendo o custo medido de cada perfil, não só o nome;
- README e COMPRESSION_ENGINES.md com a regra do teto e o motivo de o default
  não ser o perfil mais seguro.

Corrige de passagem um teste-irmão que ninguém via: o gate de transporte na UI
deixou de dizer "direct Anthropic" quando os wires OpenAI nativos entraram, mas
tests/unit/ui/omniglyphContextPage.test.tsx continuou afirmando a cópia antiga.
O arquivo inteiro estava excluído do vitest.config.ts como "#8618 pre-existing
failure", então a quebra passou silenciosa. Com a asserção alinhada o arquivo
fecha 3/3, e a exclusão sai — o próprio comentário mandava removê-la quando
corrigida.

A doc não nomeia OMNIGLYPH_MODELS: o gate de docs fabricadas está certo em
apontar que o OmniRoute nunca lê essa env — quem lê é o pacote.

* fix(i18n): paridade do locale vi com as chaves novas do perfil do omniglyph

`tests/unit/i18n-vi-completeness.test.ts` exige paridade ESTRITA de chaves entre
en e vi — diferente do ratchet `i18n:check-ui-coverage`, que passa com 80%. As 11
chaves do seletor de perfil entraram só em en e pt-BR, e o gate de cobertura
seguiu verde, então a quebra só apareceu na matriz completa do CI.

---------

Co-authored-by: Xiangzhe <bakryun0718@proton.me>
Co-authored-by: adevwithpurpose <adevwithpurpose@users.noreply.github.com>
2026-08-18 12:13:48 -03:00

208 lines
7.6 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// @vitest-environment jsdom
import React, { act } from "react";
import { createRoot } from "react-dom/client";
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
import { SAMPLE_METRICS } from "../../../src/app/(dashboard)/dashboard/context/omniglyph/sampleData.ts";
// i18n is not resolved in vitest/jsdom; the page hardcodes its engine copy in English
// anyway (catalog convention), so no next-intl mock is needed. Asserts are on
// i18n-independent content: headings, measured numbers, gate labels, data-testid hooks.
// ── Harness (mirrors tests/unit/ui/compressionPanel.test.tsx) ──────────────────
const containers: HTMLElement[] = [];
const roots: Array<{ unmount: () => void }> = [];
function mount(ui: React.ReactElement): HTMLElement {
const container = document.createElement("div");
document.body.appendChild(container);
containers.push(container);
const root = createRoot(container);
roots.push(root);
act(() => {
root.render(ui);
});
return container;
}
beforeEach(() => {
(
globalThis as typeof globalThis & { IS_REACT_ACT_ENVIRONMENT?: boolean }
).IS_REACT_ACT_ENVIRONMENT = true;
});
afterEach(async () => {
vi.restoreAllMocks();
await act(async () => {
while (roots.length > 0) roots.pop()?.unmount();
});
for (let i = 0; i < 10; i++) await Promise.resolve();
while (containers.length > 0) containers.pop()?.remove();
document.body.innerHTML = "";
});
async function flush() {
await act(async () => {
for (let i = 0; i < 10; i++) await Promise.resolve();
});
}
interface CapturedPut {
url: string;
body: Record<string, unknown>;
}
function setupFetchMock(): { puts: CapturedPut[] } {
const puts: CapturedPut[] = [];
const json = (body: unknown, status = 200) =>
new Response(JSON.stringify(body), { status, headers: { "Content-Type": "application/json" } });
// omniglyph absent from `engines` initially → disabled; rtk/caveman present so we can
// assert they SURVIVE the PUT (the store persists the whole map as one row).
const initialConfig = {
enabled: true,
engines: { rtk: { enabled: true, level: "standard" }, caveman: { enabled: false } },
};
vi.spyOn(globalThis, "fetch").mockImplementation(
async (input: RequestInfo | URL, init?: RequestInit) => {
const url = input.toString();
const method = (init?.method ?? "GET").toUpperCase();
if (url.includes("/api/settings/compression")) {
if (method === "PUT") {
const body = JSON.parse(String(init?.body ?? "{}"));
puts.push({ url, body });
return json({ ...initialConfig, ...body });
}
return json(initialConfig);
}
return json({}, 404);
}
);
return { puts };
}
// ── Tests ──────────────────────────────────────────────────────────────────────
describe("OmniglyphContextPage", () => {
it("renders the four sections with the measured numbers and the real render", async () => {
setupFetchMock();
const { default: Page } = await import(
"../../../src/app/(dashboard)/dashboard/context/omniglyph/OmniglyphContextPageClient"
);
let container!: HTMLElement;
await act(async () => {
container = mount(<Page />);
});
await flush();
const text = container.textContent ?? "";
// Header + preview status
expect(text).toContain("OmniGlyph");
expect(text).toContain("Preview");
// Economics
expect(text).toContain("~10×");
expect(text).toContain("5970%");
// Before → after: measured savings + the real rendered image
expect(text).toContain(`${SAMPLE_METRICS.savingsPct}% tokens on this block`);
const img = container.querySelector("img");
expect(img, "the rendered sample page <img> must be present").toBeTruthy();
expect(img!.getAttribute("src")).toMatch(/^data:image\/png;base64,/);
// Gates
expect(text).toContain("claude-fable-5");
// A cópia do gate deixou de dizer "direct Anthropic" quando os wires OpenAI
// nativos entraram: transporte direto é condição de TODO provider, e o que
// restringe a rota ao Anthropic é o recibo de fidelidade de bytes, não o
// rótulo do transporte.
expect(text).toContain("direct provider");
// Config control
expect(container.querySelector('[data-testid="omniglyph-enable-toggle"]')).toBeTruthy();
});
it("enabling the engine PUTs the full engines map with omniglyph on, preserving the others", async () => {
const { puts } = setupFetchMock();
const { default: Page } = await import(
"../../../src/app/(dashboard)/dashboard/context/omniglyph/OmniglyphContextPageClient"
);
let container!: HTMLElement;
await act(async () => {
container = mount(<Page />);
});
await flush();
const toggle = container.querySelector('[data-testid="omniglyph-enable-toggle"] button') as HTMLButtonElement | null;
expect(toggle, "enable toggle button must exist").toBeTruthy();
await act(async () => {
toggle!.click();
});
await flush();
expect(puts.length).toBe(1);
const engines = puts[0]!.body.engines as Record<string, { enabled: boolean }>;
expect(engines.omniglyph).toEqual({ enabled: true });
// The other engines must survive the whole-map PUT.
expect(engines.rtk?.enabled).toBe(true);
expect(engines.caveman?.enabled).toBe(false);
});
it("carrega o perfil salvo e faz PATCH só do perfil, sem reescrever o mapa de engines", async () => {
const puts: CapturedPut[] = [];
const json = (body: unknown, status = 200) =>
new Response(JSON.stringify(body), {
status,
headers: { "Content-Type": "application/json" },
});
const stored = {
enabled: true,
engines: { rtk: { enabled: true, level: "standard" } },
omniglyph: { profile: "coding-safe" },
};
vi.spyOn(globalThis, "fetch").mockImplementation(
async (input: RequestInfo | URL, init?: RequestInit) => {
const url = input.toString();
const method = (init?.method ?? "GET").toUpperCase();
if (url.includes("/api/settings/compression")) {
if (method === "PUT") {
puts.push({ url, body: JSON.parse(String(init?.body ?? "{}")) });
return json(stored);
}
return json(stored);
}
return json({}, 404);
}
);
const { default: Page } = await import(
"../../../src/app/(dashboard)/dashboard/context/omniglyph/OmniglyphContextPageClient"
);
let container!: HTMLElement;
await act(async () => {
container = mount(<Page />);
});
await flush();
const select = container.querySelector(
'[data-testid="omniglyph-profile-select"]'
) as HTMLSelectElement | null;
expect(select, "o seletor de perfil deve existir").toBeTruthy();
expect(select!.value, "o perfil salvo tem de vir selecionado").toBe("coding-safe");
// Os quatro perfis do pacote, com aggressive como primeiro (default).
expect(Array.from(select!.options).map((o) => o.value)).toEqual([
"aggressive",
"balanced",
"coding-safe",
"passthrough",
]);
await act(async () => {
select!.value = "passthrough";
select!.dispatchEvent(new Event("change", { bubbles: true }));
});
await flush();
expect(puts.length).toBe(1);
expect(puts[0]!.body).toEqual({ omniglyph: { profile: "passthrough" } });
// O perfil vive fora do mapa `engines`: mandá-lo junto reescreveria o mapa inteiro.
expect(puts[0]!.body.engines).toBeUndefined();
});
});