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