feat(miner): add schema-version migration runner across local stores#5364
Conversation
The miner's local SQLite stores only ever ran CREATE TABLE IF NOT EXISTS, with no user_version/migration mechanism — so an older on-disk file was silently reused with a stale shape. Add a lightweight shared runner, applySchemaMigrations(db, migrations), and wire it into every store (claim-ledger, event-ledger, governor-ledger, plan-store, run-state, laptop-init, portfolio-queue). Each store's bootstrap schema is treated as version 1; a store's migrations array holds only post-baseline changes (migrations[i] upgrades version i+1 to i+2). The runner reads PRAGMA user_version, runs exactly the pending migrations in order, and stamps the new version, so opening an older file runs its outstanding migrations instead of continuing on an incompatible shape. Pre-versioning files (user_version 0) already carry the baseline tables, so they advance from the baseline. Kept lightweight per the issue — no heavyweight migration framework. Portfolio-queue's existing ad-hoc leased_at ALTER is expressed as its first real migration (1 to 2), staying defensive so a file that already ran the pre-convention ALTER is not re-altered into a duplicate-column error. Closes JSONbored#4832
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
|
Tip 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✅ Gittensory review result - approve/merge recommendedReview updated: 2026-07-12 15:09:51 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.
|
Codecov Report✅ All modified and coverable lines are covered by tests.
Additional details and impacted files@@ Coverage Diff @@
## main #5364 +/- ##
==========================================
- Coverage 94.41% 85.07% -9.35%
==========================================
Files 550 551 +1
Lines 44143 44168 +25
Branches 14632 14632
==========================================
- Hits 41677 37575 -4102
- Misses 1791 5219 +3428
- Partials 675 1374 +699
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Summary
The miner's local SQLite stores only ever ran
CREATE TABLE IF NOT EXISTS, with nouser_version/migration mechanism at all — so an older on-disk database file was silently reused with a stale shape, unlike the main product'smigrations/discipline. This adds a lightweight, shared schema-versioning convention across every store.New:
packages/gittensory-miner/lib/schema-version.js(+.d.ts) exportingapplySchemaMigrations(db, migrations):BASELINE_SCHEMA_VERSION); a store'smigrationsarray holds only post-baseline changes —migrations[i]upgrades the schema from version i+1 to i+2.PRAGMA user_version, runs exactly the pending migrations in order, then stamps the new version — so opening an older file runs its outstanding migrations instead of continuing on an incompatible shape. Re-opening an up-to-date file runs none.user_version0) already carries the baseline tables (the idempotentCREATE TABLE IF NOT EXISTSran), so it advances from the baseline.PRAGMA user_versionis transactional in SQLite), so a failure part-way through the sequence leaves the file at the last fully-applied version — the next open resumes at the failed migration instead of re-running the ones that already succeeded (which, for a non-idempotentALTER, would be a duplicate-column error).DatabaseSynchandle — deterministic, no IO of its own beyond the PRAGMA read/write.Wired into all seven stores: claim-ledger, event-ledger, governor-ledger, plan-store, run-state, laptop-init, portfolio-queue.
Portfolio-queue's existing ad-hoc
leased_atALTER is expressed as its first real migration (1 → 2) — kept defensive (checkstable_info) so a version-0 file that already ran the pre-convention ad-hoc ALTER is not re-altered into a duplicate-column error. This both removes the ad-hoc branch and demonstrates the convention on a real migration.Kept lightweight per the issue's boundary — no heavyweight migration framework.
Scope
packages/), noblockedPaths, no secrets/private terms.d.tscompanion added, matching the package's existing conventionValidation
npm run typechecknpm run test:coverage(full unsharded suite)test/unit/miner-schema-version.test.ts(in-memoryDatabaseSync): baseline stamp with no migrations, full run in order on a pre-versioning file, idempotent re-apply, partial catch-up from an intermediate version, upgrade-only (no downgrade of a newer file), mid-sequence failure leaves the file at the last applied version (no re-run of succeeded migrations), atomic rollback of a failed migration's partial changes, and coercion of an absent/non-integer/negativeuser_versionmainbaseline: identical results — the Windows-only chmod/path test failures are pre-existing and unrelated); portfolio-queue'sleased_at/markFailedtests confirm the migrated behavior is preservedSafety
user_versionstamp and a migration hook; the only converted logic (portfolio-queueleased_at) keeps its exact defensive semanticsCloses #4832