Completar Margoth: estabilidad, valor clínico y distribución#1
Merged
Conversation
MainWindow.set_main_view destruia la vista saliente con deleteLater(), pero AppController reutiliza instancias unicas de cada vista. Al volver a una vista ya mostrada se referenciaba un objeto C++ destruido y la app lanzaba RuntimeError. - Reemplaza el QVBoxLayout inyectable por un QStackedWidget - Las vistas se registran una sola vez y se alternan con setCurrentWidget - Verificado con repro headless y smoke test de navegacion completa
Cubre la logica de datos headless (sin PyQt6): - PatientModel: CRUD, import_media (imagen/audio/duplicados/errores), filtrado por tipo y deteccion de extension - SemanticExerciseModel: persistencia de metricas y armado de estimulos - CAABoardModel: round-trip de tableros y tolerancia a JSON corrupto 24 tests en verde. Fixtures aislan la BD en un tmp_path por test.
- Borra apps/api/manage.py, unico vestigio de la API en la nube descartada (contradecia el requisito 100% offline) - Reescribe docs/mvp.md con los modulos clinicos reales, el modelo de datos y los principios de diseno
Corre pytest sobre Python 3.13 en cada push y pull request contra main. La capa de modelos es headless, por lo que no requiere display.
Antes el ejercicio semantico derivaba la respuesta y los distractores del nombre de archivo (p. ej. 'IMG_9921'), lo que resultaba clinicamente inutil. - patient_media gana la columna 'label' con migracion idempotente para BD existentes (ALTER TABLE ... ADD COLUMN si falta) - import_media acepta una etiqueta; por defecto usa el nombre sin extension - SemanticExerciseModel arma las opciones con la etiqueta (fallback al nombre de archivo para datos antiguos) - Dashboard: campo de etiqueta al subir un medio - Constructor CAA: la galeria muestra la etiqueta legible - Tests: label por defecto/explicita/vacia, uso en el estimulo y migracion 31 tests en verde.
Las metricas del ejercicio semantico se guardaban pero nunca se mostraban. - MetricsModel: resumen (intentos, % aciertos, tiempo promedio/mejor), ultimos intentos y precision diaria; solo lectura - ReportsView: tarjetas de estadisticas + tablas de tendencia diaria y ultimos intentos; estado vacio inline (sin modales) - ReportsController + boton 'Ver Reportes de Progreso' en el dashboard, cableado en AppController - Tests de MetricsModel (accuracy, tiempos, aislamiento, limite, diario) 37 tests en verde; smoke de navegacion incluye la vista de reportes.
- PatientModel.delete_patient: borra metricas, medios (BD) y la carpeta de medios en disco antes de eliminar al paciente; aislado por paciente - Dashboard: botones Editar (carga el paciente en el formulario, el boton Guardar pasa a Actualizar) y Eliminar con confirmacion inline en dos pasos (sin modales, cumpliendo la regla clinica de UI) - DashboardController: rutas de edicion/actualizacion/borrado con refresco - Tests de cascada (metricas+medios+carpeta), inexistente y aislamiento Validado en vivo: editar actualiza y sale de modo edicion; borrar exige segundo clic de confirmacion.
La BD SQLite no esta cifrada, pero README afirmaba 'datos locales cifrados'. - Reemplaza la afirmacion por el estado real y agrega seccion 'Seguridad y privacidad' - Documenta la migracion a SQLCipher como mejora futura y por que se difiere (binarios nativos vs empaquetado PyInstaller en Windows) - Advierte no usar en equipo compartido sin cuenta protegida
Antes save_board sobrescribia boards[0]: un solo tablero fijo 2x2 por paciente. Modelo (CAABoardModel): - Upsert por id (list_boards/load_board/delete_board); ya no se pierden los demas tableros al guardar - create_test_board y load_first_board reusan la nueva logica Constructor visual: - Selector de tablero + boton 'Nuevo'; nombre editable - Tamano de grilla configurable (1..4 filas x columnas) con preservacion de asignaciones dentro del nuevo rango; grilla en area con scroll - Cada tablero nace con id propio para que reguardar actualice (no duplique) Visor CAA (lado paciente): - Selector de tablero en el encabezado (visible con 2+ tableros) Tests: upsert sin borrar otros, actualizar por id, id autogenerado, cargar por id y borrar. 44 tests en verde; smokes de navegacion y multi-tablero.
- tools/generate_icon.py genera assets/icon.ico y icon.png (burbuja de dialogo con 'M', evoca lenguaje/comunicacion) - La app fija su icono de ventana (main.py) - build_exe.py empaqueta assets/ y embebe el icono en el .exe (--icon) - Instalador Inno Setup: version 1.1.0, publisher, SetupIconFile - README: fases 9-11 + calidad, seccion de pruebas y de regeneracion de icono Verificado en vivo: el ejecutable compilado arranca, crea data/ y media/ junto al binario y su BD ya trae la columna 'label' (codigo actualizado).
There was a problem hiding this comment.
Pull request overview
Este PR completa la estabilización y cierre funcional de Margoth como app 100% offline, fortaleciendo la navegación (sin crashes por destrucción de vistas), agregando valor clínico (métricas + reportes), robusteciendo la gestión de pacientes/medios y habilitando tableros CAA múltiples, junto con CI y empaquetado/branding (ícono/installer).
Changes:
- Estabiliza navegación con
QStackedWidgety agrega reportes de progreso basados en agregación deexercise_metrics. - Extiende persistencia:
labelenpatient_media(migración idempotente), borrado en cascada (BD + disco) y tableros CAA múltiples (upsert por id + selector + grilla 1..4). - Añade suite de tests headless de modelos, CI con GitHub Actions, y mejoras de distribución (ícono, build PyInstaller, metadata de instalador).
Reviewed changes
Copilot reviewed 31 out of 33 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/generate_icon.py | Script reproducible para generar assets/icon.png/.ico. |
| tests/conftest.py | Fixtures headless (DB/temp media) y generadores de imagen/audio. |
| tests/test_database_manager.py | Tests de esquema y migración idempotente de label. |
| tests/test_patient_model.py | Cobertura de CRUD, importación con label, y borrado en cascada. |
| tests/test_semantic_exercise_model.py | Tests de métricas y estímulos (incluye uso de label). |
| tests/test_metrics_model.py | Tests de agregación clínica (summary, recientes, tendencia). |
| tests/test_caa_board_model.py | Tests de tableros múltiples (upsert/load/delete + estado corrupto). |
| src/views/main_window.py | Reemplaza destrucción de vistas por QStackedWidget (evita crash al volver). |
| src/views/dashboard_view.py | UI para editar/eliminar pacientes, reportes, y label al subir medios (sin modales). |
| src/views/reports_view.py | Nueva vista de reportes (tarjetas + tablas de tendencia y últimos intentos). |
| src/views/caa_board_view.py | Selector de tablero en visor CAA + señal de cambio de tablero. |
| src/views/builder_view.py | Selector de tableros + “Nuevo”, tamaño de grilla 1..4, y presentación label·archivo en galería. |
| src/models/database_manager.py | Agrega label a patient_media y migración idempotente. |
| src/models/patient_model.py | Importación de medios con label + borrado de paciente (BD + disco + métricas). |
| src/models/semantic_exercise_model.py | Usa label para respuestas/opciones; persiste métricas de ejercicio. |
| src/models/metrics_model.py | Nuevo modelo de solo-lectura para agregación de métricas clínicas. |
| src/models/caa_board_model.py | Persistencia JSON de múltiples tableros (list/load/save upsert/delete). |
| src/controllers/dashboard_controller.py | Controlador para editar/eliminar pacientes y subir medios con label. |
| src/controllers/reports_controller.py | Controlador de reportes (consulta modelo y renderiza vista). |
| src/controllers/caa_controller.py | Carga/lista tableros y permite cambiar tablero activo desde la vista. |
| src/controllers/builder_controller.py | Refresca selector, carga por id, y flujo de “Nuevo” tablero. |
| src/controllers/app_controller.py | Integra ReportsView/Controller y navegación a reportes. |
| src/main.py | Setea ícono de la app si existe en assets empaquetados. |
| build_exe.py | Empaqueta carpeta assets/ completa y usa icono .ico si existe. |
| margoth_installer.iss | Metadata de instalador + SetupIconFile y bump de versión. |
| requirements-dev.txt | Agrega requirements de dev para pytest. |
| pytest.ini | Configura descubrimiento de tests y -q. |
| .github/workflows/ci.yml | CI para ejecutar pytest en pushes/PRs. |
| README.md | Documenta fases, pruebas, regeneración del ícono y aclaración de cifrado pendiente. |
| docs/mvp.md | Reescritura funcional: offline, módulos clínicos, datos y principios. |
| apps/api/manage.py | Elimina stub Django/API (alineado con requisito offline). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
62
to
66
| false_options = [] | ||
| other_rows = conn.execute( | ||
| """ | ||
| SELECT file_name | ||
| SELECT file_name, label | ||
| FROM patient_media |
Comment on lines
+110
to
+113
| # Etiqueta legible: la provista, o el nombre del archivo sin extensión. | ||
| clean_label = (label or "").strip() | ||
| if not clean_label: | ||
| clean_label = os.path.splitext(filename)[0] |
Comment on lines
+18
to
+22
| - name: Configurar Python 3.13 | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: "3.13" | ||
| cache: pip |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cierra el plan A+B+C para dar por terminada la app. 10 commits, 44 tests en verde, ejecutable verificado en vivo.
Fase A — Estabilizar
MainWindowusabadeleteLater()sobre vistas queAppControllerreutiliza →RuntimeErroral volver a una vista ya mostrada. Migrado aQStackedWidget. Reproducido y validado headless.PatientModel,SemanticExerciseModel,CAABoardModel,MetricsModel, migración de esquema.apps/api/) que contradecía el requisito 100% offline;docs/mvp.mdreescrito.pytesten cada push/PR.Fase B — Valor clínico
labelenpatient_media(migración idempotente). El ejercicio semántico ahora usa etiquetas legibles en vez del nombre de archivo.exercise_metrics(aciertos %, tiempos, tendencia diaria). Antes las métricas se guardaban pero nunca se mostraban.Fase C — Robustez y distribución
assets/icon.ico, generable contools/generate_icon.py), metadatos en el instalador,.exeregenerado y verificado en vivo (arranca, creadata/+media/, esquema conlabel).Validación
pytest: 44 tests en verde.Notas para el revisor