Publicación y ciclo de vida de borradores
Qué es esto
Cómo un cambio pasa de ser una edición a una página publicada mediante MCP: el ciclo de vida del borrador, la publicación en dos pasos (realmente tres llamadas) y el hecho que confunde a los agentes: el ID del documento rota en cada publicación, por lo que la forma duradera de nombrar una página es mediante su slug + idioma, nunca su path.
Cómo funciona
Borradores
Editar una página activa nunca la modifica. update-page escribe un nuevo documento de borrador y mantiene la URL activa mostrando el contenido antiguo hasta que publiques. Dos propiedades son importantes:
- Buscar o crear. Las ediciones repetidas en el mismo
(slug, idioma)actualizan el mismo borrador; las ediciones secuenciales se consolidan en uno solo, no en una pila. - Sin cambios (Zero-diff) no hace nada. Una edición que no cambia nada no crea un borrador, y un borrador existente que es idéntico byte a byte al activo se elimina del manifiesto, del conteo de traducciones y de la promoción.
Descarta un borrador que no desees con discard-draft; esta función rechaza rutas activas, ocultas y archivadas.
Rotación de ID de documento, el slug como identificador
El ID del documento en Firestore es el path. Cuando se edita una página activa, el nuevo borrador obtiene un ID nuevo generado automáticamente; al publicar, ese borrador se promociona y el documento activo anterior se elimina. El efecto neto: el path que sirve a una URL determinada cambia después de cada ciclo de edición-publicación. El canonical_slug de la página se conserva durante todo el ciclo.
Por lo tanto, dirígete a las páginas mediante su identificador duradero (slug, idioma) —get-page-content y update-page lo aceptan directamente— y lee el nuevo path desde publish-status.published_urls después de cada publicación. Nunca guardes en caché un path entre publicaciones.
La publicación, paso a paso
publish— una prueba. Devuelve un manifiesto de diferencias por página (change_typecreateoreplace, título/descripción antes/después + tamaños en bytes,will_publish_to) además de unconfirmation_tokende un solo uso con una TTL de 5 minutos. No escribe nada. La publicación es todo o nada en todo el proyecto: el manifiesto enumera cada borrador pendiente, no solo los tuyos; revisa la lista completa antes de confirmar.publish-confirm— consume el token, verifica nuevamente que ningún borrador o tema haya cambiado desde la prueba (un aborto por deriva), luego ejecuta la canalización de forma asíncrona: promocionar → traducir → validar en segunda pasada → desplegar. Devuelve inmediatamente{ publish_id, status: "running" }.publish-status— sondea con elpublish_idhasta que seasucceeded(devuelvepublished_urls, cada una con la nueva ruta activa) ofailed.
Traducciones
translations_planned en el manifiesto cuenta los idiomas hermanos que la canalización escribirá: la suma de los borradores de los idiomas de destino menos el idioma de origen. Cuando un proyecto no tiene idiomas de destino configurados, es 0 (sin conteo fantasma).
Cuándo usarlo
- Al crear automatizaciones que editan y luego publican, y necesitan la URL posterior a la publicación.
- Para entender por qué una segunda edición no creó un segundo borrador.
- Para explicar por qué un
pathde la semana pasada ya no funciona.
Campos que leerás
| Fuente | Campo | Significado |
|---|---|---|
Manifiesto publish | drafts[].change_type | create (nuevo) o replace (existente) |
drafts[].will_publish_to | la URL activa a la que apunta este borrador | |
summary | { total, creates, replaces } | |
translations_planned | idiomas hermanos que la canalización escribirá | |
confirmation_token | de un solo uso, TTL de 5 min | |
publish-confirm | publish_id, status | running inmediatamente |
publish-status | status | queued / running / succeeded / failed |
published_urls[] | { title, language, slug, url } — la nueva ruta activa |
Ejemplo
(two edits, one draft)update-page(project_id, slug: 'guides/intro', content: '## v1') -> draft_id Xupdate-page(project_id, slug: 'guides/intro', content: '## v2') -> draft_id X (same draft)
publish(project_id, project_name) -> manifest { drafts: [ { slug: 'guides/intro', change_type: 'replace', will_publish_to: 'https://example.com/guides/intro/' } ], summary: { total: 1, creates: 0, replaces: 1 }, translations_planned: 0 }, confirmation_token (single-use, 5-min TTL)
publish-confirm(project_id, confirmation_token) -> { publish_id, status: 'running' }publish-status(project_id, publish_id) -> { status: 'succeeded', published_urls: [ { slug: 'guides/intro', language: 'en', url: 'https://example.com/guides/intro/' } ] }Errores comunes
duplicate_draft_target— dos borradores pendientes apuntan a la misma URL(slug, idioma).publishrechaza y no genera un token; el campocollisions[]del error enumera las rutas de los borradores en conflicto. Conserva uno y usadiscard-draften el resto (o cambia un slug), luego publica de nuevo. El mismo slug en dos idiomas diferentes está bien.- Token caducado o usado —
confirmation_tokenes de un solo uso con una TTL de 5 minutos. Vuelve a ejecutarpublish. - El manifiesto cambió desde la prueba — un borrador o el tema se movió entre
publishypublish-confirm. La confirmación se aborta; vuelve a ejecutarpublish. pathobsoleto — un ID de documento anterior a una publicación ya no resuelve. Vuelve a resolver mediante(slug, idioma).
Consulta la referencia de errores para ver la lista completa.
Relacionado
- Guía de inicio — todo el ciclo en orden
- Tipos de página — qué se redacta para conocimiento frente a información
- Errores —
duplicate_draft_targety errores de token al completo - API de publicación — la canalización HTTP subyacente
- Ejemplos de flujo de trabajo — secuencias de herramientas de extremo a extremo