CodeGym /Corsi /ChatGPT Apps /Processo di release — versioni, note, migrazioni SDK/spec...

Processo di release — versioni, note, migrazioni SDK/specifiche, feature flags, rollback

ChatGPT Apps
Livello 17 , Lezione 3
Disponibile

1. Perché il processo di release per ChatGPT App è più complesso di un normale deploy

Nella parte precedente del modulo abbiamo parlato di come osservare qualità e stabilità dell’App (log, metriche, SLO). Ora vediamo come organizzare il processo di release in modo che queste metriche non si deteriorino a ogni deploy.

In una normale applicazione web è tutto relativamente semplice: fate il deploy della nuova versione di backend e frontend — l’utente aggiorna la pagina e passa alla nuova versione. Se qualcosa si rompe, spesso basta eseguire il rollback del deploy.

Nelle ChatGPT App lo stack è più complesso. Ci sono almeno quattro layer che “vivono vite” diverse:

  • Manifest e schema degli strumenti (MCP tools / OpenAPI);
  • Infrastruttura: applicazione Next.js e server MCP/Agents/ACP;
  • System prompt e altri prompt;
  • Dati: product feed, impostazioni, configurazioni.

Il problema è che il modello vive nel suo “mondo mentale”. Il contesto della chat può protrarsi per ore o giorni. Il manifest e le descrizioni dei tools vengono caricati e memorizzati in cache lato OpenAI e non si aggiornano istantaneamente in tutte le conversazioni esistenti. Se cambiate la signature di uno strumento (ad esempio, rimuovete un campo dallo schema di input), nelle chat vecchie il modello continuerà a inviare il payload precedente, mentre il vostro nuovo backend lo rifiuterà. Risultato — errori 400, risposte strane in chat e utenti molto frustrati.

Perciò, nel mondo delle ChatGPT App, una “release” non è semplicemente “fare il deploy di un nuovo Docker”. È un cambiamento coordinato di più layer, con una gestione attenta delle versioni, dei feature flag e con la possibilità di fare rollback.

2. Matrice delle versioni: cosa versionare

È utile guardare non solo alla “versione dell’App 1.3”, ma direttamente a una matrice di versioni per layer. Per GiftGenius è più o meno così.

Layer Cosa versioniamo Esempio di valore Dove conservarlo
App / Next.js Codice e build
giftgenius-app 1.4.2
package.json, tag Git
MCP / interfaccia API Set di tools e i loro schemi
tools-schema v1.7
costante nel codice, annotazioni
System / prompts System prompt, helper, esempi
prompt v3.1
file separati + metadati
Commerce / ACP / feed Formato del product feed e contratti ACP
feed v2, acp v1.3
schema nel repository dei dati

Notate che sono assi diversi. Potete rilasciare la versione 1.4.2 dell’applicazione in cui lo schema dei tools rimane v1.7, mentre il prompt passa a v3.2. Questo dovrebbe essere visibile nei log; così è più facile capire in seguito perché dopo prompt v3.2 è improvvisamente calata la conversione al checkout.

Per il codice conviene usare il versioning semantico (SemVer): MAJOR.MINOR.PATCH. MAJOR — cambiamento breaking, MINOR — nuove feature senza rotture, PATCH — bugfix. Per le versioni di interfaccia (schema, prompt) la logica è simile: MAJOR segnala un breaking change.

Conviene evidenziare separatamente la versione dell’interfaccia dei tools. Per una LLM è critico: se cambiate il contratto di uno strumento mentre il modello “pensa” che il contratto sia quello vecchio, inizia il divertimento. Perciò la policy di solito è: nelle release MINOR aggiungiamo solo nuovi campi opzionali e non rinominiamo/non rimuoviamo quelli esistenti; i cambiamenti breaking — solo tramite un nuovo strumento, ad esempio suggest_gifts_v2.

Ora che abbiamo separato i layer per versione, vediamo come queste versioni “vivono” nel ciclo di rilascio — da dev a prod.

3. Release flow di base per GiftGenius

Prima accordiamoci sulle fasi. Probabilmente avete già ambienti (dal modulo sul deploy), ma ora li guardiamo attraverso la lente delle release.

Di solito si distinguono:

  • dev — sviluppo locale, Dev Mode in ChatGPT, tunnel;
  • staging — il più simile possibile al prod: stesso tipo di database, stesso tipo di MCP/ACP, ma dati di test e pagamenti in sandbox;
  • prod — ambiente di produzione, quello a cui è collegata la ChatGPT App di produzione / il listing nello Store.

Il processo può essere così:

flowchart TD
  A[Dev: branch feature/*] --> B[PR → main]
  B --> C[CI: unit + contract + lint]
  C --> D[Deploy to Staging]
  D --> E[Smoke/E2E + verifica manuale]
  E --> F[Deploy to Prod]
  F --> G[Monitoraggio tramite metriche e log]

A ogni passo aggiungiamo “sicurezze”. Nell’ambiente dev lo sviluppatore può fare di tutto, ma ogni merge in main attiva la CI, che esegue test unitari/di contratto. Se è tutto ok — facciamo automaticamente il deploy su staging. Su staging eseguiamo un breve set di scenari E2E/smoke: ad esempio, un flusso completo di scelta del regalo e un checkout “falso” nel sistema di pagamento di test.

Solo dopo premiamo il pulsante di deploy in prod. Preferibilmente — con l’indicazione della versione e un link al CHANGELOG. Già in produzione continuiamo a guardare p95, error rate e metriche di business (conversione da raccomandazione a checkout). Se dopo la release qualcosa peggiora — dobbiamo avere un piano di rollback chiaro, di cui parleremo sotto.

4. Note di rilascio e changelog: cosa annotare

Se non avete note di rilascio, tra un mese guarderete un grafico: “perché 3 settimane fa il nostro p95 del checkout è raddoppiato?” e vi risponderete “non ne ho idea, ma abbiamo fatto una grossa release”. Non è la strategia migliore.

Di solito ci sono almeno due tipi di note.

Changelog interno — tecnico. Serve a sviluppatori, SRE e a chi mette mano al codice. Si annota quali feature sono arrivate, quali bug sono stati risolti, se ci sono stati breaking changes. Il formato si può prendere dal canone Keep a Changelog: sezioni Added, Changed, Fixed, Removed.

Note di rilascio esterne — note leggibili per utenti e per lo Store. Non serve scrivere “migrate MCP SDK 0.40.5”; meglio “Aggiunte raccomandazioni per la festività del Thanksgiving”, “Corretto un bug raro per cui alcuni regali non venivano aggiunti al carrello”.

Esempio di frammento di CHANGELOG.md per GiftGenius:

## [1.4.0] - 2025-11-20
### Added
- Nuovo tool `suggest_gifts_v2` con supporto per i tag di interessi.
- Test A/B del nuovo system prompt (flag: GG_PROMPT_V3).

### Changed
- Migliorata la gestione degli errori del checkout ACP (messaggi più amichevoli).

### Fixed
- Corretto un bug a causa del quale i prodotti senza immagine venivano nascosti dalle raccomandazioni.

È utile conservare da qualche parte anche la versione del prompt: anche solo l’hash del commit del file con il system prompt, che poi potete ricordare: “ok, dopo il prompt b3f9c2d gli utenti hanno cliccato “Compra” meno spesso”.

5. Migrazioni di SDK e specifiche: come vivere in un ecosistema che cambia rapidamente

L’ecosistema attorno a Apps SDK, MCP e Agents evolve rapidamente: nuove versioni di SDK, cambiamenti del protocollo MCP, aggiornamenti di ACP, ecc. Questo è positivo (arrivano nuove possibilità), ma anche doloroso: si può rompere tutto, e in fretta.

Pinning delle versioni e «non aggiorniamo nel giorno del rilascio»

La prima raccomandazione semplice: fissate (pin) le versioni delle dipendenze. Non ^0.4.0, ma 0.4.0. Per gli SDK che rompono spesso le API (MCP/Agents/Apps SDK), è particolarmente critico. Ho studiato ricerche sul tema, e vi si evidenzia il fenomeno della “SDK fatigue” — la fatica dovuta a update incompatibili continui, che colpisce soprattutto chi ha lasciato dipendenze a versione flottante (tipo ^0.4.0) e si è ritrovato di colpo un mucchio di errori dopo un npm install.

Mini‑esempio:

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

Seconda raccomandazione: non mescolate nello stesso rilascio le feature di business e grandi migrazioni dell’SDK. Se dovete aggiornare MCP SDK da 0.3.x a 0.4.x, è meglio fare un rilascio tecnico separato: prima l’aggiornamento dell’SDK, test e stabilizzazione, e solo dopo — il nuovo flusso di checkout.

Strategia di migrazione dell’SDK

Di solito un piano ragionevole è questo:

Nell’ambiente dev create un branch dedicato upgrade/mcp-sdk-0.4. Aggiornate la dipendenza, sistemate il codice, eseguite tutti i test unitari/di contratto, e in locale provate il flusso principale di GiftGenius tramite Dev Mode.

Poi fate il deploy di questo branch su un URL di staging separato ed eseguite su di esso i test E2E/smoke. Si può anche fare un piccolo test di carico: 50100 chiamate a suggest_gifts di fila.

Se è tutto ok — fate il merge in main, fate il deploy su staging principale, rifate lo smoke test, e solo dopo — in produzione.

Se non va — avete un rollback ovvio: basta non fare il merge di quel branch o revertarlo. Questo è proprio il senso di separare le migrazioni dell’SDK dai rilasci di prodotto.

Migrazioni degli schemi dei tools e delle API

La parte più spiacevole sono i cambiamenti di interfaccia: il modello non ne viene a conoscenza istantaneamente. Le ricerche sul tema sottolineano una regola importante: “Amplia, ma non rompere” (solo additiva). Se dovete aggiungere in suggest_gifts un nuovo argomento interests: string[], rendetelo opzionale, non obbligatorio; gli scenari vecchi continueranno a funzionare.

Esempio di evoluzione di uno schema Zod per i dati di input:

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

// v1.1 (aggiunti campi opzionali)
const suggestGiftsInputV1_1 = suggestGiftsInputV1.extend({
  interests: z.array(z.string()).optional(),
  occasion: z.string().optional()
});

Notate: non tocchiamo i campi esistenti, ma solo estendiamo.

Se invece dovete davvero rompere il contratto (ad esempio, sostituire budget con minBudget + maxBudget), è meglio creare un nuovo strumento suggest_gifts_v2 e indicare nella descrizione che è una versione migliorata. La vecchia API può rimanere come deprecata e spegnersi gradualmente, quando sarete certi che modello e utenti siano migrati.

Migrazioni dei dati: product feed e ACP

Abbiamo già parlato di migrazioni di SDK e schemi dei tools. Anche il product feed è un contratto. Se cambiate il formato di SKU, valute, localizzazioni, dovete farlo in modo coordinato: aggiornare lo schema del feed, l’elaborazione in MCP/ACP, e qualsiasi pre‑processor. Nella documentazione commerce per ChatGPT App si sottolinea che errori nel feed (campi rotti, duplicati, prezzi anomali) possono compromettere la qualità delle raccomandazioni anche con un codice perfetto.

Approccio tipico:

  1. Prima aggiungete i nuovi campi nello schema del feed come opzionali e insegnate a GiftGenius a usarli, se presenti.
  2. Poi aggiornate la pipeline che costruisce il feed in modo che inizi a valorizzare questi campi.
  3. Eseguite un validatore del feed (test di contratto sui dati) e solo dopo iniziate a dipendere da tali campi nella logica.

6. Feature flags: separiamo deploy da release

I feature flag — uno degli strumenti fondamentali per sopravvivere nel mondo delle ChatGPT App. L’idea base è semplice: fate il deploy del codice, ma non necessariamente attivate subito la nuova funzionalità. Prima vive “sotto un flag” — abilitata solo per gli sviluppatori, o per 1% degli utenti, o del tutto disattivata.

È particolarmente importante quando:

  • rilasciate un nuovo algoritmo di raccomandazione;
  • cambiate il system prompt (il che può cambiare radicalmente il comportamento del modello);
  • collegate uno strumento costoso o lento;
  • sperimentate con un nuovo flusso di checkout.

Flag semplice tramite variabili d’ambiente

Al minimo, un feature flag si può fare tramite una variabile d’ambiente:

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

Dopodiché nel codice dello strumento MCP potete usarlo così:

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

Pro di questo approccio — semplicità. Contro — è più complicato cambiare i flag a runtime: serve fare il deploy di un nuovo ambiente o almeno re‑inizializzare.

Helper centralizzato con contesto

Un approccio un po’ più maturo — avere un helper centralizzato che considera non solo flag globali, ma anche il contesto dell’utente (tenant, segmento, gruppo 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 {
  // qui può esserci logica: env, DB, servizio di flag esterno
  if (feature === "new-reco") {
    return process.env.GG_NEW_RECO === "1";
  }
  return false;
}

Nel gestore MCP:

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

Se un giorno collegherete un servizio di flag esterno (LaunchDarkly, Statsig, ecc.), vi basterà cambiare l’implementazione di isFeatureEnabled, non tutto il codice.

Esempi di scenari per GiftGenius

Test A/B del system prompt. Create PROMPT_V2 e lo abilitate solo per il 10% degli utenti con tenantId in un certo elenco. I tools MCP e il widget non cambiano, e voi confrontate la conversione.

Kill switch per uno strumento costoso. Supponiamo che abbiate costruito uno strumento che effettua una richiesta esterna complessa (ad esempio, a un modello ML di raccomandazione costoso). Se quel servizio esterno inizia a cadere o diventa improvvisamente troppo caro, volete disattivarlo in un secondo, senza fermare GiftGenius. Un feature flag è il modo più semplice.

Rollout graduale del nuovo flusso di checkout. Attivate prima Checkout v2 solo per i dipendenti dell’azienda e un paio di clienti fidati. Se le metriche sono ok — allargate il pubblico, finché non lo abilitate per tutti.

7. Rollback: come tornare indietro rapidamente quando tutto brucia

Anche con test e flag perfetti qualcosa si romperà. È importante avere una strategia chiara: cosa fate nei primi 515 minuti dopo che avete visto un picco di errori o un calo delle metriche.

Rollback veloce del codice

Se il problema è un bug puramente tecnico (NPE, variabile sbagliata, URL errato di un servizio esterno), di solito basta fare il rollback del deploy alla versione precedente. Ad esempio, su Vercel c’è il rollback istantaneo al deployment precedente.

Il vostro compito — sapere sempre quale deployment corrisponde a quale versione e come fare il rollback. Idealmente è descritto nel README per l’on‑call: “se dopo la release 1.4.0 è tutto in fiamme, tornare al deployment X”.

Seconda leva rapida — i feature flag. Se è caduta solo la nuova feature (checkout-v2), vi conviene disattivarla con il flag piuttosto che fare subito il rollback dell’intera release.

Cambiamenti pericolosi: manifest e schemi

Con manifest e schemi è più complicato. Se avete caricato nello Store un nuovo manifest con uno schema dei tools errato, e OpenAI lo ha già approvato, il rollback può richiedere giorni. La ragione è semplice: ogni cambiamento del manifest passa anch’esso attraverso la revisione di OpenAI. Nelle analisi di vari Store si dice esplicitamente che cambiamenti del manifest e degli schemi sono release “pericolose”, da preparare e testare con particolare attenzione.

Perciò è meglio separare:

  • release sicure: cambiamenti del codice MCP/Next.js, correzioni dei prompt, nuove feature nascoste dietro flag;
  • release pericolose: cambiamenti nell’elenco dei tools, negli schemi di input/output, nei contratti ACP.

Le release “pericolose” vanno distribuite separatamente, con controlli aggiuntivi e, possibilmente, prima solo tramite Dev Mode e una App di staging (senza pubblicazione nello Store).

Rollback dei dati e del feed

Con i dati è ancora più complicato (e doloroso). Se avete migrato il product feed a un nuovo schema e al contempo avete rimosso i campi vecchi, non è sempre banale tornare indietro. Perciò le migrazioni dei dati devono essere idempotenti e reversibili: o conservate una copia vecchia, oppure fate la migrazione in due passaggi (prima duplicate i dati, poi cambiate il read).

Un approccio semplice — mantenere in parallelo per un po’ i campi vecchi e nuovi e darvi la possibilità di passare dall’uno all’altro tramite un feature flag. Se qualcosa cade — tornate semplicemente alla lettura vecchia.

8. Mini‑design del processo di release per GiftGenius

Mettiamo insieme tutto ciò di cui abbiamo parlato (versioni, migrazioni dell’SDK, feature flag, rollback) in uno scenario pratico.

Immaginiamo che stiate lavorando alla release 1.4.0, in cui:

  • aggiungete un nuovo strumento suggest_gifts_v2 con input ampliato;
  • attivate un nuovo system prompt per una parte degli utenti;
  • aggiornate l’SDK MCP da 0.3 a 0.4;
  • modificate il formato del product feed (aggiungete il campo tags).

Un piano ragionevole sarebbe questo.

Prima una release tecnica separata 1.3.1: aggiornamento dell’SDK MCP + modifiche minime al codice, senza cambiamenti di schemi e feature. Eseguite CI, staging, smoke test. Se tutto è stabile — restate così per qualche giorno.

Poi branch feature/reco-v2. Lì aggiungete suggest_gifts_v2 come nuovo strumento (il vecchio suggest_gifts rimane). Il suo schema di input si espande solo aggiungendo campi opzionali. Preparate il nuovo system prompt, ma avvolgetelo nel flag GG_PROMPT_V3. In ACP/feed aggiungete il nuovo campo tags come non obbligatorio, e implementate la lettura in modo che in sua assenza tutto continui a funzionare.

In CI aggiungete alcuni nuovi test di contratto: che suggest_gifts_v2 accetti sia il payload vecchio che quello nuovo, che un feed con tags sia valido, ma che anche record vecchi senza tags non mandino in crash il server.

Dopo il merge in main:

  • la CI esegue unit/contract test;
  • su staging si eseguono 12 scenari E2E tramite il nuovo tool;
  • abilitate il nuovo prompt e tool solo per il tenant di test tramite feature flag.

Guardate le metriche: p95 dello strumento, error rate, conversione al checkout. Se è tutto ok — ampliate il flag a un numero maggiore di utenti. E solo dopo, quando vi siete assicurati della stabilità, aggiornate il manifest per lo Store (se necessario) e la descrizione promozionale dell’app.

Se lungo la strada qualcosa si rompe — sapete come tornare indietro: o disattivate a mano il flag, o fate il rollback del deployment, o, nei casi estremi, tornate alla versione precedente del manifest (ma questo è il caso che è meglio non ammettere affatto).

9. Errori tipici nel processo di release di una ChatGPT App

Errore n. 1: un’unica “versione dell’App” astratta invece della matrice di versioni.
Quando avete solo “GiftGenius v1.4”, ma non avete fissato da nessuna parte le versioni dello schema dei tools, dei prompt e del product feed, non riuscirete poi a rispondere alla domanda: “dopo quale cambiamento esatto è caduto il checkout?” Separate le versioni per layer e loggatele nei log strutturati.

Errore n. 2: cambiamenti breaking nei tools senza un nuovo nome/versione.
La parte più dolorosa: avete rinominato un campo nello schema di input o l’avete rimosso, senza cambiare il nome dello strumento. Nelle chat vecchie il modello continua a inviare il payload precedente, il backend restituisce 400, GPT inizia a “fantasticare” in risposta, gli utenti non capiscono nulla. Qualsiasi cambiamento breaking fatelo tramite un nuovo strumento (foo_v2) o una nuova versione dell’API, mentre l’interfaccia vecchia resta per un periodo di transizione.

Errore n. 3: aggiornare l’SDK “lungo la strada” verso una feature.
Classico: aggiungete una nuova feature di business e per strada aggiornate @modelcontextprotocol/sdk da 0.3 a 0.5 “così è tutto aggiornato”. Alla fine, se qualcosa si rompe, non è chiaro se il colpevole sia il codice nuovo, lo schema nuovo o l’SDK nuovo. Le migrazioni dell’SDK è meglio farle con release tecniche separate, con un piano di test chiaro e la possibilità di fare rollback.

Errore n. 4: assenza di feature flag e di kill switch istantanei.
Distribuire un nuovo algoritmo di raccomandazione subito al 100% degli utenti — è divertente finché non inizia a dare risultati strani o a mandare giù un servizio esterno. Senza feature flag, la vostra unica leva è il rollback completo della release, che può coinvolgere non solo la nuova feature ma anche una decina di miglioramenti innocui. Implementate almeno flag semplici tramite env o una piccola configurazione.

Errore n. 5: sperare in un aggiornamento “istantaneo” del manifest.
Idea diffusa — pensare che non appena cambiate i tools o openapi.yaml, il modello sappia subito del nuovo schema. In pratica, il manifest e le descrizioni dei tools sono in cache, e nelle chat già aperte possono vivere a lungo. Ignorare questo fatto porta a bug non ovvi: nelle chat nuove tutto funziona, in quelle vecchie — cade. Pianificate i cambiamenti degli schemi tenendo conto di questo comportamento e testateli tramite Dev Mode e staging prima di pubblicare nello Store.

Errore n. 6: assenza di un piano di rollback chiaro e di documentazione sulle release.
Se nel vostro team nessuno sa rispondere alle domande “come facciamo rollback in 5 minuti?”, “a quale versione torniamo?”, “come torniamo al vecchio schema del feed?” — considerate che non avete il rollback. L’on‑call deve avere uno scenario breve ma concreto: quali pulsanti premere, quali variabili cambiare e dove verificare che il rollback abbia funzionato.

Errore n. 7: release “mute” senza note di rilascio e senza collegamento alle metriche.
Rilasciare senza nemmeno un changelog — significa vivere tra qualche mese nel regime dei “indovina tu”. Quando il p95 cresce all’improvviso e la conversione cala, vi chiederete: “cosa è cambiato allora?”. L’abitudine di scrivere almeno note di rilascio minime e collegarle alle date di deploy e alle versioni facilita non solo l’audit della qualità, ma anche la vita di tutto il team.

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