fe8a5e74d1
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>
138 lines
4.3 KiB
JavaScript
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);
|
|
});
|