Version: 1.0 · Fecha: 2026-04-20
El pipeline transforma una HU V1 cruda en una HU V2 (con identidad visual Nebula) en 5 fases. Fases A, D, E son deterministas (scripts). Fases B, C usan LLM con gate humano en C.
| Fase | Tipo | Tiempo | Entrada | Salida |
|---|---|---|---|---|
| A | Script determinista | ~30 seg | PDF V1 + Anexos | extracted.yaml, mockups PNG |
| B | LLM-vision | ~3 min | mockups PNG | catalog-interfaces.yaml |
| C | LLM-texto + GATE humano | ~20 min | extracted.yaml + catalog-interfaces.yaml |
mapping-approved.yaml |
| D | Script + templates + LLM | ~30 seg | hu_spec.yaml (derivado de C) |
HU-<COD>-V2.docx |
| E | Script determinista + GATE QA | ~20 min | DOCX + extracted.yaml |
reporte_validacion.md + firma |
Extraer texto y mockups del PDF V1 + anexos, y estructurarlos en YAML consumible por fases posteriores.
pdftotext -layout (poppler-utils): preserva estructura tabular del PDF.pdfimages (poppler-utils): extrae todas las imágenes del PDF.pdftoppm (poppler-utils): convierte PDF a PNG en Fase D.01_extract_hu.sh · bash · sin LLM.02_parse_hu.py · python · sin LLM.A.1 · Extraer texto:
./01_extract_hu.sh <V1.pdf> <anexo-flujo.pdf> <anexo-casos-prueba.pdf> <out_dir>
A.2 · Extraer imágenes:
Mismo script. Filtra imágenes candidatas a wireframe (> 500×500px, no-logo).
A.3 · Detectar secciones:
Regex sobre headers REGLAS DE NEGOCIO, CRITERIOS DE ACEPTACIÓN, WIREFRAME, etc.
A.4 · Estructurar YAML:
python3 02_parse_hu.py <out_dir> --pdf-name "<V1.pdf>"
Produce extracted.yaml con:
metadata: {codigo, titulo, modulo, submodulo, version, fecha, responsable, prioridad}
descripcion: {como, quiero, para}
alcance_funcional: "<texto>"
campos_v1: [{nombre, tipo, obligatorio, formato, validacion, comportamiento, linea_origen}]
reglas_v1: [{id, texto, linea_origen}]
criterios_v1: [{id, texto, linea_origen}]
anexos: [{tipo, archivo}]
mockups: [{archivo, ancho, alto}]
extracted.yaml existe y tiene todas las secciones.Si hay errores (típicamente metadata con ruido, campos truncados por layout multicolumna del PDF), se corrigen manualmente antes de pasar a Fase B.
| Error | Causa | Solución |
|---|---|---|
metadata.responsable: "Prioridad" |
Parser confundió header de tabla | Corregir manualmente en YAML |
Campos con nombre truncado (Rango de) |
PDF multicolumna confunde tokenización | Corregir manualmente |
| 0 RN detectadas | Sección "REGLAS DE NEGOCIO" no se encontró (ej. por typo "REGLAS DE NEGOCIO Y LOGICA") | Verificar sections.tsv |
Por cada mockup PNG, identificar su propósito (listado / formulario / modal), campos visibles, botones, tablas y acciones. Produce el catálogo de interfaces (INT-ALCn-##).
PROMPT_PIPELINE_HU_V1_V2.md §Fase B.wireframe-interpreter — recibe carpeta de PNGs, produce catalog-interfaces.yaml. Ver .claude/agents/wireframe-interpreter.md.
interfaces:
- id_tentativo: "INT-01"
proposito: "listado | formulario-creacion | modal-emergente | seccion-emergente | modal-busqueda"
nombre: "<nombre inferido>"
campos:
- nombre: "..."
tipo: "Texto | Numérico | Fecha | Lista | Checkbox | Tabla"
obligatorio_aparente: true/false
bloqueado_aparente: true/false
ubicacion: "cabecera | formulario | tabla | pie"
botones:
- etiqueta: "..."
ubicacion: "..."
estado_aparente: "enabled | disabled | conditional"
tablas:
- nombre_tabla: "..."
columnas: ["col1", "col2", ...]
modales_invocables:
- etiqueta_trigger: "..."
Si el V1 no trae mockups gráficos, el LLM infiere wireframes ASCII-art desde la narrativa. Cada INT inferido se marca requiere_validacion_consultor: true para revisión en Fase C.
id_tentativo, proposito, nombre, y al menos uno de (campos, botones, tablas).campos_no_legibles: true sin nota explicativa.Cruzar el texto extraído del V1 con el catálogo de interfaces detectadas, asignando cada campo / FN / RN / CA / bullet narrativo a un INT específico.
PROMPT_PIPELINE_HU_V1_V2.md §Fase C.mapping-analyst — produce mapping.yaml con items ambiguos marcados. Ver .claude/agents/mapping-analyst.md.
El arquitecto revisa mapping.yaml y resuelve:
ambiguo: true: decide a qué INT pertenecen.El resultado se guarda en mapping-approved.yaml y se firma un gate_c4_log.md con el detalle de decisiones.
mapping:
campos:
- v1_nombre: "No. Identificación"
v1_index: 2
int_destino: "INT-01"
contexto: "columna tabla listado"
aprobado: true
aprobador: "Carlos Torres"
timestamp: "2026-04-20T15:32:00-05:00"
reglas: [...]
criterios: [...]
alcance: [...]
interfaces_inferidas_sin_mockup: [...]
A partir del mapeo aprobado, generar el hu_spec.yaml consolidado y a partir de él producir el HU-<COD>-V2.docx con identidad Nebula aplicada.
hu_spec.yamlHerramienta: Claude + prompt D4/D5 de PROMPT_PIPELINE_HU_V1_V2.md.
El LLM recibe mapping-approved.yaml + extracted.yaml y produce un YAML estructurado con:
metadatadescripcionalcances[].fns[]alcances[].ints[].layout (wireframe declarativo)alcances[].ints[].campos[]alcances[].rns[] (aplicando templates D4.1-D4.5 de RN)alcances[].cas[] (aplicando templates D5 de Gherkin)anexosHerramientas:
04_generate_docx.py (python-docx): construye las tablas del DOCX.05_render_wireframe.py (WeasyPrint + Jinja2 + Pillow): renderiza cada INT a PNG siguiendo Nebula v1.4.Invocación:
.venv/bin/python3 04_generate_docx.py hu_spec.yaml ./mockups_dir HU-<COD>-V2.docx
El script 04_generate_docx.py invoca internamente 05_render_wireframe.py una vez por cada INT con layout: definido.
Todos en scripts/templates/:
nebula.css — paleta y componentes Nebula v1.4 literales.base.html.j2 — layout global (topbar + sidebar + workspace + statusbar).list_view.html.j2form.html.j2modal.html.j2detail.html.j2wizard.html.j2Iconos en scripts/icons/lucide_icons.py (16 SVG lucide MIT).
Templates aplicados automáticamente:
| Categoría | Cuándo se genera | Plantilla |
|---|---|---|
| D4.1 RN de permiso | 1 por cada acción con permiso condicional | FN-ALCn-<X> Valida que el usuario tenga el permiso de <accion> ... |
| D4.2 Validación campo obligatorio | 1 por cada campo Obligatorio=Sí |
FN-ALCn-<X> El campo "<nombre>" es obligatorio. Si está vacío ... |
| D4.3 Cálculo derivado | 1 por cada campo bloqueado con fórmula | FN-ALCn-<X> El campo "<nombre>" se calcula como <fórmula> ... |
| D4.4 Visibilidad condicional | 1 por cada elemento con estado_aparente: conditional |
FN-ALCn-<X> El botón "<nombre>" se habilita solo cuando ... |
| D4.5 Navegación / postcondición | 1 por cada botón de navegación | FN-ALCn-<X> Al hacer clic en "<botón>", el sistema ... |
| D4.6 RN residuales V1 | Todas las RN del V1 no generadas por D4.1-D4.5 | Texto literal con prefijo FN-ALCn-<X> |
Por cada RN se emite al menos una CA con:
Dado <precondición inferida>
[Y <condición adicional>]
Cuando <acción trigger>
Entonces <postcondición>
Y aplica RN-ALCn-##
[Y aplica INT-ALCn-##]
Casos especiales (más de 1 CA por RN):
HU-<COD>-V2.docx_rendered/INT-ALCn-##.png (uno por INT)_rendered/INT-ALCn-##.spec.yaml (espec del wireframe que generó el PNG)Validar determinísticamente la calidad del DOCX generado en 4 dimensiones + gate humano QA.
03_validate_v2.py · Python + python-docx.PROMPT_VALIDACION_HU.md · prompt 7 dimensiones (gate E5).| Criterio | Qué valida | Umbral |
|---|---|---|
| E1 Trazabilidad | Cada FN tiene ≥1 RN que la refiere; cada RN tiene ≥1 CA; cada CA refiere ≥1 RN+INT | sin huérfanos |
| E2 Cobertura campos | Todos los campos de cada INT aparecen en su tabla de especificación | 100% |
| E3 Cobertura semántica V1→V2 | Todas las RN/CA/campos del V1 tienen equivalente en V2 | ≥ 85% |
| E4 Gherkin válido | Cada CA tiene Dado/Cuando/Entonces y referencias válidas | ≥ 85% |
QA aplica el prompt de 7 dimensiones al DOCX:
Veredicto objetivo: PROCESABLE POR PIPELINE (sin inconsistencias críticas).
.venv/bin/python3 03_validate_v2.py HU-<COD>-V2.docx --v1-yaml extracted.yaml --output reporte.md
reporte_validacion.md con:
| Fallo | Acción |
|---|---|
| E1 FN/RN huérfanas | Añadir RN/CA faltantes al hu_spec.yaml y regenerar D |
| E2 Campo sin INT | Agregar el campo al layout o eliminarlo de la tabla |
| E3 cobertura < 85% | Revisar qué RN/CA del V1 no se mapearon — típicamente Fase C incompleta |
| E4 Gherkin < 85% | Reformular CAs a templates D5 estrictos |
| E5 7 dimensiones CRÍTICAS | Volver a Fase C o D según la dimensión fallida |
┌──────────────────────────────────────┐
ENTRADA V1 ─────▶ │ FASE A · EXTRACCIÓN (scripts) │
│ pdftotext + pdfimages + parser │
│ → extracted.yaml + wireframes/*.png │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ FASE B · WIREFRAMES (LLM-vision) │
│ Claude Sonnet 4.6 │
│ → catalog-interfaces.yaml │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ FASE C · MAPEO (LLM + gate humano) │
│ Claude Sonnet 4.6 │
│ → mapping.yaml │
│ ⚠ GATE C4 humano obligatorio │
│ → mapping-approved.yaml │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ FASE D · SÍNTESIS (templates + LLM) │
│ D.1 Claude D4/D5 → hu_spec.yaml │
│ D.2 04_generate_docx.py │
│ invoca 05_render_wireframe.py │
│ → HU-<COD>-V2.docx + _rendered/ │
└──────────────────────────────────────┘
│
▼
┌──────────────────────────────────────┐
│ FASE E · VALIDACIÓN (scripts + gate) │
│ 03_validate_v2.py E1-E4 │
│ ⚠ GATE E5 QA (7 dimensiones) │
│ → reporte_validacion.md │
└──────────────────────────────────────┘
│
▼
EXPORT PDF
(WPS → Archivo → Exportar PDF)
│
▼
HU-<COD>-V2.pdf ✓
│
▼
Downstream Pipeline HTU v5.0
(genera DTOs, Entities, Controllers)
| Fase | Produce | Siguiente consume |
|---|---|---|
| A | extracted.yaml |
B (mockups), C (texto), E (referencia V1) |
| B | catalog-interfaces.yaml |
C |
| C | mapping-approved.yaml |
D |
| D | hu_spec.yaml + DOCX |
E (DOCX) |
| E | reporte_validacion.md |
— (terminal) |
Todas las fases son idempotentes y reanudables: si algo falla, se puede reintentar desde la fase específica sin recomputar las anteriores.
El pipeline se versiona como v<mayor>.<menor>. Cada versión congela los prompts, templates y scripts. El número de versión queda registrado en el log de auditoría.
| Version | Fecha | Autor | Descripcion |
|---|---|---|---|
| 1.0.0 | 2026-04-20 | Carlos Torres | Fases iniciales |