feat(miner): add store integrity checks and ledger retention - #5388
Conversation
doctor previously health-checked only one local store with a bare SELECT 1, and the append-only event/governor/prediction ledgers grew forever with no retention policy. Add a shared store-maintenance module: - checkStoreIntegrity: run PRAGMA integrity_check on a store file (a not-yet-created store is healthy by absence; a store that cannot be opened/read is reported as not-ok). doctor now sweeps every local store, so it flags a corrupted one instead of probing just one. - resolveLedgerRetentionPolicy / pruneLedgerByRetention: an opt-in, age- and/or size-based retention policy for the append-only ledgers, OFF by default (enabled via GITTENSORY_MINER_LEDGER_RETENTION_DAYS / _MAX_ROWS). Pruning deletes aged and excess rows atomically; the three ledgers apply it at init. Timestamp columns are UTC ISO-8601, so the age cutoff is a correct lexicographic comparison. Table/column names are fixed internal constants, validated as plain identifiers before interpolation. Pure control flow over injected inputs (DB handle, env, caller-supplied clock) — no network and no internal clock in the prune path. Fully unit-tested, including the corrupt-store and both retention bounds. Closes JSONbored#4834
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #5388 +/- ##
=======================================
Coverage 94.43% 94.44%
=======================================
Files 551 552 +1
Lines 44223 44272 +49
Branches 14654 14654
=======================================
+ Hits 41764 41813 +49
Misses 1784 1784
Partials 675 675
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ Gittensory review result - approve/merge recommendedReview updated: 2026-07-12 16:17:36 UTC
✅ Suggested Action - Approve/Merge
Review summary Nits — 5 non-blocking
Linked issue satisfactionAddressed Review context
Contributor next steps
Signal definitions
[BETA] Chat with GittensoryAsk Gittensory a question about this PR directly in a comment — grounded only in the same cached, public-safe facts shown above, never a new claim.
Full command reference: https://gittensory.aethereal.dev/docs/gittensory-commands 🟩 Safe / merged · 🟦 Advisory · 🟨 Held for review · 🟥 Blocked / closed 💰 Earn for open-source contributions like this. Gittensor lets GitHub contributors earn for the work they already do — register to start earning →. Checked by Gittensory, a quiet PR intelligence layer for OSS maintainers.
|
Summary
doctor's only SQLite health check was a bareSELECT 1against a single store, and the append-only event/governor/prediction ledgers had no retention policy — they grow forever on a long-running self-hosted instance. This adds both, via a sharedpackages/gittensory-miner/lib/store-maintenance.jsmodule.Integrity sweep —
checkStoreIntegrity(name, dbPath)runsPRAGMA integrity_checkon a store file: a not-yet-created store is healthy by absence, and a store that cannot be opened or read is reported as not-ok (so one bad store never aborts the sweep).doctornow sweeps every local store (event/governor/prediction ledgers, portfolio-queue, claim-ledger, run-state, plan-store), so it flags a corrupted store instead of probing only one.Retention —
resolveLedgerRetentionPolicy(env)reads an opt-in policy fromGITTENSORY_MINER_LEDGER_RETENTION_DAYSand/orGITTENSORY_MINER_LEDGER_RETENTION_MAX_ROWS; OFF by default (null unless an operator sets a positive value).pruneLedgerByRetention(db, spec, policy, nowMs)deletes aged rows (older than the day bound) and excess rows (beyond the row cap, keeping the newest by id) atomically in one transaction. The three append-only ledgers apply it at init, so enabling retention and re-opening a ledger prunes it.Design notes:
nowMs) — no network, and no internal clock in the prune path, so it's deterministic and unit-testable.Scope
packages/), noblockedPaths, no secrets/private terms.d.tscompanion added, matching the package conventionValidation
npm run typechecknpm run test:coverage(full unsharded suite)test/unit/miner-store-maintenance.test.ts(in-memoryDatabaseSync): integrity classify (ok / multi-problem), integrity of a missing/healthy/garbage/unopenable store, retention policy resolution (off by default; age/rows/both; zero/negative/blank/non-numeric ignored; fractional floor), and pruning (null no-op, age bound with a kept-at-cutoff row, row cap, both bounds, within-bounds no-op, unsafe-identifier rejection, transaction rollback on a failed delete)test/unit/miner-status.test.ts:doctornow lists a per-store integrity check for every store, and flags a corrupted store (exit code 1)mainbaseline (the Windows-only chmod/path test failures are pre-existing and unrelated)Safety
0.5) disables the bound rather than resolving to a dangerous0; the prune path additionally guards both bounds to be strictly positive as defence in depth (a0age or row-cap would otherwise prune the whole ledger)Closes #4834