Notre Couple
Decision du 11/10/2026 : retrait B2. Les sauvegardes/PITR B2 sont retires ; les trois instances PostgreSQL restent actives.
Recette automatisée DEV (NC-4)
Le socle E2E
utilise des fixtures identifiées par UUID de run. L'admin DEV expose prepare et
cleanup sous /api/v1/admin/dev/e2e/, avec les contrôles admin/CSRF habituels et
un verrouillage supplémentaire du namespace, de l'origine et du DSN DEV.
Quatre comptes fictifs sont créés ; les couples et actions métier passent ensuite
par les API réelles. Le nettoyage refuse les relations avec un compte extérieur.
Cette capacité n'est pas activée en production et ne remplace pas la recette NC-5.
En DEV, les pages utilisent la chaîne SSO complète. La route /api conserve
github-sso-forward-auth, mais exclut la réécriture des erreurs : les réponses
JSON 401/403 de l'application doivent parvenir intactes au formulaire, sans
être remplacées par une page HTML OAuth. Un refus d'identifiants affiche
« Adresse ou mot de passe incorrect. ». Si la session SSO expire, recharger la
page permet de refaire le parcours SSO. Chaque nouveau provisionnement des
comptes de recette A/B réinitialise leurs mots de passe.
| Élément | Valeur |
|---|---|
| Version promue | 1.1.1 — PR #953 ; prochaine cible produit 1.2 |
| Statut | Actif publiquement sur PostgreSQL HA avec frontend V1 |
| Origine | Fork indépendant de MonCouple V1.5 |
| Backend cible 1.1.0 | PostgreSQL via CloudNativePG |
| Migrations dans Git | 23 migrations additives, transactionnelles et checksummées (0001 à 0023) ; promotion du runtime séparée |
| HA | CloudNativePG / PostgreSQL 17.11, 3 instances |
| Domaine | notrecouple.fr, www redirigé vers l'apex |
| Roadmap | Plane : notrecouple-release-12 ; plan 1.2 |
Exploitation sans IA
Les procédures de diagnostic, reprise et exploitation manuelle sont regroupées dans le manuel opérateur. Elles restent utilisables si le Gateway MCP ou les agents sont indisponibles.
État GitOps
NotreCouple est réconcilié par Flux :
apps/ovh-primary/notrecoupleest référencé parapps/ovh-primary/kustomization.yaml;- le web tourne à deux réplicas derrière
Service/notrecouple; - le pool
notrecouple-overflowpasse de 0 à 3 réplicas selon KEDA ; son Deployment ne déclare passpec.replicas, pour que Flux n'écrase pas l'autoscaling ; - le data plane CloudNativePG possède sa Kustomization Flux séparée avec attente de santé ;
- le notifier tourne à
replicas: 1et le CronJob reminders est activé ; ingress.yaml,certificate.yamletmiddleware.yamlexposent l'apex en TLS et redirigentwww;- aucun Secret n'est versionné et
notrecoupleutilise le Mail Gateway interne authentifié.
MonCouple V1.5 reste un produit indépendant avec son propre datastore. NotreCouple est greenfield : aucune donnée utilisateur ou métier MonCouple ne doit être transférée vers le nouveau PostgreSQL.
PostgreSQL et isolation multi-couple
La branche de développement 1.2 ajoute la migration additive 0020_couple_book_preferences
pour NC-18 : trois choix visuels facultatifs partagés, une révision pour détecter
les conflits et une purge par cascade avec le couple. L'API vérifie les gains
acquis et le couple depuis la session ; le retour au style par défaut conserve
les gains. Cette extension doit être promue avec son image ; la version 1.1.1
promue ci-dessus conserve son registre de 19 migrations. Voir le
cadrage NC-18.
NC-19 ajoute en développement la migration 0021_couple_weekly_quests et les API
de quête facultative : acceptation explicite, semaine UTC, choix commun révisé,
progression transactionnelle et vignette unique. Le livre de Nous propose le choix
explicite, le suivi partagé et la collection de quatre vignettes illustrées locales,
sans démarrage automatique ni pénalité après une absence. Les
qualifications réelles NC-18/NC-19 sont reportées à la recette commune sur décision
du propriétaire du 6 octobre 2026. La version promue ne change pas dans ce lot.
Le registre contient les migrations 0001 à 0019 : identité/tenants, baseline runtime, notifier, sessions locales, OIDC/couple, sécurité HTTP, daily-play, souhaits, sessions/négociations/révisions, Live, inspirations, notifications, profil d'identité du couple et cycle de vie des demandes partenaire.
Le runner conserve advisory lock, validation version/nom/checksum, application atomique et relance idempotente. Les tables et stores métier utilisent le couple_id résolu côté serveur ; un identifiant de tenant fourni par le navigateur ne fait jamais autorité.
Le socle couvre notamment :
- inscription locale Argon2id, vérification email et reset ;
- Google OIDC avec
state,nonceet PKCE ; - sessions PostgreSQL digest-only ;
- création, invitation et consentement du couple ;
- daily-play ;
- souhaits, révélations et versions ;
- sessions, propositions, votes, négociations, amendements et révisions ;
- présence et attentions Live ;
- inspirations / Déclic ;
- notifier tenantisé et rappels authentifiés par Bearer dédié.
L'inscription locale affiche et valide le contrat de mot de passe (8 à 128 caractères, avec une majuscule, une minuscule et un chiffre ou caractère spécial) avant l'appel API. La mire demande sa confirmation et permet d'afficher temporairement chaque saisie. Une invitation e-mail valide permet de créer le compte ciblé sans seconde vérification, puis laisse toujours le choix explicite d'accepter ou refuser le couple. La mire /compte expose un bouton Continuer avec Google qui démarre exclusivement le flux backend GET /api/v1/auth/google/start ; le client OAuth et son Secret restent hors Git et une configuration absente est refusée côté serveur sans exposer de credential au frontend.
La migration 0013 ajoute le prénom auto-déclaré à users et les données de présentation transitoires de l'invitation aux deux chemins internes (couple_invitations et couple_join_requests). Pendant l'état pending, GET /api/v1/couple n'expose que le prénom et l'adresse saisis par l'invitant pour le partenaire, quel que soit le chemin interne, afin de ne pas révéler si l'adresse possède déjà un compte. Après consentement, la carte d'identité active utilise exclusivement users.display_name de chaque membre : le prénom choisi par l'invitant ne devient jamais l'identité durable de l'autre personne. Les comptes antérieurs à 0013 et les comptes Google sans prénom passent par GET/PATCH /api/v1/auth/profile avant de poursuivre l'onboarding ou d'accepter une invitation.
La migration 0014 unifie le suivi et l'expiration des demandes partenaire sans révéler le chemin interne utilisé. Elle fournit également le rapprochement automatique lorsque deux personnes se sont explicitement invitées mutuellement, avec sérialisation transactionnelle et conservation d'un statut public neutre pour les demandes concurrentes.
Préparation visuelle 1.1.0 — Jouer
L'écran Jouer dispose d'un pack cohérent de huit illustrations de thèmes et
de huit covers 16:9 pour les cartes d'activité. Les images sont servies par le
runtime stateless depuis /tmp/assets/visuals, après projection en lecture
seule par ConfigMap en mode Alpine. Elles n'ajoutent aucun stockage utilisateur,
PVC, dépendance S3 ou donnée métier.
Les images des thèmes sont décoratives : le nom et la progression restent
exposés en texte et via progressbar. Les covers des activités accompagnent
les titres et prompts existants, avec chargement prioritaire limité à l'activité
mise en avant et chargement différé pour les autres médias.
Stabilité refresh 1.0.4
Le polling visible de Jouer ne reconstruit plus le DOM lorsque l'état métier utile est identique. La signature de comparaison est bornée à l'état daily-play, aux catégories et aux identités d'affichage ; le bruit Live/presence ne force pas la reconstruction des cartes, covers ou chapitres. Lorsqu'un vrai changement métier nécessite un rendu, la position verticale et les scrolls horizontaux de navigation sont restaurés. La navigation principale reste sticky avec un fond lisible et les safe areas iOS sont prises en compte. Des compteurs NC_REFRESH_STABILITY_STATS permettent de vérifier en navigateur les renders réellement évités.
Release notes et modales iOS
Depuis la 1.0.4, la version technique (APP_VERSION / VERSION) ne fait plus autorité pour déclencher automatiquement une popup de nouveautés. Les patchs imposés par la roadmap restent silencieux ; les release notes utilisent un identifiant produit stable, modifié uniquement lorsqu'une release fonctionnelle notable doit réellement être présentée.
La popup reste accessible manuellement depuis le menu. Son contrôleur verrouille le scroll de fond pendant l'ouverture, remet le scroll interne en haut uniquement à l'ouverture, utilise 100dvh avec fallback 100vh, respecte les safe areas iOS et restaure exactement la position de la page à la fermeture. Le backdrop ne scrolle pas : la modal est l'unique surface verticale scrollable, afin d'éviter le double scroll Safari.
Runtime HTTP unique
Depuis #192, le pod web ne possède plus de runtime applicatif historique parallèle.
images/entrypoint.sh :
- assemble le frontend courant dans
/tmp/index.htmlavec la chaîne de patchs existante ; - remplace ensuite le shell par
notrecouple_server.pyavecexec.
Il n'existe plus de lancement de app_runner.py, de serveur loopback sur 127.0.0.1:8081, ni de fallback RUNTIME_MODE=legacy. notrecouple_server.py est l'unique frontière HTTP du web sur :8080.
Les routes supportées sont :
/api/v1/**versNotreCoupleHttpAppet ses façades tenant-safe ;/healthzpour la santé du runtime unique ;/et les routes navigateur vers le frontend généré ;- les assets PWA explicitement autorisés.
Toute route historique /api/** hors /api/v1/** est rejetée localement en 404. Aucun proxy de compatibilité ne contacte un second serveur. Cette propriété est volontairement fail-closed : si le frontend réintroduit une dépendance legacy, elle doit casser explicitement et être corrigée côté V1 plutôt que masquer la régression par un fallback.
validate_frontend.py garde le ratchet du hard-cut : le frontend généré est rejeté s'il contient une route /api/** legacy, /api/live/stream ou EventSource. test_notrecouple_server.py verrouille de son côté l'absence de app_runner.py, LEGACY_PORT, 8081, HTTPConnection, _legacy() et _legacy_stream() dans le runtime public.
Le runtime exige DATABASE_BACKEND=postgresql, DATABASE_URL et le Secret hors Git notrecouple-http (HTTP_SECRET) ; il refuse de démarrer si ces prérequis manquent.
Le packaging de livraison est un sujet distinct de l'architecture runtime : la décision propriétaire du 5 septembre 2026 met fin au mode Alpine en production et rétablit l'image immuable. Alpine reste réservé à la DEV, tandis que les validations fonctionnelles générales restent routées par défaut vers Dagger/K3s. Quel que soit le packaging, le contrat #192 reste un seul runtime applicatif web.
Observabilité applicative
La frontière HTTP émet des événements JSON structurés sur stdout/stderr. Le schéma est volontairement fermé : aucun header arbitraire, corps de requête, query string, adresse email, contenu métier, cookie, token, DSN ou Secret n'est accepté comme champ de log.
Chaque requête reçoit un request_id :
- un
X-Request-IDclient n'est conservé que s'il respecte un format borné (UUID, ULID ou identifiant hexadécimal) ; - toute autre valeur est remplacée par un identifiant aléatoire généré par le serveur ;
- l'identifiant retenu est renvoyé dans
X-Request-ID.
Un événement de fin de requête contient au minimum le composant, la méthode, la route normalisée, le statut, la durée et le résultat. Les query strings sont supprimées et les segments d'URL assimilables à un UUID, identifiant numérique ou valeur opaque sont remplacés par {id} ou {value}.
Les exceptions inattendues continuent de produire une réponse HTTP générique 500 internal_error, mais un événement request_exception est écrit côté serveur. Il contient uniquement le type d'exception, son domaine technique et des frames expurgées (file, line, function) : le message d'exception n'est jamais journalisé.
Les dépendances externes encore pertinentes disposent d'événements dédiés :
mail_gateway: envoi accepté, désactivé ou erreur de livraison, sans destinataire, sujet, contenu, URL de gateway ou caller token ;google_oidc: résultat du parcours HTTP (ok,rejected,not_configured,link_required) sanscode,state,nonce, token ou identité Google.
Il n'existe plus d'événement legacy_runtime dans le chemin actif puisque cette dépendance est supprimée.
Les succès de /healthz sont au niveau DEBUG pour ne pas polluer le flux normal des probes Kubernetes. APP_LOG_LEVEL permet de passer temporairement le runtime en DEBUG; le niveau par défaut est INFO.
Diagnostic opérateur par corrélation
- Récupérer le
X-Request-IDde la réponse concernée ou l'heure approximative. - Chercher ce
request_iddans les logs du pod web. - Lire
request_completepuis, si présent,request_exception,transport_exception,dependency_erroroudependency_resultavec le même identifiant. - Une réponse
404sur/api/**hors/api/v1/**indique une dépendance legacy réintroduite : il n'existe volontairement aucun fallback. - Ne jamais demander à un utilisateur un cookie, token reset, code OAuth ou payload métier pour compléter le diagnostic.
Façades HTTP
Les façades HTTP métier sont livrées pour :
- daily-play ;
- inspirations ;
- souhaits ;
- sessions ;
- négociations ;
- révisions ;
- Live.
Elles appliquent les mêmes garde-fous : session PostgreSQL, scope couple dérivé côté serveur, CSRF + contrôle Origin sur les écritures, rejet des champs d'autorité client (couple_id, user_id, etc.), erreurs génériques et tests cross-couple/anti-énumération.
CloudNativePG
L'opérateur CloudNativePG est installé dans cnpg-system via #61. NotreCouple utilise PostgreSQL 17.11 avec :
- 3 instances ;
- anti-affinité obligatoire ;
- 1 standby synchrone requis ;
primaryUpdateStrategy: supervised;- monitoring Prometheus.
Le stockage local-path reste node-bound. La sauvegarde/WAL/restauration demeure un chantier DR séparé suivi par #68 ; son report après le lancement est un risque explicitement accepté dans la roadmap #47.
Réconciliation anti-résurrection
Le CronJob notrecouple-erasure-reconciler conserve une deadline globale de 50 secondes et s'exécute chaque minute. Les attentes PostgreSQL sont bornées séparément ; le conteneur dispose d'un burst CPU de 500m avec une réservation de 100m afin que le démarrage et les imports Python ne consomment pas la quasi-totalité de la deadline avant la première phase instrumentée. Les logs exposent uniquement les durées techniques des phases et des compteurs non sensibles.
CI et smoke
La suite NotreCouple couvre les 22 migrations, l'identité/couple, les stores PostgreSQL, le notifier, les façades HTTP, l'isolation cross-couple, l'idempotence/concurrence, les rendus GitOps, le frontend généré et le runtime HTTP.
Le smoke synthétique Kubernetes reste le filet de sécurité de la phase fix/debug. Pour #192, la preuve statique et HTTP impose en plus :
- aucun second serveur dans l'entrypoint ;
/healthzindépendant du legacy ;/api/v1/**toujours routé vers l'application ;/api/**legacy rejeté en404;- le hard-cut frontend reste sans appel legacy.
La chaîne de build, publication et promotion de l'image immuable est active. Les validations fonctionnelles générales restent exécutées par défaut via Dagger/K3s ; GitHub Actions ne reprend que les étapes de delivery explicitement autorisées.
Références
Le livre d'aventures NC-16 est intégré à Nous : trois collections, gains datés en UTC, prochain jalon et célébration groupée par membre. La façade achievements réutilise la session PostgreSQL et les contrôles CSRF/Origin. La migration additive 0019 conserve les reçus individuels de présentation, supprimés à l'effacement. Le protocole et la recette reproductible sont décrits dans ACHIEVEMENTS_UI.md du composant NotreCouple. Les quêtes et la personnalisation restent hors NC-16.
-
47 : roadmap principale NotreCouple ;
-
61 : opérateur CloudNativePG ;
-
68 : DR / backup / restauration ;
-
114 : audit black-box cross-couple ;
-
126 : exposition publique ;
-
146 : hard-cut frontend hors
/api/**legacy ; -
186/#188 : P0 observabilité applicative ;
-
191/#193 : historique du packaging Alpine temporaire et retour immuable en production ;
-
192 : runtime web unique et retrait physique du bridge legacy ;
-
196 : restauration du bouton Google OIDC sur la mire V1 ;
-
204 : prénoms et carte d'identité du couple ;
-
208/#209 : cycle de vie des invitations partenaire et factorisation du verrouillage ;
-
42 : baseline MonCouple V1.5.
Premiers pas 1.1.0 — contrat backend
L'état du guide est persisté par utilisateur dans PostgreSQL via la migration 0017. L'API V1 expose lecture, étapes vues/terminées/passées, report de 24 heures et réinitialisation bornée. Le serveur dérive l'utilisateur de la session, exige CSRF et Origin sur les mutations et n'enregistre aucun texte libre, contenu intime ou identifiant de couple fourni par le navigateur. Le branchement UX est livré ; la fermeture de #254 reste conditionnée à la recette desktop et Safari/iOS.
Premiers pas 1.1.0 — guide frontend
v11_onboarding_guide_ui_patch.py consomme la façade ci-dessus et n'ajoute aucune règle métier. Le guide affiche une aide contextuelle par zone — Aujourd'hui, Jouer, Nos envies, Nous — sous la forme d'un bandeau intégré à la page, jamais d'une modale plein écran ni d'un tunnel obligatoire.
Quatre propriétés structurent l'implémentation :
- le serveur est la seule autorité : chaque mutation renvoie l'état complet, qui remplace le précédent. Aucun stockage navigateur ne fait autorité ;
- le guide ne navigue jamais. Il lit la zone active dans le DOM de la navigation et ne modifie ni la vue courante, ni l'URL : un deep-link suivi par #252 reste prioritaire ;
- le guide ne reconstruit rien. Il réconcilie un unique nœud frère dans
#appet le laisse en place tant que l'étape ne change pas, ce qui évite tout churn DOM lorsque le polling métier déclenche un rendu ; - deux étapes —
play_selectionetplay_start— se terminent sur le geste métier réel, observé dans l'état rendu via.v15-card.selectedet.v15-play-stage, plutôt que sur un clic déclaratif.
Le patch est inséré dans images/entrypoint.sh avant v11_design_system_ui_patch.py, donc avant le cliquet de stabilité #258 qui reste la couche la plus externe. Passer, Plus tard et, depuis Mon compte, Revoir les premiers pas appellent respectivement skip, later et reset.
Contrats associés : test_onboarding_guide_frontend.py.
Chargement à l’identité NotreCouple
Le loader structurel reprend le logo validé et un fond ivoire rosé, avec respiration
douce et indicateur champagne/bordeaux. Il conserve la détection de disponibilité
réelle, la limite de dix secondes et le bouton Réessayer ; aucune attente minimale
artificielle ni requête métier supplémentaire. Les animations sont désactivées
avec prefers-reduced-motion. Le logo WebP existant est réutilisé et mis en cache.
Synchronisation des activités et catalogue des envies
Le jeu ouvert vérifie son état via la seule façade daily-play toutes les 2,5 secondes, sans relire les autres espaces ni effacer la saisie. Une reprise de l’onglet ou du réseau déclenche une vérification immédiate ; les lectures s’arrêtent en arrière-plan. Les autres jeux restent accessibles sous l’activité, avec le plafond quotidien appliqué par le serveur et les brouillons de réponses conservés en mémoire pour l’utilisateur et la journée courants. Les réponses du partenaire restent privées jusqu’à la révélation autorisée par le serveur.
La migration additive 0022 initialise les 17 catégories publiques historiques, sans remplacer les lignes existantes. Elle remplace le seed qui était uniquement exécuté par l’ancien serveur. Un catalogue indisponible affiche une erreur avec réessai et empêche l’enregistrement d’un souhait sans catégorie.
La migration 0023_public_inspiration_catalog complète ce bootstrap V1 avec les
197 inspirations publiques historiques (17 catégories). Elle ajoute seulement
les couples catégorie/titre absents, conserve les identifiants et textes existants
et ne modifie aucune envie, aucun compte ni aucun choix du couple. Le seed ne
dépend plus du démarrage de l'ancien serveur. L'import de répétition
SQLite → PostgreSQL autorise ces catalogues publics préchargés uniquement si
leurs contenus correspondent exactement à la source SQLite. Si PostgreSQL a
attribué des IDs différents lors du seed initial, l'importeur reconstruit
atomiquement ce seul catalogue public avec les IDs SQLite, après contrôle
de l'absence de données métier. Toute divergence de contenu bloque l'import
avant écriture ; les références historiques sont conservées. Les projections Alpine incluent
la migration et changent le template du Job pour qu'un Job déjà terminé soit
remplacé par Flux. En production immuable, la promotion de l'image reste requise.
L'inventaire distingue une lecture indisponible, un catalogue réellement vide (avec réessai) et des idées toutes déjà importées/adoptées. Le test PostgreSQL part d'une base neuve, vérifie les 197 idées pour les deux membres via l'API, leur personnalisation privée et une découverte filtrée par thème. Il vérifie aussi qu'un catalogue partiel est complété sans remplacer les lignes existantes et que rejouer le SQL ne crée pas de doublons. La preuve servie en DEV reste nécessaire après intégration ; aucun accès direct à la base de production n'est requis pour ce correctif.
Cache des illustrations — 1.1.1
Le serveur remplace les URL des illustrations publiques dans le HTML généré par des URL contenant une empreinte SHA-256 du contenu (16 caractères). Ces URL reçoivent Cache-Control: public, max-age=31536000, immutable, utilisable par le navigateur et Cloudflare en production. Une URL dont l’empreinte ne correspond plus au fichier répond 404 non cachable ; elle ne sert jamais un autre contenu sous la même clé.
Les URL historiques restent disponibles avec public, max-age=0, must-revalidate et ETag ; une validation identique répond 304 sans transférer le fichier. HTML, service worker, manifeste, pages légales, erreurs et API restent no-store. Cette politique concerne uniquement les illustrations statiques explicitement autorisées. Aucun cookie ni donnée du couple n’est ajouté au cache public. Le SSO DEV reste inchangé et les noms *.lab.djayzone.com sont DNS only.
La publication suit le contrat immuable : runtime/version validés, image publiée et fumée, puis PR distincte de promotion des huit consommateurs. Le workflow historique GitHub-hosted ne doit pas être lancé sous la politique CI zéro minute active ; une voie de publication autorisée est requise.
Prochaine version : 1.2
Notre Socle : démarrage thématique (NC-67)
Une session thématique utilise le contrat V1 CLASSIC avec une à trois
theme_categories. Les thèmes doivent être des identifiants non vides,
distincts et présents dans le catalogue serveur. Un choix invalide est refusé
avant création de session ; les sessions classiques sans thème restent possibles.
Le sélecteur annonce le nombre de thèmes et désactive les choix supplémentaires à trois, tout en permettant de décocher. Il est nommé pour les lecteurs d'écran, garde le focus clavier dans la fenêtre et le restitue à la fermeture. Un catalogue indisponible ne permet pas d'ouvrir un sélecteur vide.
Le démarrage bloque le double clic et la fermeture pendant la requête. Après une réponse perdue, le frontend relit la session courante avant tout nouveau POST. Si cette vérification échoue, les thèmes restent conservés et « Vérifier le démarrage » effectue uniquement une lecture. Une session déjà active est reprise à table, y compris si le partenaire l'a démarrée entre-temps. Si la création réussit mais le refresh échoue, le message confirme le démarrage et propose d'actualiser, sans renvoyer une demande de création.
Notre Socle : accords et historique (NC-65)
La table thématique utilise les catégories persistées de la session pour limiter les envies et les inspirations proposées. « Piocher une inspiration » ouvre le catalogue correspondant directement à table, puis un éditeur avant confirmation du partage. La pose de l'idée personnalisée et la consommation du tour sont atomiques et protégées contre les retries. Les sujets hors thème restent dans l'inventaire privé et ne peuvent pas être posés pendant cette session ; le contrôle serveur s'applique aussi aux reformulations.
« Nos accords » est le référentiel des règles adoptées, avec recherche,
catégories et détail des versions communes. « Nous » conserve le livre et un
aperçu qui ouvre ce référentiel. « En reparler » rejoint la table de révision ;
la règle active reste en place jusqu’à la validation commune du nouveau texte.
Le retrait passe par les votes de révision existants.
Le vote HTTP exige expected_round, le tour réellement affiché, et le vérifie
sous verrou avant toute écriture. Une version différente répond 409 et demande
une nouvelle lecture et un nouveau consentement. Un ancien onglet qui n’envoie
pas ce champ doit être rechargé ; son vote est refusé.
L’historique utilise uniquement /api/v1/history, authentifié et isolé par
couple : bilans des sessions terminées, décisions et snapshots des anciennes
règles communes. Les anciennes versions privées et la table historique
events, dépourvue de couple_id, ne sont jamais utilisées comme secours.
Le retrait conserve le dernier texte commun et sa trace, sans republier le
contenu actuel devenu privé. Aucune migration de données n’est requise.
Les états indisponibles proposent un réessai. La création de révision est verrouillée pendant une mutation et relit le serveur avant toute tentative, y compris après une réponse réseau perdue. La recette intégrée et visuelle à deux utilisateurs reste portée par NC-66 ; la promotion PROD est séparée.
La décision du 5 octobre 2026 regroupe les prochaines fonctionnalités et corrections dans la 1.2, y compris l'ancien périmètre V1.3. Le moteur et le livre sont déjà intégrés à la 1.1.1 ; les lots restants sont la personnalisation/récompenses (NC-18), la quête hebdomadaire facultative (NC-19) et la recette intégrée (NC-17). Les pistes garder/proposer une activité (NC-50) et pas maintenant (NC-52) passent d'abord par une décision après prototype. Voir le plan et les gates et le contrat du livre. Plane pilote les priorités et états ; les anciennes Issues restent des références historiques.
Conformité et conservation — statut des documents
Les documents de confidentialité de la 1.1.0 sont des bases de travail datées, pas une certification de conformité actuelle. Lire la cartographie RGPD historique, la matrice de conservation du 13/09 et le garde de reprise anti-résurrection. Une révision des traitements, durées effectivement appliquées, sous-traitants et tests de restauration est nécessaire avant toute nouvelle publication de politique de confidentialité. Les anciennes références de tickets ne correspondent pas toujours aux identifiants Plane utilisés pour la release 1.2.