From 7802f6ea163f18f349348dbfd8710a159ac32e15 Mon Sep 17 00:00:00 2001 From: Diego Rodrigues de Sa e Souza Date: Wed, 2 Sep 2026 05:12:11 -0300 Subject: [PATCH] fix(uc): route UC error strings through sanitizeErrorMessage; allowlist the retired codex id (#12437) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drains the two remaining Fast Quality Gates reds the #11513 (UC) merge left on the tip: - error-helper: ucTts.ts and uc/ws.ts built error payloads from raw err.message (Hard Rule #12) — now wrapped in sanitizeErrorMessage(), behavior otherwise identical (uc suites 51/51). - model-lifecycle: the UC catalog registers the vendor-retired gpt-5.2-codex (bare id; only the prefixed openai/gpt-5.2-codex was allowlisted). Added to allowedRetiredInCatalog per its policy — forwarding globally would rewrite the just-approved provider's model. Tracking: Refs #12436. file-size, the third red of this window, was already drained by #12434. --- config/quality/model-lifecycle.json | 1 + open-sse/executors/uc/ws.ts | 5 +++-- open-sse/handlers/uc/ucTts.ts | 5 +++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/config/quality/model-lifecycle.json b/config/quality/model-lifecycle.json index 40ac870f9f..59da8bb77d 100644 --- a/config/quality/model-lifecycle.json +++ b/config/quality/model-lifecycle.json @@ -14,6 +14,7 @@ "claude-3-7-sonnet-20250219", "google/gemini-2.0-flash", "gpt-4-0125-preview", + "gpt-5.2-codex", "openai/gpt-5.2-codex" ], "allowedRetiredInCatalog_note": "TODO(#11503): ratchet to burn down. Each id is retired by its vendor but still routable from the provider catalog. Removing a catalog row or adding a BUILT_IN_ALIASES forward is a maintainer call (some aggregators still serve these ids), so they are allowlisted here rather than silently dropped. Delete an entry as soon as it is forwarded or removed; never add one without a tracking issue.", diff --git a/open-sse/executors/uc/ws.ts b/open-sse/executors/uc/ws.ts index cc27854332..6c2bd1f0ae 100644 --- a/open-sse/executors/uc/ws.ts +++ b/open-sse/executors/uc/ws.ts @@ -14,6 +14,7 @@ * fake socket (same pattern as muse-spark-web). */ import WebSocket from "ws"; +import { sanitizeErrorMessage } from "../../utils/error.ts"; import { UC_ORIGIN, UC_WS_HOST, UC_WS_TIMEOUT_MS } from "./constants.ts"; import { buildPersonaFrame, type UcHistoryEntry } from "./protocol.ts"; @@ -82,7 +83,7 @@ export function runUcTurn(input: UcTurnInput): Promise { resolve({ content: "", reasoning: "", - error: `ws connect failed: ${err instanceof Error ? err.message : String(err)}`, + error: `ws connect failed: ${sanitizeErrorMessage(err instanceof Error ? err.message : String(err))}`, }); return; } @@ -126,7 +127,7 @@ export function runUcTurn(input: UcTurnInput): Promise { }); ws.send(JSON.stringify(frame)); } catch (err) { - fail(`ws send failed: ${err instanceof Error ? err.message : String(err)}`); + fail(`ws send failed: ${sanitizeErrorMessage(err instanceof Error ? err.message : String(err))}`); } }; diff --git a/open-sse/handlers/uc/ucTts.ts b/open-sse/handlers/uc/ucTts.ts index 57b651d512..6e9e1e5ab4 100644 --- a/open-sse/handlers/uc/ucTts.ts +++ b/open-sse/handlers/uc/ucTts.ts @@ -28,6 +28,7 @@ * path is unit-testable with no live network. */ import { randomUUID } from "node:crypto"; +import { sanitizeErrorMessage } from "../../utils/error.ts"; import { Buffer } from "node:buffer"; import WebSocket from "ws"; @@ -151,7 +152,7 @@ export function runUcTtsSocket(input: UcTtsSocketInput): Promise, - error: `ws connect failed: ${err instanceof Error ? err.message : String(err)}`, + error: `ws connect failed: ${sanitizeErrorMessage(err instanceof Error ? err.message : String(err))}`, }); return; } @@ -194,7 +195,7 @@ export function runUcTtsSocket(input: UcTtsSocketInput): Promise