Suivis de la revue de #394 : copie nommée sur un rattrapage arrêté, violations préexistantes épinglées, délai de démarrage, rétention des copies #395

Closed
opened 2026-10-07 01:51:48 +00:00 by maximus · 0 comments
Owner

Planification du 2026-10-10 (/plan-run, milestone planned-2026-10-10-fiabilite-tests) : les sections ci-dessous, à partir de « Depends on », priment sur le texte d'analyse en cas d'écart.

Suggestions non bloquantes de la revue de la PR #394 (#390), restées hors de la PR : voir le commentaire de revue. Les suggestions 1, 3, 4 et 8 ont été appliquées en tête de la PR (commit 5910387).

1. Le Journal ne nomme pas la copie quand le rattrapage s'arrête (suggestion 2)

Sur une erreur de l'écriture de l'historique ou de apply_pending, catch_up rend Err(String) et report.backup_file est perdu. La ligne d'erreur dit applied before stopping: [...] sans le nom de la copie, alors que c'est le cas où on en a besoin.

  • Fichiers : src-tauri/src/database/profile_db.rs (catch_up, prepare_at), src/services/db.ts (describePreparation), src/services/db.test.ts
  • Correctif proposé : rendre le nom de la copie avec l'erreur et l'écrire dans la ligne d'erreur du Journal.

2. Deux comportements de la reprise sans clés étrangères ne sont épinglés nulle part (suggestion 5)

  • Le rapport des violations préexistantes : mutation RV4 côté Rust (fk_violations toujours vide) et RT2 côté Journal (la ligne point to a missing row disparaît). Les deux restent vertes.
  • La reprise ne doit pas toucher aux violations antérieures à la version : mutation RV7 (ensemble before vide), restée verte. Elle remettrait à NULL des lignes sans rapport avec la migration.
  • Fichiers : src-tauri/src/database/profile_db.rs (tests de retry_without_foreign_keys, repair_new_violations), src/services/db.test.ts
  • Correctif proposé : une violation préexistante dans le test du profil sans catégorie 31 couvre RV4 et RV7, et une assertion sur la ligne point to a missing row couvre RT2.

3. Le délai de démarrage couvre maintenant le rattrapage (suggestion 6)

App.tsx arme un délai de 10 s (STARTUP_TIMEOUT_MS) autour de connectActiveProfile. Ce délai couvre désormais le rattrapage du profil actif. Au-delà, startupError reste posé et la page d'erreur s'affiche alors que le rattrapage aboutit. Ce cas est peu probable avec des bases de taille courante.

  • Fichiers : src/App.tsx, docs/adr/0021-migrations-profils-secondaires.md (points de vigilance)
  • Correctif proposé : citer le risque dans l'ADR 0021 et mesurer la durée d'un rattrapage sur une grosse base ; appliquer la règle chiffrée de la section « Critères d'acceptation (planification) », point 3.

4. Les copies s'accumulent (suggestion 7)

Chaque lot de versions futures ajoute un -before-vN.db en clair par profil secondaire, que seule la suppression du profil retire. Une copie existante est aussi gardée telle quelle : après un rattrapage qui a échoué puis abouti plus tard à partir de la même version, elle précède les données saisies entre-temps.

  • Fichiers : src-tauri/src/database/profile_db.rs (backup_to, remove_backups), docs/guide-utilisateur.md et les clés docs.profiles.tips de src/i18n/locales/fr.json et en.json
  • Correctif proposé : une règle de rétention (garder la dernière copie) et une phrase au guide.

Critères

  • Une erreur de rattrapage écrite au Journal nomme la copie prise avant elle.
  • RV4, RV7 et RT2 font tomber au moins un test.
  • Le risque du délai de démarrage est écrit dans l'ADR 0021, avec la mesure.
  • La règle de rétention décidée le 2026-10-10 (copie fraîche, garder la dernière ; point 4 ci-dessous) est implémentée et écrite au guide FR et EN.

Depends on

Fichiers concernés (complet)

  • src-tauri/src/database/profile_db.rs (catch_up, prepare_at, backup_to, remove_backups, ProfilePreparation, tests)
  • src/services/db.ts (ProfilePreparation, describePreparation, message de repli :185-189), src/services/db.test.ts
  • src/App.tsx (STARTUP_TIMEOUT_MS, succès tardif) et son test s'il existe, sinon un test de la logique extraite
  • docs/adr/0021-migrations-profils-secondaires.md (mesure, risque, rétention)
  • docs/guide-utilisateur.md:79, clés docs.profiles.tips de src/i18n/locales/fr.json et en.json
  • CHANGELOG.md, CHANGELOG.fr.md

Critères d'acceptation (planification)

1. Copie nommée sur un rattrapage arrêté

  • Nouveau champ catch_up_backup: Option<String> de ProfilePreparation (Rust et interface TS), rempli dès que la copie est prise, même si le rattrapage échoue ensuite. La ligne d'erreur du Journal (describePreparation) le nomme.
  • Un test par chemin d'erreur après la copie : history_write_failed, pragma_failed, apply_pending.
  • Le champ ne contient que le nom de fichier renvoyé par backup_to, jamais un chemin ; test : aucune ligne d'erreur du Journal ne contient / ni \. Le message de repli JS (db.ts:185-189) passe aussi sans chemin (dossier remplacé ou message tronqué).

2. Épingles : RV4, RV7 et RT2 rougissent chacune au moins un test (corps d'origine).

3. Délai de démarrage

  • Bug vérifié : un connectActiveProfile qui réussit après le délai garde la page d'erreur (App.tsx:56-58 ne remet pas startupError à null). Corriger (succès = setStartupError(null)) et l'épingler par un test.
  • Test Rust #[ignore] qui construit un profil synthétique au plancher le plus bas reconnu par infer_floor (partir des fixtures des états publiés), avec 100 000 transactions, et mesure prepare_at (copie VACUUM INTO, foreign_key_check, réparation des drapeaux comprises) ; il affiche la durée sans l'asserter. Lancé une fois en local (cargo test -- --ignored), durée collée dans la PR.
  • Règle : durée mesurée > 3 s → STARTUP_TIMEOUT_MS = 30 000 ; sinon 10 000 inchangé. Mesure, machine, règle appliquée et risque résiduel écrits dans les points de vigilance de l'ADR 0021.

4. Rétention des copies

  • À chaque rattrapage, la copie est refaite : écrite en .tmp, synchronisée, puis renommée par-dessus une copie de même nom (jamais supprimer d'abord).
  • Après un rattrapage réussi, et seulement après le renommage de la nouvelle copie, les autres <profil>-before-v*.db (et .db.tmp) de ce profil sont supprimés : remove_backups(dir, stem, keep: Option<&str>). Rien n'est supprimé quand le rattrapage s'arrête sur une erreur ou quand la copie échoue.
  • Tests Rust : copie de même nom rafraîchie (contenu nouveau) ; anciennes copies élaguées après succès ; rien d'élagué sur erreur ; rien d'élagué si la copie échoue. Mutation « élaguer avant la copie » : rouge.
  • Guide FR/EN (guide-utilisateur.md:79, docs.profiles.tips) : une seule copie par profil, la plus récente, refaite à chaque mise à jour de la base, supprimée avec le profil.
  • CHANGELOG : Changed / Modifié (une seule copie gardée par profil) ; Fixed / Corrigé (la page d'erreur ne reste plus affichée quand le profil s'ouvre après le délai).

Review caveats

  • 🔴 (résolu) Ne jamais supprimer avant que la nouvelle copie soit durable → critères du point 4.
  • 🔴 (réfuté) Deux rattrapages concurrents après un rechargement : prepare_profile_db est synchrone, que Tauri exécute sur le thread principal (profile_commands.rs:184-191), donc les appels se suivent.
  • 🟡 Coût réel d'un rattrapage : ni réécriture de table (le plancher réel ne descend pas jusqu'à v6), mais VACUUM INTO, PRAGMA foreign_key_check et la réparation des drapeaux, proportionnels à la taille de la base. Le délai couvre aussi repair_migrations et Database.load.
  • 🟢 Refaire la copie coûte un VACUUM INTO à chaque ouverture tant que le rattrapage échoue : accepté.
  • 🟢 Depuis #408, la section exclusive de connectToProfile couvre le rattrapage : une durée > 15 s produit l'alerte « ouverture de profil » de #408 (attendu).

Décisions prises en planification

  • Rétention : copie fraîche, garder la dernière (Max, 2026-10-10).
  • Délai : mesurer, puis règle chiffrée 3 s → 30 s (Max, 2026-10-10).
  • Forme de l'erreur : champ catch_up_backup (décision de planification).
  • Sections de docs/architecture.md fixées pour toute la milestone : ### Accès DB et transactions (sous la section Base de données) et ## Tests (vitest sans jsdom) (juste avant CI/CD). La première issue de la pile qui en a besoin crée la section ; les suivantes y ajoutent.
  • Dernier maillon de la pile ; dépend de #408 (même fichier db.ts) et de #389 pour l'ordre de pile.

Spec source

spec-plan-fiabilite-tests.md (local, ignoré par git)

> **Planification du 2026-10-10** (`/plan-run`, milestone `planned-2026-10-10-fiabilite-tests`) : les sections ci-dessous, à partir de « Depends on », **priment** sur le texte d'analyse en cas d'écart. Suggestions non bloquantes de la revue de la PR #394 (#390), restées hors de la PR : voir [le commentaire de revue](https://git.lacompagniemaximus.com/maximus/Simpl-Resultat/pulls/394#issuecomment-20168). Les suggestions 1, 3, 4 et 8 ont été appliquées en tête de la PR (commit `5910387`). ## 1. Le Journal ne nomme pas la copie quand le rattrapage s'arrête (suggestion 2) Sur une erreur de l'écriture de l'historique ou de `apply_pending`, `catch_up` rend `Err(String)` et `report.backup_file` est perdu. La ligne d'erreur dit `applied before stopping: [...]` sans le nom de la copie, alors que c'est le cas où on en a besoin. - Fichiers : `src-tauri/src/database/profile_db.rs` (`catch_up`, `prepare_at`), `src/services/db.ts` (`describePreparation`), `src/services/db.test.ts` - Correctif proposé : rendre le nom de la copie avec l'erreur et l'écrire dans la ligne d'erreur du Journal. ## 2. Deux comportements de la reprise sans clés étrangères ne sont épinglés nulle part (suggestion 5) - Le rapport des violations préexistantes : mutation RV4 côté Rust (`fk_violations` toujours vide) et RT2 côté Journal (la ligne `point to a missing row` disparaît). Les deux restent vertes. - La reprise ne doit pas toucher aux violations antérieures à la version : mutation RV7 (ensemble `before` vide), restée verte. Elle remettrait à NULL des lignes sans rapport avec la migration. - Fichiers : `src-tauri/src/database/profile_db.rs` (tests de `retry_without_foreign_keys`, `repair_new_violations`), `src/services/db.test.ts` - Correctif proposé : une violation préexistante dans le test du profil sans catégorie 31 couvre RV4 et RV7, et une assertion sur la ligne `point to a missing row` couvre RT2. ## 3. Le délai de démarrage couvre maintenant le rattrapage (suggestion 6) `App.tsx` arme un délai de 10 s (`STARTUP_TIMEOUT_MS`) autour de `connectActiveProfile`. Ce délai couvre désormais le rattrapage du profil actif. Au-delà, `startupError` reste posé et la page d'erreur s'affiche alors que le rattrapage aboutit. Ce cas est peu probable avec des bases de taille courante. - Fichiers : `src/App.tsx`, `docs/adr/0021-migrations-profils-secondaires.md` (points de vigilance) - Correctif proposé : citer le risque dans l'ADR 0021 et mesurer la durée d'un rattrapage sur une grosse base ; appliquer la règle chiffrée de la section « Critères d'acceptation (planification) », point 3. ## 4. Les copies s'accumulent (suggestion 7) Chaque lot de versions futures ajoute un `-before-vN.db` en clair par profil secondaire, que seule la suppression du profil retire. Une copie existante est aussi gardée telle quelle : après un rattrapage qui a échoué puis abouti plus tard à partir de la même version, elle précède les données saisies entre-temps. - Fichiers : `src-tauri/src/database/profile_db.rs` (`backup_to`, `remove_backups`), `docs/guide-utilisateur.md` et les clés `docs.profiles.tips` de `src/i18n/locales/fr.json` et `en.json` - Correctif proposé : une règle de rétention (garder la dernière copie) et une phrase au guide. ## Critères - [ ] Une erreur de rattrapage écrite au Journal nomme la copie prise avant elle. - [ ] RV4, RV7 et RT2 font tomber au moins un test. - [ ] Le risque du délai de démarrage est écrit dans l'ADR 0021, avec la mesure. - [ ] La règle de rétention décidée le 2026-10-10 (copie fraîche, garder la dernière ; point 4 ci-dessous) est implémentée et écrite au guide FR et EN. --- ## Depends on - #408 - #389 ## Fichiers concernés (complet) - `src-tauri/src/database/profile_db.rs` (`catch_up`, `prepare_at`, `backup_to`, `remove_backups`, `ProfilePreparation`, tests) - `src/services/db.ts` (`ProfilePreparation`, `describePreparation`, message de repli `:185-189`), `src/services/db.test.ts` - `src/App.tsx` (`STARTUP_TIMEOUT_MS`, succès tardif) et son test s'il existe, sinon un test de la logique extraite - `docs/adr/0021-migrations-profils-secondaires.md` (mesure, risque, rétention) - `docs/guide-utilisateur.md:79`, clés `docs.profiles.tips` de `src/i18n/locales/fr.json` et `en.json` - `CHANGELOG.md`, `CHANGELOG.fr.md` ## Critères d'acceptation (planification) **1. Copie nommée sur un rattrapage arrêté** - [ ] Nouveau champ `catch_up_backup: Option<String>` de `ProfilePreparation` (Rust et interface TS), rempli dès que la copie est prise, **même si le rattrapage échoue ensuite**. La ligne d'erreur du Journal (`describePreparation`) le nomme. - [ ] Un test par chemin d'erreur après la copie : `history_write_failed`, `pragma_failed`, `apply_pending`. - [ ] Le champ ne contient que le **nom de fichier** renvoyé par `backup_to`, jamais un chemin ; test : aucune ligne d'erreur du Journal ne contient `/` ni `\`. Le message de repli JS (`db.ts:185-189`) passe aussi sans chemin (dossier remplacé ou message tronqué). **2. Épingles** : RV4, RV7 et RT2 rougissent chacune au moins un test (corps d'origine). **3. Délai de démarrage** - [ ] Bug vérifié : un `connectActiveProfile` qui réussit après le délai garde la page d'erreur (`App.tsx:56-58` ne remet pas `startupError` à `null`). Corriger (succès = `setStartupError(null)`) et l'épingler par un test. - [ ] Test Rust `#[ignore]` qui construit un profil synthétique au plancher le plus bas reconnu par `infer_floor` (partir des fixtures des états publiés), avec 100 000 transactions, et mesure `prepare_at` (copie `VACUUM INTO`, `foreign_key_check`, réparation des drapeaux comprises) ; il **affiche** la durée sans l'asserter. Lancé une fois en local (`cargo test -- --ignored`), durée collée dans la PR. - [ ] Règle : durée mesurée **> 3 s** → `STARTUP_TIMEOUT_MS` = 30 000 ; sinon 10 000 inchangé. Mesure, machine, règle appliquée et risque résiduel écrits dans les points de vigilance de l'ADR 0021. **4. Rétention des copies** - [ ] À chaque rattrapage, la copie est **refaite** : écrite en `.tmp`, synchronisée, puis renommée par-dessus une copie de même nom (jamais supprimer d'abord). - [ ] Après un rattrapage **réussi**, et seulement après le renommage de la nouvelle copie, les autres `<profil>-before-v*.db` (et `.db.tmp`) de ce profil sont supprimés : `remove_backups(dir, stem, keep: Option<&str>)`. Rien n'est supprimé quand le rattrapage s'arrête sur une erreur ou quand la copie échoue. - [ ] Tests Rust : copie de même nom rafraîchie (contenu nouveau) ; anciennes copies élaguées après succès ; rien d'élagué sur erreur ; rien d'élagué si la copie échoue. Mutation « élaguer avant la copie » : rouge. - [ ] Guide FR/EN (`guide-utilisateur.md:79`, `docs.profiles.tips`) : une seule copie par profil, la plus récente, refaite à chaque mise à jour de la base, supprimée avec le profil. - [ ] CHANGELOG : Changed / Modifié (une seule copie gardée par profil) ; Fixed / Corrigé (la page d'erreur ne reste plus affichée quand le profil s'ouvre après le délai). ## Review caveats - 🔴 (résolu) Ne jamais supprimer avant que la nouvelle copie soit durable → critères du point 4. - 🔴 (réfuté) Deux rattrapages concurrents après un rechargement : `prepare_profile_db` est synchrone, que Tauri exécute sur le thread principal (`profile_commands.rs:184-191`), donc les appels se suivent. - 🟡 Coût réel d'un rattrapage : ni réécriture de table (le plancher réel ne descend pas jusqu'à v6), mais `VACUUM INTO`, `PRAGMA foreign_key_check` et la réparation des drapeaux, proportionnels à la taille de la base. Le délai couvre aussi `repair_migrations` et `Database.load`. - 🟢 Refaire la copie coûte un `VACUUM INTO` à chaque ouverture tant que le rattrapage échoue : accepté. - 🟢 Depuis #408, la section exclusive de `connectToProfile` couvre le rattrapage : une durée > 15 s produit l'alerte « ouverture de profil » de #408 (attendu). ## Décisions prises en planification - Rétention : copie fraîche, garder la dernière (Max, 2026-10-10). - Délai : mesurer, puis règle chiffrée 3 s → 30 s (Max, 2026-10-10). - Forme de l'erreur : champ `catch_up_backup` (décision de planification). - Sections de `docs/architecture.md` fixées pour toute la milestone : `### Accès DB et transactions` (sous la section Base de données) et `## Tests (vitest sans jsdom)` (juste avant CI/CD). La première issue de la pile qui en a besoin crée la section ; les suivantes y ajoutent. - Dernier maillon de la pile ; dépend de #408 (même fichier `db.ts`) et de #389 pour l'ordre de pile. ## Spec source `spec-plan-fiabilite-tests.md` (local, ignoré par git)
maximus added the
status:ready
type:refactor
source:human
labels 2026-10-07 01:51:48 +00:00
maximus added this to the planned-2026-10-10-fiabilite-tests milestone 2026-10-10 23:37:37 +00:00
maximus added
status:in-progress
and removed
status:ready
labels 2026-10-13 00:02:50 +00:00
maximus added
status:review
and removed
status:in-progress
labels 2026-10-13 00:26:18 +00:00
maximus added
status:approved
and removed
status:review
labels 2026-10-13 01:04:24 +00:00
maximus removed the
status:approved
label 2026-10-14 00:29:22 +00:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: maximus/Simpl-Resultat#395
No description provided.