Skip to content

Schema Drift Monitoring ​

Track schema changes and their impact on token savings.

Overview ​

Schema Drift Monitoring detects when your database schema changes and calculates how those changes affect TONL token savings. This helps you maintain optimal performance in production.

Basic Usage ​

typescript
import { PostgresAdapter } from 'tonl-mcp-bridge';

const db = new PostgresAdapter(config);
await db.connect();

// Capture baseline
await db.trackSchema('users');

// Later, detect changes
const drift = await db.detectSchemaDrift('users');

console.log(`Schema changed: ${drift.hasChanged}`);
console.log(`New columns: ${drift.newColumns}`);
console.log(`Removed columns: ${drift.removedColumns}`);
console.log(`Type changes: ${JSON.stringify(drift.typeChanges)}`);
console.log(`Savings impact: ${drift.savingsImpact}%`);
console.log(`Recommendation: ${drift.recommendation}`);

await db.disconnect();

Drift Detection ​

Schema Baseline ​

Track your current schema:

typescript
await db.trackSchema('users');
await db.trackSchema('orders');
await db.trackSchema('products');

Baselines are stored in .tonl-schemas/ directory as JSON files.

Detect Changes ​

typescript
const drift = await db.detectSchemaDrift('users');

if (drift.hasChanged) {
  console.log('Schema has changed since baseline');
}

Drift Result Structure ​

typescript
interface SchemaDrift {
  hasChanged: boolean;
  newColumns: string[];
  removedColumns: string[];
  typeChanges: TypeChange[];
  rowCountChange: number;
  savingsImpact: number;
  recommendation: string;
}

Real-World Example ​

From production testing:

typescript
// Initial baseline
await db.trackSchema('users');

// Add column to users table
await db.query('ALTER TABLE users ADD COLUMN status VARCHAR(20) DEFAULT \'active\'');

// Detect drift
const drift = await db.detectSchemaDrift('users');

Output:

Has changed: true
New columns: ['status']
Removed columns: []
Type changes: []
Row count change: 0
Savings impact: 50.3%
Recommendation: Schema change improved savings. Update baseline.

Type Changes ​

Detect when column types change:

typescript
// Baseline: age is INTEGER
await db.trackSchema('users');

// Change type
await db.query('ALTER TABLE users ALTER COLUMN age TYPE BIGINT');

// Detect
const drift = await db.detectSchemaDrift('users');

console.log(drift.typeChanges);
// [{ column: 'age', oldType: 'number', newType: 'number' }]

Savings Impact ​

Understand how changes affect token usage:

Positive Impact ​

Adding columns increases savings:

typescript
// Adding a column
Savings impact: +50.3%
Recommendation: Schema change improved savings. Update baseline.

Negative Impact ​

Removing columns reduces savings:

typescript
// Removing columns
Savings impact: -15.2%
Recommendation: Schema change reduced savings significantly. Consider optimization.

Neutral Impact ​

Minor changes:

typescript
// Type changes without size impact
Savings impact: +2.1%
Recommendation: Schema changed but savings impact is minimal.

Production Integration ​

Automated Monitoring ​

typescript
async function monitorSchemas() {
  const db = new PostgresAdapter(config);
  await db.connect();
  
  const tables = ['users', 'orders', 'products'];
  
  for (const table of tables) {
    try {
      const drift = await db.detectSchemaDrift(table);
      
      if (drift.hasChanged) {
        console.log(`[${table}] Schema drift detected`);
        console.log(`  New columns: ${drift.newColumns.join(', ')}`);
        console.log(`  Removed columns: ${drift.removedColumns.join(', ')}`);
        console.log(`  Impact: ${drift.savingsImpact}%`);
        
        if (Math.abs(drift.savingsImpact) > 10) {
          // Alert team
          await sendAlert({
            table,
            drift,
            severity: 'high'
          });
        }
        
        // Update baseline
        await db.updateSchemaBaseline(table);
      }
    } catch (error) {
      console.error(`Failed to check drift for ${table}:`, error);
    }
  }
  
  await db.disconnect();
}

// Run daily
setInterval(monitorSchemas, 24 * 60 * 60 * 1000);

CI/CD Integration ​

typescript
// In your migration script
async function runMigration() {
  const db = new PostgresAdapter(config);
  await db.connect();
  
  // Track before migration
  await db.trackSchema('users');
  
  // Run migration
  await db.query('ALTER TABLE users ADD COLUMN email_verified BOOLEAN DEFAULT false');
  
  // Check impact
  const drift = await db.detectSchemaDrift('users');
  
  console.log(`Migration impact: ${drift.savingsImpact}%`);
  
  if (drift.savingsImpact < -20) {
    console.warn('Migration significantly reduced token savings');
  }
  
  // Update baseline
  await db.updateSchemaBaseline('users');
  
  await db.disconnect();
}

Baseline Management ​

Update Baseline ​

After confirming changes:

typescript
await db.updateSchemaBaseline('users');

Re-baseline Multiple Tables ​

typescript
const tables = ['users', 'orders', 'products'];

for (const table of tables) {
  await db.trackSchema(table);
}

Delete Baseline ​

Manual cleanup:

bash
rm .tonl-schemas/users.json

Storage ​

Baselines are stored as JSON:

json
{
  "tableName": "users",
  "columns": [
    {"name": "id", "type": "number", "nullable": false},
    {"name": "name", "type": "string", "nullable": false},
    {"name": "age", "type": "number", "nullable": true}
  ],
  "rowCount": 10,
  "capturedAt": "2025-01-15T10:30:00.000Z"
}

Location: .tonl-schemas/[table_name].json

Add to .gitignore:

.tonl-schemas/

Use Cases ​

Migration Safety ​

Validate migrations don't hurt performance:

typescript
// Before migration
await db.trackSchema('users');

// After migration
const drift = await db.detectSchemaDrift('users');

if (drift.savingsImpact < -10) {
  throw new Error('Migration reduced token savings too much');
}

Performance Regression Detection ​

typescript
const drift = await db.detectSchemaDrift('orders');

if (drift.savingsImpact < -15) {
  logger.warn('Token savings degraded', {
    table: 'orders',
    impact: drift.savingsImpact,
    recommendation: drift.recommendation
  });
}

Capacity Planning ​

typescript
const drift = await db.detectSchemaDrift('users');

console.log(`Row count change: ${drift.rowCountChange}`);
console.log(`Current savings: ${drift.savingsImpact}%`);

// Predict future costs based on growth

Database Compatibility ​

Works with:

  • PostgreSQL
  • MySQL
  • SQLite

Best Practices ​

  1. Track baselines after schema changes
  2. Monitor regularly in production
  3. Alert on significant changes (> 10% impact)
  4. Update baselines after validation
  5. Include in CI/CD pipeline

Limitations ​

  • Requires baseline to exist
  • Detects structural changes only
  • Does not track data distribution changes
  • Storage grows with number of tracked tables
  • Not suitable for frequently changing schemas

Error Handling ​

typescript
try {
  const drift = await db.detectSchemaDrift('users');
} catch (error) {
  if (error.message.includes('No baseline found')) {
    // Create baseline first
    await db.trackSchema('users');
  } else {
    throw error;
  }
}

Performance ​

Drift detection overhead:

  • Baseline load: < 1ms
  • Schema query: 10-50ms (depending on database)
  • Comparison: < 5ms
  • Total: 15-60ms

Minimal impact on production systems.

MIT Licensed | v1.0.0