From 4fff4de1e75d7fd6142236cbcaf8ff155841bb64 Mon Sep 17 00:00:00 2001 From: Lourince Daging Date: Thu, 16 Jul 2026 19:57:11 +0200 Subject: [PATCH] fix(miner): route the governor/prediction/plan local stores through openLocalStoreDb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit governor-ledger.js, prediction-ledger.js, and plan-store.js each hand-rolled their own mkdir(0o700)/DatabaseSync/chmod(0o600)/busy_timeout open, bypassing local-store.js's openLocalStoreDb — so unlike the package's other local stores their handles were never registered with registerCleanupResource, and a SIGINT/SIGTERM/uncaught-exception mid-run left them half-written instead of closed cleanly (#4826). Route all three through openLocalStoreDb, which centralizes that boilerplate (including the ':memory:' no-file case) and the crash-safe cleanup registration. Closes #6595. --- packages/loopover-miner/lib/governor-ledger.js | 10 +++------- packages/loopover-miner/lib/plan-store.js | 15 +++++---------- packages/loopover-miner/lib/prediction-ledger.js | 10 +++------- 3 files changed, 11 insertions(+), 24 deletions(-) diff --git a/packages/loopover-miner/lib/governor-ledger.js b/packages/loopover-miner/lib/governor-ledger.js index 7620121acd..4b5ecd30b6 100644 --- a/packages/loopover-miner/lib/governor-ledger.js +++ b/packages/loopover-miner/lib/governor-ledger.js @@ -1,8 +1,7 @@ -import { chmodSync, mkdirSync } from "node:fs"; import { homedir } from "node:os"; -import { dirname, join } from "node:path"; -import { DatabaseSync } from "node:sqlite"; +import { join } from "node:path"; import { normalizeGovernorLedgerEvent } from "@loopover/engine"; +import { openLocalStoreDb } from "./local-store.js"; import { applySchemaMigrations } from "./schema-version.js"; import { GOVERNOR_LEDGER_PURGE_SPEC, @@ -96,10 +95,7 @@ function rowToDecision(row) { */ export function initGovernorLedger(dbPath = resolveGovernorLedgerDbPath()) { const resolvedPath = normalizeDbPath(dbPath); - mkdirSync(dirname(resolvedPath), { recursive: true, mode: 0o700 }); - const db = new DatabaseSync(resolvedPath); - chmodSync(resolvedPath, 0o600); - db.exec("PRAGMA busy_timeout = 5000"); + const db = openLocalStoreDb(resolvedPath); db.exec(` CREATE TABLE IF NOT EXISTS governor_events ( id INTEGER PRIMARY KEY AUTOINCREMENT, diff --git a/packages/loopover-miner/lib/plan-store.js b/packages/loopover-miner/lib/plan-store.js index c5a23f8757..8d7a3be3fa 100644 --- a/packages/loopover-miner/lib/plan-store.js +++ b/packages/loopover-miner/lib/plan-store.js @@ -1,7 +1,6 @@ -import { chmodSync, mkdirSync } from "node:fs"; import { homedir } from "node:os"; -import { dirname, join } from "node:path"; -import { DatabaseSync } from "node:sqlite"; +import { join } from "node:path"; +import { openLocalStoreDb } from "./local-store.js"; import { applySchemaMigrations } from "./schema-version.js"; // Local SQLite persistence for the stateless MCP plan DAG (#2318). `loopover_build_plan`/`plan_status`/ @@ -150,13 +149,9 @@ function rowToRecord(row) { */ export function openPlanStore(dbPath = resolvePlanStoreDbPath()) { const resolvedPath = normalizeDbPath(dbPath); - // The store is a persistent local file; the special in-memory path (':memory:') has no file to create or chmod. - if (resolvedPath !== ":memory:") { - mkdirSync(dirname(resolvedPath), { recursive: true, mode: 0o700 }); - } - const db = new DatabaseSync(resolvedPath); - if (resolvedPath !== ":memory:") chmodSync(resolvedPath, 0o600); - db.exec("PRAGMA busy_timeout = 5000"); + // openLocalStoreDb centralizes the mkdir(0o700)/chmod(0o600)/busy_timeout + crash-safe cleanup registration and + // treats ':memory:' as a no-file special case, so this store no longer hand-rolls that boilerplate (#4826). + const db = openLocalStoreDb(resolvedPath); db.exec(` CREATE TABLE IF NOT EXISTS miner_plans ( plan_id TEXT PRIMARY KEY, diff --git a/packages/loopover-miner/lib/prediction-ledger.js b/packages/loopover-miner/lib/prediction-ledger.js index ce576af2ab..45545e5ec0 100644 --- a/packages/loopover-miner/lib/prediction-ledger.js +++ b/packages/loopover-miner/lib/prediction-ledger.js @@ -1,7 +1,6 @@ -import { chmodSync, mkdirSync } from "node:fs"; import { homedir } from "node:os"; -import { dirname, join } from "node:path"; -import { DatabaseSync } from "node:sqlite"; +import { join } from "node:path"; +import { openLocalStoreDb } from "./local-store.js"; import { PREDICTION_LEDGER_PURGE_SPEC, PREDICTION_LEDGER_RETENTION_SPEC, @@ -135,10 +134,7 @@ function rowToEntry(row) { */ export function initPredictionLedger(dbPath = resolvePredictionLedgerDbPath()) { const resolvedPath = normalizeDbPath(dbPath); - mkdirSync(dirname(resolvedPath), { recursive: true, mode: 0o700 }); - const db = new DatabaseSync(resolvedPath); - chmodSync(resolvedPath, 0o600); - db.exec("PRAGMA busy_timeout = 5000"); + const db = openLocalStoreDb(resolvedPath); db.exec(` CREATE TABLE IF NOT EXISTS predictions ( id INTEGER PRIMARY KEY AUTOINCREMENT,