Skip to content

Commit 49b12d1

Browse files
aparajonclaude
andcommitted
feat(github): add cutover command, sentinel recovery, and cutover UX
Add PR comment cutover command (schemabot cutover <apply-id> -e <env>), sentinel-based crash recovery for deferred cutover, and cutover comment lifecycle improvements. Key changes: - Cutover command handler with environment validation - Recovering state with sentinel table check for crash recovery - Cutover comment UX: progress freezes, cutover comment serves as summary - Progress tombstone differentiates from summary comment - Cutover and recovering state rendering in CLI and PR comments - Integration tests for sentinel recovery and cutover flows Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8fa2279 commit 49b12d1

31 files changed

Lines changed: 2142 additions & 197 deletions

TEMPLATES.md

Lines changed: 49 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1498,7 +1498,7 @@ Schema changes are being applied. Progress updates will be posted as new comment
14981498
- **`users`**: 🟦🟦🟦🟦🟦🟦🟦🟦🟦⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 48%
14991499

15001500
```sql
1501-
ALTER TABLE `users` ADD INDEX `idx_email_created` (`email`, `created_at`)
1501+
ALTER TABLE `users` ADD INDEX `idx_email_created`(`email`, `created_at`);
15021502
```
15031503
Rows: 3,500,000 / 7,200,000 · ETA: 5m 30s
15041504

@@ -1516,7 +1516,7 @@ schemabot stop apply-a1b2c3d4e5f6
15161516
<summary><a name="single-table-completed"></a><strong>Single Table: Completed</strong></summary>
15171517

15181518

1519-
## Schema Change Applied
1519+
## Schema Change Completed
15201520

15211521
**Database**: `testapp` | **Environment**: `staging` | **Apply ID**: `apply-a1b2c3d4e5f6` | **Elapsed**: 8m
15221522

@@ -1527,10 +1527,14 @@ schemabot stop apply-a1b2c3d4e5f6
15271527
- **`users`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
15281528

15291529
```sql
1530-
ALTER TABLE `users` ADD INDEX `idx_email_created` (`email`, `created_at`)
1530+
ALTER TABLE `users` ADD INDEX `idx_email_created`(`email`, `created_at`);
15311531
```
15321532

15331533

1534+
---
1535+
1536+
*See completion summary below*
1537+
15341538
</details>
15351539

15361540
<details>
@@ -1548,7 +1552,7 @@ schemabot stop apply-a1b2c3d4e5f6
15481552
- **`users`**: 🟥⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ ❌ Failed
15491553

15501554
```sql
1551-
ALTER TABLE `users` ADD INDEX `idx_email_created` (`email`, `created_at`)
1555+
ALTER TABLE `users` ADD INDEX `idx_email_created`(`email`, `created_at`);
15521556
```
15531557

15541558

@@ -1578,7 +1582,7 @@ schemabot apply -e staging
15781582
- **`users`**: 🟧🟧🟧🟧🟧🟧🟧⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ ⏹️ Stopped at 39%
15791583

15801584
```sql
1581-
ALTER TABLE `users` ADD INDEX `idx_email_created` (`email`, `created_at`)
1585+
ALTER TABLE `users` ADD INDEX `idx_email_created`(`email`, `created_at`);
15821586
```
15831587
Rows: 156,342 / 397,453
15841588

@@ -1609,19 +1613,19 @@ schemabot start apply-a1b2c3d4e5f6
16091613
- **`orders`**: ⏳ Queued
16101614

16111615
```sql
1612-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1616+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
16131617
```
16141618

16151619
- **`users`**: ⏳ Queued
16161620

16171621
```sql
1618-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1622+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
16191623
```
16201624

16211625
- **`products`**: ⏳ Queued
16221626

16231627
```sql
1624-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1628+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
16251629
```
16261630

16271631

@@ -1651,20 +1655,20 @@ schemabot stop apply-a1b2c3d4e5f6
16511655
- **`orders`**: 🟦🟦🟦🟦⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 22%
16521656

16531657
```sql
1654-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1658+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
16551659
```
16561660
Rows: 321,450 / 1,466,232 · ETA: 5m 40s
16571661

16581662
- **`users`**: ⏳ Queued
16591663

16601664
```sql
1661-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1665+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
16621666
```
16631667

16641668
- **`products`**: ⏳ Queued
16651669

16661670
```sql
1667-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1671+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
16681672
```
16691673

16701674

@@ -1694,20 +1698,20 @@ schemabot stop apply-a1b2c3d4e5f6
16941698
- **`users`**: 🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦🟦⬜⬜⬜⬜⬜⬜⬜⬜ 62%
16951699

16961700
```sql
1697-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1701+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
16981702
```
16991703
Rows: 914,707 / 1,466,232 · ETA: 3m 15s
17001704

17011705
- **`products`**: ⏳ Queued
17021706

17031707
```sql
1704-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1708+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
17051709
```
17061710

17071711
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17081712

17091713
```sql
1710-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1714+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
17111715
```
17121716

17131717

@@ -1737,20 +1741,20 @@ schemabot stop apply-a1b2c3d4e5f6
17371741
- **`products`**: 🟦🟦🟦⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ 17%
17381742

17391743
```sql
1740-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1744+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
17411745
```
17421746
Rows: 87,231 / 523,140 · ETA: 7m 0s
17431747

17441748
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17451749

17461750
```sql
1747-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1751+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
17481752
```
17491753

17501754
- **`users`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17511755

17521756
```sql
1753-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1757+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
17541758
```
17551759

17561760

@@ -1767,7 +1771,7 @@ schemabot stop apply-a1b2c3d4e5f6
17671771
<summary><a name="all-completed"></a><strong>All Completed</strong></summary>
17681772

17691773

1770-
## Schema Change Applied
1774+
## Schema Change Completed
17711775

17721776
**Database**: `testapp` | **Environment**: `staging` | **Apply ID**: `apply-a1b2c3d4e5f6` | **Elapsed**: 8m
17731777

@@ -1780,22 +1784,26 @@ schemabot stop apply-a1b2c3d4e5f6
17801784
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17811785

17821786
```sql
1783-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1787+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
17841788
```
17851789

17861790
- **`users`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17871791

17881792
```sql
1789-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1793+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
17901794
```
17911795

17921796
- **`products`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
17931797

17941798
```sql
1795-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1799+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
17961800
```
17971801

17981802

1803+
---
1804+
1805+
*See completion summary below*
1806+
17991807
</details>
18001808

18011809
<details>
@@ -1815,19 +1823,19 @@ schemabot stop apply-a1b2c3d4e5f6
18151823
- **`orders`**: 🟥⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ ❌ Failed
18161824

18171825
```sql
1818-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1826+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
18191827
```
18201828

18211829
- **`users`**: ⊘ Cancelled (not started)
18221830

18231831
```sql
1824-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1832+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
18251833
```
18261834

18271835
- **`products`**: ⊘ Cancelled (not started)
18281836

18291837
```sql
1830-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1838+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
18311839
```
18321840

18331841

@@ -1859,19 +1867,19 @@ schemabot apply -e staging
18591867
- **`users`**: 🟥🟥🟥🟥🟥🟥⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜⬜ ❌ Failed
18601868

18611869
```sql
1862-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1870+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
18631871
```
18641872

18651873
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
18661874

18671875
```sql
1868-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1876+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
18691877
```
18701878

18711879
- **`products`**: ⊘ Cancelled (not started)
18721880

18731881
```sql
1874-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1882+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
18751883
```
18761884

18771885

@@ -1903,14 +1911,14 @@ schemabot apply -e staging
19031911
- **`users`**: 🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧🟧⬜⬜⬜⬜⬜⬜ ⏹️ Stopped at 72%
19041912

19051913
```sql
1906-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1914+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
19071915
```
19081916
Rows: 1,055,687 / 1,466,232
19091917

19101918
- **`orders`**: 🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩🟩 ✓ Complete
19111919

19121920
```sql
1913-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1921+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
19141922
```
19151923

19161924

@@ -1933,34 +1941,36 @@ schemabot start apply-a1b2c3d4e5f6
19331941

19341942
*Applied by @aparajon at 2026-01-01 00:00:00 UTC*
19351943

1944+
**0/3** table(s) ready for cutover — waiting on 3
1945+
19361946
📊 3 waiting for cutover
19371947

19381948
### Table Progress
19391949

19401950
- **`orders`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 Waiting for cutover
19411951

19421952
```sql
1943-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1953+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
19441954
```
19451955

19461956
- **`users`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 Waiting for cutover
19471957

19481958
```sql
1949-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
1959+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
19501960
```
19511961

19521962
- **`products`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 Waiting for cutover
19531963

19541964
```sql
1955-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
1965+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
19561966
```
19571967

19581968

19591969
---
19601970

1961-
To proceed with cutover:
1971+
To proceed with the cutover:
19621972
```
1963-
schemabot cutover apply-a1b2c3d4e5f6
1973+
schemabot cutover apply-a1b2c3d4e5f6 -e staging
19641974
```
19651975

19661976
</details>
@@ -1975,26 +1985,28 @@ schemabot cutover apply-a1b2c3d4e5f6
19751985

19761986
*Applied by @aparajon at 2026-01-01 00:00:00 UTC*
19771987

1988+
**0/3** table(s) ready for cutover — waiting on 3
1989+
19781990
📊 3 cutting over
19791991

19801992
### Table Progress
19811993

19821994
- **`orders`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 🔄 Cutting over...
19831995

19841996
```sql
1985-
ALTER TABLE `orders` ADD INDEX `idx_user_id` (`user_id`)
1997+
ALTER TABLE `orders` ADD INDEX `idx_user_id`(`user_id`);
19861998
```
19871999

19882000
- **`users`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 🔄 Cutting over...
19892001

19902002
```sql
1991-
ALTER TABLE `users` ADD INDEX `idx_email` (`email`)
2003+
ALTER TABLE `users` ADD INDEX `idx_email`(`email`);
19922004
```
19932005

19942006
- **`products`**: 🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨🟨 🔄 Cutting over...
19952007

19962008
```sql
1997-
ALTER TABLE `products` ADD INDEX `idx_price` (`price_cents`)
2009+
ALTER TABLE `products` ADD INDEX `idx_price`(`price_cents`);
19982010
```
19992011

20002012

0 commit comments

Comments
 (0)