Pre-Fusión
Crea un PR de GitHub que enlace con el PRD y los issues de slice, luego revisa el diff completo contra los principios arquitectónicos del proyecto. Produce hallazgos como asesoramiento — no bloquea la fusión, no corrige código automáticamente ni crea issues.
Posición de Invocación
Esta es una habilidad primaria del pipeline que se utiliza después de que la implementación ha sido verificada y antes de fusionar a main, o al retomar el PR de otra persona para revisión.
Use /pre-merge cuando la rama esté lista para la creación del PR, la revisión arquitectónica y la conciliación final entre plan y código. Use /pre-merge --pr <número> cuando esté revisando un PR que usted no creó.
No lo use como sustituto de la verificación de implementación, la entrada de QA o la planificación de refactorización. Asume que el trabajo ya está construido y listo para revisar.
Modos
/pre-merge se ejecuta en uno de tres modos. Los tres reutilizan las dimensiones de revisión arquitectónica definidas en review-checklist.md; se diferencian en lo que consumen y lo que producen.
- Modo Autor (predeterminado) — se invoca en su propia rama sin el argumento
--pr. La habilidad crea el PR (Fase 2) e imprime los hallazgos en la terminal como asesoramiento (Fase 4), y luego devuelve el control — no realiza commits de corrección propios ni abre una segunda pasada. Este es el modo invocado automáticamente por/executePaso 6 en la ruta HITL. Lo que lee lo decide el estado de la rama, no una bandera: una primera revisión lee el slice completo, que es toda la rama a menos que el elemento de trabajo del slice registre dónde comenzó; una re-ejecución contra un PR que ya tiene una marca de moneda de revisión, cuya cabeza se ha movido desde entonces, toma el delta posterior a la marca — los commits después del SHA marcado — como el sujeto de la revisión, y no vuelve a leer lo que cubrió la revisión anterior. El Paso 1, paso 4, toma esa decisión y la imprime. El delta es el sujeto, no el límite de lo que un revisor puede leer:review-checklist.mdestablece lo que un revisor lee, e incluye el árbol alrededor del delta. - Modo Revisor — se invoca como
/pre-merge --pr <número>contra un PR que usted no creó. La habilidad omite la creación del PR (el PR ya existe) y produce texto de comentario borrador (Fase 4) para que usted lo revise y publique, estructurado segúnreferences/comment-craft.md(compuerta 5P, Triple-R, Señales de Comentario, Intercambio MMG). - Modo Bucle — se invoca como
/pre-merge --loop, o se ingresa automáticamente cuando/executetransfiere el control en una ejecución AFK. Ejecuta las Fases 1–4 como lo hace el modo Autor, excepto la decisión de alcance del Paso 1, paso 4: el modo bucle siempre lee toda la rama y nunca toma el delta posterior a la marca, luego continúa a la Fase 5: registra cada hallazgo en un registro duradero — en el cuerpo del PR, o en el elemento de trabajo, donde references/state-backend.md § Dónde viven los registros de la revisión dice — adjunta la evidencia que apoya o refuta cada uno, y devuelve el control al operador. Los hallazgos dejan de ser salida de terminal en este modo; se convierten en filas duraderas con propietarios. El modo bucle no arregla nada y no hace commits — el operador decide qué sucede con cada hallazgo (ver Fase 5 § Por qué el bucle no arregla).
La condición de salida del modo bucle es que cada hallazgo tenga un propietario, nunca que la revisión haya salido limpia. "Cero hallazgos" es una señal de terminación prohibida, coherente con la protección de hallazgos mínimos existente de la Fase 4, que se escribió porque una revisión casi vacía en un diff no trivial significa que la revisión se detuvo temprano, no que el código sea impecable. Un bucle que termina en revisiones limpias producirá de manera confiable revisiones limpias y nada más (Meadows, Buscando el Objetivo Erróneo; Leveson: nunca recompense recuentos bajos de incidentes — recompense la notificación en sí).
Si se está ejecutando en una rama que no es la rama de trabajo del usuario y no se proporcionó --pr, pregunte una vez si el usuario quiere decir modo revisor contra un número de PR específico en lugar de adivinar — la detección automática ahorra una pulsación de tecla, pero clasificar mal el modo produce comentarios borrador que habrían sido avisos locales o viceversa.
Cuándo Usar
- Modo Autor: después de que QA pase y antes de fusionar una rama de característica a main; después de que Ralph termine la ejecución AFK y usted haya verificado el comportamiento; o para cualquier rama que desee revisar antes de fusionar, incluso sin una ejecución completa del pipeline.
- Modo Revisor: cuando un compañero de equipo o colaborador externo abre un PR y usted desea aplicar la revisión arquitectónica completa en
review-checklist.mda su diff y producir texto de comentario constructivo. - Modo Bucle: cuando los hallazgos deben sobrevivir a la sesión que los produjo — la transferencia AFK de
/execute, o cualquier rama que revisará en varias sesiones y no desea volver a derivar cada vez. Úselo cuando el costo que está pagando es perder el rastro de los hallazgos, no hacer las correcciones.
Flujo de Ejecución
Fase 1: Recopilar Contexto
Modo Autor:
-
Pregunte por el número de issue del PRD. Acepte "ninguno" si este cambio no pasó por el pipeline completo. En el modo bucle ingresado desde una transferencia AFK de
/execute, no pregunte — tome el número de issue de la transferencia (/executePaso 6 lo pasa) y trate su ausencia como "ninguno". No hay nadie para responder, por lo que una pregunta incondicional colgaría la ejecución en su primer paso. En el backend sidecar, la respuesta es un id de elemento de trabajoW-<n>(paso 2). "Ninguno" allí deja a la Fase 2 sin nada donde registrar el PR, y a las Notas de Revisión y al registro del modo bucle sin hogar: references/state-backend.md § Dónde viven los registros de la revisión dice lo que les sucede. -
Si se proporcionó un PRD:
gh issue view <número> gh issue list --search "in:body #<prd-number>" --state all --json number,title,state,body --limit 100Analice los mapas de límites (secciones Produce/Consume) del cuerpo de cada issue de slice.
En el backend sidecar (
bash "$SC" backend slicesrespondesidecar, según references/state-backend.md; el bloque a continuación lo pregunta, y se detiene ante una negativa en lugar de recurrir agh issue), el PRD y sus slices son elementos de trabajo, y el número solicitado en el paso 1 es un idW-<n>: el slice que implementa esta rama, que/executepasa, o su PRD. No se ejecuta ningún comandogh issue; el linaje y los mapas de límites provienen de los elementos de trabajo:SC="<directorio de esta habilidad>/references/sidecar.sh" W="W-<n>" case "$(bash "$SC" backend slices)" in sidecar) ;; github) echo "el backend es github: lea el linaje con el bloque de issue anterior"; exit 0 ;; *) echo "linaje abortado: sidecar.sh backend slices falló; no adivino la ruta de github" >&2; exit 1 ;; esac J="$(bash "$SC" work view "$W" --json)" || { echo "linaje abortado: no se puede leer $W" >&2; exit 1; } case "$(jq -r '.kind // empty' <<<"$J")" in slice) PRD="$(jq -r '.parent // empty' <<<"$J")" ;; prd) PRD="$W" ;; *) echo "linaje abortado: $W no tiene kind" >&2; exit 1 ;; esac SLICES="$W" if [ -n "$PRD" ]; then bash "$SC" work view "$PRD" --json | jq -r '"# \(.id) (prd, \(.state))\n\(.body)"' SLICES="$(bash "$SC" work list --kind slice --parent "$PRD" --state all)" \ || { echo "linaje abortado: no se pueden listar los slices de $PRD" >&2; exit 1; } fi while IFS= read -r S; do [ -n "$S" ] || continue bash "$SC" work view "$S" --json | jq -r '"# \(.id) (slice, \(.state))\n\(.body)"' done <<<"$SLICES"Analice los mapas de límites de esos cuerpos exactamente como de los cuerpos de issue. Mantenga
$W: la Fase 2 registra el PR en él. -
Detecte la rama base y evalúe el diff:
SC="<directorio de esta habilidad>/references/sidecar.sh" # $BASE_REF es el extremo del rango; $BASE_BRANCH es el nombre que toma `--base`. BASE_REF="$(bash "$SC" base-ref)" || { echo "base-ref falló: no adivino una base" >&2; exit 1; } BASE_BRANCH="$(bash "$SC" base-ref --name)" || { echo "base-ref --name falló: no adivino una base" >&2; exit 1; } git diff "$BASE_REF...HEAD" --stat git log --oneline "$BASE_REF..HEAD"base-refimprime elbase_refdeclarado del sidecar cuando lo hay, y de lo contrario el valor predeterminadoorigin/HEAD. En una salida distinta de cero, no imprime ningún ref: deténgase y transmita su stderr en lugar de adivinar una base. Para un slice de PR apilado, ninguna variable establecida aquí llega a un bloque posterior: coloque el nombre de la rama del slice hermano (el upstream al que se dirigirá el PR) en el marcador de posiciónBASE_BRANCH=de cada bloque que lo consume (el bloque de la Fase 2 para su backend y el bloque de sello de la Fase 4). Si no hay diff desde la base, dígale al usuario que no hay nada que revisar y deténgase.Residual:
$BASE_REFsolo está tan actualizado como el últimogit fetch. Cuandoorigin/<base>no se resuelve,base-refmide contra la rama local y lo dice en stderr; si los recuentos parecen incorrectos, hagagit fetchy vuelva a ejecutar. -
Decida el alcance — todo el slice, o el delta posterior a la marca. Esta decisión es solo para el modo Autor. El modo Bucle la omite y establece
SCOPE_FROM="$BASE_REF"incondicionalmente, leyendo toda la rama en cada invocación, según la viñeta del modo Bucle de la Fase 3. Una primera revisión lee todo el slice:sidecar.sh rangeda su extremo izquierdo, que es el inicio registrado del slice cuando el elemento de trabajo del paso 2 nombrado tiene uno todavía en esta rama, y$BASE_REFen caso contrario, por lo que en el backendgithubun slice es toda la rama. Una re-ejecución contra un PR que esta habilidad ya selló, cuya cabeza se ha movido desde entonces — una ronda de/fix-findings, o una corrección manual después de una eliminación deliberada de bloqueo — toma el delta posterior a la marca como su sujeto. El sello vive dondebackend stampdice, según references/state-backend.md: el cuerpo del PR, o el sidecar. Lea el cuerpo del PR con la misma expresión que usa el Paso 2 de/closeout;scripts/test-review-currency-marker.shfija los dos byte-idénticos, yscripts/test-delta-review-scope.shejecuta este bloque contra un fixture para cada estado de rama que nombra, en ambos backends:SC="<directorio de esta habilidad>/references/sidecar.sh" case "$(bash "$SC" backend stamp)" in sidecar) REVIEWED_SHA=$(bash "$SC" stamp read "$(git branch --show-current)") ;; github) REVIEWED_SHA=$(gh pr list --head "$(git branch --show-current)" --json body -q '.[0].body // ""' \ | sed -n 's/.*<!-- reviewed-at: \([0-9a-f]\{40\}\) -->.*/\1/p' | tail -1) ;; *) echo "alcance abortado: sidecar.sh backend stamp falló; no adivino la ruta de github" >&2; exit 1 ;; esac W="<el W-<n> nombrado en el paso 2, o vacío en el backend github>" BASE_REF="$(bash "$SC" base-ref)" || { echo "alcance abortado: sidecar.sh base-ref falló" >&2; exit 1; } RANGE="$(bash "$SC" range ${W:+"$W"})" || { echo "alcance abortado: sidecar.sh range falló" >&2; exit 1; } SLICE_FROM="${RANGE%%..*}" SCOPE_FROM="$SLICE_FROM" if [ -n "$REVIEWED_SHA" ] \ && git merge-base --is-ancestor "$REVIEWED_SHA" HEAD 2>/dev/null \ && [ "$REVIEWED_SHA" != "$(git rev-parse HEAD)" ] \ && [ -z "$(git log --merges --format=%H "$REVIEWED_SHA..HEAD")" ]; then SCOPE_FROM="$REVIEWED_SHA" elif [ -n "$REVIEWED_SHA" ] \ && ! git merge-base --is-ancestor "$REVIEWED_SHA" HEAD 2>/dev/null \ && [ "$(git rev-parse -q --verify "$REVIEWED_SHA^{tree}")" = "$(git rev-parse 'HEAD^{tree}')" ]; then SCOPE_FROM="HEAD" fi if [ "$SCOPE_FROM" = HEAD ]; then echo "alcance de revisión: ninguno, reescritura solo de historial — HEAD lleva el árbol revisado en $REVIEWED_SHA" elif [ "$SCOPE_FROM" = "$BASE_REF" ]; then echo "alcance de revisión: rama completa, desde $BASE_REF" elif [ "$SCOPE_FROM" = "$SLICE_FROM" ]; then echo "alcance de revisión: slice completo, desde $SLICE_FROM (inicio registrado de $W)" else echo "alcance de revisión: delta posterior a la marca, desde $SCOPE_FROM" fi git diff "$SCOPE_FROM...HEAD" --stat git log --oneline "$SCOPE_FROM..HEAD"Cuatro estados recurren al slice completo, cada uno a propósito: sin sello (una primera revisión, o un PR creado manualmente); un sello que no es un ancestro de
HEADy cuyo árbolHEADya no lleva (la rama fue reescrita y el contenido cambió con ella, o el commit revisado se ha ido —/closeoutllama a esto la señal de divergencia más fuerte, y no es una revisión más pequeña); un sello igual aHEAD(nada nuevo a qué alcance); y un commit de fusión después del sello (el diff posterior a la marca llevaría los cambios de la propia rama base, que nadie en esta rama escribió). El slice completo es toda la rama a menos querangehaya encontrado un inicio registrado, y cuando encuentra uno que un pliegue o rebase reescribió, lo dice en stderr y responde$BASE_REF, nunca re-anclando el inicio. La decisión se imprime para que la lectura de la terminal y el PR digan lo mismo sobre lo que se leyó.Una reescritura que mantuvo el árbol revisado no es una divergencia. Cuando el commit sellado no es un ancestro de
HEADpero aún existe localmente y lleva el mismo árbol queHEAD, el historial cambió y el contenido no: el pliegue que ofrece la transferencia de la Fase 4 (git rebase -i --autosquash) produce exactamente esto. El bloque imprimealcance de revisión: ningunoy estableceSCOPE_FROM="HEAD". Omita la Fase 3 y todo en la Fase 4 excepto el sello, que re-sella enHEAD, y el menú de transferencia. El sello certifica el contenido revisado, y un hash de árbol es ese contenido exactamente. Si el commit sellado no está disponible localmente, el árbol no se puede comparar y la reescritura toma la alternativa de rama completa anterior.En una re-ejecución delta, el delta es el sujeto y el árbol aún es legible. Informe a cada revisor de la Fase 3 con los hallazgos que los commits posteriores a la marca afirman cerrar — la lectura anterior en esta sesión, el registro si el modo bucle escribió uno (donde references/state-backend.md § Dónde viven los registros de la revisión dice), o los propios mensajes de commit — con los veredictos del interruptor
/fix-findingscuando los haya, y con la salida debash "$SC" profile, textualmente, que el contrato de la Fase 3 entrega a cada revisor. La primera pregunta por commit es si la corrección cierra su hallazgo en cada sitio que el hallazgo nombró, que es la dimensión de Integridad de la Corrección; la segunda es...
[truncado para traducción]