diff --git a/packages/loopover-miner/lib/migrate-cli.ts b/packages/loopover-miner/lib/migrate-cli.ts index a8fffcc9c..69797069c 100644 --- a/packages/loopover-miner/lib/migrate-cli.ts +++ b/packages/loopover-miner/lib/migrate-cli.ts @@ -27,6 +27,7 @@ import { initPolicyVerdictCacheStore, resolvePolicyVerdictCacheDbPath } from "./ import { initPolicyDocCacheStore, resolvePolicyDocCacheDbPath } from "./policy-doc-cache.js"; import { initRankedCandidatesStore, resolveRankedCandidatesDbPath } from "./ranked-candidates.js"; import { initDenyHookSynthesisStore, resolveDenyHookSynthesisDbPath } from "./deny-hook-synthesis.js"; +import { openOrbExportStore, resolveOrbExportDbPath } from "./orb-export.js"; const MIGRATE_USAGE = "Usage: loopover-miner migrate [--json]"; @@ -80,6 +81,9 @@ const STORES: MigrateStoreDescriptor[] = [ { name: "policy-doc-cache", resolveDbPath: resolvePolicyDocCacheDbPath, open: initPolicyDocCacheStore }, { name: "ranked-candidates", resolveDbPath: resolveRankedCandidatesDbPath, open: initRankedCandidatesStore }, { name: "deny-hook-synthesis", resolveDbPath: resolveDenyHookSynthesisDbPath, open: initDenyHookSynthesisStore }, + // #8318: orb-export.sqlite3 (the opt-in Orb telemetry export's HMAC secret + cursor, #4277/#5681) is a + // durable local store like every entry above, but was never added when it shipped. + { name: "orb-export", resolveDbPath: resolveOrbExportDbPath, open: openOrbExportStore }, ]; /** Read a store file's stamped schema version without ever creating it -- matches checkStoreIntegrity's diff --git a/packages/loopover-miner/lib/status.ts b/packages/loopover-miner/lib/status.ts index 6b32fd91b..d2e9f0b12 100644 --- a/packages/loopover-miner/lib/status.ts +++ b/packages/loopover-miner/lib/status.ts @@ -31,6 +31,7 @@ import { resolvePolicyVerdictCacheDbPath } from "./policy-verdict-cache.js"; import { resolvePolicyDocCacheDbPath } from "./policy-doc-cache.js"; import { resolveRankedCandidatesDbPath } from "./ranked-candidates.js"; import { resolveDenyHookSynthesisDbPath } from "./deny-hook-synthesis.js"; +import { resolveOrbExportDbPath } from "./orb-export.js"; // Slim laptop-mode CLI commands (#2288): `status` (what's installed + where local state lives) and `doctor` (is // this laptop set up correctly). Both are read-only and 100% local — no repo-scanning, no coding-agent invocation, @@ -381,6 +382,9 @@ function storeIntegrityChecks(env: Record): DoctorCh ["policy-doc-cache", resolvePolicyDocCacheDbPath(env)], ["ranked-candidates", resolveRankedCandidatesDbPath(env)], ["deny-hook-synthesis", resolveDenyHookSynthesisDbPath(env)], + // #8318: orb-export.sqlite3 (the opt-in Orb telemetry export's HMAC secret + cursor, #4277/#5681) is a + // durable local store like every entry above, but was never added when it shipped. + ["orb-export", resolveOrbExportDbPath(env)], ]; return stores.map(([name, dbPath]) => checkStoreIntegrity(`store-integrity:${name}`, dbPath)); } diff --git a/test/unit/miner-migrate-cli.test.ts b/test/unit/miner-migrate-cli.test.ts index 2b5b57341..87918f120 100644 --- a/test/unit/miner-migrate-cli.test.ts +++ b/test/unit/miner-migrate-cli.test.ts @@ -34,6 +34,7 @@ const STORE_NAMES = [ "policy-doc-cache", "ranked-candidates", "deny-hook-synthesis", + "orb-export", ]; afterEach(() => { @@ -42,7 +43,7 @@ afterEach(() => { }); describe("loopover-miner migrate (#4871)", () => { - it("covers the exact same sixteen stores doctor's store-integrity sweep covers, in the same order, and skips every one when nothing has been created yet", () => { + it("covers the exact same seventeen stores doctor's store-integrity sweep covers, in the same order, and skips every one when nothing has been created yet", () => { const env = tempEnv(); const results = runMigrateChecks(env); @@ -51,6 +52,9 @@ describe("loopover-miner migrate (#4871)", () => { expect(STORE_NAMES).toEqual(expect.arrayContaining(["governor-state", "attempt-log", "replay-snapshot", "worktree-allocator"])); // REGRESSION (#8008): ranked-candidates and deny-hook-synthesis were likewise omitted from both lists. expect(STORE_NAMES).toEqual(expect.arrayContaining(["ranked-candidates", "deny-hook-synthesis"])); + // REGRESSION (#8318): orb-export.sqlite3 (the opt-in Orb telemetry export's HMAC secret + cursor) was + // never added to either list when it shipped, so a corrupted store was invisible to doctor and migrate. + expect(STORE_NAMES).toEqual(expect.arrayContaining(["orb-export"])); for (const result of results) { expect(result.ok).toBe(true); expect(result.status).toBe("skipped"); diff --git a/test/unit/miner-status.test.ts b/test/unit/miner-status.test.ts index 2af943679..b60a27016 100644 --- a/test/unit/miner-status.test.ts +++ b/test/unit/miner-status.test.ts @@ -145,6 +145,7 @@ describe("loopover-miner status/doctor (#2288)", () => { "store-integrity:policy-doc-cache", "store-integrity:ranked-candidates", "store-integrity:deny-hook-synthesis", + "store-integrity:orb-export", ]); // REGRESSION (#6768): doctor previously omitted these four durable local stores from the integrity sweep. expect(checks.map((check) => check.name)).toEqual(