La semaine dernière, j'ai effacé ma base de données de production. Mon instance de travail [Neotoma](https://neotoma.io) est passée de 6 174 observations et 3 862 entités à 84 observations et 67 entités en une seule commande. Des mois de contacts, de tâches, de conversations, de commentaires, de transactions et de règles permanentes : finis.

Je l'ai récupéré. La base de données finale compte 6 296 observations et 3 951 entités réparties sur cinq semaines d'activité. La récupération a duré environ une heure. Cet article explique comment cela s'est produit, pourquoi la récupération a été possible et ce que l'expérience a révélé sur la construction d'un système de mémoire auquel vous pouvez réellement faire confiance.

## Que s'est-il passé

Je travaillais sur la CLI Neotoma, testant un workflow de développement. J'ai exécuté une séquence de commandes qui ont réinitialisé l'état de la base de données et l'ai réinitialisé. L'intention était d'effacer les données de test d'un environnement de développement. La cible était la base de données de production.

L’erreur était banale. J'ai exécuté `neotoma reset` alors que `NEOTOMA_ENV` était mis en production. Je pensais que je ciblais les développeurs. Au moment où je l'ai remarqué, la base de données active contenait 84 nouvelles observations issues du processus de réinitialisation et rien d'autre.

## Trouver les sauvegardes

La première chose que j'ai faite a été de rechercher chaque fichier Neotoma SQLite sur ma machine. J'ai trouvé dix copies dispersées dans des répertoires de sauvegarde, des dossiers de données et des artefacts de récupération horodatés lors d'un précédent appel rapproché début mars.

| Fichier source | Observations | Entités | Dernière activité |
|---|---|---|---|
| `neotoma.prod.db.db` | 6 174 | 3 862 | 9 mars |
| `neotoma.prod 2.db` | 4 406 | 3 073 | 10 mars |
| Cible en direct (post-wipe) | 84 | 67 | 11 mars |
| `neotoma.prod.db.recovered-*` | 4 381 | 3 059 | 3 mars |
| `sauvegardes de données/copie de données/` | 4 158 | 2 955 | 2 mars |
| Divers exemplaires anciens | 3 100 à 3 931 | 2 558 à 2 806 | 17 février au 27 février |

Les copies de sauvegarde existaient parce que j'avais copié manuellement le fichier de base de données à intervalles irréguliers. Pas un système de sauvegarde formel, juste des commandes « cp » occasionnelles lorsque je m'en souvenais ou que je me sentais nerveux. L'une de ces copies, « neotoma.prod.db.db », contenait presque tout jusqu'au 9 mars. Une deuxième copie, « neotoma.prod 2.db », contenait jusqu'au 10 mars des données que la première copie manquait.

Entre ces deux fichiers et les 84 observations survivantes dans la base de données en direct, j'avais suffisamment de matériel pour reconstruire la chronologie complète.

## Comment la fusion a fonctionné

Neotoma dispose d'une commande `merge-db` intégrée pour combiner des bases de données SQLite. Le processus :

1. Sauvegardez tous les fichiers impliqués (les sources et la cible) dans un répertoire horodaté. Aucune tentative de récupération ne devrait mettre en danger les originaux.
2. Arrêtez le serveur Neotoma en cours d'exécution pour empêcher les écritures simultanées.
3. Exécutez la fusion à sec pour voir quels conflits existent.
4. Exécutez la fusion avec `--mode keep-target`, qui insère les lignes de la source qui manquent à la cible et préserve la version de la cible de toute ligne partagée par les deux bases de données.
5. Répétez l'opération pour la deuxième source.
6. Vérifiez le nombre d’observations et d’entités.
7. Redémarrez le serveur.

La fusion principale a apporté 6 174 observations à partir de la plus grande sauvegarde. La fusion secondaire en a ajouté environ 100 de plus à partir de la fenêtre du 10 mars. Le décompte final : 6 296 observations, 3 951 entités, activité s'étendant du 9 février au 11 mars.

Après le redémarrage, j'ai échantillonné les entités via le Neotoma MCP pour confirmer que tout était accessible. Contacts, tâches, conversations, enregistrements de commentaires : tous présents et correctement structurés.

## Pourquoi cette reprise a été possible

La récupération a fonctionné grâce à trois propriétés de l'architecture de Neotoma.

**Les observations sont la source de la vérité.** Neotoma ne stocke pas les entités en écrasant une ligne lorsque quelque chose change. Chaque fait entre dans le système comme une observation immuable : « L'e-mail d'Alice est alice@example.com, observé le 3 mars depuis Gmail. » L'état de l'entité est calculé à partir de l'ensemble complet des observations. Le journal d’observation est en annexe uniquement.

Cela signifie qu'une sauvegarde de base de données est un instantané complet de tous les faits que le système a jamais vus, et pas seulement du dernier état. Lorsque j'ai fusionné la sauvegarde dans la base de données active, je ne restaurais pas "le dernier état connu de chaque entité". Je rejouais toute l'histoire.

**Les instantanés d'entités sont dérivés et non primaires.** Après avoir fusionné les observations, Neotoma recalcule les instantanés d'entités à partir du journal d'observation. L'instantané de chaque entité est déterministe : étant donné les mêmes observations, vous obtenez toujours le même état d'entité. C'est pourquoi la commande de fusion inclut une étape de recalcul d'instantané. Une fois les observations mises en place, les entités se reconstruisent correctement.

**Fusion de clé primaire avec détection de conflit.** La commande `merge-db` parcourt chaque table, insère les lignes qui existent dans la source mais pas dans la cible et gère les conflits par clé primaire. En mode « garder la cible », la version de la cible gagne en cas de collision. Le mode d'exécution à sec prévisualise exactement ce qui sera inséré et ce qui sera en conflit avant que vous ne vous engagez. J'ai effectué des essais à sec pour les deux fusions et examiné les rapports de conflits avant de les exécuter.

Ensemble, ces trois propriétés permettent à la base de données d'auto-réparer, contrairement aux sauvegardes traditionnelles au niveau des lignes. Vous n'avez pas à vous soucier de savoir quelle sauvegarde contient « la bonne version » d'une entité. Vous fusionnez les observations, recalculez et l'état correct apparaît.

## Ce que j'ai appris

L’expérience a renforcé certaines choses.

**Les sauvegardes informelles valent mieux que pas de sauvegardes.** Mon habitude de copier occasionnellement le fichier de base de données m'a permis d'économiser des mois de travail. Mais les copies manuelles occasionnelles ne constituent pas un système. Ils laissent des vides. Si j'avais effacé la base de données le 7 mars au lieu du 11 mars, j'aurais perdu les données du 28 février au 7 mars car aucune copie ne couvrait complètement cette fenêtre. Je configure actuellement des sauvegardes quotidiennes automatisées avec Time Machine sur mon Mac.

**L'erreur du drapeau env est un classique.** Chaque système qui fonctionne dans des environnements de développement et de production comporte ce risque. L'atténuation consiste en des invites de confirmation pour les opérations destructrices, des invites de terminal à code couleur ou des informations d'identification distinctes par environnement. Après cet incident, j'ai ajouté une confirmation forcée à « neotoma reset » chaque fois qu'il détecte un environnement de production. L'indicateur `-y` est ignoré pour la production. Vous voyez « Réinitialisation de Neotoma (PRODUCTION) » et un avertissement avant que quoi que ce soit ne se produise.

**L'architecture basée sur les événements est payante en matière de récupération.** Si Neotoma stockait les entités en écrasant les lignes en place, un effacement de la base de données serait un événement de perte de données sans chemin de récupération propre. Étant donné que les observations sont immuables et que l’état de l’entité est dérivé, la récupération est une opération de fusion et de recalcul. Le journal d’observation est la vérité terrain. Tout le reste peut être reconstruit à partir de là.

**J'ai testé les outils que je construisais.** J'ai écrit la commande `merge-db` il y a des mois pour un cas d'utilisation différent : combiner les données d'utilisateurs exécutant plusieurs instances Neotoma. Je ne m'attendais jamais à l'utiliser sur mes propres données de production. Mais comme l’outil existait et gérait la résolution des conflits et le recalcul des instantanés, la récupération était mécanique plutôt que stressante.

## Vos données doivent survivre à vos erreurs

Cet incident a révélé des lacunes que Neotoma devrait combler afin que les utilisateurs n'aient jamais à faire ce que j'ai fait manuellement.

**Instantanés automatiques.** Neotoma doit prendre un instantané de la base de données selon un calendrier et avant toute opération destructrice. Un ensemble tournant de copies horodatées, conservées pendant 30 jours. Si vous exécutez une réinitialisation sur prod par erreur, l'instantané de pré-réinitialisation se trouve juste là. La récupération ne devrait pas dépendre du fait que vous ayez ou non pensé à exécuter « cp » cette semaine-là.

**Détection d'anomalies.** Une chute soudaine de milliers d'observations à près de zéro n'est pas normale. Neotoma pourrait détecter ce modèle et le confirmer avant de s'engager. Une simple heuristique, "cette opération supprimerait plus de 90% des observations, tu confirmes ?" aurait empêché complètement mon essuyage.

**Récupération pilotée par agent.** Étant donné que les agents constituent la principale UX de Neotoma, la récupération devrait également fonctionner via des agents. Vous dites à votre agent "ma base de données semble erronée, je pense que j'ai perdu des données". L'agent vérifie le nombre d'observations, trouve les instantanés disponibles, compare les plages de dates et vous guide tout au long de la fusion via le MCP. Aucune spéléologie CLI requise.

**Synchronisation à distance.** Les sauvegardes locales protègent contre les écrasements accidentels, mais pas contre les pannes de disque. Neotoma devrait prendre en charge la synchronisation du journal d'observation vers un emplacement distant : un bucket cloud, une deuxième machine ou un serveur auto-hébergé. Étant donné que les observations sont uniquement ajoutées, le modèle de synchronisation est simple. Envoyez de nouvelles observations à la télécommande. Reconstruisez l’état de l’entité à chaque extrémité.

La même architecture qui a rendu cette récupération possible rend ces fonctionnalités simples à créer. Les observations en ajout uniquement, l'état dérivé et le recalcul déterministe ne sont pas de simples propriétés de récupération. Ils constituent la base de la sauvegarde, de la synchronisation et de l’auto-réparation et constituent des garanties de premier ordre.

## Les chiffres

| Métrique | Avant d'essuyer | Après essuyage | Après récupération |
|---|---|---|---|
| Observations | 6 174 | 84 | 6 296 |
| Entités | 3 862 | 67 | 3 951 |
| Plage de dates | 9 février au 9 mars | 10 mars au 11 mars | 9 février au 11 mars |

Le décompte final est supérieur au décompte avant effacement, car la fusion combine les observations des trois sources : les deux fichiers de sauvegarde et les données survivantes après effacement. Certaines observations qui n'existaient que dans la sauvegarde du 10 mars ou uniquement dans la base de données active ne figuraient pas dans la sauvegarde originale la plus grande.

Si votre système de mémoire utilise un état mutable, un effacement est permanent. S'il utilise un journal d'observation en ajout uniquement avec un état d'entité dérivé, un effacement est une fusion loin d'une récupération complète. Cette différence est importante lorsque les données concernent vos contacts, vos engagements, votre historique avec les agents sur des centaines de sessions.

Neotoma est [open source sur GitHub](https://github.com/neotoma-app/neotoma). Si vous voulez une couche de mémoire où vos données peuvent survivre à vos pires erreurs, [essayez-la](https://neotoma.io/install).