362 lines
9.6 KiB
Markdown
362 lines
9.6 KiB
Markdown
# QA Checklist — Validazione PlanBundle
|
||
|
||
Criteri e checklist per validare completezza e coerenza di piano prima della pubblicazione.
|
||
|
||
---
|
||
|
||
## QA Score Calculation
|
||
|
||
**Formula:**
|
||
```
|
||
QA_Score = (Checks_Pass / Total_Checks) × Weight_Pass
|
||
|
||
0.90-1.00: ✅ Excellent (publish)
|
||
0.70-0.89: ✅ Good (publish with warnings)
|
||
0.50-0.69: ⚠️ Marginal (request review/improvements)
|
||
< 0.50: ❌ Fail (do not publish; request major fixes)
|
||
```
|
||
|
||
---
|
||
|
||
## Sezione 1: Data Completeness
|
||
|
||
### 1.1 Garden Configuration
|
||
|
||
- [ ] **orto_id** non vuoto, univoco in registry
|
||
- [ ] **Location** (provincia + regione) valide (Italia)
|
||
- [ ] **Coordinates** (lat/lon) within bounds (-90 a 90, -180 a 180)
|
||
- [ ] **Area (m²)** positivo, > 0.1 m² (sensible)
|
||
- [ ] **Clima zone** inferito correttamente (nord/centro/sud)
|
||
- [ ] **Soil type** documentato (se possibile)
|
||
- [ ] **Sun exposure** documentato (ore/giorno)
|
||
- [ ] **Drainage** valutato (buono/mediocre/scarso)
|
||
|
||
**Validation:**
|
||
```python
|
||
if not (lat >= -90 and lat <= 90): error = "Invalid latitude"
|
||
if not (lon >= -180 and lon <= 180): error = "Invalid longitude"
|
||
if area <= 0: error = "Area must be positive"
|
||
```
|
||
|
||
**Impact:** ⭐⭐⭐ (critical for all downstream skills)
|
||
|
||
---
|
||
|
||
### 1.2 Community Profile
|
||
|
||
- [ ] **n_persone** > 0
|
||
- [ ] **Dieta** definita (vegano/vegetariano/onnivoro/altro)
|
||
- [ ] **Preferenze colture** lista non vuota (min. 3)
|
||
- [ ] **Colture evitamento** lista (se allergie)
|
||
- [ ] **Esperienza** livello segnato (nessuna/dilettante/esperto)
|
||
- [ ] **Tempo disponibile** (ore/settimana) > 0
|
||
- [ ] **Accessibility requirements** documentati (se disabilità)
|
||
|
||
**Validation:**
|
||
```python
|
||
if n_persone <= 0: error = "Zero people"
|
||
if not any(diet in ["vegano", "vegetariano", "onnivoro"]):
|
||
warning = "Unknown diet"
|
||
if not preferenze_colture: error = "No crop preference"
|
||
```
|
||
|
||
**Impact:** ⭐⭐ (affect crop selection, layout)
|
||
|
||
---
|
||
|
||
## Sezione 2: Agronomic Consistency
|
||
|
||
### 2.1 Crop Diversity
|
||
|
||
**Rule:** Min. 4 gruppi botanici rappresentati (spread nutritivo)
|
||
|
||
| Gruppo | Colture Tipiche | Min Presenti |
|
||
|--------|---|---|
|
||
| Solanaceae | Pomodoro, Peperone, Melanzana | 1+ |
|
||
| Brassicaceae | Cavolo, Broccoli, Cavolfiore | 1+ |
|
||
| Leguminosae | Fagiolo, Pisello, Fava | 1+ |
|
||
| Cucurbitaceae | Zucchina, Melone, Cocomero | 1+ |
|
||
| Leafy/Erbette | Lattuga, Spinacio, Cavolo riccio | 1+ |
|
||
| Aromatiche | Basilico, Parsley, Oregano | 0+ (opzionale) |
|
||
| Root | Carota, Cipolla, Barbabietola | 1+ |
|
||
|
||
**Check:**
|
||
```python
|
||
groups_present = len([g for g in GROUPS if count[g] > 0])
|
||
if groups_present < 4: flag = "⚠️ Low diversity"
|
||
```
|
||
|
||
**Impact:** ⭐⭐⭐ (nutritional balance, pest management)
|
||
|
||
---
|
||
|
||
### 2.2 Rotation Consistency
|
||
|
||
**Rule:** No stessa famiglia botanica per 2+ anni su stessa aiuola
|
||
|
||
**Check:**
|
||
```python
|
||
for aiuola in layout:
|
||
for year in [year1, year2, year3]:
|
||
crops = layout[aiuola][year]
|
||
families = [get_family(c) for c in crops]
|
||
if len(families) != len(set(families)): # Duplicates
|
||
error = f"Rotation fail {aiuola} year {year}"
|
||
```
|
||
|
||
**Fallback:** Se spazio piccolo (< 20 m²), tollerare 2 anni (vs. 3)
|
||
|
||
**Impact:** ⭐⭐⭐ (disease/pest control)
|
||
|
||
---
|
||
|
||
### 2.3 Nutritional Coverage
|
||
|
||
**Rule:** Piano colture deve coprire ≥ 80% fabbisogno dieta user
|
||
|
||
**Calcolo:**
|
||
```
|
||
For each dietary group (proteins, carbs, vit, minerals):
|
||
estimated_supply = sum(crop_yield × nutritional_contribution)
|
||
target = user_daily × days_season
|
||
coverage = estimated_supply / target
|
||
|
||
if coverage >= 0.80: ✅ OK
|
||
elif coverage >= 0.60: ⚠️ Marginal
|
||
else: ❌ Insufficient
|
||
```
|
||
|
||
**Example (Vegano, 3 persone, estate):**
|
||
```
|
||
Proteins (legumi):
|
||
Fagiolo 10 kg × 25g protein/100g = 2.5 kg protein
|
||
Target (3pp × 60g/gg × 90gg) = 16.2 kg
|
||
Coverage = 2.5 / 16.2 = 15% ❌ INSUFFICIENT
|
||
|
||
Recommendation: Aggiungere 2ª coltura legume (Pisello autunno)
|
||
```
|
||
|
||
**Impact:** ⭐⭐ (user satisfaction, sustainability)
|
||
|
||
---
|
||
|
||
## Sezione 3: Spatial Consistency
|
||
|
||
### 3.1 Layout Coherence
|
||
|
||
- [ ] **Tutte colture** da piano_colture_annuale sono assegnate a aiuole
|
||
- [ ] **No overlaps:** Stessa aiuola non ha > 100% area
|
||
- [ ] **Consociazioni:** % positive > antagonismi nella stessa aiuola
|
||
- [ ] **Accessibilità:** Sentieri >= min requirement (0.5-0.7 m)
|
||
- [ ] **Sun exposure:** Colture assegnate a zone corrette (pieno sole, ombra, ecc.)
|
||
|
||
**Check:**
|
||
```python
|
||
total_assigned = sum(area for crop in layout)
|
||
if total_assigned > available_area:
|
||
error = f"Over-allocated: {total_assigned} > {available_area}"
|
||
|
||
for aiuola in layout:
|
||
positives = count_positive_consociations(aiuola)
|
||
negatives = count_negative_consociations(aiuola)
|
||
if positives < negatives:
|
||
warning = f"Aiuola {aiuola}: more antagonismi than positive"
|
||
```
|
||
|
||
**Impact:** ⭐⭐⭐ (physical feasibility, crop performance)
|
||
|
||
---
|
||
|
||
### 3.2 Water Zone Coherence
|
||
|
||
- [ ] **Zone ALTA (MEDIA, BASSA)** assegnate coerentemente da layout
|
||
- [ ] **No mix:** Stessa zona irrigazione non ha mix ALTA + BASSA
|
||
- [ ] **Emitters**: Ciascuna zona ha emitter assegnato
|
||
|
||
**Check:**
|
||
```python
|
||
for zone in irrigation_zones:
|
||
crops_zone = [c for c in layout if zone_assigned(c) == zone]
|
||
water_classes = [get_water_class(c) for c in crops_zone]
|
||
if len(set(water_classes)) > 2: # More than 2 different classes
|
||
warning = f"Zone {zone}: mixed water needs (may need adjustment)"
|
||
```
|
||
|
||
**Impact:** ⭐⭐⭐ (irrigation efficiency, cost)
|
||
|
||
---
|
||
|
||
## Sezione 4: Water & Irrigation
|
||
|
||
### 4.1 Water Adequacy
|
||
|
||
**Rule:** Total water demand ≤ 110% source capacity (buffer 10%)
|
||
|
||
**Calc:**
|
||
```
|
||
Demand (mm/season) = sum(ET0 × Kc for each month × area_m2)
|
||
Rainfall (mm) = avg rainfall region × season_length
|
||
Irrigation_deficit = Demand - Rainfall
|
||
|
||
Source capacity (L/day) × season_length (days) × 1000 (L to mm on area)
|
||
/ area_m2
|
||
= Max available (mm/season)
|
||
|
||
if Irrigation_deficit <= Max_available: ✅ OK
|
||
elif Irrigation_deficit <= 1.1 × Max_available: ⚠️ Tight (need mulch)
|
||
else: ❌ INSUFFICIENT
|
||
```
|
||
|
||
**Mitigation (if deficit):**
|
||
- Mulching pesante (-20-30% ET)
|
||
- Raccolta pluviale (add 50-100 L)
|
||
- Shift crops (meno ALTA, più BASSA)
|
||
|
||
**Impact:** ⭐⭐⭐ (feasibility, cost)
|
||
|
||
---
|
||
|
||
### 4.2 System Pressure
|
||
|
||
**Rule:** Pressione sistema deve essere 0.5-1.5 bar (goccia) o 2-3 bar (sprinkler)
|
||
|
||
**Check:**
|
||
```python
|
||
emitters_per_zone = plan.irrigation[zone].emitters
|
||
total_flow = sum(e.flow for e in emitters_per_zone)
|
||
if source_pressure < min_required:
|
||
warning = "Low pressure: may need pump or regulator"
|
||
elif source_pressure > max_required:
|
||
warning = "High pressure: may damage emitters"
|
||
```
|
||
|
||
**Impact:** ⭐⭐ (durability, efficiency)
|
||
|
||
---
|
||
|
||
## Sezione 5: Temporal (Calendar)
|
||
|
||
### 5.1 Seasonal Alignment
|
||
|
||
- [ ] **Tutte colture** hanno semina/trapianto entro frost windows
|
||
- [ ] **Raccolta** prima di gelo primo (se sensitive)
|
||
- [ ] **Successioni** (es. Lattuga 3x) scheduled con spacing
|
||
- [ ] **Task frequency** total time ≤ available hours/week
|
||
|
||
**Check:**
|
||
```python
|
||
for crop in piano_colture:
|
||
if sowing_date < last_frost and crop_is_frost_sensitive:
|
||
error = f"{crop} planted before frost date"
|
||
|
||
if harvest_date > first_frost and crop_is_frost_sensitive:
|
||
error = f"{crop} harvest after frost"
|
||
|
||
# Time check
|
||
total_weekly_hours = sum(task.hours for task in calendario)
|
||
if total_weekly_hours > user_available_hours:
|
||
warning = f"Tasks exceed available time by {excess} hours/week"
|
||
suggestion = "Reduce scope or automate irrigation"
|
||
```
|
||
|
||
**Impact:** ⭐⭐⭐ (feasibility, success)
|
||
|
||
---
|
||
|
||
### 5.2 Meteo Sensitivity Tagging
|
||
|
||
- [ ] **Trapianti** tagged METEO_CRITICA
|
||
- [ ] **Trattamenti fogliari** tagged METEO_DEFER
|
||
- [ ] **Raccolta** no tag (non-deferent)
|
||
- [ ] **Irrigazione** tagged METEO_SKIP
|
||
|
||
**Check:**
|
||
```python
|
||
for task in calendario:
|
||
if task.type == "trapianto":
|
||
if not task.meteo_tag: warning = "Trapianto non taggato"
|
||
if task.type == "spray_fogliare":
|
||
if task.meteo_tag != "METEO_DEFER": error = "Wrong tag"
|
||
```
|
||
|
||
**Impact:** ⭐⭐ (weather adaptation)
|
||
|
||
---
|
||
|
||
## Sezione 6: Disease & Safety
|
||
|
||
### 6.1 Preventive Coverage
|
||
|
||
- [ ] **Alto-risk crops** (Pomodoro, Melanzana, Cavolo) hanno piano preventivo
|
||
- [ ] **Treatments** (rame, zolfo, bio) sono autorizzati Italia
|
||
- [ ] **DPI** richiesti documentati
|
||
- [ ] **Carenza** (raccolta timing) rispettate
|
||
|
||
**Check:**
|
||
```python
|
||
high_risk = ["Pomodoro", "Melanzana", "Cavolo"]
|
||
for crop in piano_colture:
|
||
if crop in high_risk:
|
||
if not plan_fitopatologo[crop].preventive:
|
||
warning = f"No preventive plan for high-risk {crop}"
|
||
```
|
||
|
||
**Impact:** ⭐⭐⭐ (disease management, safety)
|
||
|
||
---
|
||
|
||
### 6.2 DPI & Safety
|
||
|
||
- [ ] **Treatments** sono bio-authorized (D.M. 18527/2012) o IPM
|
||
- [ ] **DPI required** documentati (guanti, respiratore, ecc.)
|
||
- [ ] **Warnings** per allergie/sensibilità registrati
|
||
|
||
**Check:**
|
||
```python
|
||
for treatment in piano_fitopatologo.treatments:
|
||
if treatment not in APPROVED_BIO_LIST:
|
||
error = f"Unapproved treatment: {treatment}"
|
||
```
|
||
|
||
**Impact:** ⭐⭐⭐ (legal, health)
|
||
|
||
---
|
||
|
||
## Sezione 7: QA Summary Report
|
||
|
||
**Output Model:**
|
||
|
||
```markdown
|
||
# QA Report — [ORTO_ID]
|
||
|
||
## Score Card
|
||
|
||
| Check | Status | Weight | Result |
|
||
|-------|--------|--------|--------|
|
||
| Data Completeness | ✅ 10/10 | 15% | 1.5 |
|
||
| Agronomic | ✅ 8/9 | 20% | 1.78 |
|
||
| Spatial | ✅ 9/10 | 15% | 1.35 |
|
||
| Water | ⚠️ 7/10 | 20% | 1.4 |
|
||
| Temporal | ✅ 10/10 | 15% | 1.5 |
|
||
| Disease | ✅ 8/9 | 15% | 1.33 |
|
||
| **OVERALL** | | | **0.91** |
|
||
|
||
## Recommendations
|
||
|
||
1. ⚠️ Water tight (105% capacity) → Apply mulch (-25% ET)
|
||
2. ✅ Crop diversity excellent (6 groups)
|
||
3. ✅ Rotation coherent 3-year
|
||
4. ⚠️ Time: Weekly tasks 6.5 hrs (vs. 5 available) → Automate irrigation
|
||
|
||
## Decision
|
||
|
||
✅ **APPROVED** (Score 0.91 — Excellent)
|
||
→ Publish to user with water mitigation note
|
||
|
||
---
|
||
```
|
||
|
||
---
|
||
|
||
**Ultima revisione:** 2026-03-06
|
||
**Integrazione:** orto-orchestratore Phase 3 (Data Validation)
|