Files
memind/scripts/compare-goose-v149-memory-manifest.test.mjs
T
john fe8a5e74d1 fix(goose): tighten memory drift checks and add resume smoke gate
Compare memory userId and candidate deltas during manifest drift checks,
add unit tests for false-positive cases, and verify /agent/resume plus
session history loading against local v1.49.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-09-08 21:27:14 +08:00

138 lines
4.3 KiB
JavaScript

import assert from 'node:assert/strict';
import { test } from 'node:test';
import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);
// Inline compare logic by importing via dynamic eval of exported function -
// the script only has main(); duplicate core compare here for unit tests.
function indexMemories(manifest) {
const byId = new Map();
for (const item of manifest.memories ?? []) {
byId.set(item.id, item);
}
return byId;
}
function indexCandidates(manifest) {
const byId = new Map();
for (const item of manifest.candidates ?? []) {
byId.set(item.id, item);
}
return byId;
}
function compareManifests(baseline, current) {
const drift = {
summary: {
candidateCountDelta:
(current.summary?.candidateCount ?? 0) - (baseline.summary?.candidateCount ?? 0),
},
addedMemoryIds: [],
removedMemoryIds: [],
changedMemories: [],
addedCandidateIds: [],
removedCandidateIds: [],
changedCandidates: [],
};
const base = indexMemories(baseline);
const cur = indexMemories(current);
for (const [id] of cur) {
if (!base.has(id)) drift.addedMemoryIds.push(id);
}
for (const [id] of base) {
if (!cur.has(id)) drift.removedMemoryIds.push(id);
}
for (const [id, baseItem] of base) {
const curItem = cur.get(id);
if (!curItem) continue;
const fields = [
'userId',
'memoryHash',
'status',
'sourceSessionId',
'evidenceMessageId',
];
const changes = {};
for (const field of fields) {
if (String(baseItem[field] ?? '') !== String(curItem[field] ?? '')) {
changes[field] = { baseline: baseItem[field] ?? null, current: curItem[field] ?? null };
}
}
if (Object.keys(changes).length) {
drift.changedMemories.push({ id, changes });
}
}
const baseCandidates = indexCandidates(baseline);
const curCandidates = indexCandidates(current);
for (const [id] of curCandidates) {
if (!baseCandidates.has(id)) drift.addedCandidateIds.push(id);
}
for (const [id] of baseCandidates) {
if (!curCandidates.has(id)) drift.removedCandidateIds.push(id);
}
for (const [id, baseItem] of baseCandidates) {
const curItem = curCandidates.get(id);
if (!curItem) continue;
const fields = ['userId', 'status', 'sourceSessionId'];
const changes = {};
for (const field of fields) {
if (String(baseItem[field] ?? '') !== String(curItem[field] ?? '')) {
changes[field] = { baseline: baseItem[field] ?? null, current: curItem[field] ?? null };
}
}
if (Object.keys(changes).length) {
drift.changedCandidates.push({ id, changes });
}
}
drift.ok =
drift.addedMemoryIds.length === 0
&& drift.removedMemoryIds.length === 0
&& drift.changedMemories.length === 0
&& drift.addedCandidateIds.length === 0
&& drift.removedCandidateIds.length === 0
&& drift.changedCandidates.length === 0
&& drift.summary.candidateCountDelta === 0;
return drift;
}
test('memory drift fails when userId changes for the same memory id', () => {
const baseline = {
summary: { candidateCount: 1 },
memories: [{ id: 'm1', userId: 'u1', memoryHash: 'h1', status: 'active' }],
candidates: [{ id: 'c1', userId: 'u1', status: 'pending' }],
};
const current = {
summary: { candidateCount: 6 },
memories: [{ id: 'm1', userId: 'u2', memoryHash: 'h1', status: 'active' }],
candidates: [
{ id: 'c1', userId: 'u1', status: 'pending' },
{ id: 'c2', userId: 'u1', status: 'pending' },
{ id: 'c3', userId: 'u1', status: 'pending' },
{ id: 'c4', userId: 'u1', status: 'pending' },
{ id: 'c5', userId: 'u1', status: 'pending' },
{ id: 'c6', userId: 'u1', status: 'pending' },
],
};
const report = compareManifests(baseline, current);
assert.equal(report.ok, false);
assert.equal(report.changedMemories.length, 1);
assert.equal(report.changedMemories[0].changes.userId.baseline, 'u1');
assert.equal(report.summary.candidateCountDelta, 5);
assert.ok(report.addedCandidateIds.length >= 5);
});
test('memory drift passes for identical manifests', () => {
const manifest = {
summary: { candidateCount: 0 },
memories: [{ id: 'm1', userId: 'u1', memoryHash: 'h1', status: 'active' }],
candidates: [],
};
const report = compareManifests(manifest, structuredClone(manifest));
assert.equal(report.ok, true);
});