Pipeline de investigación
Objetivo: ejecutar bash pipeline/run_pipeline.sh desde una copia limpia del repositorio más los datos brutos
data/ regenera cada conjunto de datos procesado, resultado de análisis, informe y
manuscrito. Cada script que produce algo utilizado posteriormente es llamado,
en orden de dependencias, por algún script bajo pipeline/.
Estructura
pipeline/
_common.sh # funciones compartidas, importado por todos los run_*.sh (no se ejecuta directamente)
run_pipeline.sh # orquestador principal: llama a los scripts de etapa en orden
run_preprocessing.sh # etapa: src/prepro/*.R -> output/prepro/
run_analyses.sh # etapa: src/analysis/*.R -> output/analysis/
run_reports.sh # etapa: src/reports/*.qmd -> output/reports/
run_manuscript.sh # etapa: src/manuscript/* -> output/manuscript/
run_script.sh # ejecuta un único .R / .qmd con el mismo logging
Los nombres de etapa siguen las carpetas src/ del proyecto (ej. noh-survey usa src/manu/
y run_manu.sh). Añade etapas solo para las carpetas que existan; no inventes vacías.
Convenciones
#!/usr/bin/env bashyset -euo pipefailen cada script.- Un comentario de cabecera en cada script: qué hace, la línea de uso
(
bash pipeline/<nombre>.sh), y qué etapa debe haberse ejecutado primero (Requiere ...). - Los scripts hacen
cda la raíz del proyecto mediante_common.sh, por lo que funcionan desde cualquier directorio. Todas las rutas dentro son relativas a la raíz del proyecto. - Logging:
run_pipeline.shexportaPIPELINE_LOG_DIR=logs/run_pipeline_<timestamp>. Cada etapa crea${PIPELINE_LOG_DIR:-logs}/run_<etapa>_<timestamp>/, por lo que las etapas se anidan bajo la ejecución del pipeline, o van alogs/cuando se ejecutan solas. Cada script R / documento Quarto registra su log en<nombre>_<HH-MM-SS>.txt. - En caso de fallo,
run_r/render_qmdimprime el script que falló, su ruta de log y las últimas 20 líneas del log, y detiene todo el pipeline. - Dentro de una etapa, agrupa las llamadas bajo encabezados
echo "=== Capa N: <motivo> ==="por profundidad de dependencia. Pon un comentario al final de cualquier llamada cuya dependencia no sea obvia (# necesita output/prepro/redcap-joined.rds). Las dependencias entre etapas tienen su propio bloque etiquetado (ej. un script de prepro que necesita resultados de PCA va en la etapa de análisis después de PCA). - Cada etapa hace
mkdir -pde los directorios de salida a los que escribe. - Quarto renderiza en la carpeta fuente, por lo que
render_qmdmueve el resultado aoutput/. Usa un buclefor qmd in src/reports/*.qmd(saltando plantillas) cuando todos los informes de una carpeta se renderizan de la misma manera. - Los pasos lentos llevan un
echo "NOTA: ... puede llevar mucho tiempo"antes. - Mantén las llamadas explícitas, una línea por script. No descubras automáticamente scripts R con globs: el orden es el grafo de dependencias y debe ser legible.
Plantillas
Copia estas del directorio templates/ de este skill y complétalas:
| Plantilla | Se convierte en |
|---|---|
_common.sh | pipeline/_common.sh (copia tal cual) |
run_pipeline.sh | pipeline/run_pipeline.sh |
run_stage.sh | un pipeline/run_<etapa>.sh por etapa |
run_script.sh | pipeline/run_script.sh (copia tal cual) |
_common.sh proporciona:
init_log_dir <nombre-etapa>: crea y estableceLOG_DIRrun_r <script.R> [args...]: ejecuta un script R, stdout+stderr a su log (los args se añaden al nombre del log, para ejecuciones parametrizadas como el bucle de grupos de noh-survey)run_r_console <script.R> <archivo-stdout>: stdout guardado como entregable (ej.output/manuscript/<nombre>-console.txt), stderr al logrender_qmd <doc.qmd> <dest-dir-o-archivo> [args quarto...]: renderiza y mueve la salida; pasa una ruta de archivo como destino para renombrarlo (ej. un PDF por-P group:...)find_quarto: fallback al Quarto incluido con RStudio/Positron
Flujo de trabajo
1. Inspeccionar el proyecto
- Lista
src/(yfns/,config/) y cualquierpipeline/existente. Sipipeline/existe, lee cada script antes de cambiar nada, y mantén su estilo donde difiera de estas convenciones (pregunta antes de migrar un pipeline establecido). - Lee el archivo CLAUDE.md / README del proyecto para conocer el orden de ejecución indicado.
2. Determinar el orden de dependencias
Para cada .R / .qmd en src/, encuentra qué lee y qué escribe:
grep -nE 'readRDS|read_rds|read_csv|read_excel|read\.csv|load\(|fread|readMat|source\(' <archivo>
grep -nE 'saveRDS|write_rds|write_csv|ggsave|save\(|writexl|write\.csv|pdf\(|png\(|tiff\(' <archivo>
Empareja cada lectura con el script que escribe ese archivo. Una lectura sin productor debe
ser entrada bruta en data/; si no lo es, márcala (es un paso faltante del pipeline
o una salida hecha a mano). Asigna capas: Capa 0 lee solo data/;
Capa N lee salidas de capas < N. Muestra al usuario el orden resultante para cualquier
caso no obvio antes de escribir scripts.
Salta archive/, misc/, plantillas (*template*) y scripts de prueba a menos que el
usuario indique lo contrario, y lista lo que saltaste.
3. Escribir los scripts
Copia las plantillas, completa las etapas y capas, chmod +x pipeline/*.sh.
4. Verificar cobertura y sintaxis
bash <directorio-de-este-skill>/scripts/check_coverage.sh <raíz-del-proyecto>
Esto ejecuta bash -n y shellcheck (si está instalado) en cada script del pipeline, luego
lista los archivos src/ que ningún script del pipeline menciona por nombre. Los archivos
renderizados mediante un bucle glob aparecen como no mencionados, así que revísalos manualmente.
Cada archivo restante o se añade al pipeline o se confirma como excluido intencionalmente.
5. Auditoría de reproducibilidad
Busca en src/ e informa (no corrijas en silencio) cualquiera de estos:
setwd(o rutas absolutas (/Users/,C:/,~/): fallan en otras máquinas- aleatoriedad (
sample(,rnorm(,boot,simr,set.seedfaltante) sin unset.seed() - código solo interactivo:
View(,file.choose(,readline(,browser( - salidas escritas fuera de
output/(excepto el renderizado y luego movimiento de Quarto) rm(list = ls()): oculta dependencias faltantes cuando los scripts se ejecutan en una sola sesión
6. Ejecutarlo
El pipeline completo puede llevar mucho tiempo y sobrescribe output/, así que pregunta antes de
ejecutarlo. Ofrece ejecutar una sola etapa o run_script.sh en un archivo primero. Para
verificar la reproducibilidad desde cero, mueve output/ a un lado (mv output output.bak),
no lo borres, luego ejecuta run_pipeline.sh y compara.
7. Documentarlo
Añade o actualiza una sección "Ejecutar el pipeline" en el archivo CLAUDE.md / README del proyecto: el comando único, qué hace cada etapa y cómo ejecutar un solo script.
Añadir un script a un pipeline existente
- Encuentra qué lee el nuevo script (paso 2) y, por tanto, en qué etapa y capa debe estar.
- Añade una línea
run_rallí, con un comentario de dependencia si no es obvia. - Si sus salidas alimentan scripts posteriores, comprueba que estos sigan en una capa posterior.
- Ejecuta
scripts/check_coverage.sh.