From 9591f85dca6a45942fcc874b4eacb4f24f1c2db1 Mon Sep 17 00:00:00 2001 From: Ralph Chang Date: Thu, 14 May 2026 16:53:17 +0800 Subject: [PATCH] fix(memory-diag): remove duplicate active memory candidates --- scripts/memory-diag/quality-review-model.ts | 25 +++------------------ tests/memory-diag-quality.test.ts | 13 ++++++++++- 2 files changed, 15 insertions(+), 23 deletions(-) diff --git a/scripts/memory-diag/quality-review-model.ts b/scripts/memory-diag/quality-review-model.ts index e259a49..c57772c 100644 --- a/scripts/memory-diag/quality-review-model.ts +++ b/scripts/memory-diag/quality-review-model.ts @@ -265,10 +265,9 @@ export type ReviewBoardActiveMemory = { }; export type ReviewBoardCandidate = { - concernKind: "system_mechanism" | "memory_content"; - mechanism?: "rejection_filter" | "reinforcement_rule" | "eviction_cap" | "identity_dedup" | "retention_rendering"; + concernKind: "system_mechanism"; + mechanism?: "rejection_filter" | "reinforcement_rule" | "eviction_cap" | "identity_dedup"; source: - | "active_memory" | "rejection_rule_evidence" | "missing_evidence" | "numbered_command_evidence" @@ -410,9 +409,8 @@ export function buildQualityReviewBoard( .flatMap(inputs => selectRepresentative(inputs, true).map(item => item.candidate)); const reviewCandidates = [ ...systemCandidateDisplay.candidates, - ...buildMemoryContentCandidates(model, activeMemories, raw), ]; - const activeMemoryDisplay = buildActiveMemoryDisplay(model, activeMemories, reabsorbedKeys, activeMemoryByKey, provenanceInputs, raw, options.verbose === true); + const activeMemoryDisplay = buildActiveMemoryDisplay(model, activeMemories, reabsorbedKeys, activeMemoryByKey, provenanceInputs, raw, options.verbose === true || options.json === true); const countsByClassification = countProvenanceClassifications(allSystemMechanismCandidates); const answerabilityReport = buildAnswerabilityReport(); @@ -1552,23 +1550,6 @@ function buildIdentityCandidates(model: MemoryInspectionReadModel, activeMemorie return [...replacementCandidates, ...duplicateCandidates]; } -function buildMemoryContentCandidates(model: MemoryInspectionReadModel, activeMemories: LongTermMemoryEntry[], raw: boolean): ReviewBoardCandidate[] { - return activeMemories.slice(0, ACTIVE_MEMORY_FULL_TEXT_THRESHOLD).map(memory => { - const events = model.evidenceByMemoryId.get(memory.id) ?? []; - return candidate({ - concernKind: "memory_content", - mechanism: "retention_rendering", - source: "active_memory", - id: `active:${memory.id}`, - facts: { id: memory.id, type: memory.type, source: memory.source, status: memory.status }, - evidence: { eventIds: events.map(event => event.eventId), rawReasonCodes: uniqueStrings(events.flatMap(event => event.reasonCodes)).sort(), textPreview: truncate(cleanText(memory.text, raw), 120), textAvailable: true }, - heuristicFlags: activeMemoryFlags(memory, events), - reviewQuestions: memoryContentQuestions(), - nextCommands: [`memory-diag explain ${memory.id}`], - }); - }); -} - function candidate(input: ReviewBoardCandidate): ReviewBoardCandidate { return input; } diff --git a/tests/memory-diag-quality.test.ts b/tests/memory-diag-quality.test.ts index 6c63b7d..301b6bf 100644 --- a/tests/memory-diag-quality.test.ts +++ b/tests/memory-diag-quality.test.ts @@ -301,11 +301,19 @@ test("quality review model applies active memory threshold, full text, and redac assert.equal(defaultReport.activeMemoryDisplay.items[0].text.includes("Keep full text with"), true); assert.doesNotMatch(defaultReport.activeMemoryDisplay.items[0].text, /secret-value|\/Users\/alice/); assert.match(defaultReport.activeMemoryDisplay.items[0].text, /\[REDACTED\]|/); + assert.equal(defaultReport.reviewCandidates.every(candidate => candidate.source !== "active_memory"), true); + assert.equal(defaultReport.reviewCandidates.every(candidate => candidate.concernKind === "system_mechanism"), true); const verboseReport = buildQualityReviewBoard(model, { verbose: true }, generatedAt); assert.equal(verboseReport.activeMemoryDisplay.mode, "all"); assert.equal(verboseReport.activeMemoryDisplay.shown, 41); + const jsonReport = buildQualityReviewBoard(model, { json: true }, generatedAt); + assert.equal(jsonReport.activeMemoryDisplay.mode, "all"); + assert.equal(jsonReport.activeMemoryDisplay.shown, 41); + assert.equal(jsonReport.activeMemoryDisplay.total, 41); + assert.equal(jsonReport.reviewCandidates.every(candidate => candidate.source !== "active_memory"), true); + const rawReport = buildQualityReviewBoard(model, { raw: true }, generatedAt); assert.match(rawReport.activeMemoryDisplay.items[0].text, /secret-value|\/Users\/alice/); }); @@ -524,8 +532,11 @@ test("quality review model builds system mechanism facts and neutral candidates" assert.ok(report.reviewCandidates.some(candidate => candidate.mechanism === "reinforcement_rule")); assert.ok(report.reviewCandidates.some(candidate => candidate.source === "eviction_cap_evidence" && candidate.evidence.textAvailable === false)); assert.ok(report.reviewCandidates.some(candidate => candidate.source === "identity_dedup_evidence")); + assert.ok(report.reviewCandidates.length > 0); + assert.equal(report.reviewCandidates.every(candidate => candidate.source !== "active_memory"), true); + assert.equal(report.reviewCandidates.every(candidate => candidate.concernKind === "system_mechanism"), true); assert.ok(report.reviewCandidates.every(candidate => Array.isArray(candidate.heuristicFlags) && Array.isArray(candidate.reviewQuestions))); - assert.ok(report.reviewCandidates.filter(candidate => candidate.source !== "active_memory").every(candidate => candidate.provenance)); + assert.ok(report.reviewCandidates.every(candidate => candidate.provenance)); assert.doesNotMatch(JSON.stringify(report), /secret-value|\/tmp\/private/); });