fix(db): back-fill last_ping_at + last_pinged_reset_key on provider_connections (#12470)

Merged. Clean, surgical fix with its own regression guard.

`ensureProviderConnectionsColumns()` reconciles the base columns that later data migrations assume, but `last_ping_at` / `last_pinged_reset_key` were only ever created by `123_quota_auto_ping` — so a lineage that skipped it kept a table that the quota auto-ping writes cannot target. Adding them to the reconciliation list is exactly the right place.

Validated on `release/v3.8.51`: `tests/unit/db-schema-columns-split.test.ts` 10/10, including your new `back-fills last_ping columns on a pre-123 lineage` case and the idempotency re-run. `typecheck:core` clean, `check-file-size` OK. The `changelog.d/fixes/` fragment was already correct.

Thank you — this is the shape a fix should have: root cause named, minimal diff, test that fails without it.
This commit is contained in:
Koosha Paridehpour
2026-09-04 22:33:16 -07:00
committed by GitHub
parent c3945a724c
commit 891cb26b2c
3 changed files with 22 additions and 0 deletions

View File

@@ -0,0 +1 @@
- **fix(db):** back-fill `last_ping_at` and `last_pinged_reset_key` on `provider_connections` during schema reconciliation so divergent lineages that skipped `123_quota_auto_ping` still accept quota auto-ping writes ([#12470](https://github.com/diegosouzapw/OmniRoute/pull/12470) — thanks @KooshaPari)

View File

@@ -27,6 +27,8 @@ export function ensureProviderConnectionsColumns(db: SqliteDatabase) {
["rate_limit_protection", "INTEGER DEFAULT 0"],
["last_used_at", "TEXT"],
["default_model", "TEXT"], // legacy-schema hole; later data migrations read it
["last_ping_at", "TEXT"], // added by 123_quota_auto_ping; back-filled here for divergent lineages
["last_pinged_reset_key", "TEXT"], // added by 123_quota_auto_ping; back-filled here for divergent lineages
]) {
if (!columnNames.has(column)) {
db.exec(`ALTER TABLE provider_connections ADD COLUMN ${column} ${type}`);

View File

@@ -136,6 +136,8 @@ test("ensureProviderConnectionsColumns restores base columns required by later m
assert.equal(hasColumn(db, "provider_connections", "provider_specific_data"), true);
assert.equal(hasColumn(db, "provider_connections", "default_model"), true);
assert.equal(hasColumn(db, "provider_connections", "last_ping_at"), true);
assert.equal(hasColumn(db, "provider_connections", "last_pinged_reset_key"), true);
const columnsAfterFirstRun = getTableColumns(db, "provider_connections").sort();
const indexesAfterFirstRun = (
db.prepare("PRAGMA index_list(provider_connections)").all() as Array<{ name: string }>
@@ -163,3 +165,20 @@ test("ensureProviderConnectionsColumns restores base columns required by later m
db.close?.();
}
});
test("ensureProviderConnectionsColumns back-fills last_ping columns on a pre-123 lineage", () => {
const db = openMemoryDb();
try {
db.exec("CREATE TABLE provider_connections (id TEXT PRIMARY KEY, provider TEXT NOT NULL)");
assert.equal(hasColumn(db, "provider_connections", "last_ping_at"), false);
assert.equal(hasColumn(db, "provider_connections", "last_pinged_reset_key"), false);
ensureProviderConnectionsColumns(db);
assert.equal(hasColumn(db, "provider_connections", "last_ping_at"), true);
assert.equal(hasColumn(db, "provider_connections", "last_pinged_reset_key"), true);
assert.doesNotThrow(() => ensureProviderConnectionsColumns(db));
} finally {
db.close?.();
}
});