From f038f2a072b6d9fbc0e7cab349b91b96a81fb301 Mon Sep 17 00:00:00 2001 From: Mikael Hugo Date: Thu, 14 May 2026 17:21:18 +0200 Subject: [PATCH] fix(uok-gate-runner): use correct getRelevantMemoriesRanked API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The "Memory enrichment failed for gate test: DB error" warning in test output was a real API mismatch, not a benign degradation. The previous code called getRelevantMemoriesRanked(embedding, "gotcha", 2) but the canonical signature is getRelevantMemoriesRanked(query, limit). Replace the embedding-based call with a query-string built from gateId + failureClass + rationale, and pass limit=2. The embedding helper (computeGateEmbedding) is removed entirely since the memory store does its own embedding internally. Also switch the enrichment-failure log from logWarning to debugLog — gate enrichment is best-effort and must not affect gates, so the failure path should not surface as a warning to operators. Test fixture updated to assert against the new API call shape. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../sf/tests/gate-context-enrichment.test.mjs | 14 ++-- .../extensions/sf/uok/gate-runner.js | 69 +++++++------------ 2 files changed, 33 insertions(+), 50 deletions(-) diff --git a/src/resources/extensions/sf/tests/gate-context-enrichment.test.mjs b/src/resources/extensions/sf/tests/gate-context-enrichment.test.mjs index 3f9392cdf..084782846 100644 --- a/src/resources/extensions/sf/tests/gate-context-enrichment.test.mjs +++ b/src/resources/extensions/sf/tests/gate-context-enrichment.test.mjs @@ -101,15 +101,21 @@ describe("Gate Context Enrichment (Phase 3)", () => { expect(similarFailure.content.length).toBeLessThanOrEqual(100); }); - it("queries_for_gotcha_category", async () => { + it("queries_with_gate_failure_context", async () => { memoryStore.getRelevantMemoriesRanked.mockResolvedValueOnce([]); - const result = { outcome: "fail" }; + const result = { + outcome: "fail", + failureClass: "timeout", + rationale: "Command exceeded limit", + }; await enrichGateResultWithMemory(result, "test-gate"); const callArgs = memoryStore.getRelevantMemoriesRanked.mock.calls[0]; - expect(callArgs[1]).toBe("gotcha"); + expect(callArgs[0]).toContain("uok gate failure test-gate"); + expect(callArgs[0]).toContain("timeout"); + expect(callArgs[0]).toContain("Command exceeded limit"); }); it("limits_similar_failures_to_2", async () => { @@ -120,7 +126,7 @@ describe("Gate Context Enrichment (Phase 3)", () => { await enrichGateResultWithMemory(result, "test-gate"); const callArgs = memoryStore.getRelevantMemoriesRanked.mock.calls[0]; - expect(callArgs[2]).toBe(2); // limit: 2 + expect(callArgs[1]).toBe(2); // limit: 2 }); it("degrades_gracefully_when_db_unavailable", async () => { diff --git a/src/resources/extensions/sf/uok/gate-runner.js b/src/resources/extensions/sf/uok/gate-runner.js index 5c5518be0..d79d85caa 100644 --- a/src/resources/extensions/sf/uok/gate-runner.js +++ b/src/resources/extensions/sf/uok/gate-runner.js @@ -1,3 +1,4 @@ +import { debugLog } from "../debug-logger.js"; import { getErrorMessage } from "../error-utils.js"; import { getRelevantMemoriesRanked } from "../memory-store.js"; import { @@ -7,7 +8,6 @@ import { isDbAvailable, updateGateCircuitBreaker, } from "../sf-db.js"; -import { logWarning } from "../workflow-logger.js"; import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js"; import { validateGate } from "./contracts.js"; import { appendTraceEvent } from "./trace-writer.js"; @@ -87,60 +87,37 @@ export async function enrichGateResultWithMemory(gateResult, gateId) { try { // Query: "Have we seen failures like this before?" const gateIdNorm = String(gateId || "unknown").toLowerCase(); - const embedding = await computeGateEmbedding(gateIdNorm); + const failureClass = gateResult?.failureClass + ? ` ${gateResult.failureClass}` + : ""; + const rationale = gateResult?.rationale ? ` ${gateResult.rationale}` : ""; + const query = `uok gate failure ${gateIdNorm}${failureClass}${rationale}`; + const memories = await getRelevantMemoriesRanked(query, 2); - if (embedding) { - const memories = await getRelevantMemoriesRanked( - embedding, - "gotcha", // Gate failures are often 'gotchas' - 2, // Top 2 similar failures - ); - - if (memories.length > 0) { - return { - ...gateResult, - memoryContext: { - hasHistoricalPattern: true, - similarFailures: memories.map((m) => ({ - id: m.id, - confidence: m.confidence, - content: m.content.substring(0, 100), // First 100 chars - })), - }, - }; - } + if (memories.length > 0) { + return { + ...gateResult, + memoryContext: { + hasHistoricalPattern: true, + similarFailures: memories.map((m) => ({ + id: m.id, + confidence: m.confidence, + content: m.content.substring(0, 100), // First 100 chars + })), + }, + }; } } catch (err) { // Degrade gracefully - memory enrichment never changes gate result - logWarning( - "gate-runner", - `Memory enrichment failed for gate ${gateId}: ${getErrorMessage(err)}`, - ); + debugLog("gate-memory-enrichment-failed", { + gateId, + error: getErrorMessage(err), + }); } return gateResult; } -/** - * Compute embedding for a gate ID. - */ -async function computeGateEmbedding(gateId) { - try { - const gateNorm = String(gateId || "unknown") - .toLowerCase() - .trim(); - const embedding = new Array(64).fill(0); - for (let i = 0; i < gateNorm.length; i++) { - const charCode = gateNorm.charCodeAt(i); - embedding[i % 64] += Math.sin(charCode * (i + 1)) * 0.1; - } - const norm = Math.sqrt(embedding.reduce((sum, x) => sum + x * x, 0)); - return norm > 0 ? embedding.map((x) => x / norm) : embedding; - } catch (_err) { - return null; - } -} - export class UokGateRunner { registry = new Map(); register(gate) {