# 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/)
