# 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. 🌅
