diff --git a/services/api/src/schema.ts b/services/api/src/schema.ts index 75dee2d..bab000f 100644 --- a/services/api/src/schema.ts +++ b/services/api/src/schema.ts @@ -154,6 +154,10 @@ CREATE TABLE break_note_history ( CREATE INDEX break_note_history_key ON break_note_history (asset_id, scope, key, id); INSERT INTO break_note_history (asset_id, scope, key, fingerprint, status, note, author, author_id, at) SELECT asset_id, scope, key, fingerprint, status, note, author, author_id, updated_at FROM break_notes; +`, + // v3: keep the recurring reconcileDue search off reconciled action rows. + ` +CREATE INDEX actions_due ON actions (record_time) WHERE snapshot IS NULL; `, ]; diff --git a/services/api/test/due-action-index.test.ts b/services/api/test/due-action-index.test.ts new file mode 100644 index 0000000..465347e --- /dev/null +++ b/services/api/test/due-action-index.test.ts @@ -0,0 +1,29 @@ +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { describe, expect, it } from "vitest"; +import { Db } from "../src/db.js"; +import { ORG_MIGRATIONS } from "../src/schema.js"; + +describe("due action migration index", () => { + it("upgrades a version-1 workspace and uses a partial index for unreconciled actions", () => { + const dir = mkdtempSync(join(tmpdir(), "concord-due-index-")); + const path = join(dir, "org.db"); + try { + const old = new Db(path, [ORG_MIGRATIONS[0]!]); + old.close(); + const db = new Db(path, ORG_MIGRATIONS); + try { + expect(db.get<{ user_version: number }>("PRAGMA user_version")?.user_version).toBe(ORG_MIGRATIONS.length); + const plans = db.raw.prepare( + "EXPLAIN QUERY PLAN SELECT id FROM actions WHERE snapshot IS NULL AND record_time <= ?", + ).all("2026-10-28T00:00:00Z") as Array<{ detail: string }>; + expect(plans.map((p) => p.detail).join("\n")).toContain("actions_due"); + } finally { + db.close(); + } + } finally { + rmSync(dir, { recursive: true, force: true }); + } + }); +}); diff --git a/services/api/test/fixtures/db/org-v3.db b/services/api/test/fixtures/db/org-v3.db new file mode 100644 index 0000000..dd1cfa3 Binary files /dev/null and b/services/api/test/fixtures/db/org-v3.db differ diff --git a/services/api/test/fixtures/make-db-fixtures.ts b/services/api/test/fixtures/make-db-fixtures.ts index ea182a5..e45dad4 100644 --- a/services/api/test/fixtures/make-db-fixtures.ts +++ b/services/api/test/fixtures/make-db-fixtures.ts @@ -60,6 +60,11 @@ build(join(outDir, "org-v2.db"), ORG_MIGRATIONS.slice(0, 2), (db) => { ('usd-mainnet', 'recon', 'SUPPLY_MISMATCH', '10|12', 'resolved', 'corrected', 'bob', 'u2', '2024-01-05T00:00:00Z')`); }); +// Freeze the v3 schema for future upgrade-compatibility checks. +build(join(outDir, "org-v3.db"), ORG_MIGRATIONS.slice(0, 3), (db) => { + db.exec("INSERT INTO meta (key, value) VALUES ('fixture', 'org-v3')"); +}); + build(join(outDir, "control-v1.db"), CONTROL_MIGRATIONS.slice(0, 1), (db) => { db.exec(`INSERT INTO users (id, email, name, email_verified, created_at) VALUES ('u1', 'alice@example.org', 'Alice', 1, '2024-01-01T00:00:00Z')`);