From 02f4df4b607e468ac31c38298efcc6d3b49bfd96 Mon Sep 17 00:00:00 2001 From: luvs01 Date: Fri, 7 Aug 2026 15:35:04 +0900 Subject: [PATCH 1/3] fix(routing): bound reasoning effort hydration --- src/routing/trace.ts | 19 +++++++---- tests/route-decision-trace.test.ts | 52 ++++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/src/routing/trace.ts b/src/routing/trace.ts index 169400d8d..daea4db9f 100644 --- a/src/routing/trace.ts +++ b/src/routing/trace.ts @@ -465,13 +465,20 @@ function parseCapability(raw: unknown, caps: ParseCaps): RouteCapabilityEvidence if (image !== undefined) out.image = image; const structuredOutput = unknownable(raw.structuredOutput); if (structuredOutput !== undefined) out.structuredOutput = structuredOutput; - if (Array.isArray(raw.reasoningEfforts) - && raw.reasoningEfforts.slice(0, 8).every((value): value is string => typeof value === "string")) { - if (raw.reasoningEfforts.some((value: unknown) => typeof value === "string" + const rawReasoningEfforts = Array.isArray(raw.reasoningEfforts) + ? raw.reasoningEfforts + : undefined; + const reasoningEfforts = rawReasoningEfforts + ? Array.from( + { length: Math.min(rawReasoningEfforts.length, 8) }, + (_, index) => rawReasoningEfforts[index], + ) + : undefined; + if (reasoningEfforts + && reasoningEfforts.every((value): value is string => typeof value === "string")) { + if (reasoningEfforts.some((value: unknown) => typeof value === "string" && value.length > MAX_TRACE_STRING)) caps.strings = true; - out.reasoningEfforts = raw.reasoningEfforts - .slice(0, 8) - .map(value => value.slice(0, MAX_TRACE_STRING)); + out.reasoningEfforts = reasoningEfforts.map(value => value.slice(0, MAX_TRACE_STRING)); } if (raw.serviceTier === "unknown") { out.serviceTier = "unknown"; diff --git a/tests/route-decision-trace.test.ts b/tests/route-decision-trace.test.ts index 5a0c00579..501ae32a5 100644 --- a/tests/route-decision-trace.test.ts +++ b/tests/route-decision-trace.test.ts @@ -223,6 +223,58 @@ describe("route decision traces (RI-01)", () => { expect(trace.candidates.every(candidate => candidate.exclusions.length === MAX_EXCLUSIONS_PER_CANDIDATE)).toBe(true); }); + test("normalization only inspects retained reasoning efforts", () => { + const reasoningEfforts = Array.from({ length: 1_000_000 }) as unknown[]; + reasoningEfforts.fill("medium", 0, 8); + Object.defineProperty(reasoningEfforts, reasoningEfforts.length - 1, { + get: () => { throw new Error("reasoning effort outside the retained range was inspected"); }, + }); + const raw = { + version: 1, + decisionId: "abcdef012345", + createdAt: 1, + requestedModel: "a/m1", + routeKind: "policy", + requirements: [], + candidates: [{ + provider: "a", + model: "m1", + eligible: true, + exclusions: [], + capability: { reasoningEfforts }, + }], + selected: { candidateIndex: 0, provider: "a", model: "m1", reason: "policy" }, + }; + + expect(normalizeRouteDecisionTrace(raw)?.candidates[0]?.capability?.reasoningEfforts) + .toEqual(Array.from({ length: 8 }, () => "medium")); + }); + + test("normalization rejects sparse retained reasoning efforts", () => { + const reasoningEfforts = Array(8) as unknown[]; + reasoningEfforts[0] = "low"; + reasoningEfforts[7] = "high"; + const raw = { + version: 1, + decisionId: "abcdef012345", + createdAt: 1, + requestedModel: "a/m1", + routeKind: "policy", + requirements: [], + candidates: [{ + provider: "a", + model: "m1", + eligible: true, + exclusions: [], + capability: { reasoningEfforts }, + }], + selected: { candidateIndex: 0, provider: "a", model: "m1", reason: "policy" }, + }; + + expect(normalizeRouteDecisionTrace(raw)?.candidates[0]?.capability?.reasoningEfforts) + .toBeUndefined(); + }); + test("startup hydration reads trace-sized usage rows", () => { const trace = oversizedTrace(); for (let index = 0; index < 20; index++) { From b28e60519b5c39b52bd28bf3ef37598242a15dea Mon Sep 17 00:00:00 2001 From: luvs01 <27862058+luvs01@users.noreply.github.com> Date: Sat, 8 Aug 2026 15:57:31 +0900 Subject: [PATCH 2/3] test(routing): strengthen trace hydration bounds --- tests/route-decision-trace.test.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/route-decision-trace.test.ts b/tests/route-decision-trace.test.ts index 501ae32a5..6ecee9953 100644 --- a/tests/route-decision-trace.test.ts +++ b/tests/route-decision-trace.test.ts @@ -226,7 +226,7 @@ describe("route decision traces (RI-01)", () => { test("normalization only inspects retained reasoning efforts", () => { const reasoningEfforts = Array.from({ length: 1_000_000 }) as unknown[]; reasoningEfforts.fill("medium", 0, 8); - Object.defineProperty(reasoningEfforts, reasoningEfforts.length - 1, { + Object.defineProperty(reasoningEfforts, 8, { get: () => { throw new Error("reasoning effort outside the retained range was inspected"); }, }); const raw = { @@ -271,8 +271,11 @@ describe("route decision traces (RI-01)", () => { selected: { candidateIndex: 0, provider: "a", model: "m1", reason: "policy" }, }; - expect(normalizeRouteDecisionTrace(raw)?.candidates[0]?.capability?.reasoningEfforts) - .toBeUndefined(); + const normalized = normalizeRouteDecisionTrace(raw); + expect(normalized).not.toBeNull(); + if (!normalized) throw new Error("trace normalization unexpectedly failed"); + expect(normalized.candidates).toHaveLength(1); + expect(normalized.candidates[0]?.capability?.reasoningEfforts).toBeUndefined(); }); test("startup hydration reads trace-sized usage rows", () => { From 6211610e00ad1869e7cb87fdfceef72f62886b5e Mon Sep 17 00:00:00 2001 From: luvs01 <27862058+luvs01@users.noreply.github.com> Date: Sat, 8 Aug 2026 17:10:36 +0900 Subject: [PATCH 3/3] test(routing): verify retained string truncation --- tests/route-decision-trace.test.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/route-decision-trace.test.ts b/tests/route-decision-trace.test.ts index 6ecee9953..f90d77f30 100644 --- a/tests/route-decision-trace.test.ts +++ b/tests/route-decision-trace.test.ts @@ -226,6 +226,7 @@ describe("route decision traces (RI-01)", () => { test("normalization only inspects retained reasoning efforts", () => { const reasoningEfforts = Array.from({ length: 1_000_000 }) as unknown[]; reasoningEfforts.fill("medium", 0, 8); + reasoningEfforts[0] = "x".repeat(MAX_TRACE_STRING + 1); Object.defineProperty(reasoningEfforts, 8, { get: () => { throw new Error("reasoning effort outside the retained range was inspected"); }, }); @@ -246,8 +247,12 @@ describe("route decision traces (RI-01)", () => { selected: { candidateIndex: 0, provider: "a", model: "m1", reason: "policy" }, }; - expect(normalizeRouteDecisionTrace(raw)?.candidates[0]?.capability?.reasoningEfforts) - .toEqual(Array.from({ length: 8 }, () => "medium")); + const normalized = normalizeRouteDecisionTrace(raw); + expect(normalized).not.toBeNull(); + if (!normalized) throw new Error("trace normalization unexpectedly failed"); + expect(normalized.candidates[0]?.capability?.reasoningEfforts) + .toEqual(["x".repeat(MAX_TRACE_STRING), ...Array.from({ length: 7 }, () => "medium")]); + expect(normalized.truncated?.strings).toBe(true); }); test("normalization rejects sparse retained reasoning efforts", () => {