Minggu lalu saya menghapus database produksi saya. Instance [Neotoma](https://neotoma.io) saya yang berfungsi berubah dari 6.174 observasi dan 3.862 entitas menjadi 84 observasi dan 67 entitas dalam satu perintah. Kontak, tugas, percakapan, catatan umpan balik, transaksi, dan aturan tetap selama berbulan-bulan: hilang.

Saya mendapatkannya kembali. Basis data akhir memiliki 6,296 observasi dan 3,951 entitas selama lima minggu aktivitas. Pemulihan memakan waktu sekitar satu jam. Postingan ini membahas tentang bagaimana hal itu terjadi, mengapa pemulihan dapat dilakukan, dan pengalaman apa yang terungkap tentang membangun sistem memori yang benar-benar dapat Anda percayai.

## Apa yang terjadi

Saya sedang mengerjakan Neotoma CLI, menguji alur kerja pengembangan. Saya menjalankan serangkaian perintah yang mengatur ulang status database dan menginisialisasi ulangnya. Tujuannya adalah untuk menghapus data pengujian dari lingkungan pengembang. Targetnya adalah database produksi.

Kesalahannya adalah hal biasa. Saya menjalankan `neotoma reset` sementara `NEOTOMA_ENV` disetel ke produksi. Saya pikir saya menargetkan dev. Saat saya perhatikan, database aktif memiliki 84 observasi baru dari proses inisialisasi ulang dan tidak ada yang lain.

## Menemukan cadangan

Hal pertama yang saya lakukan adalah mencari setiap file Neotoma SQLite di mesin saya. Saya menemukan sepuluh salinan tersebar di direktori cadangan, folder data, dan artefak pemulihan dengan stempel waktu dari penutupan sebelumnya pada awal Maret.

| File sumber | Pengamatan | Entitas | Aktivitas terkini |
|---|---|---|---|
| `neotoma.prod.db.db` | 6.174 | 3.862 | 9 Maret |
| `neotoma.prod 2.db` | 4.406 | 3.073 | 10 Maret |
| Target langsung (pasca penghapusan) | 84 | 67 | 11 Maret |
| `neotoma.prod.db.pulih-*` | 4.381 | 3.059 | 3 Maret |
| `cadangan data/salinan data/` | 4.158 | 2.955 | 2 Maret |
| Berbagai salinan lama | 3.100 hingga 3.931 | 2.558 hingga 2.806 | 17 Februari hingga 27 Februari |

Salinan cadangan ada karena saya menyalin file database secara manual pada interval yang tidak teratur. Bukan sistem cadangan formal, hanya perintah `cp` sesekali ketika saya ingat atau merasa gugup. Salah satu salinan tersebut, `neotoma.prod.db.db`, ​​menyimpan hampir semuanya hingga 9 Maret. Salinan kedua, `neotoma.prod 2.db`, ​​memiliki data hingga 10 Maret yang terlewatkan oleh salinan pertama.

Di antara dua file ini dan 84 pengamatan yang masih ada di database langsung, saya memiliki cukup bahan untuk merekonstruksi garis waktu secara penuh.

## Cara kerja penggabungan

Neotoma memiliki perintah `merge-db` bawaan untuk menggabungkan database SQLite. Prosesnya:

1. Cadangkan setiap file yang terlibat (baik sumber maupun target) ke dalam direktori yang diberi stempel waktu. Tidak ada upaya pemulihan yang membahayakan dokumen asli.
2. Hentikan server Neotoma yang sedang berjalan untuk mencegah penulisan secara bersamaan.
3. Lakukan uji coba penggabungan untuk melihat konflik apa saja yang ada.
4. Jalankan penggabungan dengan `--mode keep-target`, yang menyisipkan baris dari sumber yang tidak dimiliki target dan mempertahankan versi target dari baris mana pun yang digunakan bersama oleh kedua database.
5. Ulangi untuk sumber kedua.
6. Verifikasi observasi dan jumlah entitas.
7. Mulai ulang servernya.

Penggabungan utama menghasilkan 6.174 observasi dari cadangan terbesar. Penggabungan sekunder menambahkan sekitar 100 lagi dari jendela 10 Maret. Penghitungan akhir: 6.296 observasi, 3.951 entitas, aktivitas mulai 9 Februari hingga 11 Maret.

Setelah restart, saya mengambil sampel entitas melalui Neotoma MCP untuk memastikan semuanya dapat diakses. Kontak, tugas, percakapan, catatan umpan balik: semuanya ada dan terstruktur dengan benar.

## Mengapa pemulihan ini dapat dilakukan

Pemulihan berhasil karena tiga properti arsitektur Neotoma.

**Pengamatan adalah sumber kebenaran.** Neotoma tidak menyimpan entitas dengan menimpa baris ketika ada perubahan. Setiap fakta memasuki sistem sebagai pengamatan yang tidak dapat diubah: "Email Alice adalah alice@example.com, diamati pada tanggal 3 Maret dari Gmail." Status entitas dihitung dari seluruh observasi. Log observasi hanya dapat ditambahkan.

Ini berarti cadangan basis data merupakan gambaran lengkap dari setiap fakta yang pernah dilihat sistem, bukan hanya keadaan terkini. Saat saya menggabungkan cadangan ke dalam database langsung, saya tidak memulihkan "keadaan terakhir yang diketahui dari setiap entitas". Saya memutar ulang sejarah lengkapnya.

**Snapshot entitas berasal, bukan yang utama.** Setelah menggabungkan observasi, Neotoma menghitung ulang snapshot entitas dari log observasi. Snapshot untuk setiap entitas bersifat deterministik: dengan observasi yang sama, Anda selalu mendapatkan status entitas yang sama. Inilah sebabnya mengapa perintah penggabungan menyertakan langkah penghitungan ulang snapshot. Setelah observasi dilakukan, entitas membangun kembali dirinya dengan benar.

**Penggabungan kunci utama dengan deteksi konflik.** Perintah `merge-db` menelusuri setiap tabel, menyisipkan baris yang ada di sumber tetapi bukan target, dan menangani konflik berdasarkan kunci utama. Dalam mode `pertahankan target`, versi target menang pada tabrakan apa pun. Mode uji coba mempratinjau dengan tepat apa yang akan dimasukkan dan apa yang akan bertentangan sebelum Anda berkomitmen. Saya melakukan uji coba untuk kedua penggabungan dan meninjau laporan konflik sebelum mengeksekusi.

Ketiga properti ini bersama-sama membuat database melakukan pemulihan mandiri dengan cara yang tidak dapat dilakukan oleh pencadangan tingkat baris tradisional. Anda tidak perlu khawatir tentang cadangan mana yang memiliki "versi yang tepat" dari suatu entitas. Anda menggabungkan pengamatan, menghitung ulang, dan keadaan yang benar muncul.

## Apa yang saya pelajari

Pengalaman tersebut memperkuat beberapa hal.

**Pencadangan informal lebih baik daripada tidak ada pencadangan.** Kebiasaan saya yang sesekali menyalin file database menghemat waktu kerja berbulan-bulan. Namun salinan manual sesekali bukanlah sebuah sistem. Mereka meninggalkan celah. Jika saya menghapus database pada tanggal 7 Maret, bukan 11 Maret, saya akan kehilangan data dari tanggal 28 Februari hingga 7 Maret karena tidak ada salinan yang menutupi jendela tersebut sepenuhnya. Saya sekarang menyiapkan pencadangan harian otomatis dengan Time Machine di Mac saya.

**Kesalahan tanda env adalah hal yang klasik.** Setiap sistem yang beroperasi di lingkungan pengembangan dan produksi memiliki risiko ini. Mitigasinya adalah perintah konfirmasi untuk operasi yang merusak, perintah terminal berkode warna, atau kredensial terpisah per lingkungan. Setelah kejadian ini saya menambahkan konfirmasi paksa ke `neotoma reset` setiap kali mendeteksi lingkungan produksi. Bendera `-y` diabaikan untuk prod. Anda melihat "Reset Neotoma (PRODUKSI)" dan peringatan sebelum terjadi sesuatu.

**Arsitektur bersumber peristiwa memberikan hasil dalam pemulihan.** Jika Neotoma menyimpan entitas dengan menimpa baris di tempatnya, penghapusan database akan menjadi peristiwa kehilangan data tanpa jalur pemulihan yang bersih. Karena observasi tidak dapat diubah dan status entitas diturunkan, pemulihan adalah operasi penggabungan dan penghitungan ulang. Catatan observasi adalah kebenaran dasar. Segala sesuatu yang lain dapat dibangun kembali darinya.

**Saya menguji alat yang saya buat.** Saya menulis perintah `merge-db` beberapa bulan yang lalu untuk kasus penggunaan yang berbeda: menggabungkan data dari pengguna yang menjalankan beberapa instance Neotoma. Saya tidak pernah berharap untuk menggunakannya pada data produksi saya sendiri. Namun karena alat tersebut ada dan menangani resolusi konflik dan perhitungan ulang snapshot, pemulihan bersifat mekanis dan bukan penuh tekanan.

## Data Anda harus bertahan dari kesalahan Anda

Kejadian ini mengungkap celah yang harus ditutup oleh Neotoma sehingga pengguna tidak perlu melakukan apa yang saya lakukan secara manual.

**Snapshot otomatis.** Neotoma harus mengambil snapshot database sesuai jadwal dan sebelum operasi destruktif apa pun. Satu set salinan berstempel waktu yang diputar, disimpan selama 30 hari. Jika Anda tidak sengaja menjalankan reset pada prod, snapshot pra-reset ada di sana. Pemulihan tidak bergantung pada apakah Anda ingat untuk menjalankan `cp` minggu itu.

**Deteksi anomali.** Penurunan mendadak dari ribuan observasi hingga mendekati nol bukanlah hal yang normal. Neotoma dapat mendeteksi pola ini dan mengonfirmasinya sebelum melakukan. Heuristik sederhana, "operasi ini akan menghapus lebih dari 90% observasi, konfirmasi?" akan mencegah penghapusan saya sepenuhnya.

**Pemulihan berbasis agen.** Karena agen adalah UX utama untuk Neotoma, pemulihan juga harus dilakukan melalui agen. Anda memberi tahu agen Anda "database saya sepertinya salah, sepertinya saya kehilangan data." Agen memeriksa jumlah observasi, menemukan snapshot yang tersedia, membandingkan rentang tanggal, dan memandu Anda melakukan penggabungan melalui MCP. Tidak diperlukan spelunking CLI.

**Sinkronisasi jarak jauh.** Pencadangan lokal melindungi dari penimpaan yang tidak disengaja, namun tidak melindungi dari kegagalan disk. Neotoma harus mendukung sinkronisasi log observasi ke lokasi jarak jauh: cloud bucket, mesin kedua, atau server yang dihosting sendiri. Karena pengamatan hanya bersifat tambahan, model sinkronisasinya sederhana. Kirim observasi baru ke remote. Rekonstruksi status entitas di kedua ujungnya.

Arsitektur yang sama yang memungkinkan pemulihan ini membuat fitur-fitur ini mudah dibuat. Pengamatan tambahan saja, status turunan, dan penghitungan ulang deterministik bukan sekadar properti pemulihan. Ini adalah landasan untuk pencadangan, sinkronisasi, dan pemulihan mandiri sebagai jaminan kelas satu.

## Angka-angka

| Metrik | Sebelum menghapus | Setelah menghapus | Setelah pemulihan |
|---|---|---|---|
| Pengamatan | 6.174 | 84 | 6.296 |
| Entitas | 3.862 | 67 | 3.951 |
| Rentang tanggal | 9 Februari hingga 9 Maret | 10 Maret hingga 11 Maret | 9 Februari hingga 11 Maret |

Jumlah akhir lebih tinggi dibandingkan jumlah sebelum penghapusan karena penggabungan menggabungkan pengamatan dari ketiga sumber: dua file cadangan dan data pasca-penghapusan yang masih ada. Beberapa observasi yang hanya ada di cadangan 10 Maret atau hanya di database langsung tidak ada di cadangan terbesar aslinya.

Jika sistem memori Anda menggunakan keadaan yang bisa berubah, penghapusan bersifat permanen. Jika menggunakan log pengamatan tambahan saja dengan status entitas turunan, penghapusan merupakan gabungan dari pemulihan penuh. Perbedaan itu penting jika datanya adalah kontak Anda, komitmen Anda, riwayat Anda dengan agen di ratusan sesi.

Neotoma adalah [sumber terbuka di GitHub](https://github.com/neotoma-app/neotoma). Jika Anda menginginkan lapisan memori di mana data Anda dapat bertahan dari kesalahan terburuk Anda, [cobalah](https://neotoma.io/install).