@happyvertical/smrt-core 0.41.0 → 0.42.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/AGENTS.md +1 -1
  2. package/agents/schema-paths.md +79 -8
  3. package/dist/change-feed.d.ts.map +1 -1
  4. package/dist/change-feed.js +2 -2
  5. package/dist/change-feed.js.map +1 -1
  6. package/dist/change-signals.d.ts.map +1 -1
  7. package/dist/change-signals.js +8 -1
  8. package/dist/change-signals.js.map +1 -1
  9. package/dist/class.d.ts.map +1 -1
  10. package/dist/class.js +10 -9
  11. package/dist/class.js.map +1 -1
  12. package/dist/collection.d.ts.map +1 -1
  13. package/dist/collection.js +2 -2
  14. package/dist/collection.js.map +1 -1
  15. package/dist/dispatch/collections/Dispatches.d.ts.map +1 -1
  16. package/dist/dispatch/collections/Dispatches.js +5 -5
  17. package/dist/dispatch/collections/Dispatches.js.map +1 -1
  18. package/dist/dispatch/models/Dispatch.d.ts +1 -1
  19. package/dist/dispatch/models/Dispatch.d.ts.map +1 -1
  20. package/dist/dispatch/models/Dispatch.js +3 -2
  21. package/dist/dispatch/models/Dispatch.js.map +1 -1
  22. package/dist/dispatch/models/DispatchSubscription.d.ts +1 -1
  23. package/dist/dispatch/models/DispatchSubscription.d.ts.map +1 -1
  24. package/dist/dispatch/models/DispatchSubscription.js +2 -1
  25. package/dist/dispatch/models/DispatchSubscription.js.map +1 -1
  26. package/dist/embeddings/storage.d.ts.map +1 -1
  27. package/dist/embeddings/storage.js +2 -1
  28. package/dist/embeddings/storage.js.map +1 -1
  29. package/dist/learning/memory.d.ts.map +1 -1
  30. package/dist/learning/memory.js +5 -4
  31. package/dist/learning/memory.js.map +1 -1
  32. package/dist/manifest/static-manifest.js +1 -1
  33. package/dist/manifest/static-manifest.js.map +1 -1
  34. package/dist/manifest/store.js +1 -1
  35. package/dist/manifest.json +1 -1
  36. package/dist/migrations/differ.js +2 -2
  37. package/dist/migrations/differ.js.map +1 -1
  38. package/dist/migrations/index.d.ts +1 -0
  39. package/dist/migrations/index.d.ts.map +1 -1
  40. package/dist/migrations/index.js +2 -1
  41. package/dist/migrations/integer-width.d.ts +99 -0
  42. package/dist/migrations/integer-width.d.ts.map +1 -0
  43. package/dist/migrations/integer-width.js +237 -0
  44. package/dist/migrations/integer-width.js.map +1 -0
  45. package/dist/migrations/minor-units.d.ts +2 -2
  46. package/dist/migrations/minor-units.d.ts.map +1 -1
  47. package/dist/migrations/minor-units.js +16 -14
  48. package/dist/migrations/minor-units.js.map +1 -1
  49. package/dist/migrations/tracker.d.ts.map +1 -1
  50. package/dist/migrations/tracker.js +28 -20
  51. package/dist/migrations/tracker.js.map +1 -1
  52. package/dist/migrations.js +2 -1
  53. package/dist/schema/ddl/duckdb-strategy.d.ts.map +1 -1
  54. package/dist/schema/ddl/duckdb-strategy.js +1 -0
  55. package/dist/schema/ddl/duckdb-strategy.js.map +1 -1
  56. package/dist/schema/ddl/postgres-strategy.d.ts.map +1 -1
  57. package/dist/schema/ddl/postgres-strategy.js +2 -0
  58. package/dist/schema/ddl/postgres-strategy.js.map +1 -1
  59. package/dist/schema/generator.d.ts +1 -33
  60. package/dist/schema/generator.d.ts.map +1 -1
  61. package/dist/schema/generator.js +1 -150
  62. package/dist/schema/generator.js.map +1 -1
  63. package/dist/schema/index.d.ts +1 -2
  64. package/dist/schema/index.d.ts.map +1 -1
  65. package/dist/schema/index.js +1 -2
  66. package/dist/schema/live-parity.d.ts +3 -1
  67. package/dist/schema/live-parity.d.ts.map +1 -1
  68. package/dist/schema/live-parity.js +19 -0
  69. package/dist/schema/live-parity.js.map +1 -1
  70. package/dist/schema/types.d.ts +17 -10
  71. package/dist/schema/types.d.ts.map +1 -1
  72. package/dist/schema.js +1 -2
  73. package/dist/smrt-knowledge.json +7 -7
  74. package/dist/system/retention.d.ts.map +1 -1
  75. package/dist/system/retention.js +3 -3
  76. package/dist/system/retention.js.map +1 -1
  77. package/dist/system/schema.d.ts +2 -1
  78. package/dist/system/schema.d.ts.map +1 -1
  79. package/dist/system/schema.js +4 -2
  80. package/dist/system/schema.js.map +1 -1
  81. package/dist/utils/safe-integer.d.ts +19 -0
  82. package/dist/utils/safe-integer.d.ts.map +1 -0
  83. package/dist/utils/safe-integer.js +31 -0
  84. package/dist/utils/safe-integer.js.map +1 -0
  85. package/dist/utils.d.ts +2 -1
  86. package/dist/utils.d.ts.map +1 -1
  87. package/dist/utils.js +6 -3
  88. package/dist/utils.js.map +1 -1
  89. package/dist/vite-plugin/index.d.ts.map +1 -1
  90. package/dist/vite-plugin/index.js +0 -53
  91. package/dist/vite-plugin/index.js.map +1 -1
  92. package/package.json +4 -4
  93. package/dist/schema/override-system.d.ts +0 -43
  94. package/dist/schema/override-system.d.ts.map +0 -1
  95. package/dist/schema/override-system.js +0 -205
  96. package/dist/schema/override-system.js.map +0 -1
@@ -1,6 +1,7 @@
1
1
  import { detectEngine, getDDLStrategy } from "./ddl/index.js";
2
2
  import { RETIRED_SYSTEM_TABLES } from "../system/schema.js";
3
3
  import { getSystemTableShapes } from "./system-table-shapes.js";
4
+ import { collectIntegerWidthTargets, preflightIntegerWidthWidening } from "../migrations/integer-width.js";
4
5
  //#region src/schema/live-parity.ts
5
6
  /**
6
7
  * Thrown when the live database cannot be introspected. Callers fail closed:
@@ -54,6 +55,24 @@ async function checkLiveSchemaParity(options) {
54
55
  findings.push(...compareIndexes(table, liveColumns, liveIndexes));
55
56
  }
56
57
  }
58
+ const widthPreflight = await preflightIntegerWidthWidening(db, collectIntegerWidthTargets(schemas, { includeSystemTables }), { engineHint });
59
+ if (widthPreflight.supported) for (const table of widthPreflight.tables) for (const column of table.columns) {
60
+ if (column.state !== "pending") continue;
61
+ findings.push({
62
+ kind: "legacy_integer_width",
63
+ severity: "warning",
64
+ table: table.table,
65
+ target: column.column,
66
+ origin: table.table.startsWith("_smrt_") ? "system" : "application",
67
+ message: `Column \`${table.table}.${column.column}\` is legacy \`${column.declaredType}\` instead of BIGINT (${table.rowCount ?? 0} row(s) in the table).`,
68
+ recommendation: "Schedule a maintenance window, run `smrt db:migrate-int8 --dry-run`, then run `smrt db:migrate-int8` after reviewing the table-rewrite plan.",
69
+ details: {
70
+ actual: column.declaredType,
71
+ expected: "BIGINT",
72
+ rowCount: table.rowCount
73
+ }
74
+ });
75
+ }
57
76
  if (reportExtraTables) {
58
77
  const expectedNames = new Set(expected.map((table) => table.name));
59
78
  for (const liveName of liveTableNames) {
@@ -1 +1 @@
1
- {"version":3,"file":"live-parity.js","names":[],"sources":["../../src/schema/live-parity.ts"],"sourcesContent":["/**\n * Live-schema parity check (#2368)\n *\n * Compares a **live** database against the shape the model layer assumes.\n * Three inputs define \"expected\":\n *\n * 1. **Declared table shapes** — the manifest schemas the caller passes in.\n * These give tables, columns, types, nullability, and declared indexes.\n * 2. **Hand-DDL system tables** — `_smrt_*` tables parsed out of\n * `src/system/schema.ts` (see `system-table-shapes.ts`). They never enter\n * the manifest, so nothing else has ever diffed them.\n * 3. **An expected-shape index policy that does not consult the manifest** —\n * every foreign-key / cross-package-ref / tenant column carries a leading\n * index, every declared upsert conflict target is backed by a matching\n * UNIQUE index, and every `unique: true` column is actually unique in the\n * live database.\n *\n * Point 3 is the reason this module exists rather than reusing the migration\n * differ: the differ compares the live database to the manifest, i.e. to the\n * artifact that dropped the index in the first place, which is why a database\n * missing 164 tenant-column indexes reported \"in sync\" (#2356).\n *\n * This module is read-only. It emits findings; it never repairs.\n */\n\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { RETIRED_SYSTEM_TABLES } from '../system/schema.js';\nimport { detectEngine, getDDLStrategy } from './ddl/index.js';\nimport type { DatabaseEngine } from './ddl/types.js';\nimport { getSystemTableShapes } from './system-table-shapes.js';\nimport type { ColumnDefinition, SchemaDefinition } from './types.js';\n\n/** How badly a finding breaks the deployment. */\nexport type LiveParitySeverity = 'error' | 'warning' | 'info';\n\n/** The class of drift a finding describes. */\nexport type LiveParityFindingKind =\n | 'missing_table'\n | 'extra_table'\n | 'missing_column'\n | 'extra_column'\n | 'column_type_drift'\n | 'column_nullability_drift'\n | 'missing_index'\n | 'extra_index'\n | 'unindexed_reference'\n | 'conflict_target_unindexed'\n | 'conflict_target_not_unique'\n | 'unique_constraint_missing'\n | 'invalid_index';\n\n/** One difference between the live database and the expected shape. */\nexport interface LiveParityFinding {\n kind: LiveParityFindingKind;\n severity: LiveParitySeverity;\n /** Table the finding is about. */\n table: string;\n /** Column or index the finding is about, when it is narrower than a table. */\n target?: string;\n /** Whether the table is an application table or a `_smrt_*` system table. */\n origin: ExpectedTableOrigin;\n message: string;\n recommendation: string;\n details?: Record<string, unknown>;\n}\n\n/** Aggregate result of one parity run. */\nexport interface LiveSchemaParityReport {\n engine: DatabaseEngine;\n /** Expected tables that exist in the live database and were compared. */\n tablesChecked: number;\n /** Expected tables that are absent from the live database. */\n tablesMissing: number;\n /** Whether `_smrt_*` system tables participated. */\n systemTablesIncluded: boolean;\n /**\n * `full` when index metadata (uniqueness, partial predicates, PostgreSQL\n * validity) could be read for this engine; `unavailable` when it could not,\n * in which case every index-class check is skipped rather than guessed.\n */\n indexIntrospection: 'full' | 'unavailable';\n findings: LiveParityFinding[];\n counts: Record<LiveParitySeverity, number>;\n /** True when no `error`-severity finding was produced. */\n ok: boolean;\n}\n\n/** A declared upsert conflict target for one table. */\nexport interface ConflictTargetInput {\n columns: string[];\n /** Where the target came from, e.g. a class name — used in messages. */\n source?: string;\n}\n\nexport interface LiveSchemaParityOptions {\n db: DatabaseInterface;\n /** Expected application table shapes, keyed by table name. */\n schemas?: Record<string, SchemaDefinition>;\n /** Declared upsert conflict targets, keyed by table name. */\n conflictTargets?: Record<string, ConflictTargetInput[]>;\n /** Include `_smrt_*` system tables (default true). */\n includeSystemTables?: boolean;\n /** Explicit engine hint for adapters whose URL is empty or ambiguous. */\n engineHint?: string;\n /** Report live tables no expected shape covers (default true). */\n reportExtraTables?: boolean;\n}\n\n/** Whether an expected table is an application table or a system table. */\nexport type ExpectedTableOrigin = 'application' | 'system';\n\ninterface ExpectedColumn {\n name: string;\n /** Engine-materialized type text. */\n type: string;\n primaryKey: boolean;\n notNull: boolean;\n unique: boolean;\n hasDefault: boolean;\n reference?: ColumnDefinition['referenceKind'];\n}\n\ninterface ExpectedIndex {\n name: string;\n columns: string[];\n unique: boolean;\n}\n\ninterface ExpectedTable {\n name: string;\n origin: ExpectedTableOrigin;\n columns: ExpectedColumn[];\n indexes: ExpectedIndex[];\n conflictTargets: ConflictTargetInput[];\n}\n\ninterface LiveColumn {\n name: string;\n type: string;\n notNull: boolean;\n primaryKey: boolean;\n hasDefault: boolean;\n}\n\ninterface LiveIndex {\n name: string;\n columns: string[];\n unique: boolean;\n /** PostgreSQL `indisvalid`; always true on engines without the concept. */\n valid: boolean;\n /** True for the index backing a primary key. */\n primary: boolean;\n /** True when the index is partial (has a WHERE predicate). */\n partial: boolean;\n}\n\n/**\n * Thrown when the live database cannot be introspected. Callers fail closed:\n * an unreadable database is never reported as \"in sync\".\n */\nexport class LiveSchemaParityError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'LiveSchemaParityError';\n }\n}\n\n/**\n * Compare a live database against the expected shape and return every\n * difference found.\n *\n * @throws {LiveSchemaParityError} when the database cannot be reached or the\n * adapter cannot describe a table. Connection problems must fail closed.\n */\nexport async function checkLiveSchemaParity(\n options: LiveSchemaParityOptions,\n): Promise<LiveSchemaParityReport> {\n const {\n db,\n schemas = {},\n conflictTargets = {},\n includeSystemTables = true,\n engineHint,\n reportExtraTables = true,\n } = options;\n\n const engine = resolveEngine(db, engineHint);\n const expected = buildExpectedTables({\n schemas,\n conflictTargets,\n includeSystemTables,\n engine,\n });\n\n const liveTableNames = await listLiveTables(db, engine);\n const indexCatalog = await readIndexCatalog(db, engine);\n const findings: LiveParityFinding[] = [];\n\n let tablesChecked = 0;\n let tablesMissing = 0;\n\n for (const table of expected) {\n if (!liveTableNames.has(table.name)) {\n tablesMissing++;\n findings.push({\n kind: 'missing_table',\n severity: 'error',\n table: table.name,\n origin: table.origin,\n message: `Table \\`${table.name}\\` is declared but does not exist in the live database.`,\n recommendation:\n table.origin === 'system'\n ? 'Initialize SMRT system tables against this database (they are created on framework bootstrap).'\n : 'Run `smrt db:migrate` to create the missing table.',\n });\n continue;\n }\n\n tablesChecked++;\n const liveColumns = await readLiveColumns(db, table.name);\n findings.push(...compareColumns(table, liveColumns, engine));\n\n if (indexCatalog) {\n const liveIndexes = await indexCatalog.forTable(table.name);\n findings.push(...compareIndexes(table, liveColumns, liveIndexes));\n }\n }\n\n if (reportExtraTables) {\n const expectedNames = new Set(expected.map((table) => table.name));\n for (const liveName of liveTableNames) {\n if (expectedNames.has(liveName)) continue;\n if (isInternalTableName(liveName)) continue;\n // Without system tables in scope, every `_smrt_*` table would be\n // reported as unexplained; that is a scoping artifact, not drift.\n if (!includeSystemTables && liveName.startsWith('_smrt_')) continue;\n // A retired system table is not unexplained drift — the framework\n // deliberately stopped creating it and deliberately does not drop it\n // (issue #2376). Name the exact remedy instead of the generic advice.\n const retired = RETIRED_SYSTEM_TABLES.includes(liveName);\n findings.push({\n kind: 'extra_table',\n severity: 'info',\n table: liveName,\n origin: liveName.startsWith('_smrt_') ? 'system' : 'application',\n message: retired\n ? `Live table \\`${liveName}\\` is a retired SMRT system table; nothing reads or writes it.`\n : `Live table \\`${liveName}\\` is not covered by any declared schema.`,\n recommendation: retired\n ? `Drop it once you have confirmed it is unused: DROP TABLE IF EXISTS ${liveName};`\n : 'Confirm the table belongs to another application sharing this database, or remove it once its owning model is gone.',\n });\n }\n }\n\n const counts: Record<LiveParitySeverity, number> = {\n error: 0,\n warning: 0,\n info: 0,\n };\n for (const finding of findings) {\n counts[finding.severity]++;\n }\n\n return {\n engine,\n tablesChecked,\n tablesMissing,\n systemTablesIncluded: includeSystemTables,\n indexIntrospection: indexCatalog ? 'full' : 'unavailable',\n findings,\n counts,\n ok: counts.error === 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Expected shape\n// ---------------------------------------------------------------------------\n\nfunction buildExpectedTables(input: {\n schemas: Record<string, SchemaDefinition>;\n conflictTargets: Record<string, ConflictTargetInput[]>;\n includeSystemTables: boolean;\n engine: DatabaseEngine;\n}): ExpectedTable[] {\n const { schemas, conflictTargets, includeSystemTables, engine } = input;\n const strategy = getDDLStrategy(engine);\n const tables: ExpectedTable[] = [];\n\n for (const [key, schema] of Object.entries(schemas)) {\n const tableName = schema?.tableName || key;\n if (!tableName) continue;\n\n const columns: ExpectedColumn[] = Object.entries(schema.columns ?? {}).map(\n ([columnName, column]) => ({\n name: columnName,\n type: strategy.mapType(column.type),\n primaryKey: column.primaryKey === true,\n notNull: column.notNull === true || column.primaryKey === true,\n unique: column.unique === true,\n hasDefault: column.defaultValue !== undefined,\n reference: column.foreignKey ? 'foreignKey' : column.referenceKind,\n }),\n );\n\n tables.push({\n name: tableName,\n origin: 'application',\n columns,\n indexes: (schema.indexes ?? [])\n // Expression indexes (`@meta({ indexed: true })`) surface with empty\n // or null column lists in introspection, so a column-based comparison\n // can only produce false drift for them.\n .filter((index) => !index.jsonPath && (index.columns?.length ?? 0) > 0)\n .map((index) => ({\n name: index.name,\n columns: index.columns,\n unique: index.unique === true,\n })),\n conflictTargets: dedupeConflictTargets(conflictTargets[tableName] ?? []),\n });\n }\n\n if (includeSystemTables) {\n for (const shape of getSystemTableShapes(engine).values()) {\n tables.push({\n name: shape.tableName,\n origin: 'system',\n columns: shape.columns.map((column) => ({\n name: column.name,\n type: column.type,\n primaryKey: column.primaryKey,\n notNull: column.notNull || column.primaryKey,\n unique: column.unique,\n hasDefault: column.hasDefault,\n })),\n indexes: shape.indexes.map((index) => ({\n name: index.name,\n columns: index.columns,\n unique: index.unique,\n })),\n // Inline `UNIQUE (...)` constraints are what the framework upserts\n // against on system tables, so they are the conflict targets here.\n conflictTargets: dedupeConflictTargets(\n shape.uniqueConstraints.map((columns) => ({\n columns,\n source: `${shape.tableName} DDL`,\n })),\n ),\n });\n }\n }\n\n return tables;\n}\n\nfunction dedupeConflictTargets(\n targets: ConflictTargetInput[],\n): ConflictTargetInput[] {\n const seen = new Map<string, ConflictTargetInput>();\n for (const target of targets) {\n const columns = (target.columns ?? []).filter(Boolean);\n if (columns.length === 0) continue;\n const key = [...columns].sort().join(',');\n if (!seen.has(key)) {\n seen.set(key, { columns, source: target.source });\n }\n }\n return [...seen.values()];\n}\n\n// ---------------------------------------------------------------------------\n// Column comparison\n// ---------------------------------------------------------------------------\n\nfunction compareColumns(\n table: ExpectedTable,\n liveColumns: Map<string, LiveColumn>,\n engine: DatabaseEngine,\n): LiveParityFinding[] {\n const findings: LiveParityFinding[] = [];\n const expectedNames = new Set(table.columns.map((column) => column.name));\n\n for (const column of table.columns) {\n const live = liveColumns.get(column.name);\n if (!live) {\n findings.push({\n kind: 'missing_column',\n severity: 'error',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is declared but missing from the live database.`,\n recommendation:\n 'Run `smrt db:migrate` to add the column before application writes reach this table.',\n details: { expectedType: column.type },\n });\n continue;\n }\n\n if (!typesAreEquivalent(column, live, engine)) {\n findings.push({\n kind: 'column_type_drift',\n severity: 'error',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is \\`${live.type}\\` in the live database but declared \\`${column.type}\\`.`,\n recommendation:\n 'Reconcile the column type with `smrt db:migrate`, or repair the declaration if the live type is correct.',\n details: { expected: column.type, actual: live.type },\n });\n }\n\n // A declared-NOT NULL column that is nullable live silently accepts rows\n // the model layer believes cannot exist; the reverse breaks every insert\n // that omits the column, which is the worse failure.\n if (!column.primaryKey && column.notNull && !live.notNull) {\n findings.push({\n kind: 'column_nullability_drift',\n severity: 'warning',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is declared NOT NULL but is nullable in the live database.`,\n recommendation:\n 'Backfill any NULL values and add the NOT NULL constraint, or relax the declaration.',\n });\n } else if (!column.notNull && live.notNull && !live.hasDefault) {\n findings.push({\n kind: 'column_nullability_drift',\n severity: 'error',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is NOT NULL in the live database with no default, but is not declared NOT NULL. Inserts that omit it will fail.`,\n recommendation:\n 'Drop the orphan NOT NULL constraint, give the column a default, or declare the column required.',\n });\n }\n }\n\n for (const live of liveColumns.values()) {\n if (expectedNames.has(live.name)) continue;\n\n const breaksInserts = live.notNull && !live.hasDefault;\n findings.push({\n kind: 'extra_column',\n severity: breaksInserts ? 'error' : 'info',\n table: table.name,\n target: live.name,\n origin: table.origin,\n message: breaksInserts\n ? `Live column \\`${table.name}.${live.name}\\` is undeclared, NOT NULL, and has no default — every framework insert into this table will fail.`\n : `Live column \\`${table.name}.${live.name}\\` is not declared by the current schema.`,\n recommendation: breaksInserts\n ? 'Drop the orphan column or give it a default; this is the residue of a renamed or removed required field.'\n : 'Confirm the column is intentional legacy data, or drop it once nothing reads it.',\n details: { type: live.type },\n });\n }\n\n return findings;\n}\n\n/**\n * Whether a live column type satisfies its declaration.\n *\n * Two tolerances match the model layer's actual conventions, and mirror the\n * migration differ so the two tools never disagree:\n *\n * - `TEXT` ↔ `UUID` for structural identifier/reference columns, because\n * SQLite has no uuid type and older PostgreSQL deployments legitimately\n * still carry text ids (R11).\n * - `TEXT` ↔ `JSON`/`JSONB` in both directions, because SMRT serializes JSON\n * values into text columns and a native json column already holds exactly\n * that (#1335).\n */\nfunction typesAreEquivalent(\n expected: ExpectedColumn,\n live: LiveColumn,\n engine: DatabaseEngine,\n): boolean {\n const expectedType = normalizeSqlType(expected.type);\n const actualType = normalizeSqlType(live.type);\n if (expectedType === actualType) return true;\n\n const uuidTextPair =\n (expectedType === 'UUID' && actualType === 'TEXT') ||\n (expectedType === 'TEXT' && actualType === 'UUID');\n if (uuidTextPair && isStructuralReference(expected)) {\n return true;\n }\n\n const jsonTextPair =\n (expectedType === 'JSON' && actualType === 'TEXT') ||\n (expectedType === 'TEXT' && actualType === 'JSON');\n if (jsonTextPair) return true;\n\n // SQLite has dynamic typing: BOOLEAN/TIMESTAMP columns are declared with\n // affinities that pragma reports verbatim, and INTEGER/NUMERIC storage is\n // interchangeable for the values SMRT writes.\n if (engine === 'sqlite') {\n const numericPair =\n (expectedType === 'BOOLEAN' && actualType === 'INTEGER') ||\n (expectedType === 'INTEGER' && actualType === 'BOOLEAN');\n if (numericPair) return true;\n }\n\n return false;\n}\n\nfunction isStructuralReference(column: ExpectedColumn): boolean {\n return (\n column.primaryKey ||\n column.reference === 'id' ||\n column.reference === 'foreignKey' ||\n column.reference === 'crossPackageRef' ||\n column.reference === 'tenantId'\n );\n}\n\n/** Fold engine-specific type spellings into comparable buckets. */\nexport function normalizeSqlType(type: string): string {\n const upper = String(type ?? '')\n .toUpperCase()\n .trim()\n .replace(/\\(\\s*[^)]*\\s*\\)/g, '')\n .replace(/\\[\\]$/, '')\n .trim();\n\n if (\n /^(INTEGER|INT|INT2|INT4|INT8|BIGINT|SMALLINT|TINYINT|SERIAL|BIGSERIAL)$/.test(\n upper,\n )\n )\n return 'INTEGER';\n if (\n /^(TEXT|CLOB|STRING|VARCHAR|CHAR|CHARACTER|CHARACTER VARYING|NAME)$/.test(\n upper,\n )\n )\n return 'TEXT';\n if (upper === 'UUID') return 'UUID';\n if (\n /^(REAL|FLOAT|FLOAT4|FLOAT8|DOUBLE|DOUBLE PRECISION|DECIMAL|NUMERIC|NUMBER)$/.test(\n upper,\n )\n )\n return 'REAL';\n if (/^(BOOLEAN|BOOL)$/.test(upper)) return 'BOOLEAN';\n if (/^(TIMESTAMPTZ|TIMESTAMP WITH TIME ZONE)$/.test(upper))\n return 'TIMESTAMPTZ';\n if (\n /^(DATETIME|TIMESTAMP|TIMESTAMP WITHOUT TIME ZONE|DATE|TIME)$/.test(upper)\n )\n return 'TIMESTAMP';\n if (/^(BLOB|BINARY|BYTEA)$/.test(upper)) return 'BLOB';\n if (/^(JSON|JSONB)$/.test(upper)) return 'JSON';\n\n return upper;\n}\n\n// ---------------------------------------------------------------------------\n// Index comparison — the manifest-independent policy lives here\n// ---------------------------------------------------------------------------\n\nfunction compareIndexes(\n table: ExpectedTable,\n liveColumns: Map<string, LiveColumn>,\n liveIndexes: LiveIndex[],\n): LiveParityFinding[] {\n const findings: LiveParityFinding[] = [];\n const byName = new Map(liveIndexes.map((index) => [index.name, index]));\n const signatures = new Set(\n liveIndexes.map((index) => indexSignature(index.columns, index.unique)),\n );\n\n for (const index of liveIndexes) {\n if (index.valid) continue;\n findings.push({\n kind: 'invalid_index',\n severity: 'error',\n table: table.name,\n target: index.name,\n origin: table.origin,\n message: `Index \\`${index.name}\\` on \\`${table.name}\\` is INVALID — PostgreSQL will not use it and a unique index in this state enforces nothing.`,\n recommendation:\n 'Drop and rebuild it (`REINDEX INDEX CONCURRENTLY`), then re-run the parity check.',\n });\n }\n\n // 1. Declared indexes the live database does not carry in that shape.\n // Matching is by column/uniqueness signature rather than by name so an\n // equivalent index under a different name is not reported as missing\n // (#741), and so a same-name index whose uniqueness or columns drifted\n // still is.\n for (const index of table.indexes) {\n if (signatures.has(indexSignature(index.columns, index.unique))) continue;\n // Conflict-target coverage is reported below with a message that explains\n // the actual consequence; do not report the same index twice.\n if (\n table.conflictTargets.some((target) =>\n sameColumnSet(index.columns, target.columns),\n )\n ) {\n continue;\n }\n\n const sameName = byName.get(index.name);\n findings.push({\n kind: 'missing_index',\n severity: 'warning',\n table: table.name,\n target: index.name,\n origin: table.origin,\n message: sameName\n ? `Index \\`${index.name}\\` on \\`${table.name}\\` exists but its shape drifted: declared (${index.columns.join(', ')})${index.unique ? ' UNIQUE' : ''}, live (${sameName.columns.join(', ')})${sameName.unique ? ' UNIQUE' : ''}.`\n : `Declared index \\`${index.name}\\` on \\`${table.name}\\` (${index.columns.join(', ')}) is missing from the live database.`,\n recommendation:\n table.origin === 'system'\n ? 'Re-run SMRT system-table initialization to create the missing system index.'\n : 'Run `smrt db:migrate` to create the missing index.',\n });\n }\n\n // 2. Conflict targets. An upsert whose conflict target has no matching\n // UNIQUE index either errors outright (PostgreSQL) or silently inserts\n // duplicates, so this is the one index class that is an error.\n for (const target of table.conflictTargets) {\n if (target.columns.some((column) => !liveColumns.has(column))) {\n // A missing column is already reported; do not double-report it here.\n continue;\n }\n\n const candidates = liveIndexes.filter((index) =>\n sameColumnSet(index.columns, target.columns),\n );\n // A *partial* unique index cannot arbitrate a plain `ON CONFLICT (cols)`:\n // PostgreSQL only infers an index whose predicate the statement repeats,\n // and on other engines it simply does not constrain the excluded rows.\n if (candidates.some((index) => index.unique && !index.partial)) {\n continue;\n }\n\n const partialUnique = candidates.find(\n (index) => index.unique && index.partial,\n );\n const nonUnique = candidates.find((index) => !index.unique);\n const columnList = target.columns.join(', ');\n const suffix = target.source ? ` (declared by ${target.source})` : '';\n\n if (nonUnique) {\n findings.push({\n kind: 'conflict_target_not_unique',\n severity: 'error',\n table: table.name,\n target: nonUnique.name,\n origin: table.origin,\n message: `Upsert conflict target \\`${table.name}\\` (${columnList})${suffix} is backed by \\`${nonUnique.name}\\`, which is not UNIQUE.`,\n recommendation:\n 'Recreate the index as UNIQUE (`smrt db:migrate`); until then upserts insert duplicates instead of updating.',\n });\n continue;\n }\n\n findings.push({\n kind: 'conflict_target_unindexed',\n severity: 'error',\n table: table.name,\n target: partialUnique ? partialUnique.name : columnList,\n origin: table.origin,\n message: partialUnique\n ? `Upsert conflict target \\`${table.name}\\` (${columnList})${suffix} is backed only by the partial index \\`${partialUnique.name}\\`, which cannot arbitrate the upsert.`\n : `Upsert conflict target \\`${table.name}\\` (${columnList})${suffix} has no matching UNIQUE index in the live database.`,\n recommendation:\n 'Create a full UNIQUE index over exactly these columns (`smrt db:migrate`); PostgreSQL rejects the upsert outright and other engines duplicate rows.',\n });\n }\n\n // 3. Columns declared unique that are not actually unique live.\n for (const column of table.columns) {\n if (!column.unique) continue;\n if (!liveColumns.has(column.name)) continue;\n // A partial unique index constrains only the rows its predicate selects,\n // so it does not make the column unique as declared.\n const unique = liveIndexes.some(\n (index) =>\n index.unique &&\n !index.partial &&\n sameColumnSet(index.columns, [column.name]),\n );\n if (unique) continue;\n\n findings.push({\n kind: 'unique_constraint_missing',\n severity: 'error',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is declared unique but no UNIQUE index enforces it in the live database.`,\n recommendation:\n 'De-duplicate existing values and create the UNIQUE index; the declaration is currently decorative.',\n });\n }\n\n // 4. Manifest-independent coverage policy: every foreign-key, cross-package\n // reference and tenant column needs an index it *leads*, or every lookup\n // and every tenant-scoped list is a full scan (#2356).\n for (const column of table.columns) {\n if (!column.reference) continue;\n if (column.reference === 'id') continue;\n if (!liveColumns.has(column.name)) continue;\n\n const covered = liveIndexes.some(\n (index) => index.columns[0] === column.name,\n );\n if (covered) continue;\n\n findings.push({\n kind: 'unindexed_reference',\n severity: 'warning',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Reference column \\`${table.name}.${column.name}\\` (${column.reference}) leads no index in the live database.`,\n recommendation:\n 'Add an index led by this column; relationship loads, joins and tenant-scoped reads currently scan the whole table.',\n details: { referenceKind: column.reference },\n });\n }\n\n // 5. Live indexes nothing declares. Informational: an operator may have\n // hand-added them, and nothing will recreate them after a rebuild.\n // Indexes that exist because rule 4 demands them are explained, even\n // though the manifest does not declare them.\n const policyLeadColumns = new Set(\n table.columns\n .filter((column) => column.reference && column.reference !== 'id')\n .map((column) => column.name),\n );\n const declaredNames = new Set(table.indexes.map((index) => index.name));\n const declaredSignatures = new Set(\n table.indexes.map((index) => indexSignature(index.columns, index.unique)),\n );\n for (const index of liveIndexes) {\n if (index.primary) continue;\n // Constraint-owned indexes (`sqlite_autoindex_*`, PostgreSQL `*_key` /\n // `*_pkey`) exist because of a table constraint, not because anyone\n // declared an index; reporting them as undeclared is pure noise.\n if (isConstraintOwnedIndexName(index.name)) continue;\n if (policyLeadColumns.has(index.columns[0])) continue;\n if (declaredNames.has(index.name)) continue;\n if (declaredSignatures.has(indexSignature(index.columns, index.unique)))\n continue;\n if (\n table.conflictTargets.some((target) =>\n sameColumnSet(index.columns, target.columns),\n )\n ) {\n continue;\n }\n\n findings.push({\n kind: 'extra_index',\n severity: 'info',\n table: table.name,\n target: index.name,\n origin: table.origin,\n message: `Live index \\`${index.name}\\` on \\`${table.name}\\` (${index.columns.join(', ') || 'expression'}) is not declared by the current schema.`,\n recommendation:\n 'Declare it so a rebuilt database keeps it, or drop it if it is obsolete.',\n details: { unique: index.unique, partial: index.partial },\n });\n }\n\n return findings;\n}\n\nfunction isConstraintOwnedIndexName(name: string): boolean {\n return (\n name.startsWith('sqlite_autoindex_') ||\n name.endsWith('_pkey') ||\n name.endsWith('_key')\n );\n}\n\nfunction indexSignature(columns: string[], unique: boolean): string {\n return `${columns.join(',')}:${unique}`;\n}\n\n/**\n * Conflict targets and unique constraints are order-insensitive: PostgreSQL\n * matches `ON CONFLICT (a, b)` against a unique index on `(b, a)`.\n */\nfunction sameColumnSet(left: string[], right: string[]): boolean {\n if (left.length !== right.length) return false;\n const sortedLeft = [...left].sort();\n const sortedRight = [...right].sort();\n return sortedLeft.every((column, index) => column === sortedRight[index]);\n}\n\n// ---------------------------------------------------------------------------\n// Live introspection\n// ---------------------------------------------------------------------------\n\nfunction resolveEngine(\n db: DatabaseInterface,\n engineHint?: string,\n): DatabaseEngine {\n if (typeof (db as { exportTable?: unknown }).exportTable === 'function') {\n return 'json';\n }\n const dbWithConfig = db as DatabaseInterface & { config?: { url?: string } };\n return detectEngine(db.url || dbWithConfig.config?.url || '', engineHint);\n}\n\nfunction isInternalTableName(name: string): boolean {\n return (\n name.startsWith('sqlite_') ||\n name.startsWith('pg_') ||\n name.startsWith('duckdb_') ||\n name === 'information_schema'\n );\n}\n\nasync function listLiveTables(\n db: DatabaseInterface,\n engine: DatabaseEngine,\n): Promise<Set<string>> {\n const sql =\n engine === 'postgres'\n ? `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'`\n : `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`;\n\n try {\n const result = await db.query(sql);\n const rows = (result?.rows ?? []) as {\n name?: string;\n table_name?: string;\n }[];\n return new Set(\n rows.map((row) => row.name || row.table_name || '').filter(Boolean),\n );\n } catch (error) {\n throw new LiveSchemaParityError(\n `Could not list tables in the live database: ${describeError(error)}`,\n { cause: error },\n );\n }\n}\n\nasync function readLiveColumns(\n db: DatabaseInterface,\n tableName: string,\n): Promise<Map<string, LiveColumn>> {\n if (typeof db.getTableSchema !== 'function') {\n throw new LiveSchemaParityError(\n 'The configured database adapter cannot describe tables (`getTableSchema` is unavailable), so live-schema parity cannot be verified.',\n );\n }\n\n let schema: Awaited<\n ReturnType<NonNullable<DatabaseInterface['getTableSchema']>>\n >;\n try {\n schema = await db.getTableSchema(tableName);\n } catch (error) {\n throw new LiveSchemaParityError(\n `Could not read the live schema of \\`${tableName}\\`: ${describeError(error)}`,\n { cause: error },\n );\n }\n\n const columns = new Map<string, LiveColumn>();\n for (const [name, column] of Object.entries(schema?.columns ?? {})) {\n columns.set(name, {\n name,\n type: String(column?.type ?? ''),\n notNull: column?.notNull === true,\n primaryKey: column?.primaryKey === true,\n hasDefault:\n column?.defaultValue !== undefined && column?.defaultValue !== null,\n });\n }\n return columns;\n}\n\ninterface IndexCatalog {\n forTable(tableName: string): Promise<LiveIndex[]>;\n}\n\n/**\n * Build an index reader for the engine, or `null` when index metadata cannot\n * be read. A null catalog disables every index-class check rather than\n * reporting indexes as missing on an engine we cannot introspect.\n */\nasync function readIndexCatalog(\n db: DatabaseInterface,\n engine: DatabaseEngine,\n): Promise<IndexCatalog | null> {\n if (engine === 'postgres') {\n return readPostgresIndexCatalog(db);\n }\n if (engine === 'sqlite') {\n return { forTable: (tableName) => readSqliteIndexes(db, tableName) };\n }\n return readDuckDbIndexCatalog(db);\n}\n\nasync function readPostgresIndexCatalog(\n db: DatabaseInterface,\n): Promise<IndexCatalog> {\n // One catalog pass for the whole schema: `pg_index` carries uniqueness,\n // primary-key ownership and — unlike `pg_indexes` — `indisvalid`, which is\n // the only way to see an index left INVALID by a failed CONCURRENTLY build.\n const sql = `\n SELECT t.relname AS table_name,\n c.relname AS index_name,\n i.indisunique AS is_unique,\n i.indisprimary AS is_primary,\n i.indisvalid AS is_valid,\n (i.indpred IS NOT NULL) AS is_partial,\n pg_get_indexdef(i.indexrelid) AS index_def\n FROM pg_index i\n JOIN pg_class c ON c.oid = i.indexrelid\n JOIN pg_class t ON t.oid = i.indrelid\n JOIN pg_namespace n ON n.oid = t.relnamespace\n WHERE n.nspname = 'public'`;\n\n let rows: Record<string, unknown>[];\n try {\n const result = await db.query(sql);\n rows = (result?.rows ?? []) as Record<string, unknown>[];\n } catch (error) {\n throw new LiveSchemaParityError(\n `Could not read the PostgreSQL index catalog: ${describeError(error)}`,\n { cause: error },\n );\n }\n\n const byTable = new Map<string, LiveIndex[]>();\n for (const row of rows) {\n const tableName = String(row.table_name ?? '');\n if (!tableName) continue;\n const bucket = byTable.get(tableName) ?? [];\n bucket.push({\n name: String(row.index_name ?? ''),\n columns: parseIndexDefColumns(String(row.index_def ?? '')),\n unique: toBoolean(row.is_unique),\n primary: toBoolean(row.is_primary),\n valid: row.is_valid === undefined ? true : toBoolean(row.is_valid),\n partial: toBoolean(row.is_partial),\n });\n byTable.set(tableName, bucket);\n }\n\n return { forTable: async (tableName) => byTable.get(tableName) ?? [] };\n}\n\n/**\n * Extract the indexed column list from a `CREATE INDEX` definition.\n *\n * Expression components (`lower(name)`, `(meta ->> 'x')`) are kept verbatim so\n * they never collide with a plain column of the same name; ordering is\n * preserved because leading-column coverage is what the policy checks.\n */\nexport function parseIndexDefColumns(indexDef: string): string[] {\n const open = indexDef.indexOf('(');\n if (open === -1) return [];\n\n let depth = 0;\n let end = -1;\n for (let i = open; i < indexDef.length; i++) {\n if (indexDef[i] === '(') depth++;\n else if (indexDef[i] === ')') {\n depth--;\n if (depth === 0) {\n end = i;\n break;\n }\n }\n }\n if (end === -1) return [];\n\n const body = indexDef.slice(open + 1, end);\n const parts: string[] = [];\n let current = '';\n depth = 0;\n for (const char of body) {\n if (char === '(') depth++;\n if (char === ')') depth--;\n if (char === ',' && depth === 0) {\n parts.push(current);\n current = '';\n continue;\n }\n current += char;\n }\n parts.push(current);\n\n return parts\n .map((part) =>\n part\n .trim()\n // Drop operator classes and per-column modifiers PostgreSQL renders.\n .replace(/\\s+(ASC|DESC|NULLS\\s+(FIRST|LAST)|[a-z_]+_ops)\\b/gi, '')\n .trim()\n .replace(/^\"(.*)\"$/, '$1'),\n )\n .filter((part) => part.length > 0);\n}\n\nasync function readSqliteIndexes(\n db: DatabaseInterface,\n tableName: string,\n): Promise<LiveIndex[]> {\n // `pragma_index_list` — unlike `getTableSchema()` — also reports the\n // implicit indexes SQLite creates for inline UNIQUE/PRIMARY KEY table\n // constraints (`sqlite_autoindex_*`), which is exactly where system-table\n // uniqueness lives.\n let listRows: Record<string, unknown>[];\n try {\n const result = await db.query(\n `SELECT * FROM pragma_index_list(${quoteLiteral(tableName)})`,\n );\n listRows = (result?.rows ?? []) as Record<string, unknown>[];\n } catch (error) {\n throw new LiveSchemaParityError(\n `Could not read SQLite indexes for \\`${tableName}\\`: ${describeError(error)}`,\n { cause: error },\n );\n }\n\n const indexes: LiveIndex[] = [];\n for (const row of listRows) {\n const name = String(row.name ?? '');\n if (!name) continue;\n\n const infoResult = await db.query(\n `SELECT * FROM pragma_index_info(${quoteLiteral(name)})`,\n );\n const infoRows = (infoResult?.rows ?? []) as Record<string, unknown>[];\n const columns = infoRows\n .slice()\n .sort((left, right) => Number(left.seqno ?? 0) - Number(right.seqno ?? 0))\n .map((infoRow) => (infoRow.name == null ? '' : String(infoRow.name)))\n .filter((column) => column.length > 0);\n\n indexes.push({\n name,\n columns,\n unique: toBoolean(row.unique),\n primary: String(row.origin ?? '') === 'pk',\n valid: true,\n partial: toBoolean(row.partial),\n });\n }\n\n return indexes;\n}\n\nasync function readDuckDbIndexCatalog(\n db: DatabaseInterface,\n): Promise<IndexCatalog | null> {\n // DuckDB (and the DuckDB-backed JSON adapter) expose declared indexes\n // through `duckdb_indexes()`; uniqueness constraints live in\n // `duckdb_constraints()`. Both are best-effort: if either catalog is\n // unavailable the caller skips index checks entirely.\n const byTable = new Map<string, LiveIndex[]>();\n try {\n const result = await db.query(\n `SELECT table_name, index_name, is_unique, sql FROM duckdb_indexes()`,\n );\n for (const row of (result?.rows ?? []) as Record<string, unknown>[]) {\n const tableName = String(row.table_name ?? '');\n if (!tableName) continue;\n const bucket = byTable.get(tableName) ?? [];\n bucket.push({\n name: String(row.index_name ?? ''),\n columns: parseIndexDefColumns(String(row.sql ?? '')),\n unique: toBoolean(row.is_unique),\n primary: false,\n valid: true,\n partial: false,\n });\n byTable.set(tableName, bucket);\n }\n } catch {\n return null;\n }\n\n try {\n const result = await db.query(\n `SELECT table_name, constraint_type, constraint_column_names FROM duckdb_constraints()`,\n );\n for (const row of (result?.rows ?? []) as Record<string, unknown>[]) {\n const constraintType = String(row.constraint_type ?? '').toUpperCase();\n if (constraintType !== 'UNIQUE' && constraintType !== 'PRIMARY KEY') {\n continue;\n }\n const tableName = String(row.table_name ?? '');\n const columns = normalizeColumnNameList(row.constraint_column_names);\n if (!tableName || columns.length === 0) continue;\n\n const bucket = byTable.get(tableName) ?? [];\n bucket.push({\n name: `${tableName}_${columns.join('_')}_${constraintType === 'UNIQUE' ? 'key' : 'pkey'}`,\n columns,\n unique: true,\n primary: constraintType === 'PRIMARY KEY',\n valid: true,\n partial: false,\n });\n byTable.set(tableName, bucket);\n }\n } catch {\n // Constraints are not optional metadata on this engine: DuckDB requires an\n // inline UNIQUE constraint for upsert, so uniqueness lives almost entirely\n // in `duckdb_constraints()` rather than in `duckdb_indexes()`. Without it,\n // `conflict_target_unindexed` and `unique_constraint_missing` would fire as\n // *errors* against a correct database. Degrade the whole catalog instead —\n // the caller then skips every index check and the report says\n // `indexIntrospection: 'unavailable'`.\n return null;\n }\n\n return { forTable: async (tableName) => byTable.get(tableName) ?? [] };\n}\n\nfunction normalizeColumnNameList(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.map((entry) => String(entry)).filter(Boolean);\n }\n if (typeof value === 'string') {\n return value\n .replace(/^[[{]|[\\]}]$/g, '')\n .split(',')\n .map((entry) => entry.trim().replace(/^[\"']|[\"']$/g, ''))\n .filter(Boolean);\n }\n return [];\n}\n\nfunction toBoolean(value: unknown): boolean {\n if (typeof value === 'boolean') return value;\n if (typeof value === 'number') return value !== 0;\n if (typeof value === 'string') {\n return value === '1' || value.toLowerCase() === 'true' || value === 't';\n }\n return false;\n}\n\nfunction quoteLiteral(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"live-parity.js","names":[],"sources":["../../src/schema/live-parity.ts"],"sourcesContent":["/**\n * Live-schema parity check (#2368)\n *\n * Compares a **live** database against the shape the model layer assumes.\n * Three inputs define \"expected\":\n *\n * 1. **Declared table shapes** — the manifest schemas the caller passes in.\n * These give tables, columns, types, nullability, and declared indexes.\n * 2. **Hand-DDL system tables** — `_smrt_*` tables parsed out of\n * `src/system/schema.ts` (see `system-table-shapes.ts`). They never enter\n * the manifest, so nothing else has ever diffed them.\n * 3. **An expected-shape index policy that does not consult the manifest** —\n * every foreign-key / cross-package-ref / tenant column carries a leading\n * index, every declared upsert conflict target is backed by a matching\n * UNIQUE index, and every `unique: true` column is actually unique in the\n * live database.\n *\n * Point 3 is the reason this module exists rather than reusing the migration\n * differ: the differ compares the live database to the manifest, i.e. to the\n * artifact that dropped the index in the first place, which is why a database\n * missing 164 tenant-column indexes reported \"in sync\" (#2356).\n *\n * This module is read-only. It emits findings; it never repairs.\n */\n\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport {\n collectIntegerWidthTargets,\n preflightIntegerWidthWidening,\n} from '../migrations/integer-width.js';\nimport { RETIRED_SYSTEM_TABLES } from '../system/schema.js';\nimport { detectEngine, getDDLStrategy } from './ddl/index.js';\nimport type { DatabaseEngine } from './ddl/types.js';\nimport { getSystemTableShapes } from './system-table-shapes.js';\nimport type { ColumnDefinition, SchemaDefinition } from './types.js';\n\n/** How badly a finding breaks the deployment. */\nexport type LiveParitySeverity = 'error' | 'warning' | 'info';\n\n/** The class of drift a finding describes. */\nexport type LiveParityFindingKind =\n | 'missing_table'\n | 'extra_table'\n | 'missing_column'\n | 'extra_column'\n | 'column_type_drift'\n | 'column_nullability_drift'\n | 'missing_index'\n | 'extra_index'\n | 'unindexed_reference'\n | 'conflict_target_unindexed'\n | 'conflict_target_not_unique'\n | 'unique_constraint_missing'\n | 'invalid_index'\n /** Pre-#2373 PostgreSQL/DuckDB int4 column needing opt-in widening. */\n | 'legacy_integer_width';\n\n/** One difference between the live database and the expected shape. */\nexport interface LiveParityFinding {\n kind: LiveParityFindingKind;\n severity: LiveParitySeverity;\n /** Table the finding is about. */\n table: string;\n /** Column or index the finding is about, when it is narrower than a table. */\n target?: string;\n /** Whether the table is an application table or a `_smrt_*` system table. */\n origin: ExpectedTableOrigin;\n message: string;\n recommendation: string;\n details?: Record<string, unknown>;\n}\n\n/** Aggregate result of one parity run. */\nexport interface LiveSchemaParityReport {\n engine: DatabaseEngine;\n /** Expected tables that exist in the live database and were compared. */\n tablesChecked: number;\n /** Expected tables that are absent from the live database. */\n tablesMissing: number;\n /** Whether `_smrt_*` system tables participated. */\n systemTablesIncluded: boolean;\n /**\n * `full` when index metadata (uniqueness, partial predicates, PostgreSQL\n * validity) could be read for this engine; `unavailable` when it could not,\n * in which case every index-class check is skipped rather than guessed.\n */\n indexIntrospection: 'full' | 'unavailable';\n findings: LiveParityFinding[];\n counts: Record<LiveParitySeverity, number>;\n /** True when no `error`-severity finding was produced. */\n ok: boolean;\n}\n\n/** A declared upsert conflict target for one table. */\nexport interface ConflictTargetInput {\n columns: string[];\n /** Where the target came from, e.g. a class name — used in messages. */\n source?: string;\n}\n\nexport interface LiveSchemaParityOptions {\n db: DatabaseInterface;\n /** Expected application table shapes, keyed by table name. */\n schemas?: Record<string, SchemaDefinition>;\n /** Declared upsert conflict targets, keyed by table name. */\n conflictTargets?: Record<string, ConflictTargetInput[]>;\n /** Include `_smrt_*` system tables (default true). */\n includeSystemTables?: boolean;\n /** Explicit engine hint for adapters whose URL is empty or ambiguous. */\n engineHint?: string;\n /** Report live tables no expected shape covers (default true). */\n reportExtraTables?: boolean;\n}\n\n/** Whether an expected table is an application table or a system table. */\nexport type ExpectedTableOrigin = 'application' | 'system';\n\ninterface ExpectedColumn {\n name: string;\n /** Engine-materialized type text. */\n type: string;\n primaryKey: boolean;\n notNull: boolean;\n unique: boolean;\n hasDefault: boolean;\n reference?: ColumnDefinition['referenceKind'];\n}\n\ninterface ExpectedIndex {\n name: string;\n columns: string[];\n unique: boolean;\n}\n\ninterface ExpectedTable {\n name: string;\n origin: ExpectedTableOrigin;\n columns: ExpectedColumn[];\n indexes: ExpectedIndex[];\n conflictTargets: ConflictTargetInput[];\n}\n\ninterface LiveColumn {\n name: string;\n type: string;\n notNull: boolean;\n primaryKey: boolean;\n hasDefault: boolean;\n}\n\ninterface LiveIndex {\n name: string;\n columns: string[];\n unique: boolean;\n /** PostgreSQL `indisvalid`; always true on engines without the concept. */\n valid: boolean;\n /** True for the index backing a primary key. */\n primary: boolean;\n /** True when the index is partial (has a WHERE predicate). */\n partial: boolean;\n}\n\n/**\n * Thrown when the live database cannot be introspected. Callers fail closed:\n * an unreadable database is never reported as \"in sync\".\n */\nexport class LiveSchemaParityError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options);\n this.name = 'LiveSchemaParityError';\n }\n}\n\n/**\n * Compare a live database against the expected shape and return every\n * difference found.\n *\n * @throws {LiveSchemaParityError} when the database cannot be reached or the\n * adapter cannot describe a table. Connection problems must fail closed.\n */\nexport async function checkLiveSchemaParity(\n options: LiveSchemaParityOptions,\n): Promise<LiveSchemaParityReport> {\n const {\n db,\n schemas = {},\n conflictTargets = {},\n includeSystemTables = true,\n engineHint,\n reportExtraTables = true,\n } = options;\n\n const engine = resolveEngine(db, engineHint);\n const expected = buildExpectedTables({\n schemas,\n conflictTargets,\n includeSystemTables,\n engine,\n });\n\n const liveTableNames = await listLiveTables(db, engine);\n const indexCatalog = await readIndexCatalog(db, engine);\n const findings: LiveParityFinding[] = [];\n\n let tablesChecked = 0;\n let tablesMissing = 0;\n\n for (const table of expected) {\n if (!liveTableNames.has(table.name)) {\n tablesMissing++;\n findings.push({\n kind: 'missing_table',\n severity: 'error',\n table: table.name,\n origin: table.origin,\n message: `Table \\`${table.name}\\` is declared but does not exist in the live database.`,\n recommendation:\n table.origin === 'system'\n ? 'Initialize SMRT system tables against this database (they are created on framework bootstrap).'\n : 'Run `smrt db:migrate` to create the missing table.',\n });\n continue;\n }\n\n tablesChecked++;\n const liveColumns = await readLiveColumns(db, table.name);\n findings.push(...compareColumns(table, liveColumns, engine));\n\n if (indexCatalog) {\n const liveIndexes = await indexCatalog.forTable(table.name);\n findings.push(...compareIndexes(table, liveColumns, liveIndexes));\n }\n }\n\n // #2373 intentionally leaves int4/int8 equivalent to the ordinary differ\n // (and to structural parity) so fresh BIGINT DDL does not auto-rewrite a\n // production table. Surface the remaining 32-bit columns as advisory-only\n // findings here, with row counts for a maintenance-window estimate.\n const widthPreflight = await preflightIntegerWidthWidening(\n db,\n collectIntegerWidthTargets(schemas, { includeSystemTables }),\n { engineHint },\n );\n if (widthPreflight.supported) {\n for (const table of widthPreflight.tables) {\n for (const column of table.columns) {\n if (column.state !== 'pending') continue;\n findings.push({\n kind: 'legacy_integer_width',\n severity: 'warning',\n table: table.table,\n target: column.column,\n origin: table.table.startsWith('_smrt_') ? 'system' : 'application',\n message:\n `Column \\`${table.table}.${column.column}\\` is legacy \\`${column.declaredType}\\` ` +\n `instead of BIGINT (${table.rowCount ?? 0} row(s) in the table).`,\n recommendation:\n 'Schedule a maintenance window, run `smrt db:migrate-int8 --dry-run`, then run `smrt db:migrate-int8` after reviewing the table-rewrite plan.',\n details: {\n actual: column.declaredType,\n expected: 'BIGINT',\n rowCount: table.rowCount,\n },\n });\n }\n }\n }\n\n if (reportExtraTables) {\n const expectedNames = new Set(expected.map((table) => table.name));\n for (const liveName of liveTableNames) {\n if (expectedNames.has(liveName)) continue;\n if (isInternalTableName(liveName)) continue;\n // Without system tables in scope, every `_smrt_*` table would be\n // reported as unexplained; that is a scoping artifact, not drift.\n if (!includeSystemTables && liveName.startsWith('_smrt_')) continue;\n // A retired system table is not unexplained drift — the framework\n // deliberately stopped creating it and deliberately does not drop it\n // (issue #2376). Name the exact remedy instead of the generic advice.\n const retired = RETIRED_SYSTEM_TABLES.includes(liveName);\n findings.push({\n kind: 'extra_table',\n severity: 'info',\n table: liveName,\n origin: liveName.startsWith('_smrt_') ? 'system' : 'application',\n message: retired\n ? `Live table \\`${liveName}\\` is a retired SMRT system table; nothing reads or writes it.`\n : `Live table \\`${liveName}\\` is not covered by any declared schema.`,\n recommendation: retired\n ? `Drop it once you have confirmed it is unused: DROP TABLE IF EXISTS ${liveName};`\n : 'Confirm the table belongs to another application sharing this database, or remove it once its owning model is gone.',\n });\n }\n }\n\n const counts: Record<LiveParitySeverity, number> = {\n error: 0,\n warning: 0,\n info: 0,\n };\n for (const finding of findings) {\n counts[finding.severity]++;\n }\n\n return {\n engine,\n tablesChecked,\n tablesMissing,\n systemTablesIncluded: includeSystemTables,\n indexIntrospection: indexCatalog ? 'full' : 'unavailable',\n findings,\n counts,\n ok: counts.error === 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Expected shape\n// ---------------------------------------------------------------------------\n\nfunction buildExpectedTables(input: {\n schemas: Record<string, SchemaDefinition>;\n conflictTargets: Record<string, ConflictTargetInput[]>;\n includeSystemTables: boolean;\n engine: DatabaseEngine;\n}): ExpectedTable[] {\n const { schemas, conflictTargets, includeSystemTables, engine } = input;\n const strategy = getDDLStrategy(engine);\n const tables: ExpectedTable[] = [];\n\n for (const [key, schema] of Object.entries(schemas)) {\n const tableName = schema?.tableName || key;\n if (!tableName) continue;\n\n const columns: ExpectedColumn[] = Object.entries(schema.columns ?? {}).map(\n ([columnName, column]) => ({\n name: columnName,\n type: strategy.mapType(column.type),\n primaryKey: column.primaryKey === true,\n notNull: column.notNull === true || column.primaryKey === true,\n unique: column.unique === true,\n hasDefault: column.defaultValue !== undefined,\n reference: column.foreignKey ? 'foreignKey' : column.referenceKind,\n }),\n );\n\n tables.push({\n name: tableName,\n origin: 'application',\n columns,\n indexes: (schema.indexes ?? [])\n // Expression indexes (`@meta({ indexed: true })`) surface with empty\n // or null column lists in introspection, so a column-based comparison\n // can only produce false drift for them.\n .filter((index) => !index.jsonPath && (index.columns?.length ?? 0) > 0)\n .map((index) => ({\n name: index.name,\n columns: index.columns,\n unique: index.unique === true,\n })),\n conflictTargets: dedupeConflictTargets(conflictTargets[tableName] ?? []),\n });\n }\n\n if (includeSystemTables) {\n for (const shape of getSystemTableShapes(engine).values()) {\n tables.push({\n name: shape.tableName,\n origin: 'system',\n columns: shape.columns.map((column) => ({\n name: column.name,\n type: column.type,\n primaryKey: column.primaryKey,\n notNull: column.notNull || column.primaryKey,\n unique: column.unique,\n hasDefault: column.hasDefault,\n })),\n indexes: shape.indexes.map((index) => ({\n name: index.name,\n columns: index.columns,\n unique: index.unique,\n })),\n // Inline `UNIQUE (...)` constraints are what the framework upserts\n // against on system tables, so they are the conflict targets here.\n conflictTargets: dedupeConflictTargets(\n shape.uniqueConstraints.map((columns) => ({\n columns,\n source: `${shape.tableName} DDL`,\n })),\n ),\n });\n }\n }\n\n return tables;\n}\n\nfunction dedupeConflictTargets(\n targets: ConflictTargetInput[],\n): ConflictTargetInput[] {\n const seen = new Map<string, ConflictTargetInput>();\n for (const target of targets) {\n const columns = (target.columns ?? []).filter(Boolean);\n if (columns.length === 0) continue;\n const key = [...columns].sort().join(',');\n if (!seen.has(key)) {\n seen.set(key, { columns, source: target.source });\n }\n }\n return [...seen.values()];\n}\n\n// ---------------------------------------------------------------------------\n// Column comparison\n// ---------------------------------------------------------------------------\n\nfunction compareColumns(\n table: ExpectedTable,\n liveColumns: Map<string, LiveColumn>,\n engine: DatabaseEngine,\n): LiveParityFinding[] {\n const findings: LiveParityFinding[] = [];\n const expectedNames = new Set(table.columns.map((column) => column.name));\n\n for (const column of table.columns) {\n const live = liveColumns.get(column.name);\n if (!live) {\n findings.push({\n kind: 'missing_column',\n severity: 'error',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is declared but missing from the live database.`,\n recommendation:\n 'Run `smrt db:migrate` to add the column before application writes reach this table.',\n details: { expectedType: column.type },\n });\n continue;\n }\n\n if (!typesAreEquivalent(column, live, engine)) {\n findings.push({\n kind: 'column_type_drift',\n severity: 'error',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is \\`${live.type}\\` in the live database but declared \\`${column.type}\\`.`,\n recommendation:\n 'Reconcile the column type with `smrt db:migrate`, or repair the declaration if the live type is correct.',\n details: { expected: column.type, actual: live.type },\n });\n }\n\n // A declared-NOT NULL column that is nullable live silently accepts rows\n // the model layer believes cannot exist; the reverse breaks every insert\n // that omits the column, which is the worse failure.\n if (!column.primaryKey && column.notNull && !live.notNull) {\n findings.push({\n kind: 'column_nullability_drift',\n severity: 'warning',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is declared NOT NULL but is nullable in the live database.`,\n recommendation:\n 'Backfill any NULL values and add the NOT NULL constraint, or relax the declaration.',\n });\n } else if (!column.notNull && live.notNull && !live.hasDefault) {\n findings.push({\n kind: 'column_nullability_drift',\n severity: 'error',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is NOT NULL in the live database with no default, but is not declared NOT NULL. Inserts that omit it will fail.`,\n recommendation:\n 'Drop the orphan NOT NULL constraint, give the column a default, or declare the column required.',\n });\n }\n }\n\n for (const live of liveColumns.values()) {\n if (expectedNames.has(live.name)) continue;\n\n const breaksInserts = live.notNull && !live.hasDefault;\n findings.push({\n kind: 'extra_column',\n severity: breaksInserts ? 'error' : 'info',\n table: table.name,\n target: live.name,\n origin: table.origin,\n message: breaksInserts\n ? `Live column \\`${table.name}.${live.name}\\` is undeclared, NOT NULL, and has no default — every framework insert into this table will fail.`\n : `Live column \\`${table.name}.${live.name}\\` is not declared by the current schema.`,\n recommendation: breaksInserts\n ? 'Drop the orphan column or give it a default; this is the residue of a renamed or removed required field.'\n : 'Confirm the column is intentional legacy data, or drop it once nothing reads it.',\n details: { type: live.type },\n });\n }\n\n return findings;\n}\n\n/**\n * Whether a live column type satisfies its declaration.\n *\n * Two tolerances match the model layer's actual conventions, and mirror the\n * migration differ so the two tools never disagree:\n *\n * - `TEXT` ↔ `UUID` for structural identifier/reference columns, because\n * SQLite has no uuid type and older PostgreSQL deployments legitimately\n * still carry text ids (R11).\n * - `TEXT` ↔ `JSON`/`JSONB` in both directions, because SMRT serializes JSON\n * values into text columns and a native json column already holds exactly\n * that (#1335).\n */\nfunction typesAreEquivalent(\n expected: ExpectedColumn,\n live: LiveColumn,\n engine: DatabaseEngine,\n): boolean {\n const expectedType = normalizeSqlType(expected.type);\n const actualType = normalizeSqlType(live.type);\n if (expectedType === actualType) return true;\n\n const uuidTextPair =\n (expectedType === 'UUID' && actualType === 'TEXT') ||\n (expectedType === 'TEXT' && actualType === 'UUID');\n if (uuidTextPair && isStructuralReference(expected)) {\n return true;\n }\n\n const jsonTextPair =\n (expectedType === 'JSON' && actualType === 'TEXT') ||\n (expectedType === 'TEXT' && actualType === 'JSON');\n if (jsonTextPair) return true;\n\n // SQLite has dynamic typing: BOOLEAN/TIMESTAMP columns are declared with\n // affinities that pragma reports verbatim, and INTEGER/NUMERIC storage is\n // interchangeable for the values SMRT writes.\n if (engine === 'sqlite') {\n const numericPair =\n (expectedType === 'BOOLEAN' && actualType === 'INTEGER') ||\n (expectedType === 'INTEGER' && actualType === 'BOOLEAN');\n if (numericPair) return true;\n }\n\n return false;\n}\n\nfunction isStructuralReference(column: ExpectedColumn): boolean {\n return (\n column.primaryKey ||\n column.reference === 'id' ||\n column.reference === 'foreignKey' ||\n column.reference === 'crossPackageRef' ||\n column.reference === 'tenantId'\n );\n}\n\n/** Fold engine-specific type spellings into comparable buckets. */\nexport function normalizeSqlType(type: string): string {\n const upper = String(type ?? '')\n .toUpperCase()\n .trim()\n .replace(/\\(\\s*[^)]*\\s*\\)/g, '')\n .replace(/\\[\\]$/, '')\n .trim();\n\n if (\n /^(INTEGER|INT|INT2|INT4|INT8|BIGINT|SMALLINT|TINYINT|SERIAL|BIGSERIAL)$/.test(\n upper,\n )\n )\n return 'INTEGER';\n if (\n /^(TEXT|CLOB|STRING|VARCHAR|CHAR|CHARACTER|CHARACTER VARYING|NAME)$/.test(\n upper,\n )\n )\n return 'TEXT';\n if (upper === 'UUID') return 'UUID';\n if (\n /^(REAL|FLOAT|FLOAT4|FLOAT8|DOUBLE|DOUBLE PRECISION|DECIMAL|NUMERIC|NUMBER)$/.test(\n upper,\n )\n )\n return 'REAL';\n if (/^(BOOLEAN|BOOL)$/.test(upper)) return 'BOOLEAN';\n if (/^(TIMESTAMPTZ|TIMESTAMP WITH TIME ZONE)$/.test(upper))\n return 'TIMESTAMPTZ';\n if (\n /^(DATETIME|TIMESTAMP|TIMESTAMP WITHOUT TIME ZONE|DATE|TIME)$/.test(upper)\n )\n return 'TIMESTAMP';\n if (/^(BLOB|BINARY|BYTEA)$/.test(upper)) return 'BLOB';\n if (/^(JSON|JSONB)$/.test(upper)) return 'JSON';\n\n return upper;\n}\n\n// ---------------------------------------------------------------------------\n// Index comparison — the manifest-independent policy lives here\n// ---------------------------------------------------------------------------\n\nfunction compareIndexes(\n table: ExpectedTable,\n liveColumns: Map<string, LiveColumn>,\n liveIndexes: LiveIndex[],\n): LiveParityFinding[] {\n const findings: LiveParityFinding[] = [];\n const byName = new Map(liveIndexes.map((index) => [index.name, index]));\n const signatures = new Set(\n liveIndexes.map((index) => indexSignature(index.columns, index.unique)),\n );\n\n for (const index of liveIndexes) {\n if (index.valid) continue;\n findings.push({\n kind: 'invalid_index',\n severity: 'error',\n table: table.name,\n target: index.name,\n origin: table.origin,\n message: `Index \\`${index.name}\\` on \\`${table.name}\\` is INVALID — PostgreSQL will not use it and a unique index in this state enforces nothing.`,\n recommendation:\n 'Drop and rebuild it (`REINDEX INDEX CONCURRENTLY`), then re-run the parity check.',\n });\n }\n\n // 1. Declared indexes the live database does not carry in that shape.\n // Matching is by column/uniqueness signature rather than by name so an\n // equivalent index under a different name is not reported as missing\n // (#741), and so a same-name index whose uniqueness or columns drifted\n // still is.\n for (const index of table.indexes) {\n if (signatures.has(indexSignature(index.columns, index.unique))) continue;\n // Conflict-target coverage is reported below with a message that explains\n // the actual consequence; do not report the same index twice.\n if (\n table.conflictTargets.some((target) =>\n sameColumnSet(index.columns, target.columns),\n )\n ) {\n continue;\n }\n\n const sameName = byName.get(index.name);\n findings.push({\n kind: 'missing_index',\n severity: 'warning',\n table: table.name,\n target: index.name,\n origin: table.origin,\n message: sameName\n ? `Index \\`${index.name}\\` on \\`${table.name}\\` exists but its shape drifted: declared (${index.columns.join(', ')})${index.unique ? ' UNIQUE' : ''}, live (${sameName.columns.join(', ')})${sameName.unique ? ' UNIQUE' : ''}.`\n : `Declared index \\`${index.name}\\` on \\`${table.name}\\` (${index.columns.join(', ')}) is missing from the live database.`,\n recommendation:\n table.origin === 'system'\n ? 'Re-run SMRT system-table initialization to create the missing system index.'\n : 'Run `smrt db:migrate` to create the missing index.',\n });\n }\n\n // 2. Conflict targets. An upsert whose conflict target has no matching\n // UNIQUE index either errors outright (PostgreSQL) or silently inserts\n // duplicates, so this is the one index class that is an error.\n for (const target of table.conflictTargets) {\n if (target.columns.some((column) => !liveColumns.has(column))) {\n // A missing column is already reported; do not double-report it here.\n continue;\n }\n\n const candidates = liveIndexes.filter((index) =>\n sameColumnSet(index.columns, target.columns),\n );\n // A *partial* unique index cannot arbitrate a plain `ON CONFLICT (cols)`:\n // PostgreSQL only infers an index whose predicate the statement repeats,\n // and on other engines it simply does not constrain the excluded rows.\n if (candidates.some((index) => index.unique && !index.partial)) {\n continue;\n }\n\n const partialUnique = candidates.find(\n (index) => index.unique && index.partial,\n );\n const nonUnique = candidates.find((index) => !index.unique);\n const columnList = target.columns.join(', ');\n const suffix = target.source ? ` (declared by ${target.source})` : '';\n\n if (nonUnique) {\n findings.push({\n kind: 'conflict_target_not_unique',\n severity: 'error',\n table: table.name,\n target: nonUnique.name,\n origin: table.origin,\n message: `Upsert conflict target \\`${table.name}\\` (${columnList})${suffix} is backed by \\`${nonUnique.name}\\`, which is not UNIQUE.`,\n recommendation:\n 'Recreate the index as UNIQUE (`smrt db:migrate`); until then upserts insert duplicates instead of updating.',\n });\n continue;\n }\n\n findings.push({\n kind: 'conflict_target_unindexed',\n severity: 'error',\n table: table.name,\n target: partialUnique ? partialUnique.name : columnList,\n origin: table.origin,\n message: partialUnique\n ? `Upsert conflict target \\`${table.name}\\` (${columnList})${suffix} is backed only by the partial index \\`${partialUnique.name}\\`, which cannot arbitrate the upsert.`\n : `Upsert conflict target \\`${table.name}\\` (${columnList})${suffix} has no matching UNIQUE index in the live database.`,\n recommendation:\n 'Create a full UNIQUE index over exactly these columns (`smrt db:migrate`); PostgreSQL rejects the upsert outright and other engines duplicate rows.',\n });\n }\n\n // 3. Columns declared unique that are not actually unique live.\n for (const column of table.columns) {\n if (!column.unique) continue;\n if (!liveColumns.has(column.name)) continue;\n // A partial unique index constrains only the rows its predicate selects,\n // so it does not make the column unique as declared.\n const unique = liveIndexes.some(\n (index) =>\n index.unique &&\n !index.partial &&\n sameColumnSet(index.columns, [column.name]),\n );\n if (unique) continue;\n\n findings.push({\n kind: 'unique_constraint_missing',\n severity: 'error',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Column \\`${table.name}.${column.name}\\` is declared unique but no UNIQUE index enforces it in the live database.`,\n recommendation:\n 'De-duplicate existing values and create the UNIQUE index; the declaration is currently decorative.',\n });\n }\n\n // 4. Manifest-independent coverage policy: every foreign-key, cross-package\n // reference and tenant column needs an index it *leads*, or every lookup\n // and every tenant-scoped list is a full scan (#2356).\n for (const column of table.columns) {\n if (!column.reference) continue;\n if (column.reference === 'id') continue;\n if (!liveColumns.has(column.name)) continue;\n\n const covered = liveIndexes.some(\n (index) => index.columns[0] === column.name,\n );\n if (covered) continue;\n\n findings.push({\n kind: 'unindexed_reference',\n severity: 'warning',\n table: table.name,\n target: column.name,\n origin: table.origin,\n message: `Reference column \\`${table.name}.${column.name}\\` (${column.reference}) leads no index in the live database.`,\n recommendation:\n 'Add an index led by this column; relationship loads, joins and tenant-scoped reads currently scan the whole table.',\n details: { referenceKind: column.reference },\n });\n }\n\n // 5. Live indexes nothing declares. Informational: an operator may have\n // hand-added them, and nothing will recreate them after a rebuild.\n // Indexes that exist because rule 4 demands them are explained, even\n // though the manifest does not declare them.\n const policyLeadColumns = new Set(\n table.columns\n .filter((column) => column.reference && column.reference !== 'id')\n .map((column) => column.name),\n );\n const declaredNames = new Set(table.indexes.map((index) => index.name));\n const declaredSignatures = new Set(\n table.indexes.map((index) => indexSignature(index.columns, index.unique)),\n );\n for (const index of liveIndexes) {\n if (index.primary) continue;\n // Constraint-owned indexes (`sqlite_autoindex_*`, PostgreSQL `*_key` /\n // `*_pkey`) exist because of a table constraint, not because anyone\n // declared an index; reporting them as undeclared is pure noise.\n if (isConstraintOwnedIndexName(index.name)) continue;\n if (policyLeadColumns.has(index.columns[0])) continue;\n if (declaredNames.has(index.name)) continue;\n if (declaredSignatures.has(indexSignature(index.columns, index.unique)))\n continue;\n if (\n table.conflictTargets.some((target) =>\n sameColumnSet(index.columns, target.columns),\n )\n ) {\n continue;\n }\n\n findings.push({\n kind: 'extra_index',\n severity: 'info',\n table: table.name,\n target: index.name,\n origin: table.origin,\n message: `Live index \\`${index.name}\\` on \\`${table.name}\\` (${index.columns.join(', ') || 'expression'}) is not declared by the current schema.`,\n recommendation:\n 'Declare it so a rebuilt database keeps it, or drop it if it is obsolete.',\n details: { unique: index.unique, partial: index.partial },\n });\n }\n\n return findings;\n}\n\nfunction isConstraintOwnedIndexName(name: string): boolean {\n return (\n name.startsWith('sqlite_autoindex_') ||\n name.endsWith('_pkey') ||\n name.endsWith('_key')\n );\n}\n\nfunction indexSignature(columns: string[], unique: boolean): string {\n return `${columns.join(',')}:${unique}`;\n}\n\n/**\n * Conflict targets and unique constraints are order-insensitive: PostgreSQL\n * matches `ON CONFLICT (a, b)` against a unique index on `(b, a)`.\n */\nfunction sameColumnSet(left: string[], right: string[]): boolean {\n if (left.length !== right.length) return false;\n const sortedLeft = [...left].sort();\n const sortedRight = [...right].sort();\n return sortedLeft.every((column, index) => column === sortedRight[index]);\n}\n\n// ---------------------------------------------------------------------------\n// Live introspection\n// ---------------------------------------------------------------------------\n\nfunction resolveEngine(\n db: DatabaseInterface,\n engineHint?: string,\n): DatabaseEngine {\n if (typeof (db as { exportTable?: unknown }).exportTable === 'function') {\n return 'json';\n }\n const dbWithConfig = db as DatabaseInterface & { config?: { url?: string } };\n return detectEngine(db.url || dbWithConfig.config?.url || '', engineHint);\n}\n\nfunction isInternalTableName(name: string): boolean {\n return (\n name.startsWith('sqlite_') ||\n name.startsWith('pg_') ||\n name.startsWith('duckdb_') ||\n name === 'information_schema'\n );\n}\n\nasync function listLiveTables(\n db: DatabaseInterface,\n engine: DatabaseEngine,\n): Promise<Set<string>> {\n const sql =\n engine === 'postgres'\n ? `SELECT table_name FROM information_schema.tables WHERE table_schema = 'public'`\n : `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'`;\n\n try {\n const result = await db.query(sql);\n const rows = (result?.rows ?? []) as {\n name?: string;\n table_name?: string;\n }[];\n return new Set(\n rows.map((row) => row.name || row.table_name || '').filter(Boolean),\n );\n } catch (error) {\n throw new LiveSchemaParityError(\n `Could not list tables in the live database: ${describeError(error)}`,\n { cause: error },\n );\n }\n}\n\nasync function readLiveColumns(\n db: DatabaseInterface,\n tableName: string,\n): Promise<Map<string, LiveColumn>> {\n if (typeof db.getTableSchema !== 'function') {\n throw new LiveSchemaParityError(\n 'The configured database adapter cannot describe tables (`getTableSchema` is unavailable), so live-schema parity cannot be verified.',\n );\n }\n\n let schema: Awaited<\n ReturnType<NonNullable<DatabaseInterface['getTableSchema']>>\n >;\n try {\n schema = await db.getTableSchema(tableName);\n } catch (error) {\n throw new LiveSchemaParityError(\n `Could not read the live schema of \\`${tableName}\\`: ${describeError(error)}`,\n { cause: error },\n );\n }\n\n const columns = new Map<string, LiveColumn>();\n for (const [name, column] of Object.entries(schema?.columns ?? {})) {\n columns.set(name, {\n name,\n type: String(column?.type ?? ''),\n notNull: column?.notNull === true,\n primaryKey: column?.primaryKey === true,\n hasDefault:\n column?.defaultValue !== undefined && column?.defaultValue !== null,\n });\n }\n return columns;\n}\n\ninterface IndexCatalog {\n forTable(tableName: string): Promise<LiveIndex[]>;\n}\n\n/**\n * Build an index reader for the engine, or `null` when index metadata cannot\n * be read. A null catalog disables every index-class check rather than\n * reporting indexes as missing on an engine we cannot introspect.\n */\nasync function readIndexCatalog(\n db: DatabaseInterface,\n engine: DatabaseEngine,\n): Promise<IndexCatalog | null> {\n if (engine === 'postgres') {\n return readPostgresIndexCatalog(db);\n }\n if (engine === 'sqlite') {\n return { forTable: (tableName) => readSqliteIndexes(db, tableName) };\n }\n return readDuckDbIndexCatalog(db);\n}\n\nasync function readPostgresIndexCatalog(\n db: DatabaseInterface,\n): Promise<IndexCatalog> {\n // One catalog pass for the whole schema: `pg_index` carries uniqueness,\n // primary-key ownership and — unlike `pg_indexes` — `indisvalid`, which is\n // the only way to see an index left INVALID by a failed CONCURRENTLY build.\n const sql = `\n SELECT t.relname AS table_name,\n c.relname AS index_name,\n i.indisunique AS is_unique,\n i.indisprimary AS is_primary,\n i.indisvalid AS is_valid,\n (i.indpred IS NOT NULL) AS is_partial,\n pg_get_indexdef(i.indexrelid) AS index_def\n FROM pg_index i\n JOIN pg_class c ON c.oid = i.indexrelid\n JOIN pg_class t ON t.oid = i.indrelid\n JOIN pg_namespace n ON n.oid = t.relnamespace\n WHERE n.nspname = 'public'`;\n\n let rows: Record<string, unknown>[];\n try {\n const result = await db.query(sql);\n rows = (result?.rows ?? []) as Record<string, unknown>[];\n } catch (error) {\n throw new LiveSchemaParityError(\n `Could not read the PostgreSQL index catalog: ${describeError(error)}`,\n { cause: error },\n );\n }\n\n const byTable = new Map<string, LiveIndex[]>();\n for (const row of rows) {\n const tableName = String(row.table_name ?? '');\n if (!tableName) continue;\n const bucket = byTable.get(tableName) ?? [];\n bucket.push({\n name: String(row.index_name ?? ''),\n columns: parseIndexDefColumns(String(row.index_def ?? '')),\n unique: toBoolean(row.is_unique),\n primary: toBoolean(row.is_primary),\n valid: row.is_valid === undefined ? true : toBoolean(row.is_valid),\n partial: toBoolean(row.is_partial),\n });\n byTable.set(tableName, bucket);\n }\n\n return { forTable: async (tableName) => byTable.get(tableName) ?? [] };\n}\n\n/**\n * Extract the indexed column list from a `CREATE INDEX` definition.\n *\n * Expression components (`lower(name)`, `(meta ->> 'x')`) are kept verbatim so\n * they never collide with a plain column of the same name; ordering is\n * preserved because leading-column coverage is what the policy checks.\n */\nexport function parseIndexDefColumns(indexDef: string): string[] {\n const open = indexDef.indexOf('(');\n if (open === -1) return [];\n\n let depth = 0;\n let end = -1;\n for (let i = open; i < indexDef.length; i++) {\n if (indexDef[i] === '(') depth++;\n else if (indexDef[i] === ')') {\n depth--;\n if (depth === 0) {\n end = i;\n break;\n }\n }\n }\n if (end === -1) return [];\n\n const body = indexDef.slice(open + 1, end);\n const parts: string[] = [];\n let current = '';\n depth = 0;\n for (const char of body) {\n if (char === '(') depth++;\n if (char === ')') depth--;\n if (char === ',' && depth === 0) {\n parts.push(current);\n current = '';\n continue;\n }\n current += char;\n }\n parts.push(current);\n\n return parts\n .map((part) =>\n part\n .trim()\n // Drop operator classes and per-column modifiers PostgreSQL renders.\n .replace(/\\s+(ASC|DESC|NULLS\\s+(FIRST|LAST)|[a-z_]+_ops)\\b/gi, '')\n .trim()\n .replace(/^\"(.*)\"$/, '$1'),\n )\n .filter((part) => part.length > 0);\n}\n\nasync function readSqliteIndexes(\n db: DatabaseInterface,\n tableName: string,\n): Promise<LiveIndex[]> {\n // `pragma_index_list` — unlike `getTableSchema()` — also reports the\n // implicit indexes SQLite creates for inline UNIQUE/PRIMARY KEY table\n // constraints (`sqlite_autoindex_*`), which is exactly where system-table\n // uniqueness lives.\n let listRows: Record<string, unknown>[];\n try {\n const result = await db.query(\n `SELECT * FROM pragma_index_list(${quoteLiteral(tableName)})`,\n );\n listRows = (result?.rows ?? []) as Record<string, unknown>[];\n } catch (error) {\n throw new LiveSchemaParityError(\n `Could not read SQLite indexes for \\`${tableName}\\`: ${describeError(error)}`,\n { cause: error },\n );\n }\n\n const indexes: LiveIndex[] = [];\n for (const row of listRows) {\n const name = String(row.name ?? '');\n if (!name) continue;\n\n const infoResult = await db.query(\n `SELECT * FROM pragma_index_info(${quoteLiteral(name)})`,\n );\n const infoRows = (infoResult?.rows ?? []) as Record<string, unknown>[];\n const columns = infoRows\n .slice()\n .sort((left, right) => Number(left.seqno ?? 0) - Number(right.seqno ?? 0))\n .map((infoRow) => (infoRow.name == null ? '' : String(infoRow.name)))\n .filter((column) => column.length > 0);\n\n indexes.push({\n name,\n columns,\n unique: toBoolean(row.unique),\n primary: String(row.origin ?? '') === 'pk',\n valid: true,\n partial: toBoolean(row.partial),\n });\n }\n\n return indexes;\n}\n\nasync function readDuckDbIndexCatalog(\n db: DatabaseInterface,\n): Promise<IndexCatalog | null> {\n // DuckDB (and the DuckDB-backed JSON adapter) expose declared indexes\n // through `duckdb_indexes()`; uniqueness constraints live in\n // `duckdb_constraints()`. Both are best-effort: if either catalog is\n // unavailable the caller skips index checks entirely.\n const byTable = new Map<string, LiveIndex[]>();\n try {\n const result = await db.query(\n `SELECT table_name, index_name, is_unique, sql FROM duckdb_indexes()`,\n );\n for (const row of (result?.rows ?? []) as Record<string, unknown>[]) {\n const tableName = String(row.table_name ?? '');\n if (!tableName) continue;\n const bucket = byTable.get(tableName) ?? [];\n bucket.push({\n name: String(row.index_name ?? ''),\n columns: parseIndexDefColumns(String(row.sql ?? '')),\n unique: toBoolean(row.is_unique),\n primary: false,\n valid: true,\n partial: false,\n });\n byTable.set(tableName, bucket);\n }\n } catch {\n return null;\n }\n\n try {\n const result = await db.query(\n `SELECT table_name, constraint_type, constraint_column_names FROM duckdb_constraints()`,\n );\n for (const row of (result?.rows ?? []) as Record<string, unknown>[]) {\n const constraintType = String(row.constraint_type ?? '').toUpperCase();\n if (constraintType !== 'UNIQUE' && constraintType !== 'PRIMARY KEY') {\n continue;\n }\n const tableName = String(row.table_name ?? '');\n const columns = normalizeColumnNameList(row.constraint_column_names);\n if (!tableName || columns.length === 0) continue;\n\n const bucket = byTable.get(tableName) ?? [];\n bucket.push({\n name: `${tableName}_${columns.join('_')}_${constraintType === 'UNIQUE' ? 'key' : 'pkey'}`,\n columns,\n unique: true,\n primary: constraintType === 'PRIMARY KEY',\n valid: true,\n partial: false,\n });\n byTable.set(tableName, bucket);\n }\n } catch {\n // Constraints are not optional metadata on this engine: DuckDB requires an\n // inline UNIQUE constraint for upsert, so uniqueness lives almost entirely\n // in `duckdb_constraints()` rather than in `duckdb_indexes()`. Without it,\n // `conflict_target_unindexed` and `unique_constraint_missing` would fire as\n // *errors* against a correct database. Degrade the whole catalog instead —\n // the caller then skips every index check and the report says\n // `indexIntrospection: 'unavailable'`.\n return null;\n }\n\n return { forTable: async (tableName) => byTable.get(tableName) ?? [] };\n}\n\nfunction normalizeColumnNameList(value: unknown): string[] {\n if (Array.isArray(value)) {\n return value.map((entry) => String(entry)).filter(Boolean);\n }\n if (typeof value === 'string') {\n return value\n .replace(/^[[{]|[\\]}]$/g, '')\n .split(',')\n .map((entry) => entry.trim().replace(/^[\"']|[\"']$/g, ''))\n .filter(Boolean);\n }\n return [];\n}\n\nfunction toBoolean(value: unknown): boolean {\n if (typeof value === 'boolean') return value;\n if (typeof value === 'number') return value !== 0;\n if (typeof value === 'string') {\n return value === '1' || value.toLowerCase() === 'true' || value === 't';\n }\n return false;\n}\n\nfunction quoteLiteral(value: string): string {\n return `'${value.replace(/'/g, \"''\")}'`;\n}\n\nfunction describeError(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n"],"mappings":"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"}
@@ -110,6 +110,23 @@ export interface SchemaDefinition {
110
110
  ddl?: string;
111
111
  columns: Record<string, ColumnDefinition>;
112
112
  indexes: IndexDefinition[];
113
+ /**
114
+ * Always `[]` on every schema a `@smrt()` class can currently produce (#2380).
115
+ *
116
+ * `DDLStrategy.generateTriggers()` (`schema/ddl/*.ts`) renders this array into
117
+ * real `CREATE TRIGGER` DDL and runs on every table creation, but there is no
118
+ * `@smrt()`/`@field()` option that populates it — unlike `indexes`, which
119
+ * `@smrt({ indexes: [...] })` (#2357) authors directly. The one producer that
120
+ * ever set it (the AST `generateSchema()` entry point, which emitted a single
121
+ * `updated_at`-bump trigger) fed only the `smrt:schema` virtual module, which
122
+ * had no consumer, and was deleted rather than wired up: `updated_at` is
123
+ * maintained at the application layer (`SmrtObject.save()`), the migration
124
+ * differ (`migrations/differ.ts`) never diffs triggers, so a hand-populated
125
+ * one would only ever apply to newly `CREATE TABLE`d tables and never
126
+ * retrofit existing ones. Populate this only via a caller who constructs a
127
+ * `SchemaDefinition` directly (tests, or third-party tooling) — never assume
128
+ * a generated schema carries one.
129
+ */
113
130
  triggers: TriggerDefinition[];
114
131
  foreignKeys: ForeignKeyDefinition[];
115
132
  version: string;
@@ -124,16 +141,6 @@ export interface SchemaManifest {
124
141
  schemas: Record<string, SchemaDefinition>;
125
142
  dependencies: string[];
126
143
  }
127
- export interface SchemaOverride {
128
- tableName: string;
129
- addColumns?: Record<string, ColumnDefinition>;
130
- removeColumns?: string[];
131
- addIndexes?: IndexDefinition[];
132
- removeIndexes?: string[];
133
- addTriggers?: TriggerDefinition[];
134
- removeTriggers?: string[];
135
- packageName: string;
136
- }
137
144
  export interface SchemaMigration {
138
145
  id: string;
139
146
  version: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/schema/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/schema/types.ts"],"names":[],"mappings":"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"}
package/dist/schema.js CHANGED
@@ -10,7 +10,6 @@ import { SchemaManager, createSchemaManager } from "./schema/schema-manager.js";
10
10
  import { collectManifestTables, manifestColumnsToDefinitions, manifestIndexesToDefinitions, manifestSchemaToDefinition, mergeSchemaDefinitionInto, renderCollectedManifestTable } from "./schema/manifest-schema.js";
11
11
  import { LiveSchemaParityError, checkLiveSchemaParity, normalizeSqlType, parseIndexDefColumns } from "./schema/live-parity.js";
12
12
  import { SchemaCodeGenerator } from "./schema/code-generator.js";
13
- import { SchemaOverrideSystem } from "./schema/override-system.js";
14
13
  import { SchemaAggregator } from "./schema/schema-aggregator.js";
15
14
  import "./schema/index.js";
16
- export { BaseDDLStrategy, DuckDBStrategy, JsonDuckDBStrategy, LiveSchemaParityError, PostgresStrategy, SQLiteStrategy, SYSTEM_TABLE_NAMES, SchemaAggregator, SchemaCodeGenerator, SchemaGenerator, SchemaManager, SchemaOverrideSystem, checkLiveSchemaParity, collectManifestTables, createSchemaManager, detectEngine, generateDDLForEngine, generateMultiEngineDDL, getAllStrategies, getDDLStrategy, getSystemTableShapes, manifestColumnsToDefinitions, manifestIndexesToDefinitions, manifestSchemaToDefinition, mergeSchemaDefinitionInto, normalizeSqlType, parseIndexDefColumns, parseTableShapes, renderCollectedManifestTable };
15
+ export { BaseDDLStrategy, DuckDBStrategy, JsonDuckDBStrategy, LiveSchemaParityError, PostgresStrategy, SQLiteStrategy, SYSTEM_TABLE_NAMES, SchemaAggregator, SchemaCodeGenerator, SchemaGenerator, SchemaManager, checkLiveSchemaParity, collectManifestTables, createSchemaManager, detectEngine, generateDDLForEngine, generateMultiEngineDDL, getAllStrategies, getDDLStrategy, getSystemTableShapes, manifestColumnsToDefinitions, manifestIndexesToDefinitions, manifestSchemaToDefinition, mergeSchemaDefinitionInto, normalizeSqlType, parseIndexDefColumns, parseTableShapes, renderCollectedManifestTable };