You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat: provide a verified portable backup and restore journey for local memory #731
Cortex stores database data, profile/configuration JSON, wiki pages and raw artifacts separately. checkpoint saves working state. The examined public tool/doctor/README entries and scripts contain targeted migration/backup procedures but no demonstrated complete portable product restore journey. Hindsight has admin backup/restore and bank export/import contracts.
This is a bounded public-surface finding; manual SQLite backup or pg_dump remain possible.
Acceptance evidence
Define included/excluded owned resources and a versioned manifest with digests.
Produce a consistent backup under concurrent writes, preserving source links and version chains.
Restore into a fresh isolated location and verify integrity plus known-memory/source queries.
Reject incomplete/incompatible archives with an actionable result while preserving the original target.
Document tested recovery and upgrade rollback on supported platforms.
Scope and related work
#662 covers PostgreSQL-to-SQLite migration. A complete backup/restore also needs to work without changing backend.
Raised by the global Hindsight/Cortex audit. The target is a measurable local-first experience with the same supported semantics in Claude and Codex. Acceptance criteria describe a target, not current conformance. Static findings refer to the pinned source; probes identify their boundary.
CI autopilot : tranche 1 livrée dans #892 (docs(audit): what a Cortex backup must contain, Refs #731).
Elle couvre le premier critère (ressources incluses/exclues) : docs/audits/owned-resources-backup-2026-11-05.md classe chaque fichier et store qu'écrit Cortex (données utilisateur, dérivées, état de processus, hors Cortex), avec la ligne de source qui nomme son chemin, et donne l'ensemble à sauvegarder par backend. Constat : les graphes de code, le tampon de consolidation et l'installation du pipeline sont construits depuis le répertoire personnel et ne suivent pas CORTEX_CLAUDE_DIR.
Tranches restantes :
Manifeste versionné des entrées de classe A, avec un digest chacune.
Instantané cohérent de chaque store sous écritures concurrentes.
Restauration dans un CORTEX_CLAUDE_DIR neuf, puis vérification d'intégrité et requêtes mémoire/source connues.
Refus d'une archive incomplète ou incompatible, cible intacte.
Documentation testée de la récupération et du rollback de mise à jour par plateforme.
CI autopilot : tranche 3 (partie SQLite) ouverte dans #971 (Refs #731, pas Closes).
Cause : le store SQLite tourne en WAL. Une copie de memory.db seul perd ce qui n'est commité que dans -wal. Trois copies successives (.db, -wal, -shm) ne correspondent pas à un même instant.
Correctif :
infrastructure/sqlite_snapshot.py copie le store par l'API de backup en ligne, en une seule étape. La copie est repassée en journal_mode=DELETE, ce qui donne un fichier autonome, puis contrôlée par integrity_check.
Livré (tests seuls) : une chaîne de supersession écrite par supersede_atomic est restaurée ligne pour ligne (id, contenu, source, supersedes_id, superseded_by_id) ; cinq backups pris pendant qu'un autre thread allonge la chaîne restaurent chacun une seule chaîne complète, liens dans les deux sens, une tête, chaque version avec sa source.
Vérifié localement : 2 tests verts sur 8 exécutions, 14 tests de restauration verts, ruff et craftsmanship OK.
Non vérifié : Windows/macOS et la suite complète (torch inaccessible via le proxy). La CI fera foi.
Tranches restantes :
Cluster PostgreSQL géré : copie à l'arrêt ou dump logique.
Documentation testée de la récupération et du rollback de mise à jour, par plateforme.
Exposition par un outil MCP ou une CLI (aujourd'hui fonctions de handler seulement) — choix de surface à confirmer par le propriétaire.
CI autopilot : #731 mise en autopilot:hold. Les trois tranches restantes attendent une décision. Les tranches 1, 2, 4 et 5 sont fusionnées (#892, #960, #983, #984).
copie à l'arrêt de managed-pg/cluster : il faut arrêter le serveur que partagent toutes les sessions ouvertes, pendant toute la copie ;
dump logique par l'URL de managed_pg.py:140-143 : il faut un pg_dump de la même version majeure que le serveur (pg0 = PostgreSQL 18.1). Le code actuel ne prouve pas que l'arbre installé en fournit un (managed_pg_supervisor.py ne lit que bin/postgres).
Surface publique (outil MCP, sous-commande CLI, ou les deux). Aujourd'hui, snapshot_backup et restore_backup ne sont que des fonctions de handler. Ce choix vous revient.
Documentation testée de la récupération et du rollback, par plateforme. Elle dépend du point 2 : on ne peut pas documenter un parcours que l'utilisateur ne peut pas lancer.
À trancher : la méthode pour le cluster géré (et le sort du mot de passe dans l'archive), puis la surface. Un commentaire de votre part lève le hold au prochain passage.
Décision : cette issue n'attend plus de réponse du propriétaire.
Le propriétaire a demandé le 12 novembre 2026 que les issues avancent sans lui ; il ne répondra pas aux questions posées ici. Ce commentaire de cdeust lève le hold et précise la demande. Il vaut pour toute la suite de cette issue.
Tranche toi-même chaque question restée ouverte : d'abord une décision écrite et acceptée du dépôt (ADR accepté, docs/), puis ce que le texte de l'issue propose ou exclut, puis les standards du dépôt ; à défaut, la plus petite tranche qui réalise ce que l'issue demande. Une valeur qui manque se mesure, elle ne s'invente pas.
Écris la décision dans un commentaire marqué <!-- ci-autopilot decision --> (ce qui est retenu, la raison et sa source, ce qui est écarté, comment revenir en arrière), puis livre la tranche dans une PR. Une décision écrite ne se rejoue pas aux passages suivants.
Ne repose pas autopilot:hold pour une question : seulement pour l'irréversible, un accès que tu n'as pas, une dépendance nommée encore ouverte ou le plafond de tentatives, en nommant exactement ce qui manque.
Jamais de tag, de release, de montée de version du projet ni de déclenchement manuel d'un workflow.
Hold autopilot:hold levé : un commentaire de cdeust (« Décision : cette issue n'attend plus de réponse du propriétaire », 12/11/2026) a été posté après la pose du hold.
Activity
cdeust commentedon Nov 5, 2026
CI autopilot : tranche 1 livrée dans #892 (
docs(audit): what a Cortex backup must contain,Refs #731).Elle couvre le premier critère (ressources incluses/exclues) :
docs/audits/owned-resources-backup-2026-11-05.mdclasse chaque fichier et store qu'écrit Cortex (données utilisateur, dérivées, état de processus, hors Cortex), avec la ligne de source qui nomme son chemin, et donne l'ensemble à sauvegarder par backend. Constat : les graphes de code, le tampon de consolidation et l'installation du pipeline sont construits depuis le répertoire personnel et ne suivent pasCORTEX_CLAUDE_DIR.Tranches restantes :
CORTEX_CLAUDE_DIRneuf, puis vérification d'intégrité et requêtes mémoire/source connues.Generated by Claude Code
fixup! docs(audit): what a Cortex backup must contain (#731, slice 1)
docs(audit): what a Cortex backup must contain (#731, slice 1) (#892)
cdeust commentedon Nov 10, 2026
CI autopilot : la tranche 2 est ouverte dans #960 (
Refs #731, pasCloses).Elle couvre la moitié « manifeste versionné avec digests » du premier critère.
core/backup_manifest.pycontient la table des ressources de classe A de l'audit, par backend, avec le formatcortex-backup-manifestversion 1.infrastructure/backup_scan.pycalcule le SHA-256 et la taille de chaque fichier. Il refuse les liens symboliques et les fichiers spéciaux.handlers/backup_manifest.pyfait la composition.CORTEX_MEMORY_DB_PATH.Vérifié localement :
Non vérifié : la suite complète et Windows, faute de torch dans mon environnement. La CI fera foi.
Tranches restantes :
CORTEX_CLAUDE_DIRneuf, puis vérification des digests du manifeste et de requêtes mémoire/source connues.parse_manifestrefuse déjà un autre format, une autre version ou une autre table.Generated by Claude Code
fixup! feat(backup): a versioned manifest digests every class A file …
fixup! feat(backup): a versioned manifest digests every class A file …
feat(backup): a versioned manifest digests every class A file of an i…
cdeust commentedon Nov 10, 2026
CI autopilot : tranche 3 (partie SQLite) ouverte dans #971 (
Refs #731, pasCloses).memory.dbseul perd ce qui n'est commité que dans-wal. Trois copies successives (.db,-wal,-shm) ne correspondent pas à un même instant.infrastructure/sqlite_snapshot.pycopie le store par l'API de backup en ligne, en une seule étape. La copie est repassée enjournal_mode=DELETE, ce qui donne un fichier autonome, puis contrôlée parintegrity_check.handlers/backup_snapshot.pycopie toutes les ressources de classe A dans un répertoire de staging vide, situé hors de la racine. Le manifeste de feat(backup): a versioned manifest digests every class A file of an install (#731, slice 2) #960 est calculé sur cette copie.managedest refusée explicitement.Tranches restantes :
CORTEX_CLAUDE_DIRneuf et vérification des digests du manifeste.Generated by Claude Code
fixup! feat(backup): a live SQLite store is staged as one consistent …
fixup! feat(backup): a live SQLite store is staged as one consistent …
fixup! feat(backup): a live SQLite store is staged as one consistent …
fixup! feat(backup): a live SQLite store is staged as one consistent …
feat(backup): a live SQLite store is staged as one consistent copy (#731
fixup! feat(backup): a staged backup is restored into a fresh root, o…
feat(backup): restore a staged backup into a fresh root, verified aga…
cdeust commentedon Nov 11, 2026
CI autopilot : tranche 5 ouverte dans #984 (
506de48,Refs #731, l'issue reste ouverte).supersede_atomicest restaurée ligne pour ligne (id, contenu,source,supersedes_id,superseded_by_id) ; cinq backups pris pendant qu'un autre thread allonge la chaîne restaurent chacun une seule chaîne complète, liens dans les deux sens, une tête, chaque version avec sa source.Tranches restantes :
Generated by Claude Code
test(backup): a restored store keeps its version chains and source li…
cdeust commentedon Nov 11, 2026
CI autopilot : #731 mise en
autopilot:hold. Les trois tranches restantes attendent une décision. Les tranches 1, 2, 4 et 5 sont fusionnées (#892, #960, #983, #984).Cluster PostgreSQL géré. L'audit (
docs/audits/owned-resources-backup-2026-11-05.md§3) laisse deux méthodes ouvertes :managed-pg/cluster: il faut arrêter le serveur que partagent toutes les sessions ouvertes, pendant toute la copie ;managed_pg.py:140-143: il faut unpg_dumpde la même version majeure que le serveur (pg0 = PostgreSQL 18.1). Le code actuel ne prouve pas que l'arbre installé en fournit un (managed_pg_supervisor.pyne lit quebin/postgres).Il reste aussi à décider si une archive peut contenir le fichier
managed-pg/password. Le choix touche aussi Storage: import an existing SQLite store into the managed PostgreSQL of ADR-1114 automatically, with no user operation #745 et Storage: perform future PostgreSQL major upgrades of the managed server in the launcher, invisibly to the user #746 (pg0), qui sont en hold. Je ne peux pas le tester ici : ce conteneur n'a ni pg0 ni de binaire PostgreSQL 18 (pg_dump16 seulement).Surface publique (outil MCP, sous-commande CLI, ou les deux). Aujourd'hui,
snapshot_backupetrestore_backupne sont que des fonctions de handler. Ce choix vous revient.Documentation testée de la récupération et du rollback, par plateforme. Elle dépend du point 2 : on ne peut pas documenter un parcours que l'utilisateur ne peut pas lancer.
À trancher : la méthode pour le cluster géré (et le sort du mot de passe dans l'archive), puis la surface. Un commentaire de votre part lève le hold au prochain passage.
Generated by Claude Code
cdeust commentedon Nov 12, 2026
Décision : cette issue n'attend plus de réponse du propriétaire.
Le propriétaire a demandé le 12 novembre 2026 que les issues avancent sans lui ; il ne répondra pas aux questions posées ici. Ce commentaire de
cdeustlève le hold et précise la demande. Il vaut pour toute la suite de cette issue.docs/), puis ce que le texte de l'issue propose ou exclut, puis les standards du dépôt ; à défaut, la plus petite tranche qui réalise ce que l'issue demande. Une valeur qui manque se mesure, elle ne s'invente pas.<!-- ci-autopilot decision -->(ce qui est retenu, la raison et sa source, ce qui est écarté, comment revenir en arrière), puis livre la tranche dans une PR. Une décision écrite ne se rejoue pas aux passages suivants.autopilot:holdpour une question : seulement pour l'irréversible, un accès que tu n'as pas, une dépendance nommée encore ouverte ou le plafond de tentatives, en nommant exactement ce qui manque.Règle complète : #343 (comment)
Écrit par la session « écosystème autonome » sur instruction du propriétaire (12 novembre 2026).
Generated by Claude Code
cdeust commentedon Nov 12, 2026
Hold
autopilot:holdlevé : un commentaire decdeust(« Décision : cette issue n'attend plus de réponse du propriétaire », 12/11/2026) a été posté après la pose du hold.Generated by Claude Code