feat(papers): estructura, scaffolding y capability page del artefacto papers/
Nuevo tipo de artefacto para papers académicos reproducibles (papers/<NNNN-slug>/): - Plantillas docs/templates/paper.md (IMRaD completo con guías por sección: Abstract, Introduction, Related work, Methods, Results, Discussion con Limitaciones + Amenazas a la validez, Conclusion + Future work) y docs/templates/preregistration.md (H0/H1 falsable, variables, diseño, plan de análisis con test exacto + effect size + corrección múltiple, predicción cuantitativa; nota anti-HARKing de congelado). - Pipeline init_paper (bash/functions/pipelines/init_paper.sh + .md): calcula el siguiente NNNN, crea las subcarpetas (experiments data figures reviews out), copia las plantillas rellenando el frontmatter (title, slug, date, phase=question, status=draft) y crea references.md. No hace git init (fase interna local). - Función atómica reutilizable next_numbered_dir (bash/functions/io): siguiente prefijo NNNN- escaneando un directorio numerado (reutilizable por papers/reports/issues). - papers/ como artefacto local gitignored (bloque en .gitignore + papers/.gitkeep): un paper en fase interna no contamina el repo padre; al promocionar a publishable se vuelve sub-repo Gitea propio. - Página de capacidad docs/capabilities/papers.md + fila en el INDEX: tabla de funciones del grupo papers (disponibles + en construcción por la flota), ejemplo canónico end-to-end y fronteras. Reutiliza slugify_ascii del registry. Diseño: reports/0001-2026-06-30-papers-system-design.md. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
---
|
||||
name: init_paper
|
||||
kind: pipeline
|
||||
lang: bash
|
||||
domain: pipelines
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "init_paper(slug: string, [--title <t>] [--domain <d>] [--tags <csv>]) -> void"
|
||||
description: "Scaffold de un paper académico reproducible en papers/<NNNN-slug>/. Calcula el siguiente número incremental escaneando papers/, crea las subcarpetas (experiments data figures reviews out), copia las plantillas paper.md (IMRaD) + preregistration.md (anti-HARKing) rellenando el frontmatter (title, slug, date de hoy, phase=question, status=draft) y crea references.md. NO hace git init: el paper arranca en fase interna local (papers/ gitignored). Grupo de capacidad papers."
|
||||
tags: [papers, scaffold, paper, pipeline, bash, launcher]
|
||||
uses_functions:
|
||||
- next_numbered_dir_bash_io
|
||||
- slugify_ascii_py_core
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: []
|
||||
params:
|
||||
- name: slug
|
||||
desc: "identificador legible del paper; se slugifica a ASCII (espacios/acentos se normalizan) y se prefija con el siguiente NNNN incremental"
|
||||
- name: "--title"
|
||||
desc: "título del paper (string); si se omite, usa el slug limpio. No debe contener el carácter '|'"
|
||||
- name: "--domain"
|
||||
desc: "dominio del paper escrito en el frontmatter (default datascience)"
|
||||
- name: "--tags"
|
||||
desc: "tags CSV que se escriben en el frontmatter de paper.md (opcional)"
|
||||
output: "sin salida directa; crea papers/<NNNN-slug>/ con paper.md, preregistration.md, references.md y las subcarpetas experiments/ data/ figures/ reviews/ out/. Imprime el resumen y los pasos siguientes a stdout."
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "bash/functions/pipelines/init_paper.sh"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```bash
|
||||
# Scaffold de un paper nuevo (numera 0001, 0002, ... automáticamente)
|
||||
fn run init_paper mi-primer-paper --title "Mi primer paper"
|
||||
fn run init_paper reactive-loop-calls --domain datascience --tags registry,telemetria
|
||||
|
||||
# El slug se slugifica: "Áreas de Mejora" -> papers/0003-areas-de-mejora/
|
||||
fn run init_paper "Áreas de Mejora"
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando empiezas un paper académico nuevo dentro de `fn_registry` y necesitas el esqueleto del artefacto (`papers/<NNNN-slug>/`) con las plantillas IMRaD y de pre-registro listas para rellenar. Es el paso 1 del grupo de capacidad `papers` (ver `docs/capabilities/papers.md`), antes de la revisión de literatura y del pre-registro de la hipótesis.
|
||||
|
||||
## Flujo
|
||||
|
||||
1. Parsea `<slug>` (posicional) + flags `--title` / `--domain` / `--tags`. Falla con exit ≠ 0 si falta el slug.
|
||||
2. `slugify_ascii` — normaliza el slug a ASCII lowercase sin diacríticos (reutiliza la función del registry, solo stdlib).
|
||||
3. `next_numbered_dir papers/` — calcula el siguiente NNNN de 4 dígitos sin colisión.
|
||||
4. Crea `papers/<NNNN-slug>/` con las subcarpetas `experiments/ data/ figures/ reviews/ out/`.
|
||||
5. Copia `docs/templates/paper.md` + `docs/templates/preregistration.md` y rellena el frontmatter por clave de línea (title, slug, date de hoy, domain, tags; phase=question y status=draft vienen de la plantilla).
|
||||
6. Crea `references.md` vacío.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **NO hace `git init`.** El paper arranca en fase interna local; `papers/` está gitignored en el repo padre (solo `papers/.gitkeep` se versiona). Promocionar a sub-repo Gitea (fase publishable) es manual.
|
||||
- **El `--title` no debe contener el carácter `|`** (se usa como delimitador de sed al rellenar el frontmatter; los `&` y `\` sí se escapan).
|
||||
- **No indexa el paper en `registry.db`** — los artefactos `papers/<slug>/` no se indexan en esta fase (KISS); sí se indexa este pipeline.
|
||||
- Requiere `python3` (del venv del registry o del sistema) para slugificar; `slugify_ascii` solo usa stdlib, así que el venv no es obligatorio.
|
||||
- Idempotencia: si el directorio destino ya existiera, aborta con exit ≠ 0 en vez de sobrescribir.
|
||||
|
||||
## Notas
|
||||
|
||||
Cada paper es un artefacto independiente (mismo patrón que `apps/` y `analysis/`, pero para investigación). El pipeline usa `set -euo pipefail`: cualquier fallo detiene la ejecución. Parte del grupo de capacidad `papers` — diseño completo en `reports/0001-2026-06-30-papers-system-design.md`.
|
||||
@@ -0,0 +1,177 @@
|
||||
#!/usr/bin/env bash
|
||||
# init_paper
|
||||
# ----------
|
||||
# Scaffold de un paper académico reproducible en papers/<NNNN-slug>/.
|
||||
#
|
||||
# Calcula el siguiente número incremental escaneando papers/, crea el
|
||||
# directorio con todas las subcarpetas (experiments data figures reviews out),
|
||||
# copia las plantillas paper.md + preregistration.md rellenando el frontmatter
|
||||
# (title, slug, date de hoy, phase=question, status=draft) y crea references.md.
|
||||
#
|
||||
# NO hace `git init`: el paper arranca en fase interna local (papers/ está
|
||||
# gitignored en el repo padre, solo .gitkeep se versiona). La promoción a
|
||||
# sub-repo Gitea (fase publishable) es un paso posterior MANUAL.
|
||||
#
|
||||
# Compone: next_numbered_dir (helper de numeración del registry) +
|
||||
# slugify_ascii (slug ASCII del registry).
|
||||
#
|
||||
# USO:
|
||||
# ./init_paper.sh <slug> [--title "..."] [--domain <d>] [--tags a,b,c]
|
||||
#
|
||||
# EJEMPLOS:
|
||||
# ./init_paper.sh mi-primer-paper --title "Mi primer paper"
|
||||
# ./init_paper.sh reactive-loop-calls --domain datascience --tags registry,telemetria
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REGISTRY_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
|
||||
# Funciones atómicas del registry
|
||||
source "$REGISTRY_ROOT/bash/functions/io/next_numbered_dir.sh"
|
||||
|
||||
# ── Parsing de argumentos ────────────────────────────────────
|
||||
|
||||
SLUG_RAW=""
|
||||
TITLE=""
|
||||
DOMAIN="datascience"
|
||||
TAGS=""
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
--title)
|
||||
TITLE="$2"; shift 2 ;;
|
||||
--domain)
|
||||
DOMAIN="$2"; shift 2 ;;
|
||||
--tags)
|
||||
TAGS="$2"; shift 2 ;;
|
||||
-h|--help)
|
||||
grep "^#" "$0" | sed 's/^# \?//' ; exit 0 ;;
|
||||
-*)
|
||||
echo "Flag desconocido: $1" >&2 ; exit 1 ;;
|
||||
*)
|
||||
if [ -z "$SLUG_RAW" ]; then
|
||||
SLUG_RAW="$1"
|
||||
else
|
||||
echo "ERROR: argumento posicional inesperado: '$1' (solo se admite un <slug>)." >&2
|
||||
exit 1
|
||||
fi
|
||||
shift ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$SLUG_RAW" ]; then
|
||||
echo "ERROR: falta el argumento <slug>." >&2
|
||||
echo "Uso: $0 <slug> [--title \"...\"] [--domain <d>] [--tags a,b,c]" >&2
|
||||
echo " Ejemplo: $0 mi-primer-paper --title \"Mi primer paper\"" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ── Slugificar (reutiliza slugify_ascii del registry; solo stdlib) ──
|
||||
|
||||
PYBIN="$REGISTRY_ROOT/python/.venv/bin/python3"
|
||||
[ -x "$PYBIN" ] || PYBIN="$(command -v python3 || true)"
|
||||
if [ -z "$PYBIN" ]; then
|
||||
echo "ERROR: no se encontró python3 para slugificar el slug." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SLUG_CLEAN=$("$PYBIN" -c '
|
||||
import sys, os
|
||||
sys.path.insert(0, os.path.join(sys.argv[2], "python", "functions"))
|
||||
from core.slugify_ascii import slugify_ascii
|
||||
print(slugify_ascii(sys.argv[1], default="paper"))
|
||||
' "$SLUG_RAW" "$REGISTRY_ROOT")
|
||||
|
||||
# ── Resolver número incremental y directorio destino ─────────
|
||||
|
||||
PAPERS_DIR="$REGISTRY_ROOT/papers"
|
||||
mkdir -p "$PAPERS_DIR"
|
||||
|
||||
NUM=$(next_numbered_dir "$PAPERS_DIR")
|
||||
SLUG_FULL="${NUM}-${SLUG_CLEAN}"
|
||||
PAPER_DIR="$PAPERS_DIR/$SLUG_FULL"
|
||||
|
||||
if [ -d "$PAPER_DIR" ]; then
|
||||
echo "ERROR: el directorio del paper ya existe: $PAPER_DIR" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TODAY=$(date +%Y-%m-%d)
|
||||
[ -n "$TITLE" ] || TITLE="$SLUG_CLEAN"
|
||||
|
||||
TAGS_YAML="[]"
|
||||
if [ -n "$TAGS" ]; then
|
||||
TAGS_YAML="[$(echo "$TAGS" | sed 's/,/, /g')]"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
echo " INIT PAPER: ${SLUG_FULL}"
|
||||
echo " Título: ${TITLE}"
|
||||
echo " Directorio: ${PAPER_DIR}"
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
|
||||
# ── Crear estructura ─────────────────────────────────────────
|
||||
|
||||
echo "[1/3] Creando estructura..."
|
||||
mkdir -p "$PAPER_DIR"/experiments "$PAPER_DIR"/data "$PAPER_DIR"/figures \
|
||||
"$PAPER_DIR"/reviews "$PAPER_DIR"/out
|
||||
echo " experiments/ data/ figures/ reviews/ out/"
|
||||
|
||||
# ── Copiar plantillas + rellenar frontmatter ─────────────────
|
||||
|
||||
echo "[2/3] Escribiendo paper.md + preregistration.md..."
|
||||
|
||||
# Escapa caracteres especiales del RHS de sed (delimitador |)
|
||||
sed_escape() { printf '%s' "$1" | sed -e 's/[\\&|]/\\&/g'; }
|
||||
TITLE_ESC="$(sed_escape "$TITLE")"
|
||||
DOMAIN_ESC="$(sed_escape "$DOMAIN")"
|
||||
|
||||
PAPER_MD="$PAPER_DIR/paper.md"
|
||||
PREREG_MD="$PAPER_DIR/preregistration.md"
|
||||
|
||||
cp "$REGISTRY_ROOT/docs/templates/paper.md" "$PAPER_MD"
|
||||
cp "$REGISTRY_ROOT/docs/templates/preregistration.md" "$PREREG_MD"
|
||||
|
||||
sed -i \
|
||||
-e "s|^title:.*|title: \"${TITLE_ESC}\"|" \
|
||||
-e "s|^slug:.*|slug: ${SLUG_FULL}|" \
|
||||
-e "s|^date:.*|date: ${TODAY}|" \
|
||||
-e "s|^domain:.*|domain: ${DOMAIN_ESC}|" \
|
||||
-e "s|^tags:.*|tags: ${TAGS_YAML}|" \
|
||||
"$PAPER_MD"
|
||||
|
||||
sed -i \
|
||||
-e "s|^paper_slug:.*|paper_slug: ${SLUG_FULL}|" \
|
||||
"$PREREG_MD"
|
||||
|
||||
echo " $PAPER_MD"
|
||||
echo " $PREREG_MD"
|
||||
|
||||
# ── references.md ────────────────────────────────────────────
|
||||
|
||||
echo "[3/3] Escribiendo references.md..."
|
||||
cat > "$PAPER_DIR/references.md" << EOF
|
||||
# References — ${TITLE}
|
||||
|
||||
<!-- Una entrada por referencia. Formato libre (o BibTeX) hasta promocionar a publishable. -->
|
||||
EOF
|
||||
echo " $PAPER_DIR/references.md"
|
||||
|
||||
# ── Resumen ──────────────────────────────────────────────────
|
||||
|
||||
echo ""
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
echo " PAPER '${SLUG_FULL}' LISTO (fase: question, status: draft)"
|
||||
echo "════════════════════════════════════════════════════════════"
|
||||
echo ""
|
||||
echo " Pasos siguientes:"
|
||||
echo " 1. Revisión de literatura (skill /deep-research) → Related work."
|
||||
echo " 2. Pre-registro: congela H0/H1 + plan en preregistration.md (preregister_hypothesis)."
|
||||
echo " 3. Experimentos en experiments/ → análisis (grupo eda) → escritura IMRaD en paper.md."
|
||||
echo " 4. render_paper_pdf → out/paper.pdf. Peer review adversarial → reviews/."
|
||||
echo ""
|
||||
echo " papers/ está gitignored: este paper vive local hasta promocionar a publishable."
|
||||
echo ""
|
||||
Reference in New Issue
Block a user