# Correctif de concurrence du mappage forfait/produit de Launch

AUTH-03, identifié lors de l’examen des autorisations, est corrigé. Seuls le serveur Launch et ses tests de régression ont été modifiés ; aucun déploiement ni SDK publié. La frontière des décisions d’autorisation de Licentivo et du SDK reste inchangée.

## Modifier

- Lors de l’enregistrement du mappage, la transaction verrouille d’abord l’enregistrement commun du produit Launch, puis la version du forfait. Les enregistrements de forfaits ou de processus différents respectent ainsi le même verrou de produit ; une requête en conflit renvoie HTTP 409 `PRODUCT_MAPPING_CONFLICT`.
- `products.licentivo_product_id` conserve la route publique stable du produit. Après le premier enregistrement réussi du mappage, les autres forfaits du même produit Launch doivent sélectionner ce produit Licentivo ; différentes politiques de ce produit restent permises. Ce champ ne stocke ni permissions de fonctionnalité, ni quotas d’appareil, ni état d’autorisation client.
- L’identité client lit la route stable au lieu de choisir le produit selon la version maximale de tous les forfaits. La publication d’un forfait et la génération de la configuration d’intégration SDK vérifient également ce même lien.
- L’ancienne base reçoit automatiquement un champ nullable. Lorsque la route stable manque, les données consultent successivement l’historique des achats, notamment payés, l’historique des publications puis les autres mappages. Plusieurs produits au même niveau de priorité provoquent un conflit explicite, sans supposition. Un produit acheté unique prime sur les brouillons sans rapport ; l’enregistrement ultérieur d’un mappage compatible peut fixer le lien. Modifier le contenu du produit conserve ce lien.

Les anciennes données erronées ayant déjà vendu vers plusieurs produits Licentivo nécessitent toujours une vérification manuelle ; ce changement ne réécrit ni les achats ni les licences distantes. Pour utiliser un autre produit Licentivo, créez un nouveau produit Launch ; un nouveau forfait ne doit pas remplacer la route du produit d’origine.

Voir l’implémentation de [l’enregistrement des mappages](https://github.com/spf86/licentivo-launch/blob/main/internal/app/connections.go), du [routage produit](https://github.com/spf86/licentivo-launch/blob/main/internal/app/product_mapping.go), de [l’émission d’identité](https://github.com/spf86/licentivo-launch/blob/main/internal/app/identity.go), de [la validation de publication](https://github.com/spf86/licentivo-launch/blob/main/internal/app/catalog.go), de [la vérification d’intégration](https://github.com/spf86/licentivo-launch/blob/main/internal/app/integration.go) et du [modèle de données](https://github.com/spf86/licentivo-launch/blob/main/internal/storage/models.go).

## Vérification locale

| Vérifier | Résultat |
| --- | --- |
| Comparaison avec l’implémentation avant correctif | Le même test de régression détecte de façon reproductible les deux enregistrements en conflit réussissant simultanément et échoue comme prévu |
| Régression ciblée du mappage après correctif | Pour deux requêtes en conflit, une réussit et l’autre renvoie 409 ; deux enregistrements compatibles réussissent ; après synchronisation du paiement, un brouillon erroné n’affecte pas l’identité ; la couche d’intégration SDK accepte le contexte produit correct |
| Protection des données historiques | Priorité à la route achetée, erreur en cas d’ambiguïté, interdiction de publier un brouillon erroné, impossibilité de générer une configuration SDK depuis une publication historique erronée et conservation du lien lors de la modification du contenu : tous les contrôles réussissent |
| Tous les paquets source Go et régressions MySQL | 192 réussites de tests enregistrées, sous-tests inclus ; aucun échec. `TestProductUploadRoundTrip` est ignoré et n’est pas compté comme réussi |
| Mise à niveau du schéma d’une ancienne base | L’initialisation ajoute le champ nullable au schéma privé de colonne de routage ; l’initialisation répétée réussit |
| Vérification intégrée réelle de Launch, Licentivo et du SDK Go | 13 étapes métier réussies couvrant l’achat, l’exécution réelle d’une fonctionnalité signée, la restauration après fermeture ordinaire, la déconnexion, la dissociation distante, les anciennes générations, les renouvellements et remboursements, la révocation du compte et le refus d’exécution après remboursement ou contestation |
| Vérifications complémentaires finales | Régression ciblée du mappage réussie sur une nouvelle base vide, avec vérification de la configuration d’intégration des publications historiques ; `go vet` réussi |

Après la régression complète et la vérification des services réels, un contrôle de cohérence de la vérification d’intégration SDK a été ajouté. La régression ciblée incluant ce scénario et `go vet` ont ensuite été réexécutés séparément. L’échec attendu de l’ancienne implémentation démontre que le test détecte la course d’origine ; il ne constitue pas une régression non résolue.

La vérification intégrée utilise un MySQL 8.0.32 local isolé, le service Licentivo courant et le véritable SDK Go ; les fournisseurs de paiement et DeepL utilisent des simulateurs isolés, sans débit réel ni traduction payante. Les tests ciblés de concurrence et de mappages historiques erronés utilisent le véritable métier Launch, MySQL et un simulateur de protocole ; ils n’affirment pas que les neuf SDK ont chacun été intégrés aux services réels lors de cette série.

`192.168.2.177` n’a pas été consulté lors de cette série. Les processus temporaires MySQL et Licentivo démarrés pour les tests ont été arrêtés ; les services préexistants sont conservés. Les données d’origine restent dans le répertoire ignoré `.local/mapping-fix-20261024/` ; un résumé partageable figure dans les [preuves de vérification](https://github.com/spf86/licentivo-launch/blob/main/docs/product-mapping-fix-evidence-2026-10-24.json).
