Descripción técnica

Convención de carpetas

modelos/<modelo>/
├── modelo.json            id · nombre · rama · estado · descripcion (a mano)
├── drafts/                draft.md, draftv0.md, draftv1.md, … (sufijo mayor = vigente)
└── revision/
    ├── 00-indice.md       estado del modelo; línea «Draft vigente» mantenida por `modelador indice`
    └── NN-*.md            fichas de revisión

Todo lo demás se deriva del disco: orden numérico de drafts (draftv10 > draftv2), draft vigente, lista de fichas. La única redundancia es la línea Draft vigente del índice, que se trackea en git y que modelador check valida contra el sufijo mayor.

Módulos

MóduloFunción
modelos/catalogo.pydescubre modelos, ordena drafts, calcula el vigente
modelos/indice.pylee, escribe y valida la línea «Draft vigente»
modelos/enlaces.pyreescribe enlaces fuera de bloques de código: rutas del vendor de Oasis → blob/<sha> en GitHub; .md internos → .html; anclas #L → blob en main
modelos/markdown.pymarkdown-it-py (CommonMark + tablas + anclas h2/h3); tablas envueltas en .table-wrap
modelos/backlog.pyextracción tolerante: toda tabla cuya primera celda sea TK-/OP-/RP-/Rn, más los encabezados OP-nn como oportunidades; celdas guardadas como markdown en backlog.json
site/packs.pyzips deterministas (fecha fija, orden fijo): -drafts, -revision, -todo
cli/build.py · check.py · zip.py · indice.pysubcomandos de modelador

CLI

modelador build [--target all|catalogo|foss]   # public/ y data/ — solo en main
modelador check                                # restos de rutas locales, enlaces rotos, >300 KB, línea Draft vigente
modelador zip [--modelo X]                     # solo los zips
modelador indice --modelo X [--check]          # mantiene «Draft vigente» en revision/00-indice.md

Oasis

El código auditado es epsylon/oasis @ 9a657b7 (AGPL-3.0). No se commitea: vive en vendor/oasis, ignorado por git. Los enlaces de los drafts se reescriben en build hacia ese commit exacto, y modelador check falla si queda cualquier ruta local en public/.