Files

550 lines
21 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# BITÁCORA DE DESARROLLO — AR-ShipDesign
> **Propósito:** Registro técnico vivo de cada módulo funcional de la app.
> A diferencia de `CHANGELOG.md` (que registra versiones), esta bitácora documenta
> el estado interno de cada módulo: qué funciona, qué se corrigió, por qué se
> tomaron ciertas decisiones y qué queda pendiente.
>
> **Actualizar** al final de cada sesión de trabajo o al completar un feature.
---
## Convenciones de estado
| Símbolo | Significado |
|---------|-------------|
| ✅ | Implementado y verificado (tests + visual) |
| 🔧 | Implementado, pendiente verificación visual en la app |
| 🐛 | Bug conocido, no resuelto aún |
| 📋 | Planificado, no iniciado |
| ❌ | Descartado o revertido (con explicación) |
| ⚠️ | Restricción crítica — no romper |
---
## Reglas Inquebrantables (leer SIEMPRE antes de editar los visores)
### ⚠️ REGLA DE EJES — NUNCA VIOLAR
```
Vista Perfil (ProfileViewer) → nodos en EJE X (longitudinal) + EJE Z (vertical)
Vista Planta (PlanViewer) → nodos en EJE X (longitudinal) + EJE Y (transversal)
Vista Frontal (BodyPlanViewer) → nodos en EJE Y (transversal) + EJE Z (vertical)
```
Nunca bloquear nodos en ninguna vista. Nunca añadir restricciones `_hit_test` a nodos normales.
Si un cambio rompe el movimiento en alguno de estos ejes → **REVERTIR INMEDIATAMENTE**.
### ⚠️ REGLA DE SNAP
El snap de nodos de contorno (`snap_boundary_nodes_to_contours`) **solo** se ejecuta en
`_on_new_project` (wizard de creación). Nunca en `_on_offsets_edited_from_viewer` ni en
`Hull.from_dict()`. Los `x_offsets` son datos del usuario y se restauran tal cual.
---
## Sentinels de nodo especial (`viewer_lines.py`)
```python
_KEEL_IDX = -1 # nodo de quilla (keel_z[i] por estación)
_SHEER_IDX = -2 # nodo de cubierta (sheer_z[i] por estación)
_STEM_IDX = -10 # punto de control de roda
_TRANS_IDX = -20 # punto de control de espejo de popa
```
El índice `j` en `(i, j)` siendo negativo indica nodo especial, no columna de `data[i,j]`.
---
## Módulo 1 — Geometría del Casco
**Archivo clave:** `arshipdesign/core/hull.py`, `arshipdesign/core/offsets.py`
### Estructura de datos
```
Hull
├── offsets: OffsetsTable
│ ├── x_stations[n_sta] — posición X de cada estación [m]
│ ├── data[n_sta, n_wl] — semi-manga Y por (estación, LdA) [m]
│ ├── keel_z[n_sta] — Z de la quilla por estación [m]
│ ├── z_waterlines[n_wl] — Z absoluta de cada LdA [m]
│ ├── z_offsets[n_sta, n_wl] — ajuste Z local por nodo [m]
│ └── x_offsets[n_sta, n_wl] — ajuste X visual del nodo en los visores 2D [m]
├── sheer_z[n_sta] — Z de la cubierta (arrufo) por estación [m]
├── stem_ctrl[k, 2] — polígono de control de la roda (B-spline)
├── transom_ctrl[k, 2] — polígono de control del espejo de popa
└── corner_nodes: list[[i,j]] — nodos marcados como esquina (rompen suavidad)
```
### Estado ✅
- **Serialización** (`to_dict` / `from_dict`): guarda todos los arrays sin recalcular.
Al cargar, los `x_offsets` se restauran exactamente como el usuario los dejó.
- **Inserción de estaciones** (`insert_station`): interpola Y, keel_z, sheer_z y offsets.
- **Inserción de líneas de agua** (`insert_waterline`): interpola semi-mangas.
- **B-Spline de sección** (`_section_yz` en `to_mesh`): muestrea el perfil Y-Z
desde quilla → LdA de control → cubierta con grado mín(3, n-1).
- **Malla 3D** (`to_mesh`): grilla estructurada n_u × n_v interpolada entre estaciones,
triangulada para PyVista. Genera ambas bandas (estribor + babor).
- **Lazy cache** (`station_planes`, `get_sheer_z`): no recalcula si los datos no cambian.
### Bug conocido 🐛
**"Tabla en quilla"** — Si se mueve `keel_z[i]` de una sola estación muy lejos de
las vecinas, la malla 3D muestra una depresión abrupta (tabla/aleta) porque:
- Las LdA permanecen en sus Z fijos absolutas.
- La interpolación entre estaciones crea una concavidad estrecha en esa estación.
- **Workaround:** mover la quilla en varias estaciones sucesivas para distribuir el cambio.
- **Fix definitivo:** wizard de redistribución de LdA + más puntos de control de quilla.
---
## Módulo 2 — Visores 2D Interactivos
**Archivo clave:** `arshipdesign/ui/widgets/viewer_lines.py`
### Clases principales
```
_BaseViewer — zoom, paneo, drag de nodos, hit-test, HUD, fairness, selección de curva
├── BodyPlanViewer — secciones transversales Y-Z (cuadernas)
├── ProfileViewer — vista lateral X-Z (quilla, cubierta, roda, espejo)
└── PlanViewer — vista de planta X-Y (líneas de agua desde arriba)
```
### Estado 🔧
- **Drag de nodos**: todos los nodos arrastrables, sin restricciones (respeta Regla de Ejes).
- **Selección de nodo** (clic): nodo se vuelve dorado; panel `NodeInfoPanel` muestra X/Y/Z
y checkbox de esquina. Enter aplica el valor editado manualmente.
- **Selección de curva** (Shift+clic): detecta arista de la malla NURBS más cercana.
La curva completa se resalta en verde menta `#00FFB0` con 2.5 px.
- Body Plan: Shift+clic → sección completa keel→LdA→sheer (estación i)
- Perfil: Shift+clic → quilla o cubierta (curva longitudinal)
- Planta: Shift+clic → línea de agua j completa
- **Peines de curvatura** `[C]`: pelos perpendiculares a la curva.
Normalizados por max|κ| → siempre visibles aunque la curva sea casi recta.
Solo en la curva seleccionada (Shift+clic) o en todas si no hay selección.
Pelo invertido al lado opuesto = inflexión (cambio de signo de curvatura).
- **Coloreo de equidad** `[F]`: nodos coloreados verde→amarillo→rojo por |d²Y/dX²|.
- **Suavizado local** `[S]`: Laplaciano 1 paso en el nodo seleccionado.
- **Zoom**: rueda del ratón. Doble clic: fit-to-view.
- **Paneo**: botón medio o derecho + arrastrar.
- **HUD** (esquina inferior derecha): estado de [C]/[F]/[S] y nombre de la curva activa.
- **Sincronización entre vistas** (en vivo): `offsets_dragging` durante el drag,
`offsets_edited` al soltar.
- **Menú contextual** (clic derecho): insertar LdA, estación, roda, espejo, esquina.
### Historial de correcciones
| Fecha | Problema | Causa raíz | Fix aplicado |
|-------|----------|------------|--------------|
| 2026-05-28 | Nodos de borde no arrastrables en X | `_hit_test` de ProfileViewer excluía i=0 e i=n-1 para LdA normales | Revertido: loop incluye todos los nodos sin excepción |
| 2026-05-28 | Peines de curvatura invisibles | `scale = beam × 0.20` → κ≈0.02 → pelo de 2cm, invisible a escala normal | Normalizado: todos los κ ÷ max\|κ\| antes de escalar |
| 2026-05-28 | `self._selected` no existe | Nombre incorrecto del atributo | Corregido a `self._selected_idx` |
### Pendiente 📋
- Peines de curvatura en keel/sheer desde el ProfileViewer (actualmente solo en quilla/cubierta como curvas, no como Z).
- Suavizado 2D (Laplaciano transversal dentro de la cuaderna).
- Tests automatizados para fairness coloring y suavizado.
---
## Módulo 3 — Visor 3D
**Archivo clave:** `arshipdesign/ui/widgets/viewer_3d.py`
### Estado 🔧
- **Motor**: PyVista + pyvistaqt (`QtInteractor` embebido).
- **Degradación sin PyVista**: muestra `QLabel` en lugar de crashear (permite que CI pase).
- **Carga diferida**: `QtInteractor` se crea 500 ms después del arranque (evita conflicto OpenGL).
- **Tema oscuro**: fondo `#1a1d30`, casco `#3a6080`, aristas `#4da8ff`, plano de flotación `#4da8ff` al 15%.
- **Toggle mallas** (botón `⬡ Mallas` en barra superior del visor): apagado por defecto.
Llama `GetProperty().EdgeVisibilityOn/Off()` sobre el actor VTK → sin re-render.
### Historial de correcciones
| Fecha | Problema | Fix |
|-------|----------|-----|
| 2026-05-29 | Mallas siempre visibles, sin forma de apagarlas | Añadido botón toggle + `_show_edges=False` por defecto |
### Pendiente 📋
- Caras invertidas: detectar y colorear diferente (rojo/azul), comando flip.
- Capas de visualización: buttocks, waterlines, sections como actores independientes.
- Cierre de malla en AP para transom stern.
---
## Módulo 4 — Guardado y Cargado de Proyectos
**Archivos:** `arshipdesign/core/project.py`, `arshipdesign/core/hull.py`
### Formato `.arsd`
Archivo ZIP que contiene `hull.json` con formato `hull_v1`.
Incluye todos los arrays de offsets, control curves, y metadatos del buque.
### Estado ✅
- **Persistencia exacta**: todos los arrays se guardan y restauran fielmente.
- **Sin snap en carga**: `from_dict` no llama `snap_boundary_nodes_to_contours`.
### Historial de correcciones
| Fecha | Problema | Causa | Fix |
|-------|----------|-------|-----|
| 2026-05-28 | Forma diferente al recargar | `snap_boundary_nodes_to_contours` en `from_dict` recalculaba `x_offsets` | Eliminado de `from_dict` |
| 2026-05-28 | Nodos saltaban al soltar | `snap` en `_on_offsets_edited_from_viewer` sobreescribía la posición del usuario | Eliminado del handler |
---
## Módulo 5 — Hidrostáticos
**Archivos:** `arshipdesign/core/hydrostatics.py`
### Estado ✅
- Cálculo en tiempo real al modificar cualquier nodo.
- Métricas: Δ, LCB, TCB, KB, BM, GM, Cb, Cm, Cp, Cw, AWP.
- Validado contra casco analítico Wigley (IACS Rec.34 §4). Tests: 315/315 ✅
---
## Módulo 6 — Estabilidad
**Archivo:** `arshipdesign/core/stability.py`
### Estado ✅
- Curva GZ por planos de inclinación.
- Criterios IMO IS Code 2008 verificados.
---
## Módulo 7 — Generadores Paramétricos
**Archivos:** `arshipdesign/parametric/wizard_*.py`
### Familias disponibles ✅
| Familia | Archivo | Estado |
|---------|---------|--------|
| Workboat (buque de trabajo) | `wizard_workboat.py` | ✅ |
| Velero | `wizard_sailing.py` | ✅ |
| Lancha rápida | `wizard_fast.py` | ✅ |
| Remolcador | `wizard_tug.py` | ✅ |
| Ferry / pasaje | `wizard_ferry.py` | ✅ |
- **Arrufo parabólico**: `sheer_z[i] = sheer_base + camber × (1 (2x/L 1)²)`
- Snap de nodos de contorno se aplica **una sola vez** al crear el proyecto.
### Pendiente 📋
- Opción transom stern en el wizard (`has_transom: bool`, `transom_angle: float`).
- Wizard de estaciones/LdA/buttocks: definir manualmente posiciones antes de generar la malla.
---
## Módulo 8 — UI / Layout / Ribbon
**Archivos:** `arshipdesign/ui/main_window.py`, widgets varios
### Estado 🔧
- **Layout 4 viewports**: QSplitters anidados. Arriba: 3D+Perfil. Abajo: FrontalI+Planta.
- **Maximizar viewport** (botón `⬜`/`❎` o doble clic en barra de título):
oculta viewport compañero y fila opuesta. Restaurar vuelve a 50/50.
- **Ribbon**: tabs Geometría, Hidrostáticos, Estabilidad, Estructural.
Grupo "Suavizado" con botones Curvatura, Equidad, Suavizar.
- **NodeInfoPanel**: flotante, coordenadas X/Y/Z editables + checkbox esquina.
### Historial de correcciones
| Fecha | Problema | Fix |
|-------|----------|-----|
| 2026-05-28 | Enter en NodeInfoPanel no aplicaba cambio | Señal `coord_edited` no conectada | Conectada en `__init__` |
| 2026-05-29 | `QPushButton` no importado | Faltaba en bloque de imports | Añadido |
---
## Módulo 9 — Herramientas de Fairness (Equidad)
**Funciones en** `viewer_lines.py`: `_fairness_color`, `_smooth_selected_node`,
`_draw_curvature_comb`, `_curvature_comb_data`, `_dist_to_segment`
### Peines de curvatura
```
κᵢ = 2 × cross(t₁, t₂) / (l₁ + l₂) — curvatura discreta firmada
κ_normalizada = κᵢ / max|κ| — rango [-1, 1]
pelo_longitud = κ_normalizada × scale — en unidades de mundo
```
- Pelo al lado contrario de la curva = curvatura positiva (convexa).
- Pelo al mismo lado = curvatura negativa (cóncava / inflexión).
- Spine = línea que une las puntas → revela continuidad de curvatura.
### Coloreo de equidad
```
roughness = |Y[i+1] - 2·Y[i] + Y[i-1]| / (Δx²)
```
- Verde `#22cc66`: roughness < 0.005 m⁻¹
- Rojo `#e03030`: roughness > 0.150 m⁻¹
### Suavizado Laplaciano 1-paso
```
Y_new[i] = (Y[i-1] + Y[i] + Y[i+1]) / 3
```
Solo nodos interiores. Aplica a Y breadths, keel_z y sheer_z.
---
## Módulo 10 — Deshacer / Rehacer (Ctrl+Z / Ctrl+Y)
**Archivo:** `arshipdesign/ui/main_window.py`
### Estado 🔧
- **Mecanismo**: stack de snapshots `hull.to_dict()` — cada estado es una copia completa del casco serializado (arreglos numpy → listas, muy pequeño en memoria).
- **Capacidad**: 50 pasos de deshacer (`_MAX_UNDO = 50`).
- **Ctrl+Z** (`Editar → Deshacer`): restaura el estado anterior al último drag/edición.
- **Ctrl+Y** (`Editar → Rehacer`): rehace el cambio deshecho.
- Cada nueva edición **limpia el stack de redo** (rama nueva invalida el futuro).
- Al crear o abrir un proyecto, ambos stacks se limpian (`_reset_undo_history`).
- Las acciones del menú se habilitan/deshabilitan según haya pasos disponibles.
### Cómo funciona internamente
```
_last_hull_state = snapshot del hull ANTES del último edit
_undo_stack = [estado_0, estado_1, ..., estado_n] ← el más reciente al final
_redo_stack = estados deshechados disponibles
Al recibir offsets_edited:
1. push _last_hull_state → _undo_stack
2. clear _redo_stack
3. _last_hull_state = hull.to_dict() (nuevo estado actual)
Al hacer Ctrl+Z:
1. push hull.to_dict() → _redo_stack
2. hull = Hull.from_dict(_undo_stack.pop())
3. _load_hull_viewers(hull) — refresca todos los visores + hidrostáticos
```
### Qué operaciones son deshaciibles
| Operación | ¿Deshacible? |
|-----------|-------------|
| Arrastrar nodo | ✅ |
| Suavizar con [S] | ✅ (si emite offsets_edited) |
| Editar coordenada en panel | ✅ |
| Insertar estación/LdA desde menú contextual | ✅ |
| Crear nuevo proyecto | ❌ (limpia el historial) |
| Abrir proyecto | ❌ (limpia el historial) |
---
## Módulo 11 — Iconos de Ribbon (arshipdesign/ui/icons.py)
**Estado:** 🔧 Implementado — pendiente verificación visual
### Qué hace
Nuevo módulo `arshipdesign/ui/icons.py` con **50 iconos programáticos** únicos, uno por cada
botón del ribbon. Antes todos compartían el mismo icono genérico del sistema (`SP_FileDialogDetailedView`).
### Diseño técnico
- Cada icono se dibuja con `QPainter` sobre un `QPixmap(24×24)` transparente.
- Paleta coherente con el tema oscuro:
- `#c8d8e8` trazo principal
- `#4da8ff` cyan / agua
- `#00ffb0` verde mint (selección / OK)
- `#ffd060` amarillo / dorado (energía, controles)
- `#ff5555` rojo (daño, alerta)
- Función pública: `icon("clave") → QIcon` con caché `_CACHE` dict.
- Importado en `main_window.py` como `from arshipdesign.ui.icons import icon as _ico`.
### Iconos implementados por grupo
| Grupo | Claves |
|-------|--------|
| HOME / Vistas | `4views`, `lines_plan` |
| Geometría / Nuevo | `wizard`, `hull_nurbs`, `appendage` |
| Geometría / Edición NURBS | `ctrl_pts`, `extrude`, `mirror`, `lackenby` |
| Geometría / Importar | `import_offsets`, `import_dxf` |
| Geometría / Exportar | `export_iges`, `export_step`, `export_dxf` |
| Geometría / Suavizado | `smooth`, `combs`, `fairness` |
| Análisis / Hidrostática | `hydro_calc`, `hydro_curves`, `export_csv` |
| Análisis / Estabilidad | `gz_curve`, `imo`, `damage` |
| Análisis / Resistencia | `holtrop`, `savitsky`, `vpp` |
| Análisis / Seakeeping | `stf`, `spectrum` |
| Análisis / Estructura | `iso12215` |
| Tanques | `new_tank`, `model_tank`, `load_case`, `sounding`, `calc_kg` |
| Sistemas / Eléctrico | `epla` |
| Sistemas / Fluidos | `fuel`, `freshwater`, `bilge`, `firefight` |
| Sistemas / Routing 3D | `pipes`, `cables` |
| Sistemas / Clima | `hvac`, `steering` |
| Fabricación / CNC | `materials`, `nesting`, `gcode`, `postproc` |
| Fabricación / Moldes FRP | `lofting`, `laminate`, `resin`, `bom` |
### Decisiones
- Se mantienen los iconos estándar del sistema para: Nuevo, Abrir, Guardar (Archivo),
Deshacer/Rehacer (flechas del sistema), Offsets (vista de lista).
- El módulo NO importa Qt en el nivel de módulo — los QIcon solo se crean cuando se llaman,
así la importación de `icons.py` es segura antes de que exista `QApplication`.
### Corrección — Rediseño v2 (2026-05-30 sesión 2)
**Problema detectado:** La primera versión usaba trazos claros (`#c8d8e8`) sobre fondo
transparente. El ribbon de PySide6 tiene fondo blanco → los iconos eran prácticamente
invisibles (se veía solo el borde del botón).
**Solución:** Rediseño completo con estilo "flat icon":
- Relleno sólido de color por categoría + contorno oscuro `#1a2535`
- Visible en fondos claros Y oscuros
- Colores por categoría:
| Categoría | Color |
|-----------|-------|
| Geometría / Casco | Azul océano `#2a7fc8` |
| Edición NURBS | Índigo `#5548d0` |
| Suavizado | Verde vivo `#20a860` |
| Peines | Púrpura `#7040c8` + verde mint |
| Fairness | Gradiente rojo→verde |
| Análisis hidro | Teal `#1898a8` |
| Estabilidad | Azul `#2068c0` |
| Resistencia | Naranja `#d07020` |
| Tanques | Cyan `#18a0c0` |
| Sistemas eléctrico | Amarillo sobre negro |
| Fabricación | Violeta `#8838b8` |
**Estado tras rediseño:** 🔧 Pendiente verificar visualmente (requiere `python main.py`)
---
## Módulo 12 — Peines de Curvatura Mejorados
**Estado:** 🔧 Implementado — pendiente verificación visual
### Cambios en `viewer_lines.py`
**Problema:** Los peines se dibujaban usando los ~10-20 puntos crudos de la tabla de
offsets. Resultado: pelos escasos, ángulos bruscos, spine anguloso.
**Solución:** Nueva función `_resample_curve_smooth(xs, ys, n=80)`:
- Parametriza la curva por longitud de arco acumulada
- Remuestrea a **80 puntos equidistantes** usando `scipy.interpolate.CubicSpline`
- Fallback a `np.interp` (lineal) si scipy no está disponible
- Llamada al inicio de `_draw_curvature_comb` antes de calcular κ
**Resultado esperado:** 80 pelos por curva en lugar de ~10-20, spine suave.
### Regla
No aumentar más de 80 muestras sin medir impacto en FPS — la función se llama en
cada `paintEvent` (puede ser frecuente al arrastrar nodos).
---
## Módulo 13 — Visor 3D Colores Sólidos
**Estado:** 🔧 Implementado — pendiente verificación visual
### Cambios en `viewer_3d.py` — `_render_hull_mesh`
| Parámetro | Antes | Ahora | Por qué |
|-----------|-------|-------|---------|
| `smooth_shading` | `True` | `False` | Facetas planas = aspecto sólido, sin blur |
| `opacity` | `0.92` | `1.0` | Totalmente opaco = color pleno |
| `ambient` | (default ~0.2) | `0.40` | Reduce sombras duras, color más uniforme |
| `diffuse` | (default ~0.8) | `0.60` | Equilibrio iluminación |
| `specular` | (default ~0.1) | `0.05` | Sin brillos que difuminen |
| `color` | `#3a6080` | `#4a8ab0` | Tono más vivo y legible |
| `line_width` | `0.3` | `0.6` | Aristas más visibles al activar mallas |
### Nota
Si en el futuro se quiere smooth shading selectivo (solo en alta resolución),
usar `mesh.compute_normals()` primero y luego `smooth_shading=True`.
---
## Módulo 14 — Fix Freeze Curva GZ (QThread)
**Estado:** 🔧 Implementado — pendiente verificación
### Problema
`_on_show_stability``_compute_and_show_gz``compute_gz_wall_sided`
`compute_upright` (integración hidrostática pesada) → **bloqueaba el UI thread de Qt**
indefinidamente ("se trabó el programa").
### Solución
Nueva clase `_GZWorker(QObject)` con señales `finished` / `error`.
El cálculo se mueve a un `QThread`:
```
[UI thread] botón → _compute_and_show_gz()
↓ lanza QThread
[Hilo GZ] _GZWorker.run()
↓ emite finished(gz_curve, imo_result)
[UI thread] _on_gz_done() → actualiza widget + statusBar
```
### Guarda doble
Si el usuario hace clic dos veces seguidas, el segundo clic se ignora mientras el
hilo anterior sigue corriendo (`if self._gz_thread.isRunning(): return`).
### Archivos modificados
| Archivo | Cambio |
|---------|--------|
| `main_window.py` | Import `QThread, QObject`; clase `_GZWorker`; `_compute_and_show_gz` refactorizado; nuevo slot `_on_gz_done` |
---
## Roadmap Global
| Prioridad | Feature | Módulo | Estado |
|-----------|---------|--------|--------|
| 🔴 Alta | Wizard de estaciones / LdA / buttocks | Geometría | 📋 |
| 🔴 Alta | Transom stern (popa espejo) | Geometría + 3D | 📋 |
| 🟡 Media | Verificar iconos ribbon visualmente | UI | 🔧 |
| 🟡 Media | Verificar peines densidad visual | Fairness | 🔧 |
| 🟡 Media | Verificar colores sólidos 3D visual | Visor 3D | 🔧 |
| 🟡 Media | Caras invertidas 3D + flip | Visor 3D | 📋 |
| 🟡 Media | Peines de curvatura en keel/sheer (Z) | Fairness | 📋 |
| 🟡 Media | Suavizado 2D (Laplaciano transversal) | Fairness | 📋 |
| 🟢 Baja | Tests de fairness automatizados | Tests | 📋 |
| 🟢 Baja | Exportar DXF / offsets CSV | Exportación | 📋 |
| 🟢 Baja | Importar offsets desde tabla manual | Importación | 📋 |
---
## Tests y Entorno
```bash
# Ejecutar suite completa
cd "D:\Proyectos Software\AR-Shipdesign"
python -m pytest tests/ -x -q
# Lanzar la aplicación
python main.py
```
**Estado de tests:** 315/315 ✅ — Última verificación: 2026-05-30
⚠️ Tests no actualizados para GZWorker (QThread) — agregar en próxima sesión.
---
*Última actualización: 2026-05-30 (sesión 2)*
*Mantener este archivo actualizado al final de cada sesión de trabajo.*