fix(memory): address quality cleanup audit findings

This commit is contained in:
Ralph Chang
2026-04-28 14:29:28 +08:00
parent e8c95a62ec
commit 8da39c7a9d
9 changed files with 267 additions and 63 deletions
+10 -1
View File
@@ -248,6 +248,15 @@ async function logExtractionRejection(entry: ExtractionRejectionLogEntry): Promi
}
}
function redactSensitiveText(text: string): string {
return text
.replace(/bearer\s+[a-zA-Z0-9._-]+/gi, "bearer [REDACTED]")
.replace(/token[=:]\s*[a-zA-Z0-9._-]+/gi, "token=[REDACTED]")
.replace(/password[=:]\s*[a-zA-Z0-9._-]+/gi, "password=[REDACTED]")
.replace(/secret[=:]\s*[a-zA-Z0-9._-]+/gi, "secret=[REDACTED]")
.replace(/api[-_]?key[=:]\s*[a-zA-Z0-9._-]+/gi, "api_key=[REDACTED]");
}
function shouldAcceptWorkspaceMemoryCandidate(
entry: {
type: LongTermType;
@@ -278,7 +287,7 @@ function shouldAcceptWorkspaceMemoryCandidate(
void logExtractionRejection({
timestamp: new Date().toISOString(),
type: entry.type,
text,
text: redactSensitiveText(text),
reasons: quality.reasons,
source: "compaction",
});
+12 -3
View File
@@ -208,14 +208,23 @@ export async function normalizeWorkspaceMemoryWithAccounting(
// One-time migrations for legacy/low-quality snapshot violations.
// Run quality cleanup first so hard violations receive quality audit tags
// before the older P0 project-only cleanup marks progress snapshots.
const beforeQualityCleanup = result;
const qualityCleanup = runMigrationQualityCleanup(result, nowIso);
result = qualityCleanup.store;
let skipRemainingMigrations = false;
if (qualityCleanup.events.length > 0) {
await appendQualityCleanupMigrationLog(qualityCleanup.events).catch(error => {
try {
await appendQualityCleanupMigrationLog(qualityCleanup.events);
} catch (error) {
console.error("[memory] failed to write quality cleanup migration log:", error);
});
console.error("[memory] aborting migration to maintain audit trail integrity");
result = beforeQualityCleanup;
skipRemainingMigrations = true;
}
}
if (!skipRemainingMigrations) {
result = runMigrationP0Cleanup(result, nowIso);
}
result = runMigrationP0Cleanup(result, nowIso);
// P0 accounting only considers active entries. Entries that were already
// superseded before this normalization are preserved in storage; entries that