feat(confidence-engine): v0.60c identity-aware investigation storage

- loadInvestigation(id) selects by durable ID when provided, null for unknown
- saveInvestigation(snapshot, id) persists under provider-chosen key derived from id
- clearInvestigation(id) removes specific investigation by identity when provided
- localStorage representation: confidence-engine-investigation:<durable-id>
- Backward-compatible singleton path preserved for existing unmigrated callers
- 6 new targeted tests proving two independently addressable Investigations
This commit is contained in:
2026-09-03 18:09:03 +01:00
parent f23d442eb3
commit 8c85120b1c
3 changed files with 220 additions and 18 deletions
+107
View File
@@ -226,3 +226,110 @@ describe("investigation-storage provider", () => {
});
});
// ── v0.60c — identity-aware multi-investigation persistence ────────────
describe("investigation-storage v0.60c identity-aware", () => {
function newId() {
return `inv-${Math.random().toString(36).slice(2, 9)}`;
}
beforeEach(() => {
globalThis.window.localStorage.clear();
});
// ── A: saveInvestigation(A) persists A under A.id ───────────────
it("save with id persists under that id key", async () => {
const { load, save } = await getModule();
const idA = newId();
const snapA = makeSnapshot({ id: idA, title: "Alpha" });
save(snapA, idA);
const loaded = load(idA);
expect(loaded).not.toBeNull();
expect(loaded.id).toBe(idA);
expect(loaded.title).toBe("Alpha");
});
// ── B: saveInvestigation(B) persists B independently under B.id ──
it("save two investigations with different ids are independent", async () => {
const { load, save } = await getModule();
const idA = newId();
const idB = newId();
const snapA = makeSnapshot({ id: idA, title: "Alpha" });
const snapB = makeSnapshot({ id: idB, title: "Beta" });
save(snapA, idA);
save(snapB, idB);
// A survives B save
const loadedA = load(idA);
expect(loadedA).not.toBeNull();
expect(loadedA.id).toBe(idA);
expect(loadedA.title).toBe("Alpha");
});
// ── A loads by A.id ──────────────────────────────────────────────
it("loadInvestigation(A.id) returns A", async () => {
const { load, save } = await getModule();
const idA = newId();
const snapA = makeSnapshot({ id: idA, title: "Alpha" });
save(snapA, idA);
const loaded = load(idA);
expect(loaded).not.toBeNull();
expect(loaded.id).toBe(idA);
expect(loaded.title).toBe("Alpha");
});
// ── B loads by B.id ──────────────────────────────────────────────
it("loadInvestigation(B.id) returns B", async () => {
const { load, save } = await getModule();
const idA = newId();
const idB = newId();
const snapA = makeSnapshot({ id: idA, title: "Alpha" });
const snapB = makeSnapshot({ id: idB, title: "Beta" });
save(snapA, idA);
save(snapB, idB);
const loaded = load(idB);
expect(loaded).not.toBeNull();
expect(loaded.id).toBe(idB);
expect(loaded.title).toBe("Beta");
});
// ── unknown ID returns null ──────────────────────────────────────
it("loadInvestigation(unknownId) returns null", async () => {
const { load } = await getModule();
const loaded = load("non-existent-id-xyz");
expect(loaded).toBeNull();
});
// ── save does not invent or change the supplied ID ───────────────
it("saveInvestigation does not invent or replace the supplied id", async () => {
const { save } = await getModule();
const originalId = `inv-unique-77`;
const snapA = makeSnapshot({ id: originalId, title: "Alpha" });
save(snapA, originalId);
// Verify the persisted record still carries exactly the supplied id
// (the deep clone should not have mutated it)
const raw = globalThis.window.localStorage.getItem(
`confidence-engine-investigation:${originalId}`
);
expect(raw).not.toBeNull();
const parsed = JSON.parse(raw);
expect(parsed.id).toBe(originalId);
});
});