{ "scoring_version": "1.0", "description": "Acceptance test vectors for the FablePool flyability scoring rubric v1.0. See docs/12-scoring-worked-examples.md for derivations. Implementations must reproduce 'expected' exactly (breakdown scores to ±0.01).", "units": { "wind_sustained_ms": "m/s sustained at 10m", "wind_gust_ms": "m/s gust at 10m", "precip_mm_h": "mm/h", "temp_c": "degrees Celsius", "weather_code": "WMO code", "direction_sector": "spot sector classification of the wind bearing: clear | marginal | hazard", "offshore": "true if wind bearing falls in the spot's offshore sector" }, "fixtures": [ { "id": "A_single_line_fresh", "kite_type": "single_line", "input": { "wind_sustained_ms": 8.0, "wind_gust_ms": 11.2, "precip_mm_h": 0.0, "temp_c": 18.0, "weather_code": 2, "direction_sector": "clear", "offshore": false }, "expected": { "score": 72, "label": "Good", "hard_rule": null, "warnings": [], "breakdown": { "wind": { "score": 50.0, "weight": 0.5 }, "gust": { "score": 83.33, "weight": 0.2 }, "precipitation": { "score": 100.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "B_dual_line_gusty", "kite_type": "dual_line_sport", "input": { "wind_sustained_ms": 10.0, "wind_gust_ms": 17.0, "precip_mm_h": 0.3, "temp_c": 12.0, "weather_code": 51, "direction_sector": "marginal", "offshore": false }, "expected": { "score": 60, "label": "Good", "hard_rule": null, "warnings": [], "breakdown": { "wind": { "score": 66.67, "weight": 0.5 }, "gust": { "score": 37.5, "weight": 0.2 }, "precipitation": { "score": 60.0, "weight": 0.15 }, "direction": { "score": 50.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "C_kitesurf_offshore", "kite_type": "kitesurf_12m", "input": { "wind_sustained_ms": 7.0, "wind_gust_ms": 8.4, "precip_mm_h": 0.0, "temp_c": 24.0, "weather_code": 1, "direction_sector": "hazard", "offshore": true }, "expected": { "score": 25, "label": "Poor", "hard_rule": "offshore_cap", "warnings": ["offshore_wind"], "breakdown": { "wind": { "score": 100.0, "weight": 0.5 }, "gust": { "score": 100.0, "weight": 0.2 }, "precipitation": { "score": 100.0, "weight": 0.15 }, "direction": { "score": 0.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "D_thunderstorm", "kite_type": "dual_line_sport", "input": { "wind_sustained_ms": 6.0, "wind_gust_ms": 7.0, "precip_mm_h": 1.2, "temp_c": 22.0, "weather_code": 95, "direction_sector": "clear", "offshore": false }, "expected": { "score": 0, "label": "No-fly", "hard_rule": "thunderstorm", "warnings": ["thunderstorm"], "breakdown": { "wind": { "score": 100.0, "weight": 0.5 }, "gust": { "score": 100.0, "weight": 0.2 }, "precipitation": { "score": 20.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "E_calm", "kite_type": "single_line", "input": { "wind_sustained_ms": 1.0, "wind_gust_ms": 2.5, "precip_mm_h": 0.0, "temp_c": 25.0, "weather_code": 0, "direction_sector": "clear", "offshore": false }, "expected": { "score": 0, "label": "No-fly", "hard_rule": "wind_out_of_range", "warnings": [], "breakdown": { "wind": { "score": 0.0, "weight": 0.5 }, "gust": { "score": 100.0, "weight": 0.2 }, "precipitation": { "score": 100.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "F_foil_cold_rain", "kite_type": "power_foil", "input": { "wind_sustained_ms": 8.0, "wind_gust_ms": 9.6, "precip_mm_h": 3.0, "temp_c": 2.0, "weather_code": 63, "direction_sector": "clear", "offshore": false }, "expected": { "score": 83, "label": "Excellent", "hard_rule": null, "warnings": [], "breakdown": { "wind": { "score": 100.0, "weight": 0.5 }, "gust": { "score": 100.0, "weight": 0.2 }, "precipitation": { "score": 0.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 60.0, "weight": 0.05 } } } }, { "id": "G1_gust_boundary_130", "kite_type": "dual_line_sport", "input": { "wind_sustained_ms": 6.0, "wind_gust_ms": 7.8, "precip_mm_h": 0.0, "temp_c": 20.0, "weather_code": 1, "direction_sector": "clear", "offshore": false }, "expected": { "score": 100, "label": "Excellent", "hard_rule": null, "warnings": [], "breakdown": { "wind": { "score": 100.0, "weight": 0.5 }, "gust": { "score": 100.0, "weight": 0.2 }, "precipitation": { "score": 100.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "G2_gust_boundary_160", "kite_type": "dual_line_sport", "input": { "wind_sustained_ms": 6.0, "wind_gust_ms": 9.6, "precip_mm_h": 0.0, "temp_c": 20.0, "weather_code": 1, "direction_sector": "clear", "offshore": false }, "expected": { "score": 90, "label": "Excellent", "hard_rule": null, "warnings": [], "breakdown": { "wind": { "score": 100.0, "weight": 0.5 }, "gust": { "score": 50.0, "weight": 0.2 }, "precipitation": { "score": 100.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "G3_gust_boundary_200", "kite_type": "dual_line_sport", "input": { "wind_sustained_ms": 6.0, "wind_gust_ms": 12.0, "precip_mm_h": 0.0, "temp_c": 20.0, "weather_code": 1, "direction_sector": "clear", "offshore": false }, "expected": { "score": 80, "label": "Excellent", "hard_rule": null, "warnings": [], "breakdown": { "wind": { "score": 100.0, "weight": 0.5 }, "gust": { "score": 0.0, "weight": 0.2 }, "precipitation": { "score": 100.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "W1_flyable_min_edge", "kite_type": "single_line", "input": { "wind_sustained_ms": 1.5, "wind_gust_ms": 1.8, "precip_mm_h": 0.0, "temp_c": 20.0, "weather_code": 0, "direction_sector": "clear", "offshore": false }, "expected": { "score": 0, "label": "No-fly", "hard_rule": "wind_out_of_range", "warnings": [], "breakdown": { "wind": { "score": 0.0, "weight": 0.5 }, "gust": { "score": 100.0, "weight": 0.2 }, "precipitation": { "score": 100.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "W2_ideal_min_edge", "kite_type": "single_line", "input": { "wind_sustained_ms": 2.5, "wind_gust_ms": 3.0, "precip_mm_h": 0.0, "temp_c": 20.0, "weather_code": 0, "direction_sector": "clear", "offshore": false }, "expected": { "score": 100, "label": "Excellent", "hard_rule": null, "warnings": [], "breakdown": { "wind": { "score": 100.0, "weight": 0.5 }, "gust": { "score": 100.0, "weight": 0.2 }, "precipitation": { "score": 100.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } }, { "id": "P1_precip_half_edge", "kite_type": "power_foil", "input": { "wind_sustained_ms": 8.0, "wind_gust_ms": 9.0, "precip_mm_h": 0.5, "temp_c": 20.0, "weather_code": 51, "direction_sector": "clear", "offshore": false }, "expected": { "score": 94, "label": "Excellent", "hard_rule": null, "warnings": [], "breakdown": { "wind": { "score": 100.0, "weight": 0.5 }, "gust": { "score": 100.0, "weight": 0.2 }, "precipitation": { "score": 60.0, "weight": 0.15 }, "direction": { "score": 100.0, "weight": 0.1 }, "temperature": { "score": 100.0, "weight": 0.05 } } } } ], "label_bands": { "Excellent": [80, 100], "Good": [60, 79], "Marginal": [40, 59], "Poor": [20, 39], "No-fly": [0, 19] }, "rounding": "half-up to integer before labeling" }