CodeGym /Cours /ChatGPT Apps /Processus de release — versions, notes, migrations SDK/sp...

Processus de release — versions, notes, migrations SDK/spécifications, feature flags, rollback

ChatGPT Apps
Niveau 17 , Leçon 3
Disponible

1. Pourquoi le processus de release pour ChatGPT App est plus complexe qu’un déploiement classique

Dans la partie précédente du module, nous avons parlé de l’observation de la qualité et de la stabilité de l’App (logs, métriques, SLO). Voyons maintenant comment organiser le processus de release lui‑même afin que ces métriques ne s’effondrent pas à chaque déploiement.

Dans une application web classique, tout est plutôt simple : vous déployez une nouvelle version du backend et du frontend — l’utilisateur actualise la page et se retrouve sur la nouvelle version. Si quelque chose casse, on peut souvent simplement annuler le déploiement.

Dans une ChatGPT App, la pile est plus subtile. Vous avez au moins quatre couches, qui vivent des vies différentes :

  • Manifeste et schéma des outils (MCP tools / OpenAPI) ;
  • Infrastructure : application Next.js et serveur MCP/Agents/ACP ;
  • System‑prompt et autres prompts ;
  • Données : product feed, paramètres, configs.

Le problème, c’est que le modèle vit dans son « monde mental ». Le contexte du chat peut durer des heures, voire des jours. Le manifeste et les descriptions des tools sont chargés et mis en cache côté OpenAI et ne se mettent pas à jour instantanément dans toutes les conversations existantes. Si vous modifiez la signature d’un outil (par exemple, suppression d’un champ dans l’input‑schema), alors dans les anciens dialogues le modèle continuera d’envoyer l’ancien payload, tandis que votre nouveau backend le rejettera. Résultat : erreurs 400, réponses étranges dans le chat et des utilisateurs très déçus.

Ainsi, dans le monde des ChatGPT Apps, une « release » — ce n’est pas juste « déployer un nouveau Docker ». C’est une modification coordonnée de plusieurs couches, avec une gestion soigneuse des versions, des feature flags et la possibilité de rollback.

2. Matrice des versions : que faut‑il versionner, au juste

Il est utile de regarder non pas seulement « la version de l’App 1.3 », mais immédiatement la matrice des versions par couche. Pour GiftGenius, cela ressemble à peu près à ceci.

Couche Ce que l’on versionne Exemple de valeur Où stocker
App / Next.js Code et build
giftgenius-app 1.4.2
package.json, tag Git
MCP / interface API Jeu d’outils (tools) et leurs schémas
tools-schema v1.7
constante dans le code, annotations
System / prompts System‑prompt, helpers, exemples
prompt v3.1
fichiers séparés + métadonnées
Commerce / ACP / feed Format du product feed et contrats ACP
feed v2, acp v1.3
schéma dans le dépôt de données

Notez que ce sont des axes différents. Vous pouvez publier une version 1.4.2 de l’application dans laquelle le schema des tools reste en v1.7, tandis que le prompt passe en v3.2. Cela doit être visible dans les logs ; ainsi, il est ensuite plus facile de comprendre pourquoi, après prompt v3.2, la conversion checkout a soudain chuté.

Pour le code, il est pratique d’utiliser le versionnement sémantique (SemVer) : MAJOR.MINOR.PATCH. MAJOR — changement cassant, MINOR — nouvelles fonctionnalités sans casse, PATCH — corrections de bugs. Pour les versions d’interface (schémas, prompts), la logique est similaire : MAJOR signale un breaking change.

Il convient de distinguer séparément la version de l’interface des tools. Pour une LLM, c’est crucial : si vous modifiez le contrat d’un outil et que le modèle « pense » que le contrat est ancien, les ennuis commencent. La politique est donc généralement la suivante : dans les releases MINOR, on ajoute seulement de nouveaux champs optionnels et on ne renomme/supprime pas les anciens ; les changements cassants — uniquement via un nouvel outil, par exemple suggest_gifts_v2.

Maintenant que nous avons séparé les couches par versions, voyons comment ces versions « vivent » dans le cycle de release — du dev au prod.

3. Flux de release de base pour GiftGenius

Commençons par nous accorder sur les étapes. Vous avez probablement déjà des environnements (du module sur le déploiement), mais maintenant regardons‑les à travers le prisme des releases.

On distingue généralement :

  • dev — développement local, Dev Mode dans ChatGPT, tunnels ;
  • staging — au plus proche de la prod : même type de base de données, même type de MCP/ACP, mais données et paiements de test (sandbox) ;
  • prod — environnement de production, celui auquel est connecté l’App ChatGPT en prod / le listing Store.

Le processus peut ressembler à ceci :

flowchart TD
  A[Dev : branche feature/*] --> B[PR → main]
  B --> C[CI: unit + contract + lint]
  C --> D[Deploy to Staging]
  D --> E[Smoke/E2E + vérification manuelle]
  E --> F[Deploy to Prod]
  F --> G[Observation des métriques et des logs]

À chaque étape, nous ajoutons des « fusibles ». Dans l’environnement dev, le développeur peut tout expérimenter, mais chaque fusion dans main déclenche le CI, qui lance les tests unitaires/contrats. Si tout va bien — déploiement automatique sur staging. Sur staging, on exécute un court jeu de scénarios E2E/smoke : par exemple, un flux complet de recommandation de cadeau et un checkout « factice » sur une passerelle de paiement de test.

Ce n’est qu’ensuite qu’on appuie sur le bouton de déploiement en prod. Idéalement — avec l’indication de la version et un lien vers le CHANGELOG. Déjà en prod, on continue à suivre le p95, le taux d’erreur et les métriques business (conversion de la recommandation au checkout). Si après la release quelque chose se dégrade — nous devons avoir un plan de rollback clair, dont nous parlerons ci‑dessous.

4. Release notes et changelog : que consigner précisément

Sans notes de release, dans un mois vous regarderez un graphe : « pourquoi y a‑t‑il 3 semaines notre p95 checkout a doublé ? » et vous répondrez « aucune idée, mais on a eu une grosse release ». Pas la meilleure stratégie.

On a généralement au moins deux types de notes.

Changelog interne — technique. Il est destiné aux développeurs, SRE et à tous ceux qui plongent dans le code. On y note quelles fonctionnalités sont apparues, quels bugs ont été corrigés, s’il y a eu des breaking changes. On peut suivre le format canonique Keep a Changelog : sections Added, Changed, Fixed, Removed.

Release notes externes — des notes lisibles par les utilisateurs et pour le Store. Pas besoin d’écrire « migrer MCP SDK 0.40.5 » ; il vaut mieux écrire « Ajout de recommandations pour la fête de Thanksgiving », « Correction d’un bug rare qui empêchait certains cadeaux d’être ajoutés au panier ».

Extrait d’un CHANGELOG.md pour GiftGenius :

## [1.4.0] - 2025-11-20
### Added
- Nouvel outil `suggest_gifts_v2` avec prise en charge des tags d'intérêts.
- A/B test du nouveau system-prompt (flag: GG_PROMPT_V3).

### Changed
- Amélioration du traitement des erreurs du checkout ACP (messages plus conviviaux).

### Fixed
- Correction d'un bug à cause duquel les produits sans image étaient masqués des recommandations.

Il est utile de conserver à proximité la version du prompt : ne serait‑ce que le hash de commit du fichier system‑prompt, qui permettra de se souvenir plus tard : « ah, après le prompt b3f9c2d, les utilisateurs ont moins cliqué sur “Acheter” ».

5. Migrations SDK et spécifications : comment vivre dans un écosystème qui évolue vite

L’écosystème autour des Apps SDK, MCP et Agents évolue rapidement : nouvelles versions de SDK, changements du protocole MCP, mises à jour ACP, etc. C’est bien (de nouvelles possibilités), mais douloureux aussi : ça peut casser vite.

Pinning des versions et « ne pas se mettre à jour le jour de la release »

Première recommandation simple : figez les versions des dépendances. Pas ^0.4.0, mais 0.4.0. Pour les SDK qui cassent souvent leur API (MCP/Agents/Apps SDK), c’est particulièrement critique. J’ai consulté des études sur le sujet, qui soulignent le phénomène de « fatigue des SDK » — l’épuisement dû aux mises à jour incompatibles fréquentes, ressenti surtout par ceux qui ont laissé des dépendances à versions flottantes (du type ^0.4.0) et qui ont un jour soudainement attrapé une myriade d’erreurs après un npm install.

Mini‑exemple :

// package.json (extrait)
{
  "dependencies": {
    "@modelcontextprotocol/sdk": "0.4.2",
    "@openai/applications-sdk": "0.3.1"
  }
}

Deuxième recommandation : n’embarquez pas dans la même release à la fois des fonctionnalités métier et de grosses migrations de SDK. Si vous devez mettre à jour MCP SDK de 0.3.x à 0.4.x, mieux vaut faire une release technique séparée : d’abord la mise à jour du SDK, les tests et la stabilisation, puis seulement le nouveau flux de checkout.

Stratégie de migration de SDK

Un plan raisonnable ressemble généralement à ceci :

Dans l’environnement dev, vous créez une branche séparée upgrade/mcp-sdk-0.4. Vous mettez à jour la dépendance, ajustez le code, exécutez tous les tests unitaires/contrats, et vous faites tourner en local le flux principal de GiftGenius via le Dev Mode.

Ensuite, vous déployez cette branche sur une URL de staging séparée et vous y exécutez des tests E2E/smoke. Vous pouvez même faire un petit test de charge : 50100 appels consécutifs à suggest_gifts.

Si tout va bien — vous fusionnez dans main, déployez sur le staging principal, rejouez les tests smoke, puis seulement ensuite — en prod.

Sinon — vous avez un rollback évident : il suffit de ne pas merger cette branche ou de la revert. C’est tout l’intérêt de séparer les migrations de SDK des releases produit.

Migrations des schémas de tools et des API

La partie la plus délicate, ce sont les changements d’interface : le modèle n’en prend pas connaissance instantanément. Les travaux sur ce sujet soulignent particulièrement une règle importante : « Étendre, ne pas casser » (additive‑only). Si vous devez ajouter à suggest_gifts un nouvel argument interests: string[], faites‑le optionnel, et non obligatoire ; les anciens scénarios continueront de fonctionner.

Exemple d’évolution d’un schéma Zod pour les données d’entrée :

// v1
const suggestGiftsInputV1 = z.object({
  recipientName: z.string(),
  budget: z.number()
});

// v1.1 (champs optionnels ajoutés)
const suggestGiftsInputV1_1 = suggestGiftsInputV1.extend({
  interests: z.array(z.string()).optional(),
  occasion: z.string().optional()
});

Notez : nous ne touchons pas aux champs existants, nous ne faisons que l’étendre.

S’il faut réellement casser le contrat (par exemple remplacer budget par minBudget + maxBudget), mieux vaut créer un nouvel outil suggest_gifts_v2 et indiquer dans la description qu’il s’agit d’une version améliorée. L’ancienne API peut être marquée deprecated et progressivement supprimée, une fois que vous êtes certain que le modèle et les utilisateurs ont migré.

Migrations des données : product feed et ACP

Nous avons déjà parlé des migrations de SDK et des schémas des tools. Le product feed est aussi un contrat. Si vous modifiez le format des SKU, des devises, des localisations, cela doit être coordonné : mettre à jour le schéma du feed, le traitement dans MCP/ACP, ainsi que tous les pré‑processeurs. La documentation commerce pour ChatGPT App note que des erreurs dans le feed (champs corrompus, doublons, prix incohérents) peuvent dégrader la qualité des recommandations même avec un code parfait.

Approche typique :

  1. Commencez par ajouter les nouveaux champs au schéma du feed en tant qu’optionnels et apprenez à GiftGenius à les utiliser s’ils existent.
  2. Mettez ensuite à jour le pipeline qui construit le feed pour qu’il commence à remplir ces champs.
  3. Exécutez un validateur de feed (tests de contrat sur les données) et ce n’est qu’après cela que vous commencez à dépendre de ces champs dans la logique.

6. Feature flags : séparer déploiement et release

Les feature flags — l’un des principaux outils de survie dans le monde des ChatGPT Apps. L’idée de base est simple : vous déployez du code, mais vous n’activez pas forcément immédiatement la nouvelle fonctionnalité. D’abord, elle vit « sous drapeau » — activée seulement pour les développeurs, ou pour 1% des utilisateurs, ou complètement désactivée.

C’est particulièrement important lorsque :

  • vous déployez un nouvel algorithme de recommandation ;
  • vous changez le system‑prompt (ce qui peut modifier radicalement le comportement du modèle) ;
  • vous connectez un outil coûteux ou lent ;
  • vous expérimentez un nouveau flux de checkout.

Un simple flag via des variables d’environnement

En version minimale, on peut faire un feature flag via une variable d’environnement :

// lib/features.ts
export const isNewRecoEnabled =
  process.env.NEXT_PUBLIC_GG_NEW_RECO === "1";

Ensuite, dans le code de l’outil MCP, vous pouvez l’utiliser ainsi :

if (isNewRecoEnabled) {
  return runNewRecoAlgorithm(input);
}
return runOldRecoAlgorithm(input);

Avantage de cette approche : simplicité. Inconvénient : basculer les flags au runtime est plus difficile : il faut déployer un nouvel environnement ou au minimum réinitialiser.

Helper centralisé avec contexte

Approche un peu plus mature : disposer d’un helper centralisé qui tient compte non seulement des flags globaux, mais aussi du contexte utilisateur (tenant, segment, groupe A/B).

// lib/featureFlags.ts
type Feature = "new-reco" | "checkout-v2";

type Context = { userId: string; tenantId?: string };

export function isFeatureEnabled(
  feature: Feature,
  ctx: Context
): boolean {
  // ici, on peut avoir de la logique : env, BD, service de flags externe
  if (feature === "new-reco") {
    return process.env.GG_NEW_RECO === "1";
  }
  return false;
}

Dans le handler MCP :

const enabled = isFeatureEnabled("new-reco", { userId });
const result = enabled
  ? await runNewReco(input)
  : await runOldReco(input);

Si un jour vous connectez un service de flags externe (LaunchDarkly, Statsig, etc.), il suffira de changer l’implémentation de isFeatureEnabled, et non tout le code.

Exemples de scénarios pour GiftGenius

Test A/B du system‑prompt. Vous créez PROMPT_V2 et vous ne l’activez que pour 10% des utilisateurs ayant un tenantId dans une liste donnée. Les tools MCP et le widget ne changent pas, et vous comparez la conversion.

Kill‑switch pour un outil coûteux. Supposons que vous ayez créé un outil qui fait un appel externe complexe (par exemple vers un modèle ML de recommandation coûteux). Si ce service externe commence à tomber ou devient soudain très cher, vous voulez pouvoir le désactiver en une seconde, sans arrêter GiftGenius entièrement. Un feature flag est la solution la plus simple.

Déploiement progressif d’un nouveau flux de checkout. Vous activez d’abord Checkout v2 uniquement pour les employés de l’entreprise et quelques clients de confiance. Si les métriques sont bonnes — vous élargissez l’audience, jusqu’à l’activer pour tout le monde.

7. Rollback : comment revenir en arrière rapidement quand tout brûle

Même avec des tests et des flags impeccables, quelque chose finira par casser. L’important est d’avoir une stratégie claire : que faites‑vous dans les 515 premières minutes après avoir vu un pic d’erreurs ou une chute des métriques.

Rollback rapide du code

Si le problème vient d’un bug purement technique (NPE, mauvaise variable, URL incorrecte d’un service externe), il suffit généralement d’annuler le déploiement vers la version précédente. Par exemple, sur Vercel, il existe un rollback instantané vers le déploiement précédent.

Votre tâche — toujours savoir quel déploiement correspond à quelle version et comment l’annuler. Idéalement, c’est décrit dans le README pour l’on‑call : « si après la release 1.4.0 tout brûle, revenir au déploiement X ».

Deuxième levier rapide — les feature flags. Si seule la nouvelle fonctionnalité (checkout-v2) tombe en panne, il est plus simple de la désactiver via un flag que d’annuler toute la release.

Changements à risque : manifestes et schémas

Avec les manifestes et les schémas, c’est plus compliqué. Si vous avez publié dans le Store un nouveau manifeste avec un schéma erroné, et qu’il a déjà été approuvé par OpenAI, le rollback peut prendre des jours. Raison simple : chaque changement de manifeste passe également par une revue OpenAI. Les analyses de différents Stores précisent que les changements de manifeste et de schémas sont des releases « à risque », à préparer et tester avec une attention particulière.

Il vaut donc mieux distinguer :

  • releases sûres : changements de code MCP/Next.js, ajustements de prompts, nouvelles fonctionnalités cachées derrière des flags ;
  • releases à risque : changements dans la liste des tools, schémas input/output, contrats ACP.

Les releases « à risque » devraient être déployées séparément, avec des vérifications supplémentaires et, éventuellement, d’abord uniquement via le Dev Mode et une App de staging (sans publication dans le Store).

Rollback des données et du feed

Avec les données, c’est encore plus compliqué (et douloureux). Si vous avez migré le product feed vers un nouveau schéma en en supprimant les anciens champs, revenir en arrière n’est pas toujours trivial. Les migrations de données doivent donc être idempotentes et réversibles : soit vous conservez une copie ancienne, soit vous faites une migration en deux étapes (d’abord dupliquer les données, puis basculer la lecture).

Une approche simple — conserver en parallèle anciens et nouveaux champs pendant un certain temps et vous donner la possibilité de basculer entre eux via un feature flag. Si quelque chose se casse — vous revenez simplement à l’ancienne lecture.

8. Mini‑design d’un processus de release pour GiftGenius

Assemblons tout ce dont nous avons parlé ci‑dessus (versions, migrations de SDK, feature flags, rollback) en un scénario pratique.

Imaginons que vous préparez la release 1.4.0, dans laquelle :

  • vous ajoutez un nouvel outil suggest_gifts_v2 avec un input étendu ;
  • vous activez un nouveau system‑prompt pour une partie des utilisateurs ;
  • vous mettez à jour MCP SDK de 0.30.4 ;
  • vous changez le format du product feed (ajout d’un champ tags).

Un plan raisonnable ressemblerait à ceci.

D’abord une release technique séparée 1.3.1 : mise à jour du MCP SDK + corrections minimales du code, sans changement de schémas ni de fonctionnalités. Vous exécutez le CI, le staging, les tests smoke. Si tout est stable — vous vivez avec cela quelques jours.

Ensuite, une branche feature/reco-v2. Vous y ajoutez suggest_gifts_v2 en tant que nouvel outil (l’ancien suggest_gifts reste). Son schéma d’input s’étend uniquement par l’ajout de nouveaux champs optionnels. Vous préparez un nouveau system‑prompt, mais vous l’entourez d’un flag GG_PROMPT_V3. Dans ACP/le feed, vous ajoutez le nouveau champ tags comme non obligatoire, et vous codez la lecture de manière à ce qu’en son absence tout continue de fonctionner.

Dans le CI, vous ajoutez quelques nouveaux tests de contrat : que suggest_gifts_v2 accepte l’ancien et le nouveau payload, que le feed avec tags est valide, mais que les enregistrements anciens sans tags ne cassent pas non plus le serveur.

Après le merge dans main :

  • le CI exécute les tests unitaires/contrats ;
  • sur staging, 12 scénarios E2E sont lancés via le nouvel outil ;
  • vous activez le nouveau prompt et le nouvel outil uniquement pour un tenant de test via un feature flag.

Surveillez les métriques : p95 de l’outil, taux d’erreur, conversion vers le checkout. Si tout va bien — élargissez le flag à davantage d’utilisateurs. Et seulement ensuite, une fois la stabilité confirmée, mettez à jour le manifeste pour le Store (si nécessaire) et la description marketing de l’application.

Si quelque chose casse en chemin — vous savez comment revenir en arrière : soit vous désactivez le flag, soit vous annulez le déploiement, soit, en dernier recours, vous revenez à une version antérieure du manifeste (mais c’est précisément le cas qu’il vaut mieux éviter).

9. Erreurs courantes dans le processus de release d’une ChatGPT App

Erreur n° 1 : une « version d’App » abstraite au lieu d’une matrice de versions.
Lorsque vous n’avez que « GiftGenius v1.4 », mais qu’aucune version des schémas de tools, des prompts et du product feed n’est consignée, vous ne pourrez pas répondre ensuite à la question : « après quel changement précis notre checkout a‑t‑il chuté ? » Séparez les versions par couche et loguez‑les dans des logs structurés.

Erreur n° 2 : des breaking changes dans les tools sans nouveau nom/version.
Le plus douloureux : vous avez renommé un champ dans le schéma d’input ou l’avez supprimé, sans changer le nom de l’outil. Dans les anciens chats, le modèle continue d’envoyer l’ancien payload, le backend renvoie 400, GPT commence à « halluciner » en réponse, les utilisateurs ne comprennent rien. Tout changement cassant doit se faire via un nouvel outil (foo_v2) ou une nouvelle version d’API, tandis que l’ancienne interface reste disponible pendant la période de transition.

Erreur n° 3 : mise à jour du SDK « en passant » vers une fonctionnalité.
Classique : vous ajoutez une nouvelle fonctionnalité métier et, en chemin, vous mettez à jour @modelcontextprotocol/sdk de 0.3 à 0.5 « pour avoir du frais ». Au final, si quelque chose casse, il est difficile de savoir si le fautif est le nouveau code, le nouveau schéma ou le nouveau SDK. Les migrations de SDK devraient être faites dans des releases techniques séparées, avec un plan de test clair et une possibilité de rollback.

Erreur n° 4 : absence de feature flags et de kill‑switch instantanés.
Déployer un nouvel algorithme de recommandation directement sur 100% des utilisateurs — c’est amusant, jusqu’à ce qu’il commence à donner des résultats étranges ou à faire tomber un service externe. Sans feature flag, votre seul levier est un rollback complet de la release, qui peut impacter non seulement la nouvelle fonctionnalité, mais aussi une dizaine de petites améliorations. Mettez en place au moins des flags simples via des variables d’environnement ou un petit fichier de config.

Erreur n° 5 : compter sur une mise à jour « instantanée » du manifeste.
Une idée répandue — penser que dès que vous changez les tools ou le openapi.yaml, le modèle connaît immédiatement le nouveau schéma. En pratique, le manifeste et les descriptions des tools sont mis en cache, et, dans les chats déjà ouverts, ils peuvent rester longtemps. Ignorer ce fait mène à des bugs subtils : ça marche dans les nouveaux chats, ça casse dans les anciens. Planifiez les changements de schéma en tenant compte de ce comportement et testez‑les via le Dev Mode et le staging avant de publier dans le Store.

Erreur n° 6 : absence d’un plan de rollback clair et de documentation de release.
Si personne dans votre équipe ne peut répondre aux questions « comment annuler une release en 5 minutes ? », « vers quelle version allons‑nous revenir ? », « comment revenir à l’ancien schéma du feed ? » — considérez que vous n’avez pas de rollback. L’on‑call doit disposer d’un scénario court mais concret : quels boutons cliquer, quelles variables changer et où vérifier que le rollback a fonctionné.

Erreur n° 7 : des releases « muettes » sans release notes ni lien avec les métriques.
Publier des releases sans le moindre changelog — c’est se condamner aux devinettes dans quelques mois. Quand le p95 augmente soudain et que la conversion chute, vous vous demanderez : « qu’est‑ce qui a changé à ce moment‑là ? » L’habitude de rédiger au moins des notes de release minimales et de les relier aux dates de déploiement et aux versions facilite non seulement l’audit de la qualité, mais aussi la vie de toute l’équipe.

Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION