feat(confidence-engine): v0.60g1 list investigation summaries
Recover to clean v0.60f then implement only the storage listing contract. - Add listInvestigations() to provider: enumerate by prefix, project lightweight summary (id, scenario, updatedAt, investigationRevision, reportExists, reportGeneratedFromRevision), sort by updatedAt desc - Add application-facing wrapper in investigation-storage.js - Add 8 deterministic tests covering all listing invariants (coexistence, correct IDs, lightweight projection, legacy exclusion, unrelated exclusion, independent update, ordering, malformed skip) - Fix MockStorageMap WebStorage API compatibility (.length + .key(i)) - Portfolio NOT migrated — that is v0.60g2
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// Owns the canonical identity contract: snapshot.id is the sole save identity.
|
||||
// Delegates to the concrete localStorage provider internally.
|
||||
|
||||
import { loadInvestigation as _load, saveInvestigation as _save, clearInvestigation as _clear } from "./providers/local-storage.js";
|
||||
import { loadInvestigation as _load, saveInvestigation as _save, clearInvestigation as _clear, listInvestigations as _list } from "./providers/local-storage.js";
|
||||
|
||||
/**
|
||||
* Canonical save contract: snapshot.id is the sole identity authority.
|
||||
@@ -32,3 +32,11 @@ export function loadInvestigation(id) {
|
||||
export function clearInvestigation(id) {
|
||||
return _clear(id ?? undefined);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists all durable-ID Investigation records as lightweight summaries.
|
||||
* Excludes legacy singleton, sessionStorage state, unrelated storage, malformed entries.
|
||||
*/
|
||||
export function listInvestigations() {
|
||||
return _list();
|
||||
}
|
||||
|
||||
@@ -126,6 +126,55 @@ export function clearInvestigation(id) {
|
||||
}
|
||||
}
|
||||
|
||||
// ── listInvestigations (durable-ID only) ───────────────────────
|
||||
|
||||
/**
|
||||
* Enumerates all durable-ID Investigation records and returns lightweight summaries.
|
||||
* Skips malformed entries; excludes legacy singleton, sessionStorage state, unrelated keys.
|
||||
*/
|
||||
export function listInvestigations() {
|
||||
const storage = _getTargetStorage();
|
||||
if (!storage) return [];
|
||||
|
||||
const summaries = [];
|
||||
|
||||
for (let i = 0; i < storage.length; i++) {
|
||||
const key = storage.key(i);
|
||||
if (!key || !key.startsWith(INVESTIGATION_PREFIX)) continue;
|
||||
|
||||
try {
|
||||
const raw = safeGet(storage, key);
|
||||
if (!raw) continue;
|
||||
const record = JSON.parse(raw);
|
||||
if (!isPlainObject(record)) continue;
|
||||
if (!record.id) continue;
|
||||
|
||||
summaries.push({
|
||||
id: record.id,
|
||||
scenario: record.scenario ?? null,
|
||||
updatedAt: record.updatedAt ?? null,
|
||||
investigationRevision: record.investigationRevision ?? 0,
|
||||
reportExists: !!record.investigationReport,
|
||||
reportGeneratedFromRevision: record.investigationReport
|
||||
? record.investigationReport.generatedFromRevision ?? null
|
||||
: null,
|
||||
});
|
||||
} catch (_) {
|
||||
// Malformed durable-ID entry — skip silently
|
||||
}
|
||||
}
|
||||
|
||||
summaries.sort((a, b) => {
|
||||
const ta = a.updatedAt ?? "";
|
||||
const tb = b.updatedAt ?? "";
|
||||
if (ta > tb) return -1;
|
||||
if (ta < tb) return 1;
|
||||
return a.id > b.id ? -1 : 1;
|
||||
});
|
||||
|
||||
return summaries;
|
||||
}
|
||||
|
||||
// ── internals ────────────────────────────────────────────────────────
|
||||
|
||||
function _persist(storage, key, value) {
|
||||
|
||||
Reference in New Issue
Block a user