CommunityProgramación y desarrollogithub.com

merge-briefing

Informe de fusión bajo demanda para el procedimiento de aprobación previa a la fusión: la sonda previa de tres superficies, la calificación de cada hallazgo abierto por su decoración de bloqueo, el traslado de las brechas `Unverified` del ancla a un seguimiento, el informe de seis partes y la pregunta `AskUserQuestion` de aprobación que lo concluye.

¿Qué es merge-briefing?

Este skill proporciona un procedimiento estructurado y exhaustivo para obtener la aprobación explícita del usuario antes de fusionar una Pull Request (PR) en GitHub. Su propósito principal es garantizar que el desarrollador tenga una visión completa y precisa del estado real de la PR en el momento de la fusión, evitando sorpresas. El skill se basa en tres pilares: 1) Sondear las tres superficies donde residen los hallazgos (CI, línea de tiempo de la conversación y revisiones, e hilos de revisión en línea), ya que ningún comando único los cubre todos. 2) Calificar cada hallazgo por su decoración de bloqueo (`issue (blocking):`, `suggestion (non-blocking):`, etc.), no por la etiqueta, para distinguir entre lo que realmente bloquea la fusión y lo que no. 3) Trasladar las brechas de verificación no resueltas del ancla de verificación de la PR a un seguimiento documentado. El resultado es un informe de seis partes (qué cambió, qué se verificó, qué NO se verificó, riesgo/radio de explosión, elementos abiertos y la pregunta explícita de aprobación) que se presenta al usuario a través de una llamada `AskUserQuestion`. Es compatible con Claude Code u otros agentes similares que puedan ejecutar comandos `gh` y `git` y acceder a la API de GitHub. El flujo de trabajo es secuencial y no puede omitir pasos: la sonda, la calificación, la composición del informe y la pregunta final.

Compatible con✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/devseunggwan/praxis/tree/HEAD/skills/merge-briefing

Installed? Explore more Programación y desarrollo skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace merge-briefing?

Visión General

Una fusión es un estado compartido irreversible, por lo que está supeditada a la respuesta explícita del usuario por PR. La puerta es barata de satisfacer formalmente y fácil de satisfacer falsamente: la versión honesta necesita una sonda lo suficientemente amplia para respaldar "nada está abierto", y la superficie donde realmente viven los hallazgos bloqueantes — los hilos de revisión en línea — es la que una llamada de aspecto natural gh pr view --json comments,reviews omite silenciosamente.

Este skill es el hogar bajo demanda para ese procedimiento. La regla Informe de Pre-Fusión (ETHOS.md → La praxis de las reglas contiene`) mantiene la puerta; la lista de seis partes en el Paso 4 a continuación es la forma del informe; los pasos siguientes son cómo se pasa de "la PR parece estar lista" a una pregunta que el usuario puede responder con una sola palabra.

Principio fundamental: el informe es una afirmación sobre el estado de la PR, por lo que cada línea en él se sondea en el momento de la composición, no se recuerda de cuando se abrió la PR.

Cuándo Usar

  • A punto de pedir al usuario que apruebe una fusión.
  • Se solicitó una fusión y aún no has presentado un informe en esta ronda.
  • Preguntar de nuevo después de que una pregunta anterior quedó sin respuesta, o después de que CI/revisión se movió.
  • Una PR acompañante, de seguimiento o regenerada es la siguiente en un clúster que el usuario ya aprobó una vez.

La Ley Inquebrantable

  • Una PR, un informe, una respuesta. Aprobar la PR X solo aprueba la X. La única excepción es la fusión masiva: una ronda con una sección de informe separada por PR, una pregunta que las enumera y una respuesta que aprueba el conjunto listado.
  • Compón el informe a partir de la salida de la sonda de esta ronda. Un estado CLEAN al momento de la entrada no es permanente; un ancla obsoleta hace que el usuario descubra un conflicto que deberías haber detectado.
  • Nunca fusiones en base a una señal de progreso. "계속", "ok", "진행" mueven el trabajo adelante; no son consentimiento para una mutación de estado compartido.

Proceso

Paso 1: Sondear las tres superficies

Los hallazgos viven en tres superficies y ningún comando único las cubre. Ejecuta las tres antes de escribir una palabra del informe.

# 1 — CI
gh pr checks <N> --repo <owner>/<repo>

# 2 — línea de tiempo de la conversación + cuerpos de revisión + capacidad de fusión + HEAD enviado
gh pr view <N> --repo <owner>/<repo> \
  --json mergeable,mergeStateStatus,isDraft,headRefOid,reviews,comments
# 3 — hilos de revisión en línea (la superficie que #2 NO incluye)
gh api graphql --paginate -f query='
query($owner:String!, $repo:String!, $pr:Int!, $endCursor:String) {
  repository(owner:$owner, name:$repo) {
    pullRequest(number:$pr) {
      reviewThreads(first:100, after:$endCursor) {
        pageInfo { hasNextPage endCursor }
        nodes {
          id isResolved isOutdated path line
          comments(first:1) { nodes { author { login } body } }
        }
      }
    }
  }
}' -F owner=<owner> -F repo=<repo> -F pr=<N> \
  --jq '.data.repository.pullRequest.reviewThreads.nodes[]
        | select(.isResolved | not)
        | {id, path, line, author: .comments.nodes[0].author.login,
           body: .comments.nodes[0].body}'

body está en la proyección porque la etiqueta está en el texto del propio hilo, y la etiqueta es en lo que se basa el Paso 2 para calificar. --paginate con $endCursor no es decoración — una PR en la que dos bots han trabajado supera los 100 hilos, y una sola página descarta silenciosamente el resto, lo que luego se lee como "sin hilos abiertos".

La Superficie #2 también trunca en 100, y silenciosamente. gh pr view --json comments,reviews emite comments(first: 100) / reviews(first: 100) sin variable de cursor, por lo que en una PR que supere cualquiera de los conteos, la cola simplemente está ausente. Cuando uno de ellos está en 100 filas, vuelve a recopilar esa superficie a través del endpoint REST paginado antes de calificar:

gh api repos/<owner>/<repo>/pulls/<N>/reviews --paginate -q '.[] | {user: .user.login, state, body}'
gh api repos/<owner>/<repo>/issues/<N>/comments --paginate -q '.[] | {user: .user.login, body}'

Un resultado vacío aún no es una respuesta. Significa "sin hilos abiertos" y "la consulta está mal" al mismo tiempo hasta que hayas visto esta misma consulta imprimir filas en una PR que se sabe que las tiene. Ejecútala una vez contra dicha PR; ese es el control positivo en el que se basa la afirmación negativa.

En un clon de fork, --repo debe nombrar el fork en cada sonda: una llamada gh pr simple se resuelve contra el repositorio padre (ver worktree-merge-cleanup → Lista de verificación previa a la llamada).

Si la CI está pendiente o fallando, detente aquí — no preguntes aún. Un informe cuyas filas de verificación aún se están moviendo es pedirle al usuario que apruebe una suposición.

Lee qué commit cubre cada aprobación humana antes de escribir "aprobado": reviewDecision: APPROVED sobrevive a los envíos posteriores. Agrupa las revisiones por revisor y toma la revisión APPROVED más reciente de cada uno (una aprobación anterior es reemplazada por una re-aprobación; un CHANGES_REQUESTED o DISMISSED posterior del mismo revisor significa que no hay aprobación actual). Compara el commit_id de esa revisión con headRefOid y lista los commits no de fusión posteriores a él (git log --no-merges <commit_id>..<head>) en la parte 5 como "no revisado por " (ver la fila de Modos de Falla para el comando).

El estado de fusión es una lista de permitidos, no una verificación de "no está obviamente roto". Pregunta solo cuando mergeable sea MERGEABLE y mergeStateStatus sea CLEAN o HAS_HOOKS — esos dos son los únicos valores que significan fusionable con un estado de commit exitoso. Cualquier otro valor detiene la pregunta y se nombra a sí mismo en el informe:

mergeStateStatusLo que significa¿Preguntar?
CLEANFusionable y con estado de commit exitosoSí
HAS_HOOKSFusionable, exitoso, con ganchos de pre-recepción presentesSí
UNSTABLEFusionable con un estado de commit no exitosoNo — es la CI fallida de arriba
BLOCKEDLa fusión está bloqueada (regla de protección, revisión requerida)No
BEHINDLa ref de cabeza está desactualizadaNo — haz rebase primero
DIRTYNo se puede crear limpiamente el commit de fusiónNo — conflicto
UNKNOWNEl estado no se puede determinar actualmenteNo — vuelve a sondear

El estado de borrador no está en esta enumeración — es el campo separado isDraft, por lo que una PR en borrador puede reportar CLEAN. Añade isDraft a la lista --json y trata un borrador como no listo independientemente de su estado de fusión.

CLEAN no dice nada sobre los commits base que llegaron desde que se creó la rama. Cuéntalos (git fetch origin luego git rev-list --count HEAD..origin/<base>) y lista los archivos que tocaron que la PR también toca (git diff --name-only HEAD...origin/<base>). Para cada archivo compartido, busca en ese diff base los símbolos que esta PR cambia y ejecuta git merge-tree --write-tree HEAD origin/<base> — cero aciertos de símbolos y salida 0 es la evidencia de "sin superposición semántica", citada en la parte 5. Cuando se active el disparador de rebase previo a la fusión (3+ commits base, una ronda de revisión finalizada), actualiza la base con gh pr update-branch <N> (un commit de fusión, nunca una reescritura), lo que reinicia la CI y la revisión del bot: espera a ambos en la nueva cabeza, vuelve a revisar el ancla con la cabeza que se movió, luego vuelve a ejecutar los Pasos 1–3 contra la nueva cabeza y reconstruye el informe antes de preguntar — los hallazgos, el estado de fusión y la cobertura de aprobación recopilados anteriormente describen la cabeza anterior.

Paso 2: Calificar cada hallazgo en las tres superficies

Un recuento de hilos abiertos no es un recuento de bloqueadores, y la superficie de hilos no es todo el corpus. Califica cada hallazgo recopilado en el Paso 1 — hilo en línea, comentario de conversación y cuerpo de revisión por igual — por la decoración, no la etiqueta:

Primera línea del hallazgo¿Bloquea la fusión?
issue (blocking): / suggestion (blocking):Sí — la fusión espera
issue (non-blocking): / suggestion (non-blocking):No
nitpick: / note:No — sin resolver por diseño
Sin etiquetaCalifícalo tú mismo — lee el cuerpo

suggestion no es un escalón más bajo que issue: ambos llevan exactamente uno de (blocking) / (non-blocking), por lo que la decoración es todo el juicio y la etiqueta solo dice qué tipo de hallazgo es. Leer la etiqueta en su lugar es cómo un bloqueador declarado se pasa por alto como "solo una sugerencia".

Un cuerpo de revisión no es un hilo y no se puede resolver, que es exactamente por qué pasa desapercibido: nada en él parece abierto. CodeRabbit archiva sus hallazgos procesables en secciones colapsables del cuerpo de la revisión en lugar de como comentarios de línea, así que busca en los cuerpos recopilados en el Paso 1 Actionable, Nitpick, outside diff, 🧹 y califica lo que encuentres. Un comentario de conversación que plantea un defecto se califica de la misma manera. Los hallazgos bloqueantes en cualquiera de las superficies detienen la pregunta igual que uno en línea — simplemente no tienen un hilo que dejar abierto, por lo que se llevan en los elementos abiertos del informe en su lugar.

Reconcilia el recuento de CodeRabbit antes de que la calificación esté completa: cuenta sus hallazgos por los marcadores `LINES`: ** en los cuerpos y haz coincidir el total que indica el encabezado de la revisión (ej. Major comments: N). Responde al conjunto en un comentario de conversación agrupado Fixed — <sha> (n) / Not fixed (n) / False positive (n), cuyos recuentos sumen ese total.

El caso sin etiqueta es el común, no la excepción: los bots escriben en su propio vocabulario. CodeRabbit abre con su propia línea de severidad (_🎯 Functional Correctness_ | _🟠 Major_ | …), Copilot y BugBot sin ninguna. Trata la severidad de un bot como una entrada para tu calificación, nunca como la calificación — y nunca como una razón para saltarte el hallazgo porque "es solo un bot".

Un hilo que calificaste como bloqueante tiene una salida legítima antes de la fusión: se arregla y se cierra, o se recalifica — editando el comentario a (non-blocking) y publicando el aviso Revised —. Estacionar un hallazgo bloqueante en un seguimiento sin recalificar deja la rama bloqueada mientras cada etiqueta se lee como no bloqueante.

Limpiar el estado REQUEST_CHANGES a nivel de revisión es un paso separado y posterior. Ese estado pertenece a la revisión, que puede contener varios hallazgos, por lo que se limpia solo una vez que cada hallazgo bloqueante en ella está arreglado y cerrado o recalificado — nunca por la fuerza de uno solo. Recalificar el último es lo que lo desbloquea; hasta entonces, la revisión correctamente sigue bloqueando.

Paso 3: Trasladar las brechas Unverified del ancla

Abre el ancla de verificación de la PR y lee su lista Unverified. Una brecha escrita como "머지 후 실전송으로 확인" muere con la PR a menos que algo le sobreviva.

  • Superficialmente, solo aquellas brechas que nombraron una acción siguiente — una brecha sin una acción siguiente declarada no se traslada.
  • Pregunta, como parte del informe, si se debe abrir un issue de seguimiento.
  • Escribe la respuesta en la revisión final del ancla como Carried: #N o Carried: none — <사유> antes de la fusión.
  • Escribir esa revisión final necesita gh — una sesión cuya única superficie de GitHub es el servidor MCP no puede actualizar el cuerpo de un comentario cuando la lista de herramientas activas de ese servidor no expone una update de comentario (confirma antes de asumir). Allí, pon la línea Carried: en el commit de fusión o en el cuerpo de la PR, y nunca en un segundo comentario de ancla. Consulta anchor-comment-gate/spec.md → Procedimiento para una sesión sin gh`.
  • Nunca archives automáticamente el seguimiento: un nuevo issue aún necesita su propia revisión de enfoque de implementación primero.
  • Cuando el seguimiento se registra como un comentario en su lugar (Carried: <URL del comentario>), ponlo en un issue que permanezca abierto después de la fusión — el issue Ref: de la PR (ej. un issue hub/paraguas cerrado más tarde por un paso de lanzamiento), nunca el issue Closes #N, que la propia fusión cierra y nadie reabre. Lo mismo aplica para notas fuera del alcance escritas mientras la PR está abierta.
  • Cuando el issue de traslado es el que un paso de lanzamiento posterior a la fusión cierra (un issue hub cerrado por /release), el lanzamiento entierra el traslado exactamente como lo haría un objetivo Closes. Nombra ese conflicto en el informe de fusión (lanzamiento ahora y pierde los elementos abiertos, o lanzamiento después de que se verifiquen) en lugar de resolverlo silenciosamente de cualquier manera. También verifica el objetivo Closes #N después de la fusión: GitHub lo cierra solo cuando la PR se fusiona en la rama predeterminada del repositorio, por lo que una PR en una base no predeterminada (prod cuando la predeterminada es dev) lo deja abierto para el paso de lanzamiento.

Paso 4: Componer el informe de seis partes

Seis partes, en este orden (esta lista es la forma canónica; se derivó originalmente de la plantilla de flujo de trabajo de PR de los archivos dotfiles del autor):

  1. Qué cambió — abre con una oración simple de lo que hace la PR y qué cambia para el usuario si se fusiona (y si no), luego el alcance (archivos, cambios lógicos), no el título del issue nuevamente. Una parte 1 hecha de conteos y abreviaturas internas obtiene "¿qué hace?" en lugar de una respuesta, lo que restablece la ventana de aprobación y cuesta un informe completo.
  2. Qué se verificó — salida real, con el comando citado
  3. Qué NO se verificó — saltado, diferido, bloqueado, CI pendiente
  4. Riesgo / radio de explosión — quién se rompe si esto está mal
  5. Elementos abiertos — cada hallazgo que el Paso 2 calificó y dejó abierto, en las tres superficies; las brechas del Paso 3
  6. Pregunta explícita — ¿Aprobar fusión? en su propia línea, en el texto, con la llamada AskUserQuestion del Paso 5 justo después (la línea permanece aunque la herramienta pregunte, porque es el elemento que la puerta califica)

La parte 3 está bajo presión, y es la razón por la que existe el informe.

Cuando un elemento no verificado es precisamente el paso que la fusión desencadena (un despliegue posterior a la fusión, una compilación de activos que la CI nunca ejecutó, una compilación multiplataforma que ejecutaste en una plataforma), es un riesgo, no una nota al pie: ponlo en la parte 4 con lo que se rompe si ese paso falla y a quién más bloquea (despliegues posteriores de la misma pila). Para una PR cuyo valor es contable (pines de versión, catálogos, documentación), la parte 4 también dice en una línea qué sucede si no se fusiona — el usuario pregunta eso antes de aprobar una PR de bajo riesgo que aún desencadena un despliegue.

Anti-patrones de la parte 3: "완료했습니다, 머지할까요?" sin evidencia; una verificación omitida degradada a un comentario al margen; informar en el momento de la fusión lo que debería haber salido a la luz en el momento de la PR lista.

Cierra los elementos de la parte 3 observando, no leyendo. Cuando el usuario te pida que verifiques los elementos no verificados, ve elemento por elemento y ejecuta la sonda más barata que resuelva la pregunta — comprueba la salida de CI de la PR para la compilación de activos, una conexión SSH a un host de staging para el script de despliegue, el resultado de git diff para el pin de versión — y escribe la evidencia o nombre el fracaso. No se aceptan lecturas de segunda mano del ancla de verificación.

Paso 5: Preguntar

<AskUserQuestion>
¿Aprobar fusión?
</AskUserQuestion>

Eso es todo. La línea de texto está ahí porque es el elemento que la puerta califica, y la llamada está ahí porque es la herramienta que usa la puerta. No envuelvas la pregunta en otra cosa; el hecho de que la herramienta tome una respuesta no es una razón para no poner la pregunta en el texto. Si la herramienta puede tomar una respuesta de opción múltiple, las opciones son Sí / No, y Sí significa "fusiónalo ahora".

Cuando el usuario responde No, el agente no tiene contexto sobre qué no hacer — no puede fusionar esa PR en esta ronda. Si el usuario da una razón, el agente reacciona inmediatamente (etiquetando de nuevo, verificando...) y luego vuelve a preguntar con la misma herramienta pero con el informe delante, no sin él. Responder una razón y luego saltar a otra PR es cómo una PR se fusiona sin que su informe haya sido respondido.

Una respuesta afirmativa es un permiso único — el agente no vuelve a preguntar por esta PR en esta ronda.

Modos de falla

EscenarioLo que el informe muestraRespuesta del agente
El usuario responde con una pregunta sobre un elemento del informeEl informe sigue sin respuestaResponde la pregunta, vuelve a preguntar con el mismo informe
El usuario responde con una instrucción para cambiar la PREl informe está obsoleto — la PR ha cambiadoHaz el cambio, espera CI/revisión (sin puerta de la PR), luego re-ejecuta Pasos 1–5 desde cero
El usuario responde a la pregunta de una PR con una respuesta que nombra un conjunto diferente de PRs ("fusiona esta y la PR #42 también")Una PR adicional no informadaNo fusiones ninguna de las dos. Rechaza la respuesta con "No puedo fusionar múltiples PRs basado en eso — por favor, aprueba cada PR por separado, o usa la fusión masiva si están relacionadas"
La PR está en un clúster aprobado (el usuario ya respondió el informe para el grupo)El canal de informe para esta PR aún no se ha abiertoLlama al informe directamente, sin pasar por los pasos anteriores — pero aún vuelve a sondear el estado de fusión
El usuario responde a una pregunta de una PR anterior con una respuesta que no coincide con ninguna PR abiertaUna PR anterior está obsoletaIgnórala como basura de una ronda anterior
Cada respuesta humana a una AskUserQuestion tiene que coincidir con una PR abierta visitable; una respuesta que nombre una PR que no está en la visita actual se rechaza en el momento. (Una respuesta que nombra la PR correcta pero se refiere al informe de una PR anterior se ignora — firma una verificación caducada.)

Fusión Masiva: Varias PRs, una respuesta

Cuando varias PRs comparten un tema, un clúster de despliegue o un caso de revisión donde la respuesta del usuario a la PR A es idéntica a la respuesta para las PRs B y C, todas las PRs del clúster hacen el intento en una ronda, cada una con una sección de informe separada numerada A, B, C..., y la pregunta al final enumera el conjunto que la respuesta aprobaría.

Reglas

  • Cada sección individual del informe debe cumplir los mismos criterios de informe de seis partes que una PR independiente.
  • Cuando una PR en el conjunto tiene un bloqueador, su sección dice "BLOQUEADA — " en la parte 5 y se omite de la pregunta (no se puede aprobar lo que no se ha informado como fusionable).
  • La pregunta al final:
    • Enumera solo las PRs fusionables, usando su número y título corto.
    • Si alguna PR en el conjunto no es fusionable, confirma primero que el usuario aún quiere fusionar el resto (en lugar de abortar todo el lote).
  • La respuesta del usuario nombra exclusivamente ese subconjunto. "Sí" sin calificar, cuando el conjunto completo está desbloqueado, es permiso para fusionar todo el lote.

Cuándo NO usar la fusión masiva

  • Las PRs tienen diferentes razones para existir (una corrección de error y una característica, dos características no relacionadas).
  • El usuario necesita decidir sobre cada una por separado (alta fricción de reversión, diferentes propietarios de revisión).
  • Una PR en el lote no ha sido informada en esta ronda (no hay sección de informe para la PR B, por lo que no se puede votar).

En esos casos, cada PR obtiene su propia ronda de informe.

Seguridad del comando

Este procedimiento utiliza los siguientes comandos de gh y git. Las banderas de seguridad (ej. --repo <propietario>/<repo>) son obligatorias en todos los contextos de fork y deben ser correctas para el destino de la fusión. Una llamada gh pr merge sin --repo se resuelve contra el repositorio ascendente del fork, que no es donde la PR se fusionará.

ComandoPropósito en el procedimientoContexto seguro requerido
gh pr checks <N> --repo <o>/<r>Pedir el estado de CI--repo establece el destino real
gh pr view <N> --repo <o>/<r> --json ...Sondear la superficie #2igual que arriba
gh api graphql --paginate ... -F repo=<r> ...Sondear la superficie #3igua
gh api repos/<o>/<r>/issues/<N>/comments --paginateVolver a recopilar superficie #2 cuando se truncaigual que arriba
git fetch origin / git rev-list --count HEAD..origin/<base>Contar commits base desde que se creó la ramaorigin debe apuntar al destino de la fusión
git diff --name-only HEAD...origin/<base>Encontrar archivos compartidos tocados por commits base y PRigual que arriba
git merge-tree --write-tree HEAD origin/<base>Verificar superposición semánticaigual que arriba
gh pr update-branch <N>Traer la base después del disparador de rebase--repo es obligatorio en fork

Consejo de depuración

Problema: una PR completamente revisada y aprobada se muestra como "no revisada" en el informe. Causa más probable: gh pr view --json reviews truncó silenciosamente en 100 revisiones. La reviewDecision: APPROVED de la PR sigue siendo correcta pero la lista de revisores individuales está incompleta. Arreglo: vuelve a recopilar las revisiones a través del endpoint paginado.

Problema: un hilo abierto conocido no aparece en la sonda de la superficie #3. Causa más probable: la PR supera los 100 hilos y --paginate no se configuró (consulta la superficie #3 arriba para la sintaxis correcta). Arreglo: añade --paginate -f endCursor=$cursor con el cursor de la respuesta anterior.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills relacionados