Skip to content

fix(miner): orb-export.ts, deny-hook-synthesis.ts, and laptop-init.ts bypass local-store.js's crash-safe openLocalStoreDb #8319

Description

@JSONbored

Context

packages/loopover-miner/lib/local-store.ts provides openLocalStoreDb, the shared crash-safe DB-open helper: it creates the parent directory (0700), opens the DatabaseSync handle, chmods the file (0600), sets PRAGMA busy_timeout, and — critically — calls registerCleanupResource(db) so a SIGINT/SIGTERM/uncaught-exception mid-run closes the handle instead of leaving the SQLite file half-written. Its own doc comment explains this crash-safety registration explicitly (#4826). Most stores in this package already route through it (e.g. plan-store.ts's openPlanStore and attempt-log.ts's initAttemptLog both call openLocalStoreDb directly, and claim-ledger.ts's real store-open path does too). Closed issue #6595 previously fixed this exact bypass for governor-ledger.js, prediction-ledger.js, and plan-store.js.

Three more stores still hand-roll the same open boilerplate directly against node:sqlite's DatabaseSync, bypassing openLocalStoreDb and its crash-safety registration entirely:

  • packages/loopover-miner/lib/orb-export.ts's openOrbExportStore: const db = new DatabaseSync(resolvedPath); chmodSync(resolvedPath, 0o600); db.exec("PRAGMA busy_timeout = 5000");
  • packages/loopover-miner/lib/deny-hook-synthesis.ts's initDenyHookSynthesisStore: the identical new DatabaseSync(resolvedPath); chmodSync(...); db.exec("PRAGMA busy_timeout = 5000") sequence.
  • packages/loopover-miner/lib/laptop-init.ts's initLaptopState: const db = new DatabaseSync(dbPath); (plus its own separate mkdirSync/chmodSync calls) with no busy-timeout and no crash-safety registration at all.

For all three, a SIGINT/SIGTERM/uncaught-exception during a write (e.g. mid-batch orb-export cursor update, mid-refresh deny-hook-synthesis proposal upsert, or during laptop-init's bootstrap insert) is not guaranteed to close the handle cleanly the way every openLocalStoreDb-routed store already is.

Requirements

⚠️ Required pattern. Replace each hand-rolled new DatabaseSync(...) + manual mkdirSync/chmodSync/PRAGMA busy_timeout sequence with a call to openLocalStoreDb(resolvedPath) from local-store.ts — the exact substitution plan-store.ts's openPlanStore and attempt-log.ts's initAttemptLog already demonstrate. openLocalStoreDb performs the mkdir/chmod/busy-timeout/cleanup-registration internally; do not duplicate any of those steps at the call site afterward.

  • orb-export.ts's openOrbExportStore: replace the new DatabaseSync/chmodSync/PRAGMA busy_timeout sequence with const db = openLocalStoreDb(resolvedPath);. Drop the now-redundant mkdirSync/chmodSync/PRAGMA lines (the mkdirSync(dirname(resolvedPath), ...) call already present can be dropped too — openLocalStoreDb does its own mkdirSync on the parent dir).
  • deny-hook-synthesis.ts's initDenyHookSynthesisStore: same substitution.
  • laptop-init.ts's initLaptopState: same substitution, importing openLocalStoreDb from ./local-store.js. Verify no import cycle: local-store.ts imports only from process-lifecycle.js and store-db-adapter.js, neither of which imports laptop-init.ts, so this import is safe (the file's existing "avoid import cycles" comment is about its own resolveMinerStateDir mirroring status.js's path-resolution helper, a separate concern from the DB-open helper — do not remove that comment or change the local resolveMinerStateDir duplication, which is out of scope here).
  • Each store's close() must keep working as before — openLocalStoreDb's returned handle already wraps close() to unregister the cleanup hook, so no additional change is needed at the call sites beyond the open substitution.

Deliverables

  • orb-export.ts opens its store via openLocalStoreDb.
  • deny-hook-synthesis.ts opens its store via openLocalStoreDb.
  • laptop-init.ts opens its store via openLocalStoreDb.

Test Coverage Requirements

packages/loopover-miner/** is not Codecov-gated, but npm run test:ci must stay green. test/unit/miner-orb-export.test.ts, the deny-hook-synthesis test file, and test/unit/miner-laptop-init.test.ts should keep passing unmodified where they test read/write behavior (the on-disk contract — table names, permissions, busy-timeout — is unchanged); add or extend a test in each file asserting the store is registered for crash-safe cleanup (e.g. asserting the returned handle's close() still tears down cleanly, or checking registerCleanupResource/process-lifecycle.js's test seam the way plan-store.ts's or attempt-log.ts's own tests already verify their openLocalStoreDb usage, if such a test precedent exists in this repo — otherwise a plain open/write/close round-trip test is sufficient since the behavior itself doesn't change, only the crash-safety wiring).

Expected Outcome

All local SQLite stores in packages/loopover-miner — not just most of them — get the same SIGINT/SIGTERM/uncaught-exception crash-safety guarantee, closing #6595's fix class for the three stores it missed.

Links & Resources

Metadata

Metadata

Assignees

No one assigned

    Labels

    gittensor:bugGittensor-scored bug fix — scores a 0.05x multiplier.help wantedExtra attention is needed

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions