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:
@@ -54,6 +54,13 @@ reports/*
|
||||
!reports/.gitkeep
|
||||
projects/*/reports/
|
||||
|
||||
# Papers — artefacto local: papers académicos reproducibles. En fase interna viven
|
||||
# local y gitignored (como los reports); al promocionar a fase publishable se
|
||||
# vuelven sub-repo Gitea propio (como apps/analyses). Solo el marcador .gitkeep se
|
||||
# versiona. Convención: docs/capabilities/papers.md
|
||||
papers/*
|
||||
!papers/.gitkeep
|
||||
|
||||
# Node / pnpm
|
||||
**/node_modules/
|
||||
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
name: next_numbered_dir
|
||||
kind: function
|
||||
lang: bash
|
||||
domain: io
|
||||
version: "1.0.0"
|
||||
purity: impure
|
||||
signature: "next_numbered_dir(parent_dir: string, [width: int]) -> string"
|
||||
description: "Calcula el siguiente prefijo numerico NNNN- para un directorio numerado incremental. Escanea los subdirectorios directos de parent_dir cuyo nombre empiece por NNNN- (4+ digitos seguidos de guion), toma el maximo, le suma 1 y lo imprime con zero-padding al ancho width (default 4). Si parent_dir no existe o no tiene subdirs que matcheen, imprime 0001."
|
||||
tags: [papers, io, scaffold]
|
||||
uses_functions: []
|
||||
uses_types: []
|
||||
returns: []
|
||||
returns_optional: false
|
||||
error_type: "error_go_core"
|
||||
imports: []
|
||||
params:
|
||||
- name: parent_dir
|
||||
desc: "directorio padre cuyos subdirectorios numerados (NNNN-...) se escanean; obligatorio"
|
||||
- name: width
|
||||
desc: "ancho del zero-padding del numero impreso (default 4); opcional"
|
||||
output: "el siguiente numero como string con zero-padding a width digitos a stdout (ej. 0003); usage a stderr y exit 1 si falta parent_dir"
|
||||
tested: false
|
||||
tests: []
|
||||
test_file_path: ""
|
||||
file_path: "bash/functions/io/next_numbered_dir.sh"
|
||||
---
|
||||
|
||||
## Ejemplo
|
||||
|
||||
```bash
|
||||
source bash/functions/io/next_numbered_dir.sh
|
||||
|
||||
# Sobre un papers/ que ya contiene 0001-foo y 0002-bar
|
||||
mkdir -p /tmp/papers/{0001-foo,0002-bar}
|
||||
next_numbered_dir /tmp/papers
|
||||
# -> 0003
|
||||
|
||||
# Directorio vacio o inexistente -> primer numero
|
||||
next_numbered_dir /tmp/papers_nuevo
|
||||
# -> 0001
|
||||
|
||||
# Ancho de padding distinto
|
||||
next_numbered_dir /tmp/papers 6
|
||||
# -> 000003
|
||||
```
|
||||
|
||||
## Cuando usarla
|
||||
|
||||
Cuando scaffoldees un artefacto numerado incremental (papers/, reports/, issues/) y necesites el siguiente NNNN sin colision: escanea lo que ya existe en disco y te da el numero libre listo para crear `<NNNN>-<slug>`.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **Impura**: lee el filesystem (estado del directorio en el momento de la llamada). No crea nada — solo calcula e imprime el numero.
|
||||
- **Octal**: los numeros con cero a la izquierda (`08`, `09`) se interpretan como octal en aritmetica bash y romperian el calculo. La funcion fuerza base 10 con `10#$num` para evitarlo.
|
||||
- **Solo subdirectorios**: cuenta unicamente subdirs directos. Archivos sueltos (`.gitkeep`, `notas.md`) y subdirs que no matcheen el patron se ignoran. No es recursivo.
|
||||
- **Patron estricto**: el prefijo debe ser `NNNN-` (minimo 4 digitos seguidos de guion). Un subdir `12-foo` o `0001foo` (sin guion) NO se cuenta.
|
||||
- No hay deteccion de huecos: devuelve `max+1`, no el primer numero libre intermedio. Si tienes `0001` y `0003`, devuelve `0004`, no `0002`.
|
||||
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
# next_numbered_dir — Compute the next NNNN- prefix for a numbered directory.
|
||||
#
|
||||
# Scans the DIRECT subdirectories of <parent_dir> whose names start with a
|
||||
# numeric prefix of the form `NNNN-` (4+ digits followed by a hyphen), takes
|
||||
# the maximum number, adds 1, and prints it zero-padded to <width> (default 4).
|
||||
# If <parent_dir> does not exist or contains no matching subdir, prints the
|
||||
# first number (0001 at default width).
|
||||
|
||||
next_numbered_dir() {
|
||||
local parent_dir="${1:-}"
|
||||
local width="${2:-4}"
|
||||
|
||||
if [[ -z "$parent_dir" ]]; then
|
||||
echo "usage: next_numbered_dir <parent_dir> [width]" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local max=0
|
||||
local entry base num
|
||||
|
||||
if [[ -d "$parent_dir" ]]; then
|
||||
# Iterate only over direct subdirectories. The trailing slash in the
|
||||
# glob ensures files (e.g. .gitkeep) are skipped — only dirs match.
|
||||
for entry in "$parent_dir"/*/; do
|
||||
# If the glob matched nothing it stays literal; guard with -d.
|
||||
[[ -d "$entry" ]] || continue
|
||||
base="$(basename "$entry")"
|
||||
# Require a prefix of 4+ digits followed by a hyphen.
|
||||
if [[ "$base" =~ ^([0-9]{4,})- ]]; then
|
||||
num="${BASH_REMATCH[1]}"
|
||||
# Force base 10 so leading zeros (08, 09) are not read as octal.
|
||||
num=$((10#$num))
|
||||
if (( num > max )); then
|
||||
max=$num
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
printf "%0*d\n" "$width" $(( max + 1 ))
|
||||
}
|
||||
|
||||
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
|
||||
next_numbered_dir "$@"
|
||||
fi
|
||||
@@ -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 ""
|
||||
@@ -39,6 +39,7 @@ Indice de grupos de capacidades del registry. Cada grupo agrupa >=3 funciones qu
|
||||
| [cpp-tables](tql.md) | 9 | Table Query Language C++ puro: filter, group, agg, sort, join, stats, formulas Lua, round-trip emit/apply |
|
||||
| [data-table-renderers](data_table_renderers.md) | 1 | API declarativa de cell renderers para data_table: Badge, Progress, Duration, Icon via TableInput.column_specs |
|
||||
| [scheduler](scheduler.md) | 4 | Cron expression parsing, matching, next-run y traduccion humana (consume `apps/dag_engine`) |
|
||||
| [papers](papers.md) | — | Papers académicos reproducibles en `papers/<NNNN-slug>/`: scaffold del artefacto (`init_paper` + helper `next_numbered_dir`), plantillas IMRaD + pre-registro anti-HARKing, y (en construcción por la flota) congelar hipótesis, funciones estadísticas (effect size/CI/corrección múltiple), render md→PDF y peer-review adversarial. Reutiliza `deep-research`, grupo `eda` y el motor PDF de `datascience`. Diseño: `reports/0001-2026-06-30-papers-system-design.md` |
|
||||
| [extractor](extractor.md) | 15 | Funciones que leen datos de fuentes externas (BD, API, archivos, web). Nodos input de `data_factory` |
|
||||
| [transformer](transformer.md) | 15 | Funciones que clean/dedup/aggregate/feature-engineer datos. Nodos intermedios de `data_factory` |
|
||||
| [sink](sink.md) | 11 | Funciones que escriben datos a destino externo (BD, dashboard, alerta, email). Nodos output |
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
# papers — papers académicos reproducibles
|
||||
|
||||
Grupo de capacidad para producir **papers académicos** dentro de `fn_registry`: investigación con hipótesis falsables, experimentos reproducibles, análisis estadístico honesto y escritura en formato IMRaD. Cada paper es un artefacto nuevo en `papers/<NNNN-slug>/` que reutiliza infraestructura existente (skill `deep-research` para la revisión de literatura, grupo `eda` para el análisis, motor md→PDF de `datascience`, patrón de verificación adversarial del orquestador) y añade lo que falta como funciones del registry.
|
||||
|
||||
Diseño completo y decisiones: `reports/0001-2026-06-30-papers-system-design.md`.
|
||||
|
||||
> **Regla de oro anti paper-mill:** una hipótesis que **podía** fallar + un experimento con riesgo real de refutación + estadística que no es teatro. Si no hay riesgo de refutación, no es un paper. Los claims nunca superan a la evidencia. El antídoto al HARKing es el **pre-registro**: el plan de análisis se congela *antes* de mirar los datos.
|
||||
|
||||
## Estructura del artefacto
|
||||
|
||||
```
|
||||
papers/0001-mi-paper/
|
||||
paper.md # frontmatter (title, slug, authors, date, status, phase, tags, domain, hypothesis_id) + cuerpo IMRaD
|
||||
preregistration.md # H0/H1 + plan de análisis CONGELADO (frozen_at + content_hash) antes de correr
|
||||
references.md # bibliografía
|
||||
experiments/ # código / notebooks por experimento (exp01_*, exp02_*)
|
||||
data/ # crudos + procesados (gitignored si pesa)
|
||||
figures/ # gráficos generados
|
||||
reviews/ # outputs del peer-review adversarial
|
||||
out/ # paper.pdf — entregable final
|
||||
.git/ # SOLO cuando promociona a fase publishable (sub-repo Gitea)
|
||||
```
|
||||
|
||||
`papers/` está gitignored en el repo padre (solo `papers/.gitkeep` se versiona): un paper en fase interna no contamina el repo. Al promocionar a `status: publishable` se vuelve sub-repo Gitea `dataforge/<slug>` (como apps y analyses).
|
||||
|
||||
### Fases (campo `phase` de `paper.md`)
|
||||
|
||||
```
|
||||
question → review → hypothesis → design → running → analysis → writing → internal-review
|
||||
→ [DONE interno] → polish → submitted [solo en fase publishable]
|
||||
```
|
||||
|
||||
## Funciones
|
||||
|
||||
| ID | Pureza | Estado | Qué hace |
|
||||
|---|---|---|---|
|
||||
| `init_paper_bash_pipelines` | impure | ✅ disponible | Scaffold de `papers/<NNNN-slug>/`: calcula el siguiente NNNN, crea las subcarpetas, copia `paper.md` + `preregistration.md` con el frontmatter relleno (slug, title, date de hoy, `phase: question`, `status: draft`) y `references.md` vacío. NO hace `git init` (el paper arranca en fase interna local). |
|
||||
| `next_numbered_dir_bash_io` | impure | ✅ disponible | Dado un directorio, devuelve el siguiente número incremental de 4 dígitos (`0001`, `0002`, …) escaneando los subdirs con prefijo `NNNN-`. Helper de numeración de `init_paper` (reutilizable por reports/issues). |
|
||||
| `preregister_hypothesis` | impure | 🚧 en construcción (flota) | Congela el `preregistration.md` (H0/H1 + plan de análisis) con `frozen_at` + `content_hash`, pasa `status` a `frozen` y escribe `hypothesis_id` en `paper.md`. Mata el HARKing: tras congelar, el plan no se edita. |
|
||||
| `cohens_d` (effect size) | pure | 🚧 en construcción (flota) | Tamaño del efecto (Cohen's d) entre dos grupos. Reporta magnitud, no solo significancia. |
|
||||
| `confidence_interval` | pure | 🚧 en construcción (flota) | Intervalo de confianza de una métrica (media/diferencia). |
|
||||
| `holm_bonferroni` | pure | 🚧 en construcción (flota) | Corrección de comparaciones múltiples (Holm-Bonferroni / FWER) para el plan de análisis. |
|
||||
| `render_paper_pdf` | impure | 🚧 en construcción (flota) | Markdown IMRaD (`paper.md` + figuras) → `out/paper.pdf`, reutilizando el motor md→PDF del grupo `eda`/`datascience`. |
|
||||
|
||||
> Las funciones estadísticas reutilizan lo que ya exista en `datascience` (p.ej. `fdr_correction_py_datascience` cubre la corrección de comparaciones múltiples por FDR; el agente del rigor experimental decide si añade Holm-Bonferroni o reusa lo existente). Buscar antes de duplicar: `mcp__registry__fn_search query="effect size" domain="datascience"`.
|
||||
|
||||
### Peer review (no es función del registry)
|
||||
|
||||
El agente adversarial `.claude/agents/paper-reviewer.md` (🚧 en construcción por la flota) puntúa novedad, rigor, reproducibilidad y validez, e intenta **refutar** cada claim. Default a "failed" si la evidencia no soporta. Escribe su veredicto en `reviews/`. Es el equivalente al verificador adversarial del orquestador aplicado al paper.
|
||||
|
||||
## Ejemplo canónico (end-to-end)
|
||||
|
||||
```bash
|
||||
# 1. Scaffold del paper (fase question, local). Crea papers/0001-mi-paper/.
|
||||
./fn run init_paper mi-paper --title "¿El bucle reactivo reduce las calls inline?" --domain datascience --tags registry,telemetria
|
||||
|
||||
# 2. Revisión de literatura → llena Related work (skill deep-research, fase review).
|
||||
# /deep-research "..."
|
||||
|
||||
# 3. Pre-registro: congela H0/H1 + plan de análisis ANTES de mirar datos (fase hypothesis).
|
||||
./fn run preregister_hypothesis papers/0001-mi-paper # 🚧 en construcción
|
||||
|
||||
# 4. Experimentos en papers/0001-mi-paper/experiments/ (fase running) →
|
||||
# análisis con el grupo `eda` + funciones de effect size / CI / corrección múltiple (fase analysis).
|
||||
|
||||
# 5. Escritura IMRaD en paper.md (fase writing) → render del entregable PDF.
|
||||
./fn run render_paper_pdf papers/0001-mi-paper # 🚧 en construcción → out/paper.pdf
|
||||
|
||||
# 6. Peer review adversarial (fase internal-review).
|
||||
# Agent(subagent_type="paper-reviewer", prompt="Revisa papers/0001-mi-paper ...") # 🚧 en construcción
|
||||
```
|
||||
|
||||
## Fronteras
|
||||
|
||||
- **NO es para reports de trabajo.** Un report (`reports/`) es el entregable escrito de una tarea (resumen + evidencia + gaps); un paper es investigación con hipótesis falsable y experimento. Ver `.claude/rules/reports.md`.
|
||||
- **NO se indexa en `registry.db` en esta fase.** No hay tabla `papers` ni `entity_type` `paper` (KISS); se añadiría con migración propia si se decide. Las *funciones* del grupo sí se indexan (viven en `bash/functions/`, `python/functions/`), pero los artefactos `papers/<slug>/` no.
|
||||
- **NO hace `git init` en el scaffold.** El paper arranca en fase interna local y gitignored. La promoción a sub-repo Gitea (fase publishable) es un paso manual posterior.
|
||||
- **NO soporta LaTeX/arXiv todavía.** Formato elegido: Markdown como fuente + PDF como entregable. El soporte LaTeX se añadiría al promocionar un paper a fase publishable.
|
||||
|
||||
## Estado
|
||||
|
||||
Fase de scaffolding. Disponible: estructura del artefacto, plantillas (`docs/templates/paper.md`, `docs/templates/preregistration.md`), pipeline `init_paper` + helper `next_numbered_dir`, esta página y el bloque gitignore de `papers/`. En construcción por la flota: `preregister_hypothesis`, funciones estadísticas (effect size / CI / corrección múltiple), `render_paper_pdf` y el agente `paper-reviewer`. Validación end-to-end con un paper piloto real: pendiente.
|
||||
Vendored
+94
@@ -0,0 +1,94 @@
|
||||
---
|
||||
title: "TITULO DEL PAPER"
|
||||
slug: NNNN-slug
|
||||
authors: [Enmanuel]
|
||||
date: 2026-01-01
|
||||
status: draft # draft | internal | publishable
|
||||
phase: question # question -> review -> hypothesis -> design -> running -> analysis -> writing -> internal-review -> polish -> submitted
|
||||
tags: []
|
||||
domain: datascience
|
||||
hypothesis_id: "" # lo rellena preregister_hypothesis al congelar el preregistro
|
||||
---
|
||||
|
||||
<!--
|
||||
Paper académico reproducible (formato IMRaD). Esta es la FUENTE editable en Markdown;
|
||||
el entregable PDF se genera con render_paper_pdf (grupo `papers`).
|
||||
|
||||
Regla de oro anti paper-mill: una hipótesis que PODÍA fallar + un experimento con
|
||||
riesgo real de refutación + estadística que no es teatro. Si no hay riesgo de
|
||||
refutación, no es un paper. Los claims nunca superan a la evidencia.
|
||||
-->
|
||||
|
||||
# {{título del paper}}
|
||||
|
||||
## Abstract
|
||||
|
||||
<!--
|
||||
Resumen estructurado en 4-6 frases: contexto -> gap -> método -> resultados -> conclusión.
|
||||
Sin citas, sin abreviaturas sin definir. Es lo único que mucha gente leerá: que se sostenga solo.
|
||||
-->
|
||||
|
||||
## 1. Introduction
|
||||
|
||||
<!--
|
||||
Embudo en cuatro movimientos:
|
||||
1. Contexto — el área y por qué importa.
|
||||
2. Gap — qué NO se sabe todavía (el hueco que este paper llena).
|
||||
3. Pregunta / hipótesis — formulada de forma falsable (ver preregistration.md).
|
||||
4. Contribución — lista explícita de lo que aporta este trabajo ("Contributions:").
|
||||
-->
|
||||
|
||||
## 2. Related work
|
||||
|
||||
<!--
|
||||
Qué existe ya y por qué no basta. Agrupa por enfoque, no por autor. Cada cita debe
|
||||
justificar por qué el gap sigue abierto. Output de la fase de revisión (skill deep-research).
|
||||
-->
|
||||
|
||||
## 3. Methods
|
||||
|
||||
<!--
|
||||
Diseño REPRODUCIBLE: otra persona lo corre y obtiene lo mismo.
|
||||
- Variables: independiente(s), dependiente(s), control.
|
||||
- Diseño: N, condiciones, muestreo, aleatorización.
|
||||
- Métricas y cómo se miden.
|
||||
- Protocolo paso a paso + dónde vive el código (experiments/) y los datos (data/).
|
||||
Debe ser coherente con el preregistration.md congelado (no se cambia el plan tras ver datos).
|
||||
-->
|
||||
|
||||
## 4. Results
|
||||
|
||||
<!--
|
||||
Datos SIN interpretar. Tablas y figuras (figures/) con su lectura literal.
|
||||
Reporta effect size + intervalos de confianza, no solo p-valores.
|
||||
Incluye también los resultados negativos / no significativos (anti cherry-picking).
|
||||
-->
|
||||
|
||||
## 5. Discussion
|
||||
|
||||
<!--
|
||||
Interpretación de los resultados a la luz de la pregunta. Claims <= evidencia.
|
||||
-->
|
||||
|
||||
### 5.1 Limitaciones
|
||||
|
||||
<!-- Qué no cubre el estudio, supuestos, datos faltantes. Honestidad explícita. -->
|
||||
|
||||
### 5.2 Amenazas a la validez
|
||||
|
||||
<!--
|
||||
- Validez interna — ¿la causa es lo que decimos o hay confusores?
|
||||
- Validez externa — ¿generaliza fuera de esta muestra/condiciones?
|
||||
- Validez de constructo — ¿la métrica mide lo que dice medir?
|
||||
- Validez estadística — ¿N suficiente, supuestos del test cumplidos, comparaciones múltiples corregidas?
|
||||
-->
|
||||
|
||||
## 6. Conclusion + Future work
|
||||
|
||||
<!--
|
||||
Cierre en 2-4 frases: qué se aprendió (sin overclaiming) + las siguientes preguntas que abre.
|
||||
-->
|
||||
|
||||
## References
|
||||
|
||||
<!-- Ver references.md. -->
|
||||
Vendored
+59
@@ -0,0 +1,59 @@
|
||||
---
|
||||
paper_slug: NNNN-slug
|
||||
frozen_at: "" # timestamp ISO — lo rellena preregister_hypothesis al congelar
|
||||
content_hash: "" # hash del contenido congelado — lo rellena preregister_hypothesis
|
||||
status: draft # draft -> frozen (preregister_hypothesis lo pasa a frozen; tras congelar NO se edita)
|
||||
---
|
||||
|
||||
> **⚠️ ESTE DOCUMENTO SE CONGELA ANTES DE MIRAR LOS DATOS (anti-HARKing).**
|
||||
> El plan de análisis se fija aquí *antes* de ejecutar el experimento. Una vez congelado
|
||||
> (`status: frozen`, con `frozen_at` + `content_hash`), **no se edita**. Inventar o ajustar
|
||||
> la hipótesis después de ver los resultados (HARKing) invalida el paper. Si el plan cambia
|
||||
> tras ver datos, eso es análisis exploratorio y se reporta como tal, no como confirmatorio.
|
||||
|
||||
# Pre-registro — {{título del paper}}
|
||||
|
||||
## 1. Pregunta de investigación
|
||||
|
||||
<!-- La pregunta concreta, en una frase. Debe poder responderse con un experimento. -->
|
||||
|
||||
## 2. Hipótesis
|
||||
|
||||
<!-- Falsable (Popper): una predicción que PODRÍA fallar. -->
|
||||
|
||||
- **H0 (nula):** <!-- no hay efecto / no hay diferencia. Es lo que el test intenta rechazar. -->
|
||||
- **H1 (alternativa):** <!-- el efecto esperado, con dirección si la hay. -->
|
||||
|
||||
## 3. Variables
|
||||
|
||||
- **Independiente(s):** <!-- lo que se manipula. -->
|
||||
- **Dependiente(s):** <!-- lo que se mide (la métrica de resultado). -->
|
||||
- **Control:** <!-- lo que se mantiene fijo / se cubre estadísticamente. -->
|
||||
|
||||
## 4. Diseño
|
||||
|
||||
<!--
|
||||
- N: tamaño de muestra (y justificación / power analysis si aplica).
|
||||
- Condiciones / grupos.
|
||||
- Muestreo y aleatorización.
|
||||
- Criterios de inclusión / exclusión de datos (definidos AHORA, no después).
|
||||
-->
|
||||
|
||||
## 5. Plan de análisis
|
||||
|
||||
<!--
|
||||
El plan estadístico EXACTO, decidido antes de ver los datos:
|
||||
- Test estadístico concreto (p.ej. t-test de Welch, Mann-Whitney U, regresión...).
|
||||
- Métrica de effect size (p.ej. Cohen's d, diferencia de medias, odds ratio).
|
||||
- Criterio de decisión (umbral alpha, qué resultado confirma/refuta H1).
|
||||
- Corrección por comparaciones múltiples (p.ej. Holm-Bonferroni) si hay >1 contraste.
|
||||
- Manejo de supuestos (normalidad, varianzas) y qué se hace si no se cumplen.
|
||||
-->
|
||||
|
||||
## 6. Predicción cuantitativa
|
||||
|
||||
<!--
|
||||
La predicción numérica concreta que el experimento pondrá a prueba.
|
||||
P.ej. "esperamos d >= 0.5 con IC95% que no cruza 0" o "una reducción >= 15% en la métrica X".
|
||||
Cuanto más específica, más falsable.
|
||||
-->
|
||||
Reference in New Issue
Block a user