trusty-mpm 1.7.0

trusty-mpm: unified multi-agent orchestration platform (core, daemon, CLI, TUI, Telegram)
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
# Database Migration Decision Trees

This guide helps you make critical database migration decisions through clear decision trees and selection criteria.

## Table of Contents

- [Schema Migration Strategy]#schema-migration-strategy
- [Zero-Downtime Deployment Patterns]#zero-downtime-deployment-patterns
- [Rollback Strategy Selection]#rollback-strategy-selection
- [Migration Tool Choice]#migration-tool-choice
- [Data Migration Approach]#data-migration-approach

---

## Schema Migration Strategy

### Decision Tree

```
Making a schema change?
│
├─ Breaking change (drops data or incompatible)?
│   │
│   ├─ YES → Multi-phase migration required
│   │   │
│   │   ├─ Phase 1: Add new (nullable)
│   │   ├─ Phase 2: Dual-write old + new
│   │   ├─ Phase 3: Backfill data
│   │   ├─ Phase 4: Migrate reads to new
│   │   ├─ Phase 5: Remove old
│   │   │
│   │   ✅ Zero downtime maintained
│   │   ✅ Can rollback at each phase
│   │   ✅ Production-safe
│   │
│   └─ NO → Additive change?
│       │
│       ├─ YES → Single-phase migration
│       │   ✅ Add columns as nullable initially
│       │   ✅ Set defaults after data loaded
│       │   ✅ Safe and simple
│       │
│       └─ NO → Data-only change (no schema)?
│           └─ Use data migration script
│               ✅ No schema changes
│               ✅ Easier rollback
│
└─ Creating new table/index?
    │
    ├─ Large table (millions of rows)?
    │   └─ Use CONCURRENTLY for indexes
    │       ✅ No table locks (PostgreSQL)
    │       ⚠️  Takes longer but zero downtime
    │
    └─ Small table?
        └─ Standard CREATE
            ✅ Fast and simple
```

### When to Use Multi-Phase Migrations

✅ **Use multi-phase when:**
- Renaming columns or tables
- Changing column types
- Removing columns or tables
- Adding NOT NULL constraints
- Changing foreign key relationships

**Example: Renaming a column**

```sql
-- ❌ Bad: Breaking change in one step
ALTER TABLE users RENAME COLUMN email TO email_address;
-- Breaks running application immediately!

-- ✅ Good: Multi-phase approach
-- Phase 1: Add new column
ALTER TABLE users ADD COLUMN email_address VARCHAR(255) NULL;

-- Phase 2: Deploy code that writes to both columns
UPDATE users SET email_address = email WHERE email_address IS NULL;

-- Phase 3: Migrate reads to new column (code deploy)

-- Phase 4: Remove old column (after new code deployed)
ALTER TABLE users DROP COLUMN email;
```

### When to Use Single-Phase Migrations

✅ **Use single-phase when:**
- Adding new nullable columns
- Adding new tables
- Adding indexes (use CONCURRENTLY)
- Adding new foreign keys to nullable columns

```sql
-- ✅ Safe: Additive changes
ALTER TABLE users ADD COLUMN phone VARCHAR(20) NULL;
ALTER TABLE users ADD COLUMN created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP;

-- Can safely deploy with running application
```

---

## Zero-Downtime Deployment Patterns

### Decision Tree

```
Need zero-downtime deployment?
│
├─ Schema change required?
│   │
│   ├─ YES → Expand-Contract pattern
│   │   │
│   │   ├─ Step 1: EXPAND schema (add new)
│   │   ├─ Step 2: Deploy NEW code (dual-write)
│   │   ├─ Step 3: MIGRATE data (backfill)
│   │   ├─ Step 4: Deploy NEW code (read from new)
│   │   ├─ Step 5: CONTRACT schema (remove old)
│   │   │
│   │   ✅ Zero downtime guaranteed
│   │   ✅ Rollback at each step
│   │
│   └─ NO → Code-only deployment?
│       └─ Standard rolling deployment
│           ✅ Simple and fast
│
├─ Data migration required?
│   │
│   ├─ Large dataset (millions of rows)?
│   │   └─ Background worker pattern
│   │       ✅ Batch processing
│   │       ✅ No blocking
│   │       ✅ Progress tracking
│   │
│   └─ Small dataset?
│       └─ Synchronous migration
│           ✅ Simple and fast
│
└─ Index creation?
    │
    ├─ PostgreSQL?
    │   └─ CREATE INDEX CONCURRENTLY
    │       ✅ No locks
    │       ⚠️  Slower than regular CREATE
    │
    └─ MySQL?
        └─ ALGORITHM=INPLACE, LOCK=NONE (5.6+)
            ✅ Online DDL
```

### Expand-Contract Pattern (Best Practice)

**Phase 1: EXPAND**
```sql
-- Add new schema elements
ALTER TABLE products ADD COLUMN price_cents INTEGER NULL;
```

**Phase 2: Deploy Code (Dual Write)**
```python
# Application writes to BOTH old and new
product.price = Decimal("19.99")
product.price_cents = 1999  # New field
product.save()
```

**Phase 3: MIGRATE Existing Data**
```sql
-- Backfill in batches
UPDATE products
SET price_cents = CAST(price * 100 AS INTEGER)
WHERE price_cents IS NULL
LIMIT 1000;
-- Repeat until all migrated
```

**Phase 4: Deploy Code (Read New)**
```python
# Application now reads from new field
price = Decimal(product.price_cents) / 100
```

**Phase 5: CONTRACT**
```sql
-- Remove old schema
ALTER TABLE products DROP COLUMN price;
ALTER TABLE products RENAME COLUMN price_cents TO price;
```

### Blue-Green Deployment Pattern

✅ **Use blue-green when:**
- Complete database swap needed
- Testing production-like data required
- Instant rollback critical

```
┌─────────────────┐      ┌─────────────────┐
│   Blue (Live)   │      │  Green (New)    │
│                 │      │                 │
│  App v1         │      │  App v2         │
│  DB Schema v1   │      │  DB Schema v2   │
└────────┬────────┘      └────────┬────────┘
         │                        │
         │  1. Replicate data     │
         │  2. Apply migrations   │
         │  3. Test green         │
         │  4. Switch traffic ────▶
         │                        │
         │  5. Monitor            │
         │  6. Rollback if needed │
```

---

## Rollback Strategy Selection

### Decision Tree

```
Planning rollback strategy?
│
├─ Migration added new schema only?
│   │
│   ├─ YES → Simple rollback
│   │   │
│   │   └─ Run DOWN migration
│   │       ✅ Removes new additions
│   │       ✅ Safe (no data loss)
│   │
│   └─ NO → Migration modified/removed schema?
│       │
│       └─ Complex rollback needed
│           │
│           ├─ Data was migrated?
│           │   └─ Restore from backup + replay transactions
│           │       ⚠️  Complex, test thoroughly
│           │
│           └─ No data migration yet?
│               └─ Reverse migration safe
│                   ✅ Schema-only rollback
│
├─ Can tolerate data loss?
│   │
│   ├─ YES → Snapshot rollback
│   │   └─ Restore from backup
│   │       ⚠️  Loses recent data
│   │
│   └─ NO → Point-in-time recovery required
│       └─ Use transaction log replay
│           ✅ No data loss
│           ⚠️  Complex setup
│
└─ How fast must rollback be?
    │
    ├─ Immediate (< 1 minute)?
    │   └─ Blue-green deployment
    │       ✅ Traffic switch only
    │       ✅ Instant rollback
    │
    └─ Can wait (5-30 minutes)?
        └─ Reverse migration
            ✅ Standard approach
```

### Rollback Strategies

**Strategy 1: Reverse Migration (Default)**

```python
# Alembic example
def upgrade():
    op.add_column('users', sa.Column('full_name', sa.String(255)))

def downgrade():
    op.drop_column('users', 'full_name')
```

**When to use:**
- Additive changes only
- No data migration performed
- Testing/staging environments

**Strategy 2: Multi-Phase Rollback**

```
Migration in progress:
  Phase 1: ✅ Add new column       → Rollback: Drop new column
  Phase 2: ✅ Dual-write deployed  → Rollback: Deploy old code
  Phase 3: 🔄 Backfilling data     → Rollback: Stop backfill, drop new column
  Phase 4: ❌ Not started          → Cannot rollback beyond this point safely

Rule: Can only rollback to phases already completed
```

**Strategy 3: Snapshot Rollback**

```bash
# Take snapshot before migration
pg_dump -Fc mydb > backup_before_migration.dump

# If rollback needed
pg_restore -d mydb backup_before_migration.dump
```

**When to use:**
- Development/staging only
- Data loss acceptable
- Need fast rollback

**⚠️ Warning:** Loses all data created after snapshot

**Strategy 4: Point-in-Time Recovery (Production)**

```sql
-- PostgreSQL PITR
-- 1. Enable WAL archiving
archive_mode = on
archive_command = 'cp %p /archive/%f'

-- 2. Take base backup
pg_basebackup -D /backup/base

-- 3. If rollback needed
# Restore base backup
# Replay WAL up to migration point
recovery_target_time = '2025-12-03 10:00:00'
```

**When to use:**
- Production databases
- Zero data loss required
- Have WAL archiving setup

---

## Migration Tool Choice

### Decision Tree

```
Choosing migration tool for project?
│
├─ What's your tech stack?
│   │
│   ├─ Python (Django)?
│   │   └─ Django Migrations (built-in)
│   │       ✅ Integrated with ORM
│   │       ✅ Auto-generates migrations
│   │       ✅ Schema + data migrations
│   │
│   ├─ Python (other frameworks)?
│   │   └─ Alembic
│   │       ✅ Works with SQLAlchemy
│   │       ✅ Auto-detection
│   │       ✅ Flask, FastAPI compatible
│   │
│   ├─ Node.js / TypeScript?
│   │   │
│   │   ├─ Using Prisma ORM?
│   │   │   └─ Prisma Migrate
│   │   │       ✅ Type-safe
│   │   │       ✅ Schema as code
│   │   │
│   │   ├─ Using Drizzle ORM?
│   │   │   └─ Drizzle Kit
│   │   │       ✅ TypeScript-first
│   │   │       ✅ Zero dependencies
│   │   │
│   │   └─ Framework-agnostic?
│   │       └─ Knex.js or node-pg-migrate
│   │           ✅ Simple and flexible
│   │           ✅ No ORM required
│   │
│   ├─ Ruby (Rails)?
│   │   └─ ActiveRecord Migrations (built-in)
│   │       ✅ Integrated with Rails
│   │       ✅ DSL for schema changes
│   │
│   ├─ Go?
│   │   └─ golang-migrate or goose
│   │       ✅ Fast and simple
│   │       ✅ No ORM dependency
│   │
│   └─ Language-agnostic?
│       └─ Flyway or Liquibase
│           ✅ Works with any language
│           ✅ Enterprise features
│           ✅ Team tracking
│
└─ Database-specific needs?
    │
    ├─ PostgreSQL-only?
    │   └─ Sqitch or dbmate
    │       ✅ PostgreSQL optimized
    │
    └─ Multi-database support?
        └─ Flyway or Liquibase
            ✅ Supports 20+ databases
```

### Comparison Matrix

| Tool | Language | Auto-Gen | Zero-Downtime | Best For |
|------|----------|----------|---------------|----------|
| **Django Migrations** | Python | ✅ Yes | ⚠️  Manual | Django projects |
| **Alembic** | Python | ✅ Yes | ⚠️  Manual | SQLAlchemy, Flask, FastAPI |
| **Prisma Migrate** | TypeScript | ✅ Yes | ⚠️  Manual | Prisma ORM, type-safe apps |
| **Drizzle Kit** | TypeScript | ✅ Yes | ⚠️  Manual | Drizzle ORM, lightweight |
| **Knex.js** | JavaScript | ❌ No | ⚠️  Manual | Node.js, framework-agnostic |
| **ActiveRecord** | Ruby | ✅ Yes | ⚠️  Manual | Rails applications |
| **Flyway** | Any | ❌ No | ✅ Patterns | Enterprise, multi-DB |
| **Liquibase** | Any | ❌ No | ✅ Patterns | Enterprise, XML/YAML |
| **golang-migrate** | Go | ❌ No | ⚠️  Manual | Go microservices |

### When to Use Each Tool

**Django Migrations**
```python
# Auto-generate from models
python manage.py makemigrations

# Apply migrations
python manage.py migrate
```

✅ **Use when:** Building Django applications with ORM

**Alembic (SQLAlchemy)**
```bash
# Auto-generate from models
alembic revision --autogenerate -m "add user table"

# Apply
alembic upgrade head
```

✅ **Use when:** Flask, FastAPI, or any Python with SQLAlchemy

**Prisma Migrate**
```bash
# Generate migration from schema
npx prisma migrate dev --name add_user_table

# Apply to production
npx prisma migrate deploy
```

✅ **Use when:** TypeScript projects with type-safe database access

**Flyway (Enterprise)**
```sql
-- migrations/V1__create_users.sql
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    email VARCHAR(255) NOT NULL
);
```

```bash
flyway migrate
```

✅ **Use when:** Multi-language teams, enterprise requirements

---

## Data Migration Approach

### Decision Tree

```
Migrating data between schemas?
│
├─ How much data?
│   │
│   ├─ Small (< 10,000 rows)?
│   │   └─ Synchronous in-migration approach
│   │       ✅ Simple UPDATE statement
│   │       ✅ Runs during migration
│   │       ✅ Fast enough
│   │
│   ├─ Medium (10k - 1M rows)?
│   │   └─ Batched migration approach
│   │       ✅ Process in chunks (1000 rows)
│   │       ✅ Avoid long locks
│   │       ✅ Resumable if interrupted
│   │
│   └─ Large (> 1M rows)?
│       └─ Background worker approach
│           ✅ Process asynchronously
│           ✅ Track progress
│           ✅ Zero downtime
│
├─ Complex transformations needed?
│   │
│   ├─ YES → Application-level migration
│   │   │
│   │   └─ Use background jobs
│   │       ✅ Business logic in code
│   │       ✅ Easy to test
│   │       ✅ Can retry failures
│   │
│   └─ NO → SQL-level migration
│       └─ Direct UPDATE/INSERT
│           ✅ Faster
│           ✅ Less code
│
└─ Can tolerate temporary inconsistency?
    │
    ├─ YES → Lazy migration
    │   │
    │   └─ Migrate on read/write
    │       ✅ Zero downtime
    │       ✅ Gradual migration
    │       ✅ No batch jobs needed
    │
    └─ NO → Eager migration required
        └─ Backfill before switching reads
            ✅ Consistent data
            ⚠️  Requires coordination
```

### Data Migration Patterns

**Pattern 1: Synchronous (Small Data)**

```sql
-- Simple one-shot migration
UPDATE products
SET price_cents = CAST(price * 100 AS INTEGER)
WHERE price_cents IS NULL;
```

**When to use:**
- < 10,000 rows
- Fast transformation
- No locks concern

**Pattern 2: Batched (Medium Data)**

```python
def migrate_in_batches(batch_size=1000):
    while True:
        updated = db.execute("""
            UPDATE products
            SET price_cents = CAST(price * 100 AS INTEGER)
            WHERE price_cents IS NULL
            LIMIT :batch_size
        """, batch_size=batch_size)

        if updated == 0:
            break  # All migrated

        time.sleep(0.1)  # Breather between batches
```

**When to use:**
- 10k - 1M rows
- Want to avoid long locks
- Need progress tracking

**Pattern 3: Background Worker (Large Data)**

```python
# Celery task example
@celery.task
def backfill_price_cents():
    products = Product.objects.filter(price_cents__isnull=True)[:1000]

    for product in products:
        product.price_cents = int(product.price * 100)
        product.save()

    if products.count() == 1000:
        # More to process, schedule next batch
        backfill_price_cents.apply_async(countdown=1)
```

**When to use:**
- > 1M rows
- Complex transformations
- Need monitoring/retry

**Pattern 4: Lazy Migration (Zero Downtime)**

```python
class Product(models.Model):
    price = models.DecimalField()
    price_cents = models.IntegerField(null=True)

    def save(self, *args, **kwargs):
        # Migrate on write
        if self.price_cents is None:
            self.price_cents = int(self.price * 100)
        super().save(*args, **kwargs)

    @property
    def current_price_cents(self):
        # Migrate on read
        if self.price_cents is None:
            self.price_cents = int(self.price * 100)
            self.save()
        return self.price_cents
```

**When to use:**
- True zero downtime needed
- Gradual migration acceptable
- No batch processing infrastructure

---

## Migration Checklist

Before executing migrations, verify:

1. **Backup Taken** → Full database backup exists
2. **Tested on Staging** → Migration tested on production-like data
3. **Rollback Plan** → Know how to reverse the migration
4. **Monitoring Ready** → Can detect issues quickly
5. **Team Notified** → Coordinate with team on timing
6. **Load Tested** → Tested with production-scale data
7. **Read-Only Mode** → Can enable read-only if issues
8. **Runbook Created** → Step-by-step execution guide

---

## Related References

- **[Troubleshooting]./troubleshooting.md** - Common migration failures and recovery procedures
- **[Zero-Downtime Patterns]./zero-downtime-patterns.md** - Detailed zero-downtime deployment strategies (coming soon)
- **[Tool Guides]./tool-guides.md** - Framework-specific migration tool guides (coming soon)