Memories / Documentation

Sur cette page

Architecture et protocole v1

Stockage

Le schéma de la base de données comprend header, state et checkpoints. Hormis les métadonnées de format, le sel et les numéros de séquence des lignes, les valeurs sont des textes chiffrés authentifiés. Les journaux contiennent également du texte chiffré. Aucun index FTS persistant en clair n'existe. Les mémoires ordinaires autorisées sont divisées en fragments chevauchants respectant Unicode, puis segmentées avec Jieba avant leur insertion dans un index SQLite FTS5 en mémoire. La clé du cache dépend de la politique, de la révision et de l'état de quarantaine du coffre ; il est réutilisé entre les requêtes. Les modifications, la synchronisation et les changements de politique l'invalident, et le verrouillage le vide. Le stockage temporaire SQLite est délibérément limité à la mémoire. Les vecteurs sont normalisés et mis en cache uniquement en mémoire ; ni les index en clair ni les plongements ne figurent dans les données de sauvegarde ou de synchronisation.

La clé dérivée du mot de passe enveloppe une clé maîtresse aléatoire ; celle-ci chiffre l'état et les points de contrôle locaux. Chaque époque d'autorisation possède une clé de coffre, et chaque révision possède une clé de données aléatoire enveloppée par la clé de son époque. Le contenu est sérialisé et divisé en fragments de 256 KiB authentifiés individuellement, dont la position et le nombre total sont liés aux données associées. La signature de révision couvre l'ID de la ressource, ses parents, la tête de politique, le marqueur de suppression, le texte chiffré et le certificat de l'appareil.

Les mutations sont préparées sur un état cloné et validées avec l'état chiffré et le point de contrôle dans une transaction SQLite unique utilisant synchronous=FULL. Les intentions de lecture et d'exécution sont validées avant la livraison. Une défaillance du disque interdit donc la livraison ; un plantage après la validation de l'intention peut laisser un résultat inconnu.

Un verrou exclusif du système d'exploitation autorise un seul processus d'écriture local coopérant. L'initialisation construit une base complète dans le même répertoire, la ferme et la synchronise, puis la publie sans écraser une destination existante. Une préparation interrompue ne bloque pas une nouvelle tentative. Chaque appareil doit disposer de son propre stockage local ; copier des fichiers SQLite actifs via un client de synchronisation cloud ne garantit pas la sécurité transactionnelle entre appareils.

Identités et transport

Les clés Ed25519 des utilisateurs certifient les clés de signature Ed25519 et d'échange X25519 des appareils. Les certificats seuls ne suffisent pas : chaque politique de coffre autorise délibérément les appareils. Les clés des appareils sont indépendantes, y compris entre appareils appartenant au même utilisateur. L'autorité de signature initiale de l'utilisateur est livrée aux appareils personnels approuvés dans un paquet authentifié chiffré pour le destinataire ; cette autorité ne peut pas contourner la liste des appareils autorisés d'un coffre après la révocation d'un appareil.

Une enveloppe contient une version de format, la clé de l'appareil émetteur, la clé d'échange du destinataire, une clé publique X25519 éphémère, une charge utile AEAD et une signature Ed25519. HKDF dérive la clé de transport. L'identité du destinataire et la clé éphémère sont authentifiées. L'appareil rejoignant le groupe utilise une demande signée avec expiration et épingle délibérément la clé publique de l'appareil approbateur ; les demandes ne sont consommées qu'après une validation réussie.

La première version utilise des chaînes et des fichiers de demande/approbation plutôt que la lecture de QR par caméra. Les empreintes sont des condensats SHA-256 complets ; les valeurs abrégées affichées dans les listes ne doivent jamais constituer l'unique contrôle d'approbation.

Politiques et fusion

Les politiques de coffre sont des historiques linéaires signés contenant les membres, les rôles, la liste des appareils autorisés, un ensemble de révocations d'appareils à croissance monotone et l'époque. Les contrôles de rôle utilisent la politique précédente. Les utilisateurs ordinaires peuvent autoriser un autre appareil pour leur propre identité sans modifier les membres. Un Admin peut modifier les appartenances Admin, Editor et Reader et autoriser l'appareil d'un membre. Un Admin ne peut pas ajouter, supprimer ou modifier un Owner, révoquer des appareils ou transférer la propriété. Les Owners le peuvent. Le transfert de propriété conserve exactement un Owner.

Les historiques de ressources forment un DAG adressé par contenu commun à tous les types modifiables (mémoire, carte — y compris les métadonnées de connaissance, brain, persona et carte protégée — fichier et identifiant). Chaque enregistrement ajoute une révision signée ; il n'existe ni stockage d'historique distinct réservé au wiki ni élagage automatique. history liste les révisions avec auteur et résumé ; diff renvoie une projection textuelle unifiée (titre, métadonnées structurées, corps) entre deux révisions ou par rapport au HEAD actuel. Les différences de fichiers omettent les charges utiles binaires ; les corps secrets des identifiants restent inaccessibles par lecture/diff. Plusieurs révisions non consommées d'une ressource constituent un conflit ; une révision de résolution nomme tous les parents visibles. Un marqueur de suppression retire la ressource des vues actuelles sans supprimer l'historique.

La synchronisation valide les historiques complets de politique, de révision et d'audit avant leur fusion dans un état candidat. Les écritures inconnues d'époques remplacées sont mises en quarantaine. Les écritures locales hors ligne absentes d'un instantané entrant de politique plus récent le sont également. La quarantaine ne peut être examinée/réappliquée que localement, et non levée par un champ entrant non fiable.

Les bifurcations d'autorisations exigent une signature du propriétaire couvrant la tête choisie et toute la chaîne de politiques écartée. Le signataire doit être propriétaire sur les deux branches. Les politiques écartées restent vérifiables pour les révisions historiques/en quarantaine. Une résolution réussie avance la politique sélectionnée et renouvelle sa clé. Les résolutions concurrentes ou incompatibles échouent en refusant l'accès.

API locale

service::Request est l'interface partagée d'opérations typées, sérialisée avec le discriminant op en snake case. Les champs inconnus au niveau supérieur sont rejetés. L'IPC local utilise des trames JSON préfixées par une longueur de 32 bits en big-endian (enveloppe Wire version-1). L'écoute HTTP/WebSocket facultative et le RPC par relais utilisent le même encadrement JSON binaire WebSocket (AuthFrame puis Wire) après authentification par jeton. Les capacités MCP sont contrôlées séparément avant la distribution. RunBound est distribué comme RemoteExec : run_bound_prepare autorise et déchiffre sous le verrou du service, le thread IPC exécute le programme sans verrou, et run_bound_finish audite le résultat. Les liaisons d'exécution résident dans State.run_bindings, local à l'appareil, et non dans un coffre.

Les transports réseau peuvent acheminer des Requests encadrées authentifiées par jeton. Les jetons proviennent uniquement des options/de l'environnement (jamais de TOML), sont comparés en temps constant et effacés au verrouillage du stockage. Les appelants distants utilisent des espaces de noms d'élévation stables (ws:remote / relay:remote) qui n'héritent pas de l'élévation locale cli:{pid} ; le déverrouillage et sudo via une connexion distante élèvent cet espace de noms afin que les connexions CLI ponctuelles conservent l'élévation. Les hôtes HTTP/relais de bureau distribuent toute la surface handle_client (mêmes contrôles d'élévation que l'IPC local). La FFI mobile et Share conservent la liste d'interdiction de la plateforme et n'inventent pas sur téléphone des fonctions réservées au bureau. L'écoute HTTP utilise la boucle locale par défaut ; les liaisons hors boucle locale exigent --allow-non-loopback et un avertissement. HTTP/WS en clair ne nécessite aucun certificat ; --tls-cert / --tls-key activent HTTPS/WSS. Le RPC par relais utilise WSS hors du périmètre de confiance, avec un ID de salle à forte entropie et un jeton ; la synchronisation des coffres conserve /v1/channel. La WebUI propose une projection d'état en lecture seule et un éditeur restreint de cartes ordinaires ; ce n'est pas un transport de Request. Voir démon distant et SECURITY.md.

Les Centers d'autorisation facultatifs ([[centers]] dans la configuration) interdisent l'auto-amorçage local et l'émission locale d'autorisations MCP ; l'inscription et les autorisations sont distribuées sous forme de tickets signés par le Center avec des périmètres délibérés (allow_all / read / write / read_write / read_write_delete). Voir Center.

Le mode hébergé facultatif du Center (--data DIR) possède un Store chiffré distinct au format du démon sous DIR/store/, ouvert avec un mot de passe serveur détenu par l'opérateur. Son RPC HTTP de contenu utilise dans Service un distributeur fermé d'autorisations par coffre ; l'élévation locale à l'opération couvre les contenus protégés/privés et les pièces jointes sans modifier l'autorisation MCP du démon. Il s'agit d'un chiffrement côté serveur, pas d'un chiffrement de bout en bout côté client. Des routes HTTP d'administration séparées gèrent le verrouillage/déverrouillage hébergé et les autorisations nommées durables dans DIR/members.json, accessible uniquement au propriétaire. Les tickets de déverrouillage signés autorisent seulement le déverrouillage par mot de passe de l'appareil local ; les clés d'appareil ne parviennent jamais à un Center limité aux tickets. Une seule entrée [[centers]] avec mode = "saas" fait utiliser au RPC de contenu du démon ce backend hébergé et son jeton bearer d'environnement, sans chemin parallèle de contenu local ni élévation des capacités MCP. Les contrôles d'appareil/d'administration ne font pas partie de la surface de contenu des autorisations. Voir coffre hébergé du Center pour les limites et la migration.

L'ABI mobile est déclarée dans crates/ffi/memories.h. Les handles sont des ID numériques de registre, pas des pointeurs Rust bruts. Chaque chaîne renvoyée doit être libérée une fois avec memories_free. Un JSON invalide produit une erreur générique sans reproduire l'entrée. memories_lock_all avance une génération globale de verrouillage lors du passage en arrière-plan et supprime les réponses tardives en cours. Le registre stocke des verrous de service par handle à comptage de références ; les opérations réseau ne détiennent ni le verrou du registre ni celui d'écriture. Un handle occupé applique un verrouillage en attente avant sa requête suivante. Le mobile exclut l'exécution de processus et la création d'autorisations MCP.

Le sélecteur de mode Flutter (mobile/lib/app_mode.dart) dirige Standalone vers la bibliothèque locale et Center/SaaS vers HostedCenterPage. Ici, Center désigne un serveur auto-hébergé avec stockage hébergé ; SaaS sélectionne le point d'accès fixe https://memories.ivjn.us. Tous deux utilisent les mêmes opérations FFI Rust hosted_* et HostedClient ; la sélection ne modifie pas le TOML du démon, n'inscrit pas d'appareil géré par tickets et ne déplace pas de données entre stockages.

Le mode sélectionné est une préférence non secrète. Center et SaaS enregistrent chacun un profil URL/jeton dans le stockage sécurisé de la plateforme. Le changement verrouille le service local, arrête le partage et détruit la page/session hébergée. Le passage en arrière-plan efface le contenu hébergé et invalide les réponses tardives ; la reconnexion au retour est explicite. Voir configuration mobile pour les clés de profil et le comportement de mise à niveau, et le guide mobile pour les étapes destinées aux utilisateurs.

Zone de notification du bureau et projection d'état

Request::DesktopStatus renvoie une projection typée de l'état d'initialisation/verrouillage, des nombres de bibliothèques et de connexions, des types de fournisseurs configurés et des nombres d'éléments dans les files de synchronisation. Elle s'exécute avant la distribution des opérations déverrouillées et ne clone ni ne valide l'état chiffré, ne touche pas aux temporisations d'inactivité/d'élévation et n'expose aucun identifiant, résumé de compte, contenu ou identifiant secret. Les réponses verrouillées ne contiennent aucun détail. La liste d'autorisation MCP existante refuse cette requête.

La bibliothèque CLI héberge le tableau de bord local et la zone de notification Windows/macOS. memories tray et le lanceur autonome memories-tray utilisent tous deux une boucle d'événements native sur le thread principal. Le serveur HTTP et le processus de sondage d'état borné fonctionnent séparément afin qu'un démon occupé ne bloque ni la zone de notification ni le navigateur. Le sondage invoque la CLI voisine via l'IPC normal authentifié par le système d'exploitation, avec une échéance et un nettoyage du processus enfant. La surface HTTP sert les ressources intégrées, la projection d'état fixe et une liste délibérée d'opérations autorisées de modification des cartes ordinaires/types. Elle ne peut pas déverrouiller, élever les privilèges, révéler des secrets ou distribuer des requêtes de service arbitraires. Voir SECURITY.md pour la limite des jetons et de l'origine du navigateur, et utilisation sur bureau.

Recherche et orchestration des modèles

search::Cache possède au maximum deux index de coffre, chacun limité à 10,000 fragments, 16 MiB de texte source/métadonnées et 32 MiB de vecteurs. Il exclut avant indexation les contenus privés, les identifiants, les fichiers et les contenus supprimés, en quarantaine ou conflictuels. BM25 pondère titre/corps/métadonnées à 5/1/2. La recherche vectorielle utilise la similarité cosinus ; la recherche hybride combine les deux classements par fusion de rangs réciproques. Le reclassement par défaut favorise la couverture de la requête et les correspondances exactes d'expressions dans un ensemble borné de candidats. Un point d'accès de modèle configuré peut effectuer un reclassement appris.

Retrieve, RagIndex, RagStatus et RagAsk conservent l'autorisation de coffre et les périmètres des autorisations MCP. L'IPC exécute les opérations de modèle hors du mutex du service et revérifie la génération de déverrouillage, la validité de l'autorisation, l'accès et l'empreinte de révision source avant/après le travail externe et avant la livraison. Les intentions signées précèdent l'inférence/l'export ; les réussites/échecs et les ID des sources livrées sont audités sans prompts ni clés. Les références de ressource/révision source utilisent la projection partagée d'ID courts ; les hachages de fragments et les étiquettes de citation [S1] ne sont pas des ID de ressources.

rag::Runtime charge paresseusement l'inférence ONNX native et les ressources EmbeddingGemma Q4 épinglées, ou appelle une URL de plongement Gemini/compatible configurée. Il prend également en charge des URL de génération et de reclassement configurées, des clés API référencées par l'environnement, des proxys et des nouvelles tentatives. Les fichiers de modèle natifs sont des données publiques de modèle ; les enregistrements utilisateur chiffrés ne deviennent jamais des poids de modèle. Le texte récupéré constitue des données non fiables dans les prompts de génération, et les ID de citation renvoyés sont validés par rapport aux sources sélectionnées. Cela valide les références, pas l'exactitude factuelle de la prose générée par le modèle.

La FFI mobile bénéficie de la recherche lexicale améliorée et prend en charge BM25 retrieve. Les opérations utilisant un modèle emploient actuellement le démon de bureau configuré ; cette version n'ajoute à Flutter aucune interface de configuration ou d'inférence de modèle.

Tâches cryptographiques sur bureau

jobs::Job décrit les outils, les fichiers/arborescences d'entrée épinglés, les liaisons d'identifiants, les étapes ordonnées, le nettoyage et un nouveau chemin de sortie. Les recettes crypto de la CLI construisent ce plan pour S/MIME/OpenPGP et la signature Android/iOS. L'approbation est vérifiée avant la résolution des ID courts, de sorte que son condensat lie exactement les références présentées à l'appelant. Le service vérifie l'élévation locale et l'accès au coffre, résout uniquement les ressources d'identifiants, valide une intention d'exécution, puis invoque l'exécuteur partagé du cœur.

L'exécuteur revérifie les outils, copie et vérifie les entrées, matérialise les identifiants dans un espace de travail privé, exécute les commandes sans shell, supprime leur sortie et ne publie qu'un artefact réussi. L'expansion des espaces réservés substitue uniquement des chemins et n'interprète pas récursivement leur contenu. La liste d'autorisation MCP et la FFI mobile refusent les tâches de processus. La sémantique existante de run reste inchangée.

Compétences des clients IA

memories inject est une opération d'installation réservée à la CLI. skills.rs intègre le fichier versionné crates/cli/skills/memories/SKILL.md dans l'exécutable et l'installe dans les répertoires de découverte documentés de Codex, OpenCode ou Claude Code. Elle s'exécute avant la création du répertoire de données et n'ouvre jamais le stockage ni n'appelle le démon. Les périmètres utilisateur et projet partagent le même texte d'instructions ; aucun chemin de stockage, ID de coffre, jeton d'autorisation ou secret n'y est interpolé.

L'installateur contrôle toutes les cibles au préalable, préserve les fichiers identiques, exige --force pour des contenus différents, rejette les fichiers/répertoires de compétence liés et publie chaque fichier au moyen d'un fichier temporaire synchronisé dans son répertoire de destination. Les nouveaux fichiers sont publiés sans écraser un fichier créé simultanément. Il s'agit d'une atomicité par fichier, pas d'une transaction entre clients. Les ressources voisines et la configuration des clients existantes sont préservées. La compétence achemine la recherche ordinaire, la recherche citée, les réponses configurées et les écritures via les interfaces MCP ou CLI existantes ; elle n'ajoute aucune capacité d'autorisation.

Autorisation cloud

La CLI de bureau effectue OAuth dans le navigateur avec PKCE, un rappel en boucle locale et des points d'accès de fournisseur fixes. CloudBegin crée sous sudo un ticket expirant lié à l'appelant/au fournisseur/au client. Les requêtes réseau s'exécutent hors du démon ; CloudComplete vérifie le ticket et l'autorisation actuelle avant validation. Le verrouillage, la déconnexion et le redémarrage invalident les tickets en attente, empêchant des résultats tardifs de rétablir la connexion.

State.cloud_accounts stocke les jetons chiffrés sur l'appareil local. L'état renvoie uniquement les métadonnées des comptes ; les sauvegardes, l'appairage, la synchronisation des coffres et MCP excluent les jetons. La connexion n'établit pas l'appartenance à un coffre.

Synchronisation des objets cloud

State.cloud_sync contient des reçus durables de boîte d'envoi/réception dans le même blob d'état chiffré. CloudSyncEnqueue écrit les octets exacts de l'enveloppe sérialisée et un descripteur signé avant toute E/S de transport. Les ID d'objets sont le SHA-256 de ces octets ; les nouvelles tentatives les réutilisent. CloudSyncWork renvoie le texte chiffré et les curseurs de liste sans jetons OAuth. sync::execute effectue des put/get/list bornés sans le mutex du service. CloudSyncAck vérifie une génération de session locale au processus, puis valide ensemble les indicateurs d'envoi, les ID découverts, les octets téléchargés et les fusions de coffres. Les descripteurs arrivant avant leurs objets restent en attente. Le verrouillage, le déverrouillage et la déconnexion incrémentent la session pour empêcher l'importation par des accusés tardifs. memories cloud sync demande au démon de renouveler les jetons, d'envoyer et de télécharger via les dossiers d'application OneDrive ou Google Drive ; ce HTTP s'exécute hors du verrou d'écriture. Les jetons ne sont jamais renvoyés par IPC. Les tests utilisent également MemoryTransport et des jeux de test Graph/Drive en boucle locale. Les charges utiles terminées des files sont compactées en reçus de hachage et estampilles de publication par fournisseur/destinataire. Les reçus restent locaux et ne suppriment pas l'historique cloud. Les objets manquants sont réessayés avec un délai exponentiel persistant ; la capacité en attente exerce une contre-pression sur les listes. Les processus des fournisseurs sérialisent par compte et refusent les résultats de renouvellement/importation d'une session invalidée. La distribution IPC utilise au maximum 16 connexions simultanées.

Voir la conception de la synchronisation et le guide d'autorisation.

Sessions distantes

Le démon de bureau possède les connexions SSH, FTP, TCP, MySQL, Redis et PostgreSQL. RemoteOpen valide la liste des hôtes autorisés de l'identifiant, enregistre une intention de connexion, puis se connecte hors du verrou d'écriture. SSH s'authentifie avec un identifiant de mot de passe ou une clé privée OpenSSH importée, éventuellement accompagnée d'un identifiant de certificat OpenSSH. CredentialGenerate crée des clés SSH et des certificats TLS sous sudo ; la clé privée est stockée comme identifiant et n'est jamais renvoyée. CredentialPublic dérive des clés publiques SSH ou des certificats PEM de ce matériel stocké. Les sessions de base de données activent TLS par défaut et peuvent ajouter au magasin de confiance du client un identifiant CA PEM facultatif (tls_ca). La vérification du nom d'hôte est obligatoire ; l'épinglage de certificat n'est pas implémenté. Chaque instruction est proposée comme ticket dont l'empreinte couvre la session, la séquence et l'instruction canonique. RemoteApprove est à usage unique et lié à l'appelant élevé ; RemoteExec exécute uniquement ce ticket sur la session existante. Le verrouillage, l'expiration d'inactivité et la déconnexion abandonnent les connexions actives et les tickets en attente. Les opérations de fichier utilisent FTP ; les sessions SSH et de base de données acceptent exec/query. ProxyStart lie un écouteur en boucle locale après les mêmes contrôles d'identifiant et de liste d'hôtes autorisés que RemoteOpen. Les clients locaux se connectent sans secrets ; le démon détient l'authentification SSH ou de base de données en amont. proxy.start enregistre l'intention de connexion avant la liaison ; proxy.stop enregistre l'intention d'arrêt. Le socket lié est transféré directement à Tokio sans intervalle de fermeture/nouvelle liaison. PostgreSQL SSLRequest et MySQL SSLRequest précèdent le passage à TLS ; Redis utilise TLS directement. PostgreSQL SCRAM vérifie le nonce et la signature du serveur. MySQL prend en charge l'authentification native et caching-SHA-256, y compris les changements de plugin ; l'échange complet du mot de passe exige TLS. Les négociations de base de données ont une échéance de 30 secondes, une limite de paquets de 64 KiB et une limite de 16 clients par écouteur. Le saut local vers la base de données est en clair et les champs de connexion/démarrage de base ne remplacent pas l'identité en amont configurée. Les clients locaux autorisent des instructions distantes sans restriction dans les permissions de ce compte. La boucle locale ne fournit aucune authentification par utilisateur. Le verrouillage, l'expiration d'inactivité du coffre, l'arrêt délibéré et la destruction du service annulent les écouteurs et les sessions actives. Les proxys ont une durée de vie maximale de 30 minutes ; le trafic ne prolonge pas le déverrouillage du coffre. MCP ne peut pas gérer les proxys. Le service possède chaque processus de proxy et attend sa terminaison lors d'un arrêt/verrouillage ; une réponse réussie ne peut donc pas entrer en concurrence avec une connexion qui transmet encore des instructions.

Exécution de fichiers de configuration

memories file exec combine la requête Read autorisée existante avec la matérialisation locale des fichiers et la supervision des processus par la CLI. Elle n'introduit aucune nouvelle requête de service, catégorie de fichier, cryptographie ou permission d'exécution mobile/MCP. Le démon audite la livraison du fichier par le chemin de lecture existant, puis la CLI exécute l'enfant au premier plan sans occuper le verrou du service. La CLI possède l'instantané temporaire en clair jusqu'à la fin de l'enfant direct ; les changements ou le verrouillage ultérieurs du coffre ne modifient/révoquent pas cet instantané déjà livré.

Récupération

Les sauvegardes contiennent l'état local signé et le matériel secret de récupération dans une enveloppe Argon2id/AEAD indépendante. La récupération génère de nouvelles clés d'appareil et crée des ID de coffre indépendants, en préservant le contenu actif et les têtes de conflit. Les historiques signés originaux sont conservés dans une archive chiffrée en lecture seule. La récupération ne prétend pas qu'une appartenance partagée historique soit toujours actuelle. Les coffres propres à un appareil, les autorisations cloud et les reçus cloud d'envoi/réception sont exclus ; chaque appareil récupéré se connecte séparément aux fournisseurs cloud.

Cartes et projections sûres

Kind::Card partage l'autorisation des mémoires ordinaires, avec des métadonnées typées stockées dans les révisions chiffrées. CardLink ajoute des liens dirigés au sein du même coffre. Les graphes projettent uniquement les nœuds visibles actuels et non ambigus et les liens dont les deux extrémités sont visibles. La recherche utilise le cache FTS5 borné en mémoire décrit ci-dessus, couvrant les corps ordinaires, les étiquettes/sources et les métadonnées de cartes protégées autorisées. Les corps des identifiants n'entrent jamais dans cet index. Recherche/liste/graphe exposent une projection summary sûre ; les lectures de cartes conservent la référence opaque à l'identifiant sans jamais résoudre sa valeur.

protected_card valide une entrée account/env/token/TOTP/HOTP (y compris l'import d'URI otpauth), écrit un identifiant et sa carte dans un même état candidat, puis les valide ensemble. Le put générique ne peut pas attacher ou remplacer des références protégées. Les opérations secrètes résolvent les révisions actuelles des identifiants et vérifient leur type. otp_code implémente RFC 6238 (TOTP) et RFC 4226 (HOTP), avance le compteur HOTP dans la même validation et enregistre l'intention de livraison avant de renvoyer un code. La construction des en-têtes HTTP marque les valeurs bearer/cookie comme sensibles, désactive les redirections et supprime les réponses.

Le contenu des mémoires et cartes peut aussi contenir une table secrets associant une étiquette stable à un ID canonique de ressource d'identifiant. protect_secret remplace les correspondances exactes du corps par {{secret:LABEL}} et crée l'identifiant dans la même transaction. Le put générique exige que les associations existantes restent inchangées et ne peut pas les inventer ou les rediriger. Les modifications CLI et mobiles transmettent la table existante. MCP card_write omet la table ; les mises à jour de cartes contenant des références secrètes échouent donc à la validation. La projection client abrège seulement les ID typés d'identifiants, laissant les marqueurs du corps stables. La récupération de sauvegarde préserve les ID de ressource non ambigus ; les associations survivent donc à la récupération. credential_copy résout directement une étiquette, une carte protégée ou un identifiant, exige une élévation locale et valide une intention d'audit avant de renvoyer du texte UTF-8 en clair au client de presse-papiers. MCP refuse les deux nouvelles opérations. Aucune opération générique de lecture, recherche ou graphe ne résout un secret. Les corps historiques signés ne sont pas modifiés par le remplacement ; voir les limites du wiki et du presse-papiers dans SECURITY.md.

Le service renvoie {"secret":"..."} uniquement à l'appelant local de copie autorisé. La CLI consomme cette réponse dans clipboard.rs et renvoie {"copied":true} dans son enveloppe de sortie normale uniquement après la réussite de l'écriture dans le presse-papiers. Le mobile utilise le canal de presse-papiers Flutter et vérifie sa génération de cycle de vie avant livraison. L'audit enregistre credential.copy avec delivery_intent, pas un reçu de réussite du presse-papiers du système d'exploitation. Voir le guide d'utilisation.

State.local_vaults marque les coffres propres à un appareil dans l'état local chiffré. local_config enregistre les métadonnées de version et de répertoire collectées par le client dans un tel coffre. L'approbation d'appareils exclut ces coffres ; l'export direct d'appartenance et la synchronisation sont refusés ; store::backup les retire de son instantané exporté. Les ID de ressource non ambigus survivent à la récupération dans un nouveau coffre, préservant les références de graphe et de carte vers identifiant tout en laissant les historiques signés originaux archivés.