fix(uok-gate-runner): use correct getRelevantMemoriesRanked API

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) <noreply@anthropic.com>
This commit is contained in:
Mikael Hugo 2026-05-14 17:21:18 +02:00
parent 6851869c00
commit f038f2a072
2 changed files with 33 additions and 50 deletions

View file

@ -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 () => {

View file

@ -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) {