Lot G : 8 écarts clos, dont trois qui n'existaient pas
Trois cartes « Bascule prod » se ferment sans une ligne de code : l'export Mongo, lu plutôt que supposé, montre qu'il n'y avait rien à perdre. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
c180230f49
commit
1321f0cebe
14
STATUS.md
14
STATUS.md
@ -308,6 +308,20 @@ Les lots 1 et 2 sont terminés. **Le lot 3 et le lot médias sont tous les deux
|
|||||||
|
|
||||||
**Chemin critique** : A (assainir) → B (geler le schéma) → G (`MigrationController`) → H (tests) → **J (RGPD)** → I (bascule). C, D, D-bis, E, F se parallélisent.
|
**Chemin critique** : A (assainir) → B (geler le schéma) → G (`MigrationController`) → H (tests) → **J (RGPD)** → I (bascule). C, D, D-bis, E, F se parallélisent.
|
||||||
|
|
||||||
|
**Lot G — les 8 écarts sont clos le 2026-08-11. Reste le dry run.** `dotnet build` vert, `dotnet test` **143/143**.
|
||||||
|
|
||||||
|
**Trois des huit n'existaient pas.** Le plan les décrivait en « perte de données » ; l'export Mongo dit qu'il n'y a rien à perdre :
|
||||||
|
- **(a)** `BuildSection` couvre exactement les types présents : les 327 sections de l'export ne contiennent que les valeurs 0 à 10. `SectionEvent` et `SectionParcours` sont nés avec Postgres v3.
|
||||||
|
- **(f)** `IsQRCode`/`IsSearchText`/`IsSearchNumber` n'existent pas dans Mongo — `false` est le bon défaut. Contrôle inverse fait : les cinq réglages qui *existent* (`IsDate`, `IsHour`, `IsSectionImageBackground`, `RoundedValue`, `ScreenPercentageSectionsMainPage`) sont bien mappés sur `AppConfigurationLink`.
|
||||||
|
- **(g)** tombé avec le rename du lot B.
|
||||||
|
|
||||||
|
**Les cinq vrais, corrigés** :
|
||||||
|
- **(b)** mesuré : **5 sections quiz portent 41 questions**, toutes jetées. Migrées avec leurs réponses, en `MultipleChoice` (le type de validation n'existait pas dans l'ancien modèle). Les agendas n'ont aucun événement dans Mongo et les parcours n'y existent pas : leurs collections vides sont correctes.
|
||||||
|
- **(c)** tout est généré ou dérivé, cf. v1-plan.
|
||||||
|
- **(d)** Mongo n'a **pas de champ Role** : le `ContentEditor` en dur dégradait les 10 utilisateurs en silence. Passé à `InstanceAdmin`. ⚠️ Aucun `SuperAdmin` n'est créé par la migration.
|
||||||
|
- **(e)** passe par `ResourceStorage` (L5) ; `StoragePath` n'était pas écrit du tout. L'échec du `HEAD` remonte désormais dans le rapport.
|
||||||
|
- **(h)** transaction unique, et **500 au lieu de 200 OK** sur échec fatal.
|
||||||
|
|
||||||
**Lot C1 — livré le 2026-08-11.** Calculateur `StoragePath`/`SizeBytes` extrait dans `Helpers/ResourceStorage.cs`, avec 13 tests (`dotnet test` **143/143**). Il ferme le lien **L5** : C2 (backfill) et l'écart (e) du lot G appelleront le même code au lieu d'en écrire deux.
|
**Lot C1 — livré le 2026-08-11.** Calculateur `StoragePath`/`SizeBytes` extrait dans `Helpers/ResourceStorage.cs`, avec 13 tests (`dotnet test` **143/143**). Il ferme le lien **L5** : C2 (backfill) et l'écart (e) du lot G appelleront le même code au lieu d'en écrire deux.
|
||||||
|
|
||||||
- ⚠️ **L'extraction a prouvé la divergence qu'elle devait empêcher.** `ResourceController` a **deux** chemins de création : le chemin **multipart** écrivait `SizeBytes` mais laissait **`StoragePath` nul**, seul le chemin JSON écrivait les deux. Le §1quater annonçait « `StoragePath`/`SizeBytes` écrits à `Create` depuis le 10/08 » — c'était vrai d'un chemin sur deux. Une partie des lignes à rattraper par C2 vient de là.
|
- ⚠️ **L'extraction a prouvé la divergence qu'elle devait empêcher.** `ResourceController` a **deux** chemins de création : le chemin **multipart** écrivait `SizeBytes` mais laissait **`StoragePath` nul**, seul le chemin JSON écrivait les deux. Le §1quater annonçait « `StoragePath`/`SizeBytes` écrits à `Create` depuis le 10/08 » — c'était vrai d'un chemin sur deux. Une partie des lignes à rattraper par C2 vient de là.
|
||||||
|
|||||||
46
kanban.html
46
kanban.html
@ -459,8 +459,8 @@
|
|||||||
<div class="stat"><span class="n n-warn">6</span><span class="k">Bugs ouverts</span></div>
|
<div class="stat"><span class="n n-warn">6</span><span class="k">Bugs ouverts</span></div>
|
||||||
<div class="stat"><span class="n">6</span><span class="k">À tester</span></div>
|
<div class="stat"><span class="n">6</span><span class="k">À tester</span></div>
|
||||||
<div class="stat"><span class="n">20</span><span class="k">Planifié</span></div>
|
<div class="stat"><span class="n">20</span><span class="k">Planifié</span></div>
|
||||||
<div class="stat"><span class="n n-gate">11</span><span class="k">Bascule prod</span></div>
|
<div class="stat"><span class="n n-gate">7</span><span class="k">Bascule prod</span></div>
|
||||||
<div class="stat"><span class="n n-good">28</span><span class="k">Fait récemment</span></div>
|
<div class="stat"><span class="n n-good">30</span><span class="k">Fait récemment</span></div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="filters" role="group" aria-label="Filtrer par domaine">
|
<div class="filters" role="group" aria-label="Filtrer par domaine">
|
||||||
@ -812,7 +812,7 @@
|
|||||||
|
|
||||||
<!-- BASCULE PROD -->
|
<!-- BASCULE PROD -->
|
||||||
<section class="col" style="--stripe: var(--gate)">
|
<section class="col" style="--stripe: var(--gate)">
|
||||||
<div class="col-head"><h2>Bascule prod</h2><span class="count">11</span></div>
|
<div class="col-head"><h2>Bascule prod</h2><span class="count">7</span></div>
|
||||||
<div class="stack">
|
<div class="stack">
|
||||||
|
|
||||||
<article class="card" data-area="backend infra">
|
<article class="card" data-area="backend infra">
|
||||||
@ -824,34 +824,6 @@
|
|||||||
<span class="src">security/audit-securite-manager-service.md · v1-plan.md L1, I0</span>
|
<span class="src">security/audit-securite-manager-service.md · v1-plan.md L1, I0</span>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
<article class="card" data-area="backend">
|
|
||||||
<div class="card-meta"><span class="tag">MigrationController</span><span class="flag f-critical">Silencieux</span></div>
|
|
||||||
<h3>Instance : 4 champs migrés sur ~35</h3>
|
|
||||||
<p>Le plus dangereux, parce qu'il <em>ne produit aucune erreur</em> : <code>SubscriptionPlanId</code> null → quotas à 0, <code>PublicApiKey</code> null → <strong>les apps visiteur ne s'authentifient plus</strong>, <code>WebSlug</code> null → visitapp-web injoignable, <code>IsMobile</code>/<code>IsTablet</code>/<code>IsWeb</code>/<code>IsAssistant</code> à false. La migration se déclare réussie et le lieu est inaccessible.</p>
|
|
||||||
<span class="src">MigrationController.cs:106-112 · STATUS.md §1quinquies c</span>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article class="card" data-area="backend">
|
|
||||||
<div class="card-meta"><span class="tag">MigrationController</span><span class="flag f-critical">Perte de données</span></div>
|
|
||||||
<h3>11 types de section sur 13</h3>
|
|
||||||
<p><code>BuildSection</code> a été écrit avant <code>SectionEvent</code> et <code>SectionParcours</code> : les deux tombent dans le <code>default</code>, une ligne dans le rapport d'erreurs et la section n'est pas migrée. Ce sont précisément les types du scénario carnaval.</p>
|
|
||||||
<span class="src">MigrationController.cs:458-613 · §1quinquies a</span>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article class="card" data-area="backend">
|
|
||||||
<div class="card-meta"><span class="tag">MigrationController</span><span class="flag f-critical">Perte de données</span></div>
|
|
||||||
<h3>Collections filles jamais remplies</h3>
|
|
||||||
<p><code>QuizQuestions = new()</code>, <code>EventAgendas = new()</code>, aucun <code>GuidedPath</code>/<code>GuidedStep</code> : un quiz arrive sans ses questions, un agenda sans ses événements. Et <code>Role</code> est forcé à <code>ContentEditor</code> — <strong>plus aucun administrateur</strong> après la bascule.</p>
|
|
||||||
<span class="src">MigrationController.cs:225, :526, :591 · §1quinquies b, d</span>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article class="card" data-area="backend">
|
|
||||||
<div class="card-meta"><span class="tag">MigrationController</span><span class="flag f-warn">Robustesse</span></div>
|
|
||||||
<h3>Aucune transaction globale</h3>
|
|
||||||
<p>Neuf étapes, un <code>SaveChangesAsync</code> chacune, et un <code>catch</code> qui renvoie <strong>200 OK</strong> avec l'erreur dans le corps. Un échec au milieu laisse la base à moitié remplie ; la reprise ne tient qu'aux tests d'idempotence — qui existent et sont corrects. Idem : <code>StoragePath</code> et les colonnes IA ne sont pas renseignés, et <code>SizeBytes</code> sort d'un <code>HEAD</code> dont l'échec est avalé.</p>
|
|
||||||
<span class="src">MigrationController.cs:68-86, :172-181 · §1quinquies e, h</span>
|
|
||||||
</article>
|
|
||||||
|
|
||||||
<article class="card" data-area="backend infra">
|
<article class="card" data-area="backend infra">
|
||||||
<div class="card-meta"><span class="tag">étape 15</span><span class="flag f-good">Sans risque</span></div>
|
<div class="card-meta"><span class="tag">étape 15</span><span class="flag f-good">Sans risque</span></div>
|
||||||
<h3>Dry run + comparaison des comptages</h3>
|
<h3>Dry run + comparaison des comptages</h3>
|
||||||
@ -901,9 +873,19 @@
|
|||||||
|
|
||||||
<section class="done">
|
<section class="done">
|
||||||
<h2>Fait récemment</h2>
|
<h2>Fait récemment</h2>
|
||||||
<p>Vingt-huit chantiers clos entre le 5 et le 11 août 2026.</p>
|
<p>Trente chantiers clos entre le 5 et le 11 août 2026.</p>
|
||||||
<div class="done-grid">
|
<div class="done-grid">
|
||||||
|
|
||||||
|
<div class="done-item">
|
||||||
|
<strong>MigrationController — trois des huit écarts n'existaient pas</strong>
|
||||||
|
<span>Le plan les décrivait en « perte de données ». L'export Mongo, lu plutôt que supposé, dit qu'il n'y a rien à perdre. <strong>(a) « 11 types de section sur 13 »</strong> : les 327 sections de l'export ne contiennent que les types 0 à 10 — <code>SectionEvent</code> et <code>SectionParcours</code> sont nés avec Postgres v3, le <code>default</code> est un filet et non un trou, et le « scénario carnaval » qu'on croyait menacé est du contenu <em>à créer</em>, pas à migrer. <strong>(f) les trois booléens forcés à false</strong> : ces colonnes n'existent pas dans Mongo, <code>false</code> est le bon défaut — et le contrôle inverse a été fait, les cinq réglages qui <em>existent</em> vraiment dans l'export (<code>IsDate</code>, <code>IsHour</code>, <code>IsSectionImageBackground</code>, <code>RoundedValue</code>, <code>ScreenPercentageSectionsMainPage</code>) sont bien mappés sur <code>AppConfigurationLink</code>. <strong>(g)</strong> était tombé avec le rename du lot B. Trois cartes de la colonne « Bascule prod » se ferment sans une ligne de code.</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="done-item">
|
||||||
|
<strong>MigrationController — les cinq écarts réels, corrigés</strong>
|
||||||
|
<span><strong>(b)</strong> <code>QuizQuestions = new()</code> jetait les questions : mesuré sur l'export, <strong>5 sections quiz en portent 41</strong>, réponses comprises. Migrées, en <code>MultipleChoice</code> puisque le type de validation n'existait pas dans l'ancien modèle. Les agendas (aucun événement dans Mongo) et les parcours (inexistants avant) gardent leurs collections vides à raison. <strong>(d)</strong> était pire que décrit : Mongo <strong>n'a pas de champ Role</strong>, donc les 10 utilisateurs y avaient un accès complet, et le <code>ContentEditor</code> en dur les dégradait <em>tous</em> en silence — plus personne n'aurait pu gérer les utilisateurs de son instance. Passé à <code>InstanceAdmin</code> ; aucun SuperAdmin n'est créé par la migration, à poser à la main. <strong>(c)</strong> tout est généré ou dérivé, la source ne contenant que 4 champs. <strong>(e)</strong> <code>StoragePath</code> n'était pas écrit du tout : passe par le calculateur commun, et l'échec du <code>HEAD</code>, jusqu'ici avalé, remonte dans le rapport. <strong>(h)</strong> transaction unique, et surtout <strong>500 au lieu de 200 OK</strong> sur échec fatal — le piège était qu'un script de bascule testant le code HTTP concluait au succès. <code>dotnet test</code> 143/143.</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="done-item">
|
<div class="done-item">
|
||||||
<strong>Le schéma est gelé — lot B, et le lot G peut enfin commencer</strong>
|
<strong>Le schéma est gelé — lot B, et le lot G peut enfin commencer</strong>
|
||||||
<span>Le point d'articulation du plan : tant qu'un changement de modèle restait ouvert, réécrire <code>MigrationController</code> revenait à l'écrire deux fois. <strong>Une seule migration EF</strong> porte les trois changements. <code>SectionMap.MapResourceId</code> → <code>IconResourceId</code>, ce qui fait tomber l'<strong>écart (g)</strong> de la bascule tout seul — et il fallait renommer la propriété de navigation <code>MapResource</code> avec, sinon la convention EF fabriquait un FK fantôme. Point vérifié plutôt que supposé : EF a produit un <code>RenameColumn</code>, <em>pas</em> un drop+add — les icônes déjà configurées survivent. <code>SectionEvent.ParcoursIds</code> supprimé (l'avertissement de perte de données d'EF ne porte que sur lui, c'est l'intention). Filigrane : <code>Instance.IsImageWatermark</code> remplace le <code>instanceId == "633ee379…"</code> en dur. <strong>Référence tenue : 130/130 tests avant comme après</strong>, build Debug <em>et</em> Release verts.</span>
|
<span>Le point d'articulation du plan : tant qu'un changement de modèle restait ouvert, réécrire <code>MigrationController</code> revenait à l'écrire deux fois. <strong>Une seule migration EF</strong> porte les trois changements. <code>SectionMap.MapResourceId</code> → <code>IconResourceId</code>, ce qui fait tomber l'<strong>écart (g)</strong> de la bascule tout seul — et il fallait renommer la propriété de navigation <code>MapResource</code> avec, sinon la convention EF fabriquait un FK fantôme. Point vérifié plutôt que supposé : EF a produit un <code>RenameColumn</code>, <em>pas</em> un drop+add — les icônes déjà configurées survivent. <code>SectionEvent.ParcoursIds</code> supprimé (l'avertissement de perte de données d'EF ne porte que sur lui, c'est l'intention). Filigrane : <code>Instance.IsImageWatermark</code> remplace le <code>instanceId == "633ee379…"</code> en dur. <strong>Référence tenue : 130/130 tests avant comme après</strong>, build Debug <em>et</em> Release verts.</span>
|
||||||
|
|||||||
12
v1-plan.md
12
v1-plan.md
@ -188,14 +188,14 @@ Les 8 écarts a→h du §1quinquies. Ne démarre qu'après les lots B et C1 (**L
|
|||||||
|
|
||||||
| Écart | Quoi | Attention |
|
| Écart | Quoi | Attention |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| c | `Instance` : 4 champs migrés sur ~35 — **requalifié le 2026-08-11 : ce n'est pas un oubli de mapping.** `OldInstance` et l'export réel ne contiennent que `_id`, `Name`, `DateCreation`, `PinCode`. Les 31 autres colonnes **n'existent pas dans la source** : elles sont nées avec Postgres v3. Il n'y a donc rien à mapper, il faut **générer, dériver ou décider**. `PublicApiKey` → générer · `WebSlug` → dériver du `Name` (`SlugHelper` existe) · `IsMobile`/`IsTablet`/`IsWeb` → dériver des `ApplicationInstance` réellement présentes · `SubscriptionPlanId` → décidé, voir ci-dessous | **Le plus dangereux : aucune erreur levée.** `PublicApiKey` null = les apps visiteur ne s'authentifient plus ; `WebSlug` null = visitapp-web injoignable ; `SubscriptionPlanId` null = quotas à 0, donc `AiTokensPerMonth = 0`, donc **rien ne s'indexe** et l'IA tourne sans compteur. Réutiliser `ApplyPlanQuotas` |
|
| ~~c~~ ✅ **2026-08-11** | `Instance` : 4 champs migrés sur ~35 — **requalifié : ce n'était pas un oubli de mapping.** `OldInstance` et l'export réel ne contiennent que `_id`, `Name`, `DateCreation`, `PinCode`. Les 31 autres colonnes **n'existent pas dans la source** : elles sont nées avec Postgres v3. Il n'y a donc rien à mapper, il faut **générer, dériver ou décider**. `PublicApiKey` → générer · `WebSlug` → dériver du `Name` (`SlugHelper` existe) · `IsMobile`/`IsTablet`/`IsWeb` → dériver · `SubscriptionPlanId` → décidé.<br>**Livré** : `PublicApiKey` générée avec le même schéma que l'inscription self-service (`ap_` + 32 octets cryptographiques) · `WebSlug` via `SlugHelper.GenerateUniqueSlug` (accents et collisions déjà gérés) · `IsTablet`/`IsMobile` dérivés des configurations Mongo, comme le fait déjà `MigrateApplicationInstancesAsync` ; `IsWeb` reste faux, le canal web n'existait pas · plan affecté par nom, un nom inconnu retombant sur **Pro**, jamais sur un plan qui offrirait l'IA · `IsAssistant` allumé seulement si le plan donne des jetons.<br>⚠️ `ApplyPlanQuotas` est **dupliqué** depuis `InstanceController` plutôt qu'appelé : la migration ne doit pas casser si ce contrôleur change de forme. Les deux doivent rester alignées | **Le plus dangereux : aucune erreur levée.** `PublicApiKey` null = les apps visiteur ne s'authentifient plus ; `WebSlug` null = visitapp-web injoignable ; `SubscriptionPlanId` null = quotas à 0, donc `AiTokensPerMonth = 0`, donc **rien ne s'indexe** et l'IA tourne sans compteur. Réutiliser `ApplyPlanQuotas` |
|
||||||
| ~~a~~ | ⛔ **Fausse alerte — vérifiée dans l'export le 2026-08-11.** `BuildSection` couvre **exactement les types que Mongo contient**. L'enum va de `Map`=0 à `Weather`=10, puis `Event`=11 et `Parcours`=12 ; or `TabletDb.Sections.json` (327 sections) ne contient **que les valeurs 0 à 10**. `SectionEvent` et `SectionParcours` **n'existaient pas dans Mongo** — ce sont des types nés avec Postgres v3. Le `default` est un filet, pas un trou | Le kanban parlait de « perte de données » et du « scénario carnaval » : ce scénario est du **contenu à créer** dans Postgres, pas du contenu à migrer. Vérifié aussi : le renommage `SectionPuzzle` → `SectionGame` est **déjà traité** — la branche `Game` parse `OldPuzzleDTO` et pose `GameType = GameTypes.Puzzle`, et la valeur 8 n'a pas bougé |
|
| ~~a~~ | ⛔ **Fausse alerte — vérifiée dans l'export le 2026-08-11.** `BuildSection` couvre **exactement les types que Mongo contient**. L'enum va de `Map`=0 à `Weather`=10, puis `Event`=11 et `Parcours`=12 ; or `TabletDb.Sections.json` (327 sections) ne contient **que les valeurs 0 à 10**. `SectionEvent` et `SectionParcours` **n'existaient pas dans Mongo** — ce sont des types nés avec Postgres v3. Le `default` est un filet, pas un trou | Le kanban parlait de « perte de données » et du « scénario carnaval » : ce scénario est du **contenu à créer** dans Postgres, pas du contenu à migrer. Vérifié aussi : le renommage `SectionPuzzle` → `SectionGame` est **déjà traité** — la branche `Game` parse `OldPuzzleDTO` et pose `GameType = GameTypes.Puzzle`, et la valeur 8 n'a pas bougé |
|
||||||
| b | Collections filles jamais remplies (`QuizQuestions = new()`, `EventAgendas = new()`, aucun `GuidedPath`/`GuidedStep`) | Un quiz arrive sans ses questions |
|
| ~~b~~ ✅ **2026-08-11** | Collections filles jamais remplies | **Vrai, et mesuré** : `QuizQuestions = new()` jetait les questions de **5 sections quiz, soit 41 questions**, réponses comprises. Migrées. Le type de validation n'existant pas dans l'ancien modèle (tout y était à choix multiples), elles arrivent en `MultipleChoice` plutôt qu'au défaut `Simple`. **En revanche `EventAgendas = new()` et l'absence de `GuidedPath` sont corrects** : les agendas Mongo ne portent que `mapProvider` et `resourceIds`, aucun événement, et SectionParcours est né avec Postgres |
|
||||||
| d | `Role = UserRole.ContentEditor` en dur | Plus aucun administrateur après la bascule |
|
| ~~d~~ ✅ **2026-08-11** | `Role = UserRole.ContentEditor` en dur | **Vrai, et pire que décrit** : Mongo **n'a pas de champ Role**, donc les 10 utilisateurs y avaient un accès complet. Le défaut les **dégradait tous en silence** — plus personne n'aurait pu gérer les utilisateurs de son instance. Passé à `InstanceAdmin`, ce qui préserve leurs droits d'hier et correspond au rôle que l'inscription self-service donne au premier utilisateur. ⚠️ Aucun `SuperAdmin` n'est créé par la migration : à poser à la main |
|
||||||
| e | Colonnes `Resource` non renseignées, `SizeBytes` déduit d'un `HEAD` avalé | **L5** — appeler le calculateur C1 |
|
| ~~e~~ ✅ **2026-08-11** | Colonnes `Resource` non renseignées, `SizeBytes` déduit d'un `HEAD` avalé | **L5 fermé** : passe par `ResourceStorage.Apply`, le même calculateur que la création et le backfill — `StoragePath` n'était pas écrit **du tout**. Et l'échec du `HEAD`, jusqu'ici silencieux, **remonte dans le rapport** : une ressource à 0 octet que le quota compte pour rien, ça se sait |
|
||||||
| f | `IsQRCode`/`IsSearchText`/`IsSearchNumber` forcés à `false` | Réglages de configuration perdus |
|
| ~~f~~ | ⛔ **Fausse alerte — vérifiée dans l'export le 2026-08-11.** Ces trois colonnes **n'existent pas dans Mongo** : les forcer à `false` est le bon défaut, pas une perte. Contrôle inverse fait aussi — les cinq réglages qui, eux, **existent** dans l'export (`IsDate`, `IsHour`, `IsSectionImageBackground`, `RoundedValue`, `ScreenPercentageSectionsMainPage`) **sont bien mappés**, sur `AppConfigurationLink` | Rien à corriger |
|
||||||
| g | `MapResourceId = dto?.iconResourceId` | **L6** — tombe avec le lot B |
|
| g | `MapResourceId = dto?.iconResourceId` | **L6** — tombe avec le lot B |
|
||||||
| h | Pas de transaction globale, `catch` qui renvoie 200 OK avec `FatalError` dans le corps | Transaction + vrai code d'erreur. Les tests `AnyAsync` d'idempotence, eux, sont corrects |
|
| ~~h~~ ✅ **2026-08-11** | Pas de transaction globale, `catch` qui renvoie 200 OK | Transaction unique sur les neuf étapes : soit tout est là, soit rien. Et l'échec fatal renvoie désormais **500** — le piège était qu'un script de bascule testant le code HTTP concluait au succès, l'erreur n'étant que dans le corps. En `dryRun`, pas de transaction ouverte : rien n'est écrit |
|
||||||
|
|
||||||
Puis : **dry run** (`dryRun=true`) sur l'export Mongo de `manager-service/migration-data/`, et **comparaison des comptages par entité** avec Mongo. C'est la seule preuve que les écarts a, b et c sont fermés.
|
Puis : **dry run** (`dryRun=true`) sur l'export Mongo de `manager-service/migration-data/`, et **comparaison des comptages par entité** avec Mongo. C'est la seule preuve que les écarts a, b et c sont fermés.
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user