CodeGym /Cursos /ChatGPT Apps /Proceso de release — versiones, notas, migraciones de SDK...

Proceso de release — versiones, notas, migraciones de SDK/spec, feature flags, rollback

ChatGPT Apps
Nivel 17 , Lección 3
Disponible

1. Por qué el proceso de release para ChatGPT App es más complejo que un deploy normal

En la parte anterior del módulo hablamos de cómo observar la calidad y la estabilidad de la App (logs, métricas, SLO). Ahora veamos cómo organizar el propio proceso de release para que esas métricas no se rompan en cada deploy.

En una aplicación web normal todo es más o menos sencillo: desplegáis una nueva versión del backend y del frontend — el usuario actualiza la página y ya usa la versión nueva. Si algo se rompe, a menudo basta con revertir el deploy.

En ChatGPT App la pila es más caprichosa. Tenéis como mínimo cuatro capas que viven vidas distintas:

  • Manifiesto y esquema de herramientas (MCP tools / OpenAPI);
  • Infraestructura: aplicación Next.js y servidor MCP/Agents/ACP;
  • System‑prompt y otros prompts;
  • Datos: product feed, ajustes, configs.

El problema es que el modelo vive en su propio «mundo mental». El contexto del chat puede alargarse horas y días. El manifiesto y las descripciones de tools se cargan y se cachean por parte de OpenAI y no se actualizan al instante en todos los diálogos existentes. Si vais y cambiáis la signatura de una herramienta (por ejemplo, elimináis un campo del input‑schema), en los chats antiguos el modelo seguirá enviando el payload viejo, y vuestro backend nuevo lo rechazará. Resultado: errores 400, respuestas raras en el chat y usuarios muy tristes.

Por eso, en el mundo de ChatGPT App «release» no es solo «desplegar un Docker nuevo». Es un cambio coordinado de varias capas, con gestión cuidadosa de versiones, feature flags y capacidad de rollback.

2. Matriz de versiones: qué versionar en realidad

Es útil mirar no solo «la versión de la App 1.3», sino directamente una matriz de versiones por capas. Para GiftGenius sería algo así.

Capa Qué versionamos Ejemplo de valor Dónde guardar
App / Next.js Código y build
giftgenius-app 1.4.2
package.json, tag de Git
MCP / interfaz de API Conjunto de tools y sus esquemas
tools-schema v1.7
constante en el código, anotaciones
System / prompts System‑prompt, helpers, ejemplos
prompt v3.1
archivos separados + metadatos
Commerce / ACP / feed Formato del product feed y contratos ACP
feed v2, acp v1.3
esquema en el repositorio de datos

Fijaos: son ejes distintos. Podéis publicar la versión 1.4.2 de la aplicación, en la que el schema de tools siga en v1.7, mientras que el prompt pase a v3.2. Esto debería verse en los logs; así luego es más fácil entender por qué después de prompt v3.2 de repente cayó la conversión de checkout.

Para el código conviene usar versionado semántico (SemVer): MAJOR.MINOR.PATCH. MAJOR: cambio incompatible; MINOR: funcionalidades nuevas sin romper; PATCH: correcciones de bugs. Para versiones de interfaz (schema, prompts) la lógica es parecida: MAJOR señala breaking change.

Conviene destacar por separado la versión de la interfaz de tools. Para una LLM es crítico: si cambiáis el contrato de la herramienta mientras el modelo «cree» que el contrato es el viejo, empieza la diversión. Por eso la política suele ser: en releases MINOR solo añadimos campos nuevos opcionales y no renombramos/ni eliminamos los antiguos; los cambios incompatibles — solo a través de una herramienta nueva, por ejemplo suggest_gifts_v2.

Ahora que separamos las capas por versiones, veamos cómo «viven» esas versiones en el ciclo de release — de dev a prod.

3. Flujo básico de release para GiftGenius

Primero, pongámonos de acuerdo en las etapas. Seguramente ya tenéis entornos (del módulo sobre deploy), pero ahora mirémoslos a través del prisma de los releases.

Normalmente se distinguen:

  • dev — desarrollo local, Dev Mode en ChatGPT, túneles;
  • staging — lo más parecido a prod: mismo tipo de base de datos, mismo tipo de MCP/ACP, pero datos de prueba y pagos en sandbox;
  • prod — entorno de producción, al que está conectado el ChatGPT App de producción / listado en la Store.

El proceso puede verse así:

flowchart TD
  A[Dev: rama feature/*] --> B[PR → main]
  B --> C[CI: unit + contract + lint]
  C --> D[Deploy to Staging]
  D --> E[Smoke/E2E + verificación manual]
  E --> F[Deploy to Prod]
  F --> G[Monitorización por métricas y logs]

En cada paso añadimos «salvaguardas». En el entorno dev el desarrollador puede hacer lo que quiera, pero cada merge en main dispara el CI, que ejecuta tests unit/contract. Si todo va bien — desplegamos automáticamente a staging. En staging ejecutamos un conjunto corto de escenarios E2E/smoke: por ejemplo, un flujo completo de selección de regalo y un checkout «falso» en el procesador de pagos de prueba.

Y solo después de esto pulsamos el botón de deploy en prod. Idealmente — con etiqueta de versión y enlace a CHANGELOG. Ya en prod seguimos mirando p95, error rate y métricas de negocio (conversión de recomendación a checkout). Si algo cae después del release — debemos tener un plan de rollback claro, del que hablaremos más abajo.

4. Release notes y changelog: qué registrar exactamente

Si no tienes notas de release, dentro de un mes estarás mirando un gráfico: «¿por qué hace 3 semanas nuestro p95 de checkout se duplicó?» y respondiéndote «ni idea, pero hicimos un release grande». No es la mejor estrategia.

Normalmente hay al menos dos tipos de notas.

Changelog interno — técnico. Lo necesitan los desarrolladores, SRE y todos los que tocan el código. Ahí se escribe qué funcionalidades aparecieron, qué bugs se corrigieron, si hubo breaking changes. El formato puede seguir el canon de Keep a Changelog: secciones Added, Changed, Fixed, Removed.

Release notes externas — notas legibles para usuarios y para la Store. No hace falta escribir «migrate MCP SDK 0.40.5»; mejor escribe «Añadimos recomendaciones para la festividad de Thanksgiving», «Corregimos un bug raro por el que algunos regalos no se añadían al carrito».

Ejemplo de fragmento de CHANGELOG.md para GiftGenius:

## [1.4.0] - 2025-11-20
### Added
- Nueva tool `suggest_gifts_v2` con soporte de etiquetas de intereses.
- Test A/B de un nuevo system-prompt (flag: GG_PROMPT_V3).

### Changed
- Mejora del manejo de errores del checkout de ACP (mensajes más amigables).

### Fixed
- Se corrige un bug por el que los productos sin imagen se ocultaban de las recomendaciones.

Es útil guardar cerca también la versión del prompt: aunque sea solo el hash de commit del archivo con el system‑prompt, que luego permita recordar: «ajá, después del prompt b3f9c2d los usuarios pulsaban con menos frecuencia «Comprar»».

5. Migraciones de SDK y especificaciones: cómo vivir en un ecosistema que cambia rápido

El ecosistema alrededor de Apps SDK, MCP y Agents evoluciona rápido: nuevas versiones de SDK, cambios en el protocolo MCP, actualizaciones de ACP, etc. Eso es bueno (aparecen posibilidades), pero también doloroso: también se puede romper rápido.

Pinning de versiones y «no actualizar el mismo día del release»

Primera recomendación simple: fija las versiones de dependencias. No ^0.4.0, sino 0.4.0. Para SDK que rompen a menudo el API (MCP/Agents/Apps SDK), esto es especialmente crítico. He revisado estudios sobre este tema, y en ellos se destaca el fenómeno «SDK fatigue» — cansancio por actualizaciones incompatibles constantes, que sienten especialmente quienes dejaron dependencias con versiones flotantes (tipo ^0.4.0) y un día se encontraron de golpe con un montón de errores tras npm install.

Mini‑ejemplo:

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

Segunda recomendación: no juntes en el mismo release funcionalidades de negocio y migraciones grandes de SDK. Si necesitas actualizar MCP SDK de 0.3.x a 0.4.x, mejor haz un release técnico separado: primero actualización del SDK, tests y estabilización, y ya después — el nuevo flujo de checkout.

Estrategia de migración de SDK

Un plan razonable suele verse así:

En el entorno dev creas una rama aparte upgrade/mcp-sdk-0.4. Actualizas la dependencia, corriges el código, ejecutas todos los tests unit/contract, y localmente pasas el flujo principal de GiftGenius por Dev Mode.

Luego despliegas esa rama en una URL de staging separada y ejecutas allí tests E2E/smoke. Incluso puedes hacer una pequeña prueba de carga: 50100 llamadas a suggest_gifts seguidas.

Si todo va bien — haces merge en main, despliegas en el staging principal, vuelves a ejecutar smoke, y solo después — a prod.

Si no — tienes un rollback obvio: simplemente no hacer merge de esa rama o revertirla. En eso consiste separar las migraciones de SDK de los releases de producto.

Migraciones de esquemas de tools y API

La parte más desagradable son los cambios de interfaz: el modelo no se entera al instante de ellos. Los estudios sobre el tema destacan una regla importante: «Amplía, pero no rompas» (additive‑only). Si necesitas añadir en suggest_gifts un argumento nuevo interests: string[], hazlo opcional y no obligatorio; los escenarios antiguos seguirán funcionando.

Ejemplo de evolución de un esquema Zod para los datos de entrada:

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

// v1.1 (se añadieron campos opcionales)
const suggestGiftsInputV1_1 = suggestGiftsInputV1.extend({
  interests: z.array(z.string()).optional(),
  occasion: z.string().optional()
});

Fíjate: no tocamos los campos existentes, solo ampliamos.

Si realmente necesitas romper el contrato (por ejemplo, reemplazar budget por minBudget + maxBudget), mejor crea una herramienta nueva suggest_gifts_v2 e indica en la descripción que es una versión mejorada. El API antiguo puede quedar como deprecated y desactivarse gradualmente, cuando compruebes que el modelo y los usuarios se han migrado.

Migraciones de datos: product feed y ACP

Ya hablamos de migraciones de SDK y de esquemas de tools. El product feed — también es un contrato. Si cambias el formato de SKU, divisas, localizaciones, hay que hacerlo de forma coordinada: actualizar el esquema del feed, el tratamiento en MCP/ACP y cualquier preprocesador. En la documentación de commerce para ChatGPT App se señala que errores en el feed (campos corruptos, duplicados, precios extraños) pueden matar la calidad de las recomendaciones incluso con código perfecto.

Enfoque típico:

  1. Primero añades campos nuevos al esquema del feed como opcionales y enseñas a GiftGenius a usarlos si están presentes.
  2. Luego actualizas el pipeline que construye el feed para que empiece a rellenar esos campos.
  3. Ejecutas un validador del feed (tests de contrato sobre datos) y solo después empiezas a depender de esos campos en la lógica.

6. Feature flags: separamos deploy de release

Los feature flags — uno de los instrumentos clave para sobrevivir en el mundo de ChatGPT App. La idea principal es simple: despliegas el código, pero no necesariamente activas la funcionalidad nueva de inmediato. Primero vive «bajo bandera» — activada solo para desarrolladores, o para el 1% de usuarios, o directamente desactivada.

Esto es especialmente importante cuando:

  • publicas un algoritmo nuevo de recomendaciones;
  • cambias el system‑prompt (que puede modificar radicalmente el comportamiento del modelo);
  • conectas una herramienta cara o lenta;
  • experimentas con un flujo de checkout nuevo.

Flag sencillo mediante variables de entorno

En el mínimo, un feature flag puede hacerse con una variable de entorno:

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

Luego, en el código de la herramienta MCP, puedes usarlo así:

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

Ventaja de este enfoque — simplicidad. Desventaja — cambiar flags en runtime es más difícil: hay que desplegar un entorno nuevo o, como mínimo, reinicializar.

Helper centralizado con contexto

Un enfoque un poco más maduro — tener un helper centralizado, que tenga en cuenta no solo flags globales, sino también el contexto del usuario (tenant, segmento, grupo 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 {
  // aquí puede haber lógica: env, BD, servicio externo de flags
  if (feature === "new-reco") {
    return process.env.GG_NEW_RECO === "1";
  }
  return false;
}

En el handler de MCP:

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

Si algún día conectas un servicio externo de flags (LaunchDarkly, Statsig, etc.), bastará con cambiar la implementación de isFeatureEnabled, y no todo el código.

Ejemplos de escenarios para GiftGenius

Test A/B de system‑prompt. Creas PROMPT_V2 y lo activas solo para el 10% de los usuarios con tenantId en una lista determinada. Al mismo tiempo, los tools de MCP y el widget no cambian, y comparas la conversión.

Kill switch para una herramienta cara. Supongamos que hiciste una herramienta que hace una llamada externa compleja (por ejemplo, a algún modelo ML de recomendaciones, que es caro). Si ese servicio externo empieza a fallar o encarece de golpe, quieres poder desactivarlo en un segundo, sin parar GiftGenius entero. Un feature flag — la forma más sencilla.

Rollout gradual de un checkout nuevo. Primero activas Checkout v2 solo para empleados de la empresa y un par de clientes de confianza. Si las métricas están bien — amplías la audiencia hasta activarlo para todos.

7. Rollback: cómo revertir rápido cuando todo arde

Incluso con tests y flags perfectos algo se romperá. Importa tener una estrategia clara: qué haces en los primeros 515 minutos tras ver un pico de errores o una caída de métricas.

Rollback rápido del código

Si el problema es un bug puramente técnico (NPE, variable errónea, URL incorrecta de un servicio externo), normalmente basta con volver al deployment anterior. Por ejemplo, en Vercel hay rollback instantáneo al deployment previo.

Tu tarea — saber siempre qué deployment corresponde a qué versión y cómo revertirlo. Idealmente esto está descrito en el README para on‑call: «si después del release 1.4.0 todo arde, revertir al deployment X».

La segunda palanca rápida — los feature flags. Si solo cayó la funcionalidad nueva (checkout-v2), te será más fácil desactivarla con un flag que revertir todo el release.

Cambios peligrosos: manifiestos y esquemas

Con manifiestos y esquemas es más complicado. Si subiste a la Store un manifiesto nuevo con un esquema de tools incorrecto, y OpenAI ya lo aprobó, el rollback puede tardar días. La razón es sencilla: cada cambio de manifiesto también pasa por revisión de OpenAI. En analíticas de distintas Stores se dice claramente que los cambios de manifiesto y de esquemas son releases «peligrosos», que hay que preparar y probar con especial cuidado.

Por eso conviene separar:

  • releases seguros: cambios en el código de MCP/Next.js, ajustes de prompts, funcionalidades nuevas escondidas tras flags;
  • releases peligrosos: cambios en la lista de tools, en los esquemas de input/output, en los contratos ACP.

Los releases «peligrosos» conviene desplegarlos aparte, con comprobaciones adicionales y, posiblemente, primero solo a través de Dev Mode y una App de staging (sin publicación en la Store).

Rollback de datos y del feed

Con los datos la situación es aún más compleja (y dolorosa). Si migraste el product feed a un esquema nuevo y eliminaste campos antiguos, volver atrás no siempre es trivial. Por eso las migraciones de datos deben ser idempotentes y reversibles: o guardas una copia antigua, o haces la migración en dos pasos (primero duplicas los datos, luego cambias la lectura).

Un enfoque sencillo — mantener durante un tiempo los campos antiguos y nuevos en paralelo y darte la posibilidad de conmutar entre ellos mediante un feature flag. Si algo cae — vuelves simplemente a la lectura antigua.

8. Mini‑diseño del proceso de release para GiftGenius

Vamos a reunir todo lo que comentamos arriba (versiones, migraciones de SDK, feature flags, rollback) en un único escenario práctico.

Imaginemos que estás preparando el release 1.4.0, en el que:

  • añades una herramienta nueva suggest_gifts_v2 con input ampliado;
  • activas un system‑prompt nuevo para parte de los usuarios;
  • actualizas MCP SDK de 0.30.4;
  • cambias el formato del product feed (añades el campo tags).

Un plan razonable se vería así.

Primero, un release técnico separado 1.3.1: actualización de MCP SDK + correcciones mínimas de código, sin cambios de esquemas ni funcionalidades. Ejecutas CI, staging, tests smoke. Si todo es estable — convives con ello un par de días.

Luego la rama feature/reco-v2. Ahí añades suggest_gifts_v2 como herramienta nueva (la antigua suggest_gifts permanece). Su esquema de entrada se amplía solo añadiendo campos opcionales nuevos. Preparas el system‑prompt nuevo, pero lo envuelves en el flag GG_PROMPT_V3. En ACP/feed añades el campo nuevo tags como no obligatorio, y haces la lectura de forma que, si falta, todo siga funcionando.

En el CI añades varios tests de contrato nuevos: que suggest_gifts_v2 acepta payloads viejos y nuevos, que un feed con tags es válido, pero que los registros antiguos sin tags tampoco rompen el servidor.

Tras el merge en main:

  • el CI ejecuta unit/contract;
  • en staging se lanzan 12 escenarios E2E a través de la herramienta nueva;
  • activas el prompt y la herramienta nuevos solo para un tenant de pruebas mediante feature flag.

Observas las métricas: p95 de la herramienta, error rate, conversión a checkout. Si todo está bien — amplías el flag a más usuarios. Y solo después, cuando confirmes la estabilidad, actualizas el manifiesto para la Store (si hace falta) y la descripción promocional de la aplicación.

Si en algún punto algo se rompe — sabes cómo revertir: o desactivas el flag manualmente, o haces rollback del deployment, o, en casos extremos, vuelves atrás con la versión del manifiesto (pero ese es el caso que mejor no permitir nunca).

9. Errores típicos en el proceso de release de una ChatGPT App

Error n.º 1: una «versión de App» abstracta en lugar de una matriz de versiones.
Cuando solo tienes «GiftGenius v1.4», pero en ningún sitio están fijadas las versiones del esquema de tools, de los prompts y del product feed, luego no podrás responder a la pregunta: «¿después de qué cambio exactamente cayó nuestro checkout?» Separa las versiones por capas y regístralas en logs estructurados.

Error n.º 2: cambios incompatibles en tools sin nombre/versión nuevos.
Lo más doloroso: fuiste y renombraste un campo en el esquema de input o lo eliminaste, sin cambiar el nombre de la herramienta. En los chats antiguos el modelo sigue enviando el payload viejo, el backend devuelve 400, GPT empieza a «alucinar» en la respuesta, y los usuarios no entienden nada. Cualquier cambio incompatible hazlo mediante una herramienta nueva (foo_v2) o una versión nueva del API, y deja la interfaz antigua durante un periodo de transición.

Error n.º 3: actualizar el SDK «de camino» hacia una funcionalidad.
Un clásico: añades una funcionalidad nueva de negocio y, de paso, actualizas @modelcontextprotocol/sdk de 0.3 a 0.5 «para tenerlo fresquito». Al final, si algo se rompe, no está claro si la culpa es del código nuevo, del esquema nuevo o del SDK nuevo. Las migraciones de SDK es mejor hacerlas como releases técnicos separados, con un plan de tests claro y con posibilidad de rollback.

Error n.º 4: ausencia de feature flags y de kill switches instantáneos.
Desplegar un algoritmo de recomendaciones nuevo directamente al 100% de los usuarios — es divertido hasta que empieza a dar resultados raros o tumba un servicio externo. Sin feature flag tu única palanca es el rollback completo del release, que puede afectar no solo a la funcionalidad nueva, sino también a una decena de mejoras inocuas. Implementa al menos flags sencillos mediante variables de entorno o un pequeño config.

Error n.º 5: confiar en una actualización «instantánea» del manifiesto.
Una creencia común — pensar que en cuanto cambias los tools o el openapi.yaml, el modelo se entera enseguida del esquema nuevo. En la práctica, el manifiesto y las descripciones de tools se cachean, y en chats ya abiertos pueden vivir mucho tiempo. Ignorar esto lleva a bugs no obvios: en chats nuevos todo funciona, en los antiguos — falla. Planifica los cambios de esquemas teniendo en cuenta este comportamiento y pruébalos mediante Dev Mode y staging antes de publicarlos en la Store.

Error n.º 6: falta de un plan claro de rollback y de documentación de releases.
Si en tu equipo nadie puede responder a «¿cómo revertir un release en 5 minutos?», «¿a qué versión revertiremos?», «¿cómo volver al esquema antiguo del feed?» — cuenta con que no tienes rollback. El on‑call debe tener un guion corto pero concreto: qué botones pulsar, qué variables cambiar y dónde comprobar que el rollback funcionó.

Error n.º 7: releases «mudos» sin release notes y sin vínculo con métricas.
Publicar releases sin nada de changelog — significa que dentro de unos meses vivirás en modo adivinanzas. Cuando el p95 subió de repente y la conversión cayó, estarás preguntándote: «¿qué cambió entonces?» El hábito de escribir aunque sea notas de release mínimas y vincularlas con fechas de deploy y versiones facilita no solo la auditoría de calidad, sino también la vida de todo el equipo.

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