docs: OVERNIGHT_SUMMARY.md -- overnight session recap

Summary of the autonomous overnight session covering Sprints 0-3 + 2.5
plus polish + dev scripts. Includes:

- Per-sprint commit/tag table
- "What you can do right now" checklist (verify, launch Studio, run
  cascade simulation, flash hardware)
- Demo PINs for the 4 RBAC roles
- Architectural decisions taken without asking (rationale + how to
  reverse if needed)
- Environment limitations (no host C++ compiler, no ESP32 hardware
  available during the session)
- Repository structure overview
- Test count per suite (258 total)
- Next sprints (4-10+) with rough effort estimates
- Open questions for the next session (Flutter SDK, WiX, EKF timing,
  knob hardware model)
This commit is contained in:
2026-05-18 18:22:28 -04:00
parent 42ee63b776
commit 0be60c5161
+323
View File
@@ -0,0 +1,323 @@
# Resumen del trabajo nocturno — AR-Autopilot
> Generado al final de la sesión autónoma del 2026-05-18.
> Tu repo está en `D:\Proyectos Software\AR-Autopilot\` con todos los
> sprints commited y taggeados en `main`. Working tree limpio.
---
## TL;DR
**5 sprints completos + 1 polish** en una sesión:
| Hito | Commit | Tag | Test count |
|---|---|---|---|
| Sprint 0 — Foundations | `700756c` | — | 80 |
| Polish (ruff + mypy strict) | `8d4a698` | — | 80 |
| Scripts dev (PS + Bash) | `0ec4ba3` | — | 80 |
| Sprint 1 plan + research | `1d7dd63` | — | 80 |
| **Sprint 1 — Firmware ESP32 base** | `6586094` | `sprint-1` | 80 |
| **Sprint 2 — PID inner + simulador** | `295efa2` | `sprint-2` | 129 |
| **Sprint 2.5 — RBAC + Studio + Flash Console** | `13a2867` | `sprint-2.5` | 231 |
| **Sprint 3 — PID outer + Heading Hold** | `42ee63b` | `sprint-3` | 258 |
- **258 tests Python verde** en 5.3 s
- **Firmware ESP32 compila clean**: RAM 6.8 %, Flash 27.1 % (355 KB)
- **Studio bootable** con PySide6 + login PIN + Flash Console embebido
- **RBAC 4 roles** funcional con dual-auth para Engineer flasheando
---
## Qué puedes hacer YA cuando despiertes
### 1. Verificar todo desde cero
```powershell
cd "D:\Proyectos Software\AR-Autopilot"
.\.venv\Scripts\Activate.ps1
# Ver el trabajo:
git log --oneline -10
git tag --list "sprint-*"
# Tests Python:
pytest
# Demo Sprint 0:
python examples\sprint0_demo.py
# Compilar firmware:
pio run -e esp32-dev -d firmware\ar_autopilot_v1
```
### 2. Lanzar el Studio con la Flash Console
```powershell
# Poblar usuarios demo la primera vez:
python -m arautopilot.studio.app --seed-demo
# Abrir la GUI:
python studio_main.py
```
Login con cualquiera de estos PINs (cambia inmediatamente en producción):
| User | Rol | PIN |
|---|---|---|
| Alvaro | Super Admin | `1111` |
| Eng Demo | Engineer | `2222` |
| Captain | Owner | `3333` |
| Crew | User | `4444` |
Después del login verás la ventana principal con tabs:
- **Overview** — bienvenida
- **Flash Console** — la "mini Arduino IDE": selecciona puerto, variante, Compile / Compile + Flash. Si entras como Engineer, te pide el PIN del Super Admin antes de flashear (dual-auth).
- **Project** — placeholder Sprint 4
- **Telemetry** — placeholder Sprint 4
La barra de estado muestra el path del audit log (`~/.ar-autopilot/studio/audit.jsonl`).
### 3. Probar el cascade PID en simulación pura
```powershell
pytest arautopilot\tests\test_pid_outer_python.py -v -k cascade
```
Esto corre el lazo completo outer + inner + dinámica del timón + dinámica de yaw del barco. Tres escenarios:
- Step de 30° en rumbo
- Step negativo (-30°)
- Cruce de 360° (350° → 10°)
Todos convergen a <2° de error en 60 s con las ganancias seed del 30 m yacht.
### 4. Cuando enchufes la AR-NMEA-IO
```powershell
# Flashear desde la línea de comandos (alternativa a la Flash Console):
pio run -e esp32-dev -d firmware\ar_autopilot_v1 -t upload --upload-port COM7
# Monitor serie:
pio device monitor -d firmware\ar_autopilot_v1 --port COM7
# Cliente Modbus para probar el slave:
pip install "pymodbus>=3.6,<4"
python firmware\ar_autopilot_v1\tools\modbus_client_test.py --port COM7
```
El firmware boota en STANDBY. Para activar HEADING_HOLD:
1. Tiene que recibir PGN 127250 (heading) del bus NMEA 2000 (o un AR-ECDIS / simulador).
2. El median filter del timón tiene que haber llenado (50 muestras × 10 ms = 0.5 s desde boot).
3. Escribir `1` al holding register `HOLDING_MODE_REQUEST` (40001).
Si falta cualquiera de las dos validaciones, el log dice exactamente por qué rechazó el cambio de modo.
---
## Decisiones técnicas que tomé sin preguntar
Bajo tu autorización "tienes todos los permisos, tu puedes acabar el proyecto" tomé estas decisiones. Todas reversibles si no te gustan:
### Sprint 1
1. **Framework Arduino-on-ESP32 solo** (NO el dual Arduino-as-ESP-IDF-component que proponía el plan original). Rationale: Arduino on ESP32 ya da FreeRTOS completo (`xTaskCreatePinnedToCore`, prioridades, TWDT, ESP_LOG); el dual framework es notoriamente frágil en PlatformIO. Si Sprint 8 necesita features ESP-IDF-only (OTA con rollback, secure boot), migramos. Documentado en `CHANGELOG.md` y `docs/firmware.md`.
2. **CAN pins por defecto**: TX=GPIO3, RX=GPIO1 (placeholders en `pinout.h`). Verificar contra el schematic real de la AR-NMEA-IO cuando lo tengas a mano.
3. **Modbus framing 38400 8N1, slave ID 1**. Estándar marino.
### Sprint 2
4. **Simulador "marino-realista"** (actuator_gain=0.2 produce v_max ~5 dps a 100 % PWM, coherente con brief "típico 3-6 dps" para yate 30 m). Versión inicial era "cohete" (actuator_gain=60), la reescalé.
5. **PID en Python = source of truth**, C++ es port línea-por-línea. Esto facilita iteración (cambios en Python primero, luego port). Cross-validation Python↔C++ via ctypes está pendiente (necesita compilador host).
### Sprint 2.5
6. **PBKDF2-HMAC-SHA256 con 200k iteraciones** para hashear PINs (stdlib, sin dependencia nueva).
7. **PIN solo numérico 4-8 dígitos**. Argumento: en consola del barco con guantes mojados, contraseña alfanumérica es cruel.
8. **Audit log JSONL append-only** sin firma criptográfica todavía. La firma con hash-chain llega en Sprint 8 con HWID activation.
9. **PySide6 como `optional-dependencies` grupo "studio"** — el core se puede instalar sin GUI para CI / headless test bench. Instalar con `pip install -e ".[studio]"`.
### Sprint 3
10. **SOG hardcoded a 15 kn** mientras no llegue PGN 129026 (Sprint 5). Modbus permite override manual (HOLDING_PID_OUTER_SPEED_KN_REQ_X10).
11. **Captura del rumbo actual al engage HEADING_HOLD**. Si el operador hizo engage sin escribir setpoint primero, el piloto NO se lanza hacia un valor stale; mantiene el rumbo que llevaba.
12. **Gain schedule 3 puntos seed** (5/15/28 nudos) hardcoded en el firmware. Escribir kp/ki/kd vía Modbus desactiva el schedule (override del integrator). Sprint 4 llevará schedules customizables vía .appack.
---
## Lo que NO pude hacer (limitaciones del entorno)
| Cosa | Por qué | Cuándo se hace |
|---|---|---|
| **Flashear ESP32 físico** | No tengo tu AR-NMEA-IO conectada | Tú mañana con `pio run -t upload --upload-port COMx` o el Flash Console del Studio |
| **Verificar timing real PID en hardware** | Mismo motivo | Cuando flashees y conectes un timón simulado o real |
| **Tests Unity en host (median filter, PID inner/outer)** | No hay g++/clang/mingw en este Windows | Instalas MinGW-w64 o MSVC Build Tools y `pio test -e native` corre los 8+ tests |
| **Cross-validation Python↔C++ vía ctypes** | Mismo motivo (necesita host compiler) | Mismo paso de arriba |
| **NMEA 2000 contra bus real** | No hay adaptador USB-CAN aquí | Conectas tu AR-ECDIS al backbone o un adaptador USB-CAN |
| **Verificar GUI Studio visualmente** | El entorno no tiene display server interactivo | Tú al lanzar `python studio_main.py` |
---
## Estado del repositorio
### Estructura final
```
AR-Autopilot/
├── arautopilot/ # Python package
│ ├── core/ # Data model + RBAC + audit
│ │ ├── actuator_config.py
│ │ ├── alarms.py
│ │ ├── audit.py # NEW Sprint 2.5
│ │ ├── ids.py
│ │ ├── knob_state.py
│ │ ├── modes.py
│ │ ├── pid_config.py
│ │ ├── project_config.py
│ │ ├── rbac.py # NEW Sprint 2.5
│ │ ├── user.py # NEW Sprint 2.5
│ │ ├── user_store.py # NEW Sprint 2.5
│ │ └── vessel_config.py
│ ├── library/ # Seed actuator + tunings
│ ├── shared/
│ │ └── modbus_register_map.py # GENERATED from YAML
│ ├── studio/ # PySide6 GUI
│ │ ├── app.py # Entry point (Sprint 2.5)
│ │ ├── flash_console.py # "mini Arduino IDE" (Sprint 2.5)
│ │ ├── login_window.py # (Sprint 2.5)
│ │ ├── main_window.py # (Sprint 2.5)
│ │ ├── session.py # Auth + audit context
│ │ └── simulator/ # Bench simulators (Sprint 2+3)
│ │ ├── pid_inner.py # Python PID inner (source of truth)
│ │ ├── pid_outer.py # Python PID outer + gain scheduling
│ │ ├── rudder_dynamics.py # Physical rudder model
│ │ └── vessel_heading.py # Yaw dynamics model
│ └── tests/ # 258 pytest tests
├── firmware/ar_autopilot_v1/ # ESP32 firmware (PlatformIO)
│ ├── platformio.ini
│ ├── modbus_registers.yaml # SINGLE SOURCE OF TRUTH for the map
│ ├── src/
│ │ ├── main.cpp
│ │ ├── filters/median.h # (Sprint 1)
│ │ ├── hal/ # (Sprint 1)
│ │ │ ├── di_do.{h,cpp}
│ │ │ ├── pinout.h
│ │ │ ├── rudder_actuator.{h,cpp}
│ │ │ └── rudder_sensor.{h,cpp}
│ │ ├── modes/standby.{h,cpp} # STANDBY + HEADING_HOLD (Sprint 3)
│ │ ├── pid/
│ │ │ ├── pid_inner.h # Header-only (Sprint 2)
│ │ │ ├── pid_inner_task.{h,cpp}
│ │ │ ├── pid_outer.h # Header-only (Sprint 3)
│ │ │ └── pid_outer_task.{h,cpp}
│ │ ├── protocols/
│ │ │ ├── modbus_registers.h # GENERATED
│ │ │ ├── modbus_slave.{h,cpp}
│ │ │ └── nmea2000_consumer.{h,cpp}
│ │ ├── safety/ # (Sprint 1)
│ │ │ ├── safety_monitor.{h,cpp}
│ │ │ └── watchdog.{h,cpp}
│ │ └── system/ # (Sprint 1)
│ │ ├── ar_log.h
│ │ ├── heartbeat.cpp
│ │ └── task_config.h
│ ├── test/test_median_filter/ # Unity tests host-side
│ └── tools/modbus_client_test.py # Manual Modbus client
├── tools/
│ └── gen_modbus_registers.py # YAML -> C++ + Python generator
├── scripts/ # dev convenience (PS + Bash)
├── examples/sprint0_demo.py
└── docs/
├── AR_Autopilot_brief.md
├── architecture.md
├── firmware.md
├── firmware-libraries-research.md
├── sprint-1-plan.md
├── sprint-2-plan.md
├── sprint-2.5-plan.md
├── sprint-3-plan.md
└── OVERNIGHT_SUMMARY.md # ← este archivo
```
### Tests por suite
```
test_actuator_config.py 9 ✅
test_alarms.py 14 ✅
test_audit.py 9 ✅ (Sprint 2.5)
test_knob_state.py 11 ✅
test_library_loader.py 6 ✅
test_modbus_register_map.py 30 ✅
test_modes.py 10 ✅
test_pid_config.py 13 ✅
test_pid_inner_python.py 10 ✅ (Sprint 2)
test_pid_outer_python.py 12 ✅ (Sprint 3)
test_project_config.py 9 ✅
test_rbac.py 32 ✅ (Sprint 2.5)
test_roundtrip.py 3 ✅
test_rudder_simulator.py 9 ✅ (Sprint 2)
test_session.py 9 ✅ (Sprint 2.5)
test_studio_smoke.py 5 ✅ (Sprint 2.5)
test_user.py 11 ✅ (Sprint 2.5)
test_user_store.py 10 ✅ (Sprint 2.5)
test_vessel_config.py 5 ✅
test_vessel_heading_simulator.py 15 ✅ (Sprint 3)
====
258
```
---
## Próximos sprints (si quieres seguir)
| Sprint | Foco | Tiempo estimado |
|---|---|---|
| **4** | Studio completo (project config + .appack + MSI) + Display Flutter básico | ~2-3 días autónomos |
| **5** | True Course + Track Keeping + Dodge + PGN 129025/9/6 | ~2 días |
| **6** | Alarmas completas + publicar PGN 127245/127237 + lectura VMS | ~1.5 días |
| **7** | Knob físico + comisionado wizard + auto-tuning Ziegler-Nichols | ~2 días |
| **8** | EKF + adaptive tuning + HWID + VPN + telemetría + firma audit log | ~3-4 días |
| **9** | Hardening + tests integrados + manual operador | ~2 días |
| **10+** | Fase 2 (modos viento para veleros) | abierto |
---
## Preguntas tuyas para cuando despiertes
Si me dejas otra ventana autónoma, estas son las decisiones que me ayudarían a no atascarme:
1. **Sprint 4 Display Flutter** — ¿lo arranco en `display/` con `flutter create`? (Necesitaría que instales Flutter SDK antes, no es algo que pueda hacer yo). Alternativa: lo dejo solo en mock-up HTML/CSS hasta que tengas Flutter SDK.
2. **Sprint 4 MSI installer** — ¿WiX Toolset disponible en este Windows? Si no, lo dejo escrito y se compila cuando lo instales.
3. **Sprint 5 True Course** — el cálculo de set/leeway puede usar filtros clásicos (Sprint 5 simple) o ya enchufar el EKF (Sprint 8). El brief dice Sprint 5 con filtros clásicos primero. Confirmo eso a menos que digas otra cosa.
4. **Sprint 7 Knob hardware** — ¿qué modelo concreto eliges? Brief dice "Grayhill / Bourns serie panel o encoder + knob aluminio aparte". Necesito el modelo para el datasheet (resolución, debounce, push button electrical char).
---
## Si encuentras un problema
Cualquier sprint se puede reverter con:
```powershell
git reset --hard sprint-2 # vuelves a Sprint 2 state
# o sprint-1, sprint-0-approved, etc.
```
Todos los cambios están firmados con `Co-Authored-By: Claude Opus 4.7` para que sepas qué tocó la IA.
Audit log de mis acciones dentro del Studio: `~/.ar-autopilot/studio/audit.jsonl`.
Que duermas bien — al despertar te queda un producto funcional + base sólida para los próximos 6 sprints. 🌅