SXXXXXXX_PyMsc/doc/ARTOS_Architecture_Decisions.md

591 lines
24 KiB
Markdown

# ARTOS: Architecture Decision Record (ADR)
## Living Document - Decisioni Architetturali e Rationale
**Data inizio:** 09 Gennaio 2026
**Ultima modifica:** 09 Gennaio 2026
**Versione:** 0.1.0
---
## 📋 Indice
1. [Panoramica e Obiettivi](#panoramica-e-obiettivi)
2. [Decisione 1: Architettura a Layer Separati](#decisione-1-architettura-a-layer-separati)
3. [Decisione 2: GUI Modulare con Docking System](#decisione-2-gui-modulare-con-docking-system)
4. [Decisione 3: Dual-Mode Test System](#decisione-3-dual-mode-test-system)
5. [Piano di Implementazione](#piano-di-implementazione)
6. [Domande Aperte e Decisioni Future](#domande-aperte-e-decisioni-future)
---
## Panoramica e Obiettivi
### Problema Iniziale
Il sistema PyMSC attuale presenta un'architettura monolitica dove:
- La GUI è il punto centrale di controllo
- La logica di test è accoppiata alla GUI (script_manager basato su WIDGET_MAP)
- Non esiste una chiara separazione tra hardware abstraction, orchestrazione e test
- Aggiungere nuovi moduli (video, target simulator) è complesso
### Obiettivi Strategici
1. **Modularità:** Ogni componente HW ha il suo modulo indipendente
2. **Testabilità:** Test automatici eseguibili sia da GUI che da CLI
3. **Estensibilità:** Facile aggiunta di nuovi moduli e algoritmi
4. **Usabilità:** GUI moderna con workspace personalizzabili
5. **Dual-mode:** Supportare sia test programmatici (Python) che registrazioni GUI
---
## Decisione 1: Architettura a Layer Separati
### Contesto
Ispirandoci a ARTOS Technical Design Specification, vogliamo separare chiaramente i livelli funzionali.
### Decisione
Adottiamo un'architettura a 4 livelli:
```
┌─────────────────────────────────────────────────────────────┐
│ L3: Test Execution Layer │
│ ├── Python Test Scripts (programmatic) │
│ └── GUI-Recorded Sequences (user-generated) │
├─────────────────────────────────────────────────────────────┤
│ L2: Dynamic Algorithm Library │
│ ├── Target Validation │
│ ├── Video Analysis │
│ └── Timing Analysis │
├─────────────────────────────────────────────────────────────┤
│ L1: Orchestrator Core (TestContext + Module Manager) │
│ ├── TestContext: Unified API │
│ ├── Module Lifecycle Management │
│ └── Event Bus (pub/sub) │
├─────────────────────────────────────────────────────────────┤
│ L0: Hardware Abstraction Layer │
│ ├── Bus1553Module │
│ ├── VideoModule (SFP frame capture) │
│ └── TargetSimModule │
└─────────────────────────────────────────────────────────────┘
```
### Rationale
- **Separazione delle responsabilità:** Ogni layer ha uno scopo chiaro
- **TestContext come pivot:** Fornisce API unificata per accesso ai moduli
- **Indipendenza test da GUI:** Test possono girare headless via CLI
- **Algoritmi riutilizzabili:** Logic di validazione centralizzata in L2
### Impatto
- ✅ Facilita testing automatico
- ✅ Permette esecuzione batch senza GUI
- ✅ Semplifica aggiunta di nuovi moduli hardware
- ⚠️ Richiede refactoring significativo del codice esistente
---
## Decisione 2: GUI Modulare con Docking System
### Contesto
La GUI attuale (`main_window.py`) è un TabWidget monolitico con tutte le pagine hardcoded. Aggiungere nuovi pannelli è invasivo e non c'è flessibilità nel layout.
### Decisione
**Implementare un sistema di GUI modulare basato su Docking Widgets:**
#### Architettura GUI Proposta
```
┌──────────────────────────────────────────────────────────────────┐
│ MainWindow (Docking Container) │
│ ┌────────────────┬──────────────────┬──────────────────────┐ │
│ │ MCS Control │ MFD Display │ Test Control Panel │ │
│ │ Dock │ Dock │ Dock │ │
│ │ │ │ │ │
│ │ [1553 Msgs] │ [Video Frame] │ [Run Tests] │ │
│ │ [Commands] │ [Overlays] │ [Record Sequence] │ │
│ │ │ │ [Test Library] │ │
│ ├────────────────┴──────────────────┴──────────────────────┤ │
│ │ SAR Image Display Dock │ │
│ │ [SAR Map] [Controls] [Analysis Tools] │ │
│ ├───────────────────────────────────────────────────────────┤ │
│ │ Target Simulator Dock │ Recording Dock │ │
│ │ [Inject Target] [Scenarios] │ [Actions] [Playback] │ │
│ └─────────────────────────────────┴─────────────────────────┘ │
└──────────────────────────────────────────────────────────────────┘
```
#### Caratteristiche dei Dock
1. **Floating e Ridimensionabili:** Ogni dock può essere spostato/ridimensionato
2. **Ownership Modulare:** Ogni modulo HW controlla il proprio dock
3. **Layout Salvabile:** L'utente può salvare/caricare configurazioni workspace
4. **Hot-plug:** Dock possono essere aggiunti/rimossi a runtime
#### Struttura Implementativa
```python
artos/
└── gui/
├── main_docking_window.py # ★ Container principale (QMainWindow/tkinter.dnd)
├── dock_registry.py # Registro dock disponibili
├── workspace_manager.py # Save/Load layout utente
└── docks/
├── base_dock.py # Classe base per tutti i dock
├── mcs_control_dock.py # Pannello MCS (ex main_window tabs)
├── mfd_display_dock.py # Video MFD real-time
├── sar_display_dock.py # SAR image + analysis
├── test_control_dock.py # Test execution panel
├── recorder_dock.py # GUI recording controls
└── target_sim_dock.py # Target injection controls
```
### Implementazione Tecnica
#### Opzione A: Tkinter + ttkbootstrap + Custom Docking ✅ **SCELTA**
**Pro:**
- ✅ Già usato nel progetto - zero curva apprendimento
- ✅ Stdlib Python - zero dipendenze esterne critiche
- ✅ Libreria `ttkbootstrap` per temi moderni
-`PanedWindow` nativo per split dinamici
- ✅ Performance adeguata per 20-30 FPS video
- ✅ Nessun licensing concern
- ✅ Distribuzione semplificata (PyInstaller friendly)
**Contro:**
- ⚠️ Docking system custom (richiede implementazione)
- ⚠️ Look & feel meno "native" (mitigabile con ttkbootstrap)
#### Opzione B: PyQt6 con QDockWidget (Scartata)
**Pro:**
- Sistema di docking nativo robusto
- Performance eccellenti per video
- Integrazione OpenGL per SAR/MFD
**Contro:**
- ❌ Dipendenza esterna pesante (~50MB)
- ❌ Licensing complesso (GPL o commerciale costoso)
- ❌ Curva apprendimento ripida
- ❌ Debugging più complesso (errori C++)
- ❌ Potenziali problemi compatibilità OS/Python
- ❌ Overengineering per le nostre esigenze
#### **Decisione Finale: Tkinter + Custom Docking System**
**Data decisione:** 09 Gennaio 2026
**Motivazione:**
1. **Affidabilità:** Tkinter è stdlib, sempre disponibile, zero rischi dipendenze
2. **Preservazione codebase:** Tutto il lavoro fatto rimane valido
3. **Pragmatismo:** Performance sufficienti per i nostri requisiti (30 FPS max)
4. **Manutenibilità:** Team già esperto in Tkinter
5. **Distribuzione:** Nessun licensing concern, build più semplici
**Implementazione:**
- `DockFrame`: Classe base custom per pannelli dockabili
- `WorkspaceManager`: Gestione layout con `tk.PanedWindow`
- `ttkbootstrap`: Temi moderni e widget styled
- `PIL/Pillow`: Video frame display (già in uso)
### Rationale Architetturale
- **Modularità:** Ogni modulo registra il proprio dock all'avvio
- **Flessibilità utente:** Layout personalizzabili per diversi scenari di test
- **Scalabilità:** Facile aggiunta di nuovi pannelli (es. future telemetry dock)
### Impatto
- ✅ GUI più professionale e moderna
- ✅ Ogni sviluppatore può lavorare su un dock indipendente
- ✅ Utenti possono personalizzare workspace per task specifici
- ✅ Zero dipendenze esterne aggiuntive
- ⚠️ Richiede implementazione custom docking (DockFrame, WorkspaceManager)
---
## Decisione 3: Dual-Mode Test System
### Contesto
Vogliamo supportare DUE tipi di test:
1. **Test Programmatici (Python):** Script scritti a mano, versionabili, ripetibili
2. **Test Registrati (GUI):** Sequenze catturate dall'utente, rapide da creare
### Decisione
**Implementare un sistema ibrido dove entrambi i modi coesistono:**
#### Architettura Test System
```
┌────────────────────────────────────────────────────────────────┐
│ Test Execution Engine (L3) │
│ ┌──────────────────────────┬─────────────────────────────┐ │
│ │ Python Test Runner │ GUI Sequence Player │ │
│ │ ├── test_loader.py │ ├── sequence_loader.py │ │
│ │ ├── test_executor.py │ ├── sequence_executor.py │ │
│ │ └── assertion_lib.py │ └── action_replayer.py │ │
│ └──────────────────────────┴─────────────────────────────┘ │
│ ▼ │
│ Unified TestContext Interface │
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ context.send_command() │ │
│ │ context.get_message() │ │
│ │ context.run_algorithm() │ │
│ │ context.wait_for_condition() │ │
│ └─────────────────────────────────────────────────────────┘ │
└────────────────────────────────────────────────────────────────┘
```
#### 1. Test Programmatici (Python)
**Esempio: `tests/functional/test_radar_track.py`**
```python
from artos.test_execution import TestCase, assert_equal
class TestRadarTracking(TestCase):
"""Test radar target tracking capability"""
def test_track_single_target(self, context):
"""Verify radar can track a single injected target"""
# Setup
context.target_sim.inject_target(id=101, distance=50, azimuth=0)
context.wait(seconds=2)
# Action
context.send_command("rdr_mode", "TWS")
context.wait_for_condition(
lambda: context.get_message("B6").track_count > 0,
timeout=5
)
# Validation
result = context.run_algorithm("TargetValidator", tolerance=0.5)
assert_equal(result["status"], "PASS", "Target not detected")
# Cleanup
context.target_sim.clear_all_targets()
```
**Caratteristiche:**
- ✅ Versionabili in git
- ✅ Code review possibile
- ✅ Parametrizzabili con pytest fixtures
- ✅ Eseguibili in CI/CD pipeline
#### 2. Test Registrati (GUI Sequence)
**Esempio: `sequences/manual/radar_mode_check.json`**
```json
{
"name": "Radar Mode Switching Check",
"description": "Recorded sequence of mode changes",
"date": "2026-01-09T10:30:00",
"recorder_version": "2.0",
"actions": [
{
"timestamp": 0.0,
"dock": "mcs_control",
"widget": "rdr_mode_combo",
"action": "select_value",
"value": "RWS",
"delay_ms": 1000
},
{
"timestamp": 1.0,
"dock": "mcs_control",
"widget": "range_scale_spin",
"action": "set_value",
"value": 80,
"delay_ms": 500
},
{
"timestamp": 1.5,
"validation": {
"algorithm": "MessageValidator",
"params": {"msg_id": "B7", "field": "rdr_mode_tellback"},
"expected": "RWS"
}
}
]
}
```
**Caratteristiche:**
- ✅ Rapidi da creare (record & play)
- ✅ Ideali per smoke testing
- ✅ Non richiedono programmazione
- ✅ Convertibili in test Python (export feature)
#### Registrazione dalle Docking Area
**Flow di Recording:**
```
┌─────────────────────────────────────────────────────────────┐
│ User interacts with GUI Dock │
│ ↓ │
│ Dock emits action event (Qt Signal / Tkinter callback) │
│ ↓ │
│ RecorderService intercepts event │
│ ↓ │
│ Event serialized to JSON action │
│ ↓ │
│ Action appended to current sequence │
│ ↓ │
│ Sequence saved to file on Stop Recording │
└─────────────────────────────────────────────────────────────┘
```
**Implementazione:**
```python
# artos/gui/recording/recorder_service.py
class RecorderService:
"""Intercepts actions from all docks and serializes them"""
def register_dock(self, dock: BaseDock):
"""Connect to dock signals for recording"""
dock.action_performed.connect(self._on_action)
def _on_action(self, dock_id: str, widget_id: str, action: str, value: Any):
if self.is_recording:
self.current_sequence.append({
"dock": dock_id,
"widget": widget_id,
"action": action,
"value": value,
"timestamp": time.time() - self.start_time
})
```
### Conversione Sequence → Python Test
**Feature:** Export automatico di sequenze GUI in test Python
```python
# artos/test_execution/sequence_to_test.py
def export_sequence_to_python(sequence_file: str, output_file: str):
"""Converts a GUI sequence JSON to a Python test case"""
with open(sequence_file) as f:
seq = json.load(f)
test_code = f"""
class Test{seq['name'].replace(' ', '')}(TestCase):
def test_generated(self, context):
\"\"\"Auto-generated from sequence: {seq['description']}\"\"\"
"""
for action in seq['actions']:
if action.get('validation'):
test_code += f" result = context.run_algorithm('{action['validation']['algorithm']}', ...)\n"
else:
test_code += f" context.send_command('{action['widget']}', {action['value']})\n"
with open(output_file, 'w') as f:
f.write(test_code)
```
### Rationale
- **Flexibilità:** Utenti possono scegliere il metodo più adatto al task
- **Onboarding:** Non-programmatori possono registrare test
- **Maintenance:** Test complessi meglio gestiti come Python
- **Best of both worlds:** Sequence per smoke test, Python per integration
### Impatto
- ✅ Abbassa barriera d'ingresso per test creation
- ✅ Permette test rapidi senza programmazione
- ✅ Test Python per scenari complessi
- ⚠️ Serve infrastruttura di recording più sofisticata
- ⚠️ Maintenance di due sistemi (ma condividono TestContext)
---
## Piano di Implementazione
### Fase 1: Fondamenta (2-3 settimane)
**Obiettivo:** Creare L1 (Orchestrator Core) senza rompere GUI esistente
#### Step 1.1: TestContext
- [ ] Creare `artos/core/test_context.py`
- [ ] Implementare basic API (get_message, send_command)
- [ ] Unit test per TestContext
- [ ] Integrare con bus1553_module esistente
#### Step 1.2: Module Manager
- [ ] Creare `artos/core/module_manager.py`
- [ ] Gestione lifecycle moduli (init, start, stop)
- [ ] Registry pattern per moduli
#### Step 1.3: Backward Compatibility
- [ ] GUI esistente continua a funzionare
- [ ] TestContext disponibile opzionalmente
**Deliverable:** TestContext funzionante, usabile da script Python esterni
---
### Fase 2: GUI Modulare con Tkinter Docking (3-4 settimane)
**Obiettivo:** Sistema docking custom con Tkinter
#### Step 2.1: Infrastruttura Base [IN CORSO]
- [x] Decisione: Tkinter + custom docking
- [ ] Creare `DockFrame` base class
- [ ] Creare `WorkspaceManager` con PanedWindow
- [ ] POC con 1-2 dock esempio
- [ ] Sistema save/load layout (JSON)
#### Step 2.2: Migrazione MCS Dock [IN CORSO]
- [ ] Creare MainDockingWindow
- [ ] Migrare contenuto main_window.py in MCS Dock
- [ ] Testare funzionalità esistenti (spinbox, combobox, tabs)
- [ ] Validare performance refresh loop
#### Step 2.3: Dock Placeholder
- [ ] Test Control Dock (vuoto, UI base)
- [ ] Recorder Dock (vuoto, UI base)
- [ ] Video Display Dock (vuoto, canvas placeholder)
- [ ] Target Sim Dock (vuoto, UI base)
**Deliverable:** GUI con sistema docking funzionante e MCS migrato
---
### Fase 3: Test System Dual-Mode (2-3 settimane)
**Obiettivo:** Supporto sia Python che GUI sequences
#### Step 3.1: Python Test Runner
- [ ] Creare `artos/test_execution/test_runner.py`
- [ ] Test loader per file .py
- [ ] Integrazione con TestContext
- [ ] Esempio test suite in `tests/functional/`
#### Step 3.2: Sequence Recording
- [ ] RecorderService per intercettare azioni dock
- [ ] Serializzazione a JSON
- [ ] Sequence player con playback
#### Step 3.3: Export Feature
- [ ] Tool per convertire sequence → Python
- [ ] CLI per eseguire test headless
**Deliverable:** Entrambi i sistemi funzionanti e documentati
---
### Fase 4: Algorithm Library (1-2 settimane)
**Obiettivo:** Creare L2 con algoritmi riutilizzabili
#### Step 4.1: Base Infrastructure
- [ ] BaseAlgorithm interface
- [ ] Algorithm registry
- [ ] 2-3 algoritmi esempio (MessageValidator, TimingChecker)
**Deliverable:** Libreria algoritmi funzionale
---
### Fase 5: Pulizia e Documentazione (1 settimana)
- [ ] Deprecare codice legacy
- [ ] Aggiornare README e manuals
- [ ] Video tutorial per nuovo workflow
---✅ Decisioni Prese
#### D1: Framework GUI ✅ DECISO
**Decisione:** Tkinter + custom docking system
**Rationale:**
- Stdlib affidabile, zero dipendenze critiche
- Team già esperto
- Performance adeguate per i nostri requisiti
- Nessun licensing concern
- Rischi significativamente ridotti vs PyQt6
**Status:** Implementazione iniziata (Fase 2 in corso)
---
### 🤔 Da Decidere
- B) Tkinter + custom docking (più semplice ma limitato)
- C) PySide6 (simile a PyQt6, LGPL)
**Prossimo step:** POC con PyQt6 per validare performance video
---
#### Q2: Event Bus Implementation
**Domanda:** Serve un event bus per comunicazione cross-modulo?
**Scenario:** MFD Dock mostra alert quando 1553 rileva warning
**Opzioni:**
- A) TestContext funge da mediator (più semplice)
- B) Event bus separato (Qt Signals, o custom pub/sub)
**Decisione temporanea:** Posticipare, iniziare con TestContext come mediator
---
#### Q3: Video Streaming Architecture
**Domanda:** Come gestire streaming video real-time verso MFD/SAR dock?
**Opzioni:**
- A) VideoModule scrive frames in shared memory, Dock legge
- B) Qt Signal/Slot per frame updates
- C) ZeroMQ per IPC video
**Prossimo step:** Profiling performance con diverse soluzioni
---
#### Q4: Test Report Format
**Domanda:** Formato standard per test reports?
**Opzioni:**
- A) JUnit XML (integrazione CI/CD)
- B) HTML custom (leggibile)
- C) JSON + template engine
### 2026-01-09 (Pomeriggio) - Decisione Framework GUI + Inizio Implementazione
- **DECISIONE CRITICA:** Scelta Tkinter + custom docking invece di PyQt6
- Motivazione: Affidabilità stdlib, zero licensing, team expertise, rischi ridotti
- Aggiornato piano Fase 2: Implementazione custom docking in Tkinter
- **IMPLEMENTAZIONE COMPLETATA - Prima Iterazione:**
- ✅ Creata struttura `pymsc/gui/docking/` con:
- `DockFrame`: base class per pannelli dockabili (minimize, close, title bar)
- `WorkspaceManager`: gestione layout con `tk.PanedWindow` (splits orizzontali/verticali)
- `MCSDock`: migrazione completa controlli MCS in dock con tab (Page 01-07)
- `PlaceholderDock`: dock generici per moduli futuri
- ✅ Creato `MainDockingWindow`: finestra principale con:
- Layout a 3 pannelli: Left (MCS) | Right Top (Nav, IRST) | Right Bottom (Logger)
- Menu bar con File, View, System, Help
- Save/Load layout con JSON serialization
- Theme: ttkbootstrap "darkly"
- ✅ Script launcher: `scripts/launch_docking_gui.py`
- ✅ Documentazione aggiornata: corretto "Impatto" sezione Decision 2
### 2026-01-09 - ranea:** JUnit XML per CI + HTML per human
---
### 📝 Decisioni da Rivedere
- **Sincrono vs Asincrono TestContext:** Iniziare sincrono, valutare async se bottleneck
- **Recording Granularity:** Registrare ogni singola azione o solo "meaningful events"?
---
## Log delle Modifiche
### 2026-01-09 - Inizializzazione ADR
- Creato documento iniziale
- Documentate decisioni su architettura layered
- Proposta GUI modulare con docking
- Definito dual-mode test system
- Piano di implementazione a 5 fasi
---
## Prossimi Passi Immediati
1. **Revisione con team:** Discutere scelte architetturali (questo documento)
2. **POC PyQt6:** Test pratico docking system + video streaming
3. **Implementazione Fase 1:** Creare TestContext funzionante
4. **Update documento:** Aggiornare ADR con risultati POC
---
## Riferimenti
- [ARTOS Technical Design Specification](./ARTOS%20Technical%20Design%20Specification.md)
- [PyQt6 QDockWidget Documentation](https://doc.qt.io/qt-6/qdockwidget.html)
- [pytest Framework](https://docs.pytest.org/)