{
  "version": "0.1.0",
  "counts": {
    "tools": 323,
    "stable": 213,
    "vectors": 5608,
    "checks": 22729,
    "failures": 0
  },
  "tools": [
    {
      "id": "aviation.airspace.tfr-area",
      "title": "TFR and NOTAM area",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 8,
      "checks": {
        "numeric": 20,
        "exact": 17
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GeodSolve and Planimeter (tools/vectors/gen_tfr.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 7
        },
        {
          "source": "add-practitioner-essentials TFR scenario (3 NM geodesic circle, SFC to 3,000 ft MSL) (GeodSolve: GeographicLib version 2.7)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.area.value",
        "error": 2.4012791755012586e-11,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.000024012791755012586
      },
      "exampleSource": "add-practitioner-essentials TFR scenario: a 3 NM geodesic circle, exportable as GeoJSON with its altitude limits"
    },
    {
      "id": "aviation.airspeed.cas-to-tas",
      "title": "True airspeed from indicated or calibrated airspeed",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 21,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the Gracey (NASA RP-1046) airspeed relations, with supersonic Mach by bisection (tools/vectors/gen_aviation.py) (NASA RP-1046 (1980))",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.tas.value",
        "error": 3.979039320256561e-11,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 0.000019416901626997823
      },
      "exampleSource": "add-aviation-suite airspeed scenario: Mach 0.4523, TAS 288.6 kt, EAS 248.1 kt"
    },
    {
      "id": "aviation.airspeed.tas-to-cas",
      "title": "Calibrated airspeed from true airspeed or Mach",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 12,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the Gracey (NASA RP-1046) airspeed relations, with supersonic Mach by bisection (tools/vectors/gen_aviation.py) (NASA RP-1046 (1980))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.cas.value",
        "error": 7.958078640513122e-13,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 6.880102013574728e-7
      },
      "exampleSource": "Round trip of the add-aviation-suite FL350 scenario (Gracey RP-1046 equations)"
    },
    {
      "id": "aviation.airspeed.tat-sat",
      "title": "Total and static air temperature",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 10,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the Gracey (NASA RP-1046) airspeed relations, with supersonic Mach by bisection (tools/vectors/gen_aviation.py) (NASA RP-1046 (1980))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.sat.value",
        "error": 3.375077994860476e-14,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 3.357486314758226e-8
      },
      "exampleSource": "add-aviation-suite airspeed scenario: SAT -48.73 °C, ram rise 28.73 K"
    },
    {
      "id": "aviation.altimetry.cold-temperature",
      "title": "Cold temperature altitude correction",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 57,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "ICAO 2020 equation and AIM Table 7-3-1 worked in Python (tools/vectors/gen_coldtemp.py) (2026)",
          "count": 5
        },
        {
          "source": "add-aviation-suite cold-temperature scenarios (1,500 ft above a 2,000 ft airport at -30 °C: about +218 ft, the 4% rule about +246 ft) (2026)",
          "count": 1
        },
        {
          "source": "add-aviation-suite cold-temperature scenarios (no correction when warmer than ISA) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.isa_deviation.value",
        "error": 0,
        "abs": 0.000001,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-aviation-suite cold-temperature scenario: 1,500 ft above the airport at -30 °C corrects by about +218 ft, the 4% rule by about +246 ft"
    },
    {
      "id": "aviation.altimetry.density-altitude",
      "title": "Density altitude",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 21,
        "exact": 21
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the ICAO Doc 7488/3 defining equations (tools/vectors/gen_aviation.py) (Doc 7488/3 (1993))",
          "count": 20
        },
        {
          "source": "FAA Pilot's Handbook of Aeronautical Knowledge (FAA-H-8083-25C), worked example read from the published chart or table (FAA-H-8083-25C (2023))",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v021",
        "path": "result.density_altitude.value",
        "error": 9.564794514699315,
        "abs": 100,
        "rel": 0,
        "used": 0.09564794514699315
      },
      "exampleSource": "add-aviation-suite altimetry scenario: PA 5,112 ft, ISA 4.87 °C, DA 7,937 ft (±5 ft), 118.8 rule 8,098 ft"
    },
    {
      "id": "aviation.altimetry.flight-level",
      "title": "Flight level and altitude",
      "version": "1.1.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 20,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "ISA altimetry worked in Python (tools/vectors/gen_qcodes.py) (2026)",
          "count": 6
        },
        {
          "source": "add-aviation-suite altimetry scenarios (lowest usable flight level FL185 at 29.42 inHg, 14 CFR 91.121(b)) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v010",
        "path": "result.fl_of_altitude",
        "error": 5.684341886080802e-14,
        "abs": 0.000001,
        "rel": 0.000001,
        "used": 3.2862585599587104e-10
      },
      "exampleSource": "add-aviation-suite lowest-usable-flight-level scenario: FL185 at 29.42 inHg, with the FAA table cited"
    },
    {
      "id": "aviation.altimetry.isa-temperature",
      "title": "ISA temperature and deviation",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 6,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the ICAO Doc 7488/3 defining equations (tools/vectors/gen_aviation.py) (Doc 7488/3 (1993))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.isa_temperature.value",
        "error": 4.263256414560601e-14,
        "abs": 0.000001,
        "rel": 1e-12,
        "used": 4.263015556198935e-8
      },
      "exampleSource": "add-aviation-suite altimetry scenario: -56.5 °C above 36,089 ft"
    },
    {
      "id": "aviation.altimetry.pressure-altitude",
      "title": "Pressure altitude",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 25,
        "exact": 25
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the ICAO Doc 7488/3 defining equations (tools/vectors/gen_aviation.py) (Doc 7488/3 (1993))",
          "count": 19
        },
        {
          "source": "FAA Pilot's Handbook of Aeronautical Knowledge (FAA-H-8083-25C), chapter 11: pressure altitude is the field elevation plus the figure 11-3 correction for the altimeter setting (FAA-H-8083-25C (2023))",
          "count": 3
        },
        {
          "source": "FAA Pilot's Handbook of Aeronautical Knowledge (FAA-H-8083-25C), worked example read from the published chart or table (FAA-H-8083-25C (2023))",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v022",
        "path": "result.pressure_altitude.value",
        "error": 0.4118077164624765,
        "abs": 1,
        "rel": 0,
        "used": 0.4118077164624765
      },
      "exampleSource": "add-aviation-suite altimetry scenario: 5,112 ft (±1 ft); rule of thumb 5,120 ft"
    },
    {
      "id": "aviation.altimetry.q-codes",
      "title": "QNH, QFE, and QNE",
      "version": "1.1.1",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 28,
        "exact": 13
      },
      "failures": [],
      "sources": [
        {
          "source": "ISA altimetry worked in Python (tools/vectors/gen_qcodes.py) (2026)",
          "count": 8
        },
        {
          "source": "add-aviation-suite altimetry scenarios (QFE from QNH 1013 hPa at 1,000 ft by the ISA pressure-height relation) (2026)",
          "count": 1
        },
        {
          "source": "FAA Aviation Weather Handbook (FAA-H-8083-28B) section 24.4.3.11: altimeter settings are given to hundredths of an inch of mercury; QFE and pressure altitude by the ISA relation as in v001 to v015 (FAA-H-8083-28B)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v008",
        "path": "result.qnh.value",
        "error": 0.000013132054867526222,
        "abs": 0.000001,
        "rel": 0.000001,
        "used": 0.42478096629399653
      },
      "exampleSource": "add-aviation-suite QFE scenario: QFE by the ISA pressure-height relation; with QFE set the altimeter reads 0 ft on the ground"
    },
    {
      "id": "aviation.altimetry.true-altitude",
      "title": "True altitude",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 18,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "ICAO 2020 equation and AIM Table 7-3-1 worked in Python (tools/vectors/gen_coldtemp.py) (2026)",
          "count": 6
        },
        {
          "source": "add-aviation-suite cold-temperature scenarios (ISA -20 °C at 8,000 ft indicated: true altitude below indicated) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.true_altitude.value",
        "error": 0,
        "abs": 0.000001,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-aviation-suite true-altitude scenario: in colder air the true altitude is below the indicated one, and the difference is reported"
    },
    {
      "id": "aviation.atmosphere.cloud-base",
      "title": "Cloud base and freezing level",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 22,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "Heading arithmetic and Bolton (1980) eq. 15 worked in Python (tools/vectors/gen_heading.py) (2026)",
          "count": 6
        },
        {
          "source": "add-aviation-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.cloud_base_lcl.value",
        "error": 4.547473508864641e-13,
        "abs": 0.000001,
        "rel": 0,
        "used": 4.547473508864641e-7
      },
      "exampleSource": "add-aviation-suite cloud-base scenario (about 4,000 ft AGL by the rule, the LCL alongside)"
    },
    {
      "id": "aviation.atmosphere.humidity",
      "title": "Humidity and moist air",
      "version": "1.0.1",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 48,
        "exact": 14
      },
      "failures": [],
      "sources": [
        {
          "source": "Moist-air relations worked in Python (tools/vectors/gen_humidity.py) (2026)",
          "count": 9
        },
        {
          "source": "add-aviation-suite humid-density scenario (30 °C, 1,000 hPa, dew point 24 °C: moist density below dry) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.virtual_temperature.value",
        "error": 3.4083846855992306e-14,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0.000023824787504343844
      },
      "exampleSource": "add-aviation-suite humid-density scenario: moist air is lighter than dry air at the same temperature and pressure, and both are reported"
    },
    {
      "id": "aviation.atmosphere.isa",
      "title": "Standard atmosphere",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 86,
        "exact": 22
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the ICAO Doc 7488/3 defining equations (tools/vectors/gen_aviation.py) (Doc 7488/3 (1993))",
          "count": 10
        },
        {
          "source": "ambiance (independent Python implementation of the ICAO standard atmosphere 1993) (ambiance 1.3.1)",
          "count": 8
        },
        {
          "source": "U.S. Standard Atmosphere 1976, Table I (geometric altitude), printed to 5 significant figures (NOAA-S/T 76-1562 (1976))",
          "count": 4
        }
      ],
      "worst": {
        "vector": "v020",
        "path": "result.pressure.value",
        "error": 0.0005877124172002368,
        "abs": 0,
        "rel": 0.000003,
        "used": 0.6822548244259079
      },
      "exampleSource": "ICAO Doc 7488/3: 268.338 K, 696.82 hPa, 0.904637 kg/m³ at 3,048 m geopotential"
    },
    {
      "id": "aviation.ifr.dme-arc-lead",
      "title": "DME arc lead points",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 24,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "Right-triangle and turn geometry worked in Python (tools/vectors/gen_dme.py) (2026)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.lead_radials.value",
        "error": 8.881784197001252e-16,
        "abs": 1e-9,
        "rel": 0,
        "used": 8.881784197001251e-7
      },
      "exampleSource": "Hand check: radius 120 ÷ (60π) = 0.64 NM; lead asin(0.64 ÷ 9.36) = 3.9°, rule 3.8°"
    },
    {
      "id": "aviation.ifr.dme-slant-range",
      "title": "DME slant range to ground distance",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 18,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "Right-triangle and turn geometry worked in Python (tools/vectors/gen_dme.py) (2026)",
          "count": 5
        },
        {
          "source": "add-practitioner-essentials scenarios (overhead) (2026)",
          "count": 1
        },
        {
          "source": "add-practitioner-essentials scenarios (slant range: 4.902 NM) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.elevation_angle.value",
        "error": 7.105427357601002e-15,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.000007105427357601001
      },
      "exampleSource": "add-practitioner-essentials slant-range scenario (4.902 NM)"
    },
    {
      "id": "aviation.ifr.hold-entry",
      "title": "Holding pattern entry",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 35,
      "checks": {
        "numeric": 82,
        "exact": 82
      },
      "failures": [],
      "sources": [
        {
          "source": "AIM 5-3-8j FIG 5-3-4 sectors worked by position in Python (tools/vectors/gen_hold_part107.py): the side of the holding course and of the 70-degree line the aircraft comes from (AIM basic with Change 3 (July 9, 2026))",
          "count": 14
        },
        {
          "source": "AIM 5-3-8j FIG 5-3-4 sectors worked by position in Python (tools/vectors/gen_hold_part107.py), with the 5-degree zone of flexibility on the sector boundaries from ICAO Doc 8168 Vol I and TC AIM RAC 10.5 (AIM basic with Change 3 (July 9, 2026))",
          "count": 8
        },
        {
          "source": "AIM 5-3-8 figure 5-3-2 sectors and table 5-3-1 speeds, applied by hand (AIM (2026))",
          "count": 7
        },
        {
          "source": "AIM 5-3-8j FIG 5-3-4 sectors worked by position in Python (tools/vectors/gen_hold_part107.py), with the 5-degree zone of flexibility on the sector boundaries from ICAO Doc 8168 Vol I and TC AIM RAC 10.5; exactly on the teardrop/parallel line the tool names the teardrop for either turn direction, so a left hold mirrors a right one (AIM basic with Change 3 (July 9, 2026))",
          "count": 2
        },
        {
          "source": "Required inputs: an entry needs both the inbound course and the heading to the fix (AIM basic with Change 3 (July 9, 2026))",
          "count": 2
        },
        {
          "source": "AIM 5-3-8j FIG 5-3-4 sectors worked by position in Python (tools/vectors/gen_hold_part107.py); 3 rad = 171.887 deg (AIM basic with Change 3 (July 9, 2026))",
          "count": 1
        },
        {
          "source": "TC AIM (TP 14371E, AIM 2026-1) RAC 10.2 example 2: arriving on track 234 deg at ZHZ, make a right turn and hold on an inbound track of 234 deg (the RAC 10.5 sector 3 direct entry) (TC AIM 2026-1, effective March 19, 2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v008",
        "path": "result.outbound_course.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "AIM 5-3-8 FIG 5-3-4: an arrival 90° right of the inbound course is in the direct sector"
    },
    {
      "id": "aviation.ifr.hold-speed-limit",
      "title": "Maximum holding airspeed",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 6,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "AIM 5-3-8 figure 5-3-2 sectors and table 5-3-1 speeds, applied by hand (AIM (2026))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.max_ias.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "AIM 5-3-8 table 5-3-1: 230 KIAS from 6,001 ft through 14,000 ft"
    },
    {
      "id": "aviation.ifr.hold-wind-timing",
      "title": "Holding wind correction and timing",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 15,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the holding wind triangle and triple-the-drift rule in FAA-H-8083-15B (tools/vectors/gen_aviation.py) (FAA-H-8083-15B (2012))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.inbound_wca.value",
        "error": 0,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 0
      },
      "exampleSource": "FAA-H-8083-15B chapter 10 method: correct into the wind inbound, triple it outbound"
    },
    {
      "id": "aviation.ifr.radial-fix",
      "title": "Fix from a radial and distance",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 23,
        "exact": 9
      },
      "failures": [],
      "sources": [
        {
          "source": "GeodSolve fixes and WMM2025 declinations (tools/vectors/gen_radial.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 5
        },
        {
          "source": "add-practitioner-essentials variation scenario (the station's variation is used, and a difference over 1° from WMM is warned) (GeodSolve: GeographicLib version 2.7)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.fix_lat.value",
        "error": 2.1316282072803006e-14,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.000021316282072803006
      },
      "exampleSource": "add-practitioner-essentials variation scenario: the fix uses the station's 11° E, and the difference from WMM is reported and warned when over 1°"
    },
    {
      "id": "aviation.ifr.radial-intercept",
      "title": "Heading to intercept a radial",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 9,
      "checks": {
        "numeric": 28,
        "exact": 11
      },
      "failures": [],
      "sources": [
        {
          "source": "Plane geometry: the heading of course ± the angle whose track crosses the radial (tools/vectors/gen_dme.py) (2026)",
          "count": 7
        },
        {
          "source": "Right-triangle and turn geometry worked in Python (tools/vectors/gen_dme.py) (2026)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.heading.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "FAA-H-8083-15B chapter 9 course interception; 30° off, so a 60° intercept: heading 180 + 60 = 240"
    },
    {
      "id": "aviation.ifr.time-to-station",
      "title": "Time and distance to a station",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 22,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "Right-triangle and turn geometry worked in Python (tools/vectors/gen_dme.py) (2026)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.time.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Hand check: rule 60 × 2 ÷ 10 = 12 min; exact 2 ÷ sin 10° = 11.52 min"
    },
    {
      "id": "aviation.loading.ballast",
      "title": "Ballast to move the CG",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 8,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Weight-shift and ballast proportions worked in Python (tools/vectors/gen_shift.py) (2026)",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.ballast.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Worked from moments: 2,250 × (83.0 − 84.3) ÷ (10 − 83.0) = 40.1 lb"
    },
    {
      "id": "aviation.loading.fuel-plan",
      "title": "Fuel planning",
      "version": "1.1.0",
      "stability": "experimental",
      "vectors": 12,
      "checks": {
        "numeric": 53,
        "exact": 17
      },
      "failures": [],
      "sources": [
        {
          "source": "Fuel arithmetic worked in Python (tools/vectors/gen_fuel.py) (2026)",
          "count": 10
        },
        {
          "source": "add-aviation-suite fuel scenarios (rotorcraft VFR: 20 minutes, 14 CFR 91.151(b)) (2026)",
          "count": 1
        },
        {
          "source": "add-aviation-suite fuel scenarios (VFR night: 45 minutes at the cruise burn, cited to 14 CFR 91.151(a)(2)) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v008",
        "path": "result.total.value",
        "error": 3.552713678800501e-15,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.0000035527136788005005
      },
      "exampleSource": "add-aviation-suite VFR night scenario: a 45-minute reserve at the entered cruise burn, cited to 14 CFR 91.151(a)(2)"
    },
    {
      "id": "aviation.loading.fuel-weight",
      "title": "Fuel weight",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 5,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python weight-and-balance arithmetic per FAA-H-8083-1B chapter 2 (tools/vectors/gen_aviation.py) (FAA-H-8083-1B (2016))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.weight.value",
        "error": 2.842170943040401e-14,
        "abs": 0.000001,
        "rel": 1e-12,
        "used": 2.8416679678100983e-8
      },
      "exampleSource": "add-aviation-suite fuel scenario: 240 lb at the nominal 6.0 lb/gal (FAA-H-8083-1B chapter 2)"
    },
    {
      "id": "aviation.loading.table-interpolate",
      "title": "Performance table lookup",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 13,
      "checks": {
        "numeric": 11,
        "exact": 20
      },
      "failures": [],
      "sources": [
        {
          "source": "Multilinear interpolation worked in Python (tools/vectors/gen_table.py) (2026)",
          "count": 10
        },
        {
          "source": "add-aviation-suite scenarios (2026)",
          "count": 2
        },
        {
          "source": "add-aviation-suite no-POH scenario (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v009",
        "path": "result.table_value",
        "error": 2.2737367544323206e-13,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.00022737367544323203
      },
      "exampleSource": "add-aviation-suite bilinear scenario: the four cells around 3,000 ft and 25 °C"
    },
    {
      "id": "aviation.loading.weight-balance",
      "title": "Weight and balance",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 47,
        "exact": 24
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python weight-and-balance arithmetic per FAA-H-8083-1B chapter 2 (tools/vectors/gen_aviation.py) (FAA-H-8083-1B (2016))",
          "count": 20
        },
        {
          "source": "FAA Aircraft Weight and Balance Handbook (FAA-H-8083-1B), worked example (FAA-H-8083-1B (2016))",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v022",
        "path": "result.cg.value",
        "error": 0.004944707740918375,
        "abs": 0.005,
        "rel": 0,
        "used": 0.988941548183675
      },
      "exampleSource": "add-aviation-suite weight-and-balance scenario: 2,250 lb at 84.30 in (FAA-H-8083-1B chapter 2 method)"
    },
    {
      "id": "aviation.loading.weight-shift",
      "title": "Weight shift",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 15,
        "exact": 9
      },
      "failures": [],
      "sources": [
        {
          "source": "Weight-shift and ballast proportions worked in Python (tools/vectors/gen_shift.py) (2026)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.new_cg.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Worked from the handbook proportion: 50 × (90 − 150) ÷ 2,250 = −1.33 in, so the CG moves to 82.97 in"
    },
    {
      "id": "aviation.performance.climb-gradient",
      "title": "Climb gradient and vertical speed",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 10,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the turn, gradient, glide, and pivotal-altitude relations in FAA-H-8083-3C and FAA-H-8083-16B (tools/vectors/gen_aviation.py) (FAA-H-8083-16B (2017))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.vertical_speed.value",
        "error": 2.2737367544323206e-13,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 1.0658141036401503e-7
      },
      "exampleSource": "add-aviation-suite climb scenario: 400 fpm"
    },
    {
      "id": "aviation.performance.glide",
      "title": "Glide range with wind",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 15,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the turn, gradient, glide, and pivotal-altitude relations in FAA-H-8083-3C and FAA-H-8083-16B (tools/vectors/gen_aviation.py) (FAA-H-8083-3C (2021))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.sink_rate.value",
        "error": 1.1368683772161603e-13,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 6.359588350103397e-8
      },
      "exampleSource": "add-aviation-suite glide scenario: still air 7.41 NM, headwind 5.29 NM"
    },
    {
      "id": "aviation.performance.pivotal-altitude",
      "title": "Pivotal altitude",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 5,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the turn, gradient, glide, and pivotal-altitude relations in FAA-H-8083-3C and FAA-H-8083-16B (tools/vectors/gen_aviation.py) (FAA-H-8083-3C (2021))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.pivotal_altitude.value",
        "error": 1.1368683772161603e-13,
        "abs": 0.000001,
        "rel": 1e-12,
        "used": 1.135862680214008e-7
      },
      "exampleSource": "add-aviation-suite pivotal-altitude scenario: about 885 ft AGL (AFH chapter 6: GS²/11.3)"
    },
    {
      "id": "aviation.performance.specific-range",
      "title": "Specific range",
      "version": "1.0.1",
      "stability": "experimental",
      "vectors": 8,
      "checks": {
        "numeric": 18,
        "exact": 11
      },
      "failures": [],
      "sources": [
        {
          "source": "Specific range worked in Python (tools/vectors/gen_range.py) (2026)",
          "count": 8
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.air_range",
        "error": 1.7763568394002505e-15,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.0000017763568394002503
      },
      "exampleSource": "Worked from the definition: 120 ÷ 8.5 = 14.12 NM per gallon through the air, 105 ÷ 8.5 = 12.35 over the ground"
    },
    {
      "id": "aviation.performance.top-of-descent",
      "title": "Top of descent",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 39,
        "exact": 20
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the turn, gradient, glide, and pivotal-altitude relations in FAA-H-8083-3C and FAA-H-8083-16B (tools/vectors/gen_aviation.py) (FAA-H-8083-16B (2017))",
          "count": 19
        },
        {
          "source": "FAA Instrument Procedures Handbook (FAA-H-8083-16B), worked example (FAA-H-8083-16B)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v007",
        "path": "result.vertical_speed.value",
        "error": 6.821210263296962e-13,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 2.3667607412609398e-7
      },
      "exampleSource": "add-aviation-suite descent scenario: 100.5 NM (3:1 rule 96 NM), 2,229 fpm (5 × GS rule 2,100 fpm)"
    },
    {
      "id": "aviation.performance.turn",
      "title": "Turn performance and load factor",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 18,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the turn, gradient, glide, and pivotal-altitude relations in FAA-H-8083-3C and FAA-H-8083-16B (tools/vectors/gen_aviation.py) (FAA-H-8083-3C (2021))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.radius.value",
        "error": 1.8189894035458565e-12,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 1.413662137764391e-7
      },
      "exampleSource": "add-aviation-suite turn scenario: bank 15.36°, rule of thumb 17°"
    },
    {
      "id": "aviation.performance.vdp",
      "title": "Visual descent point",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 42,
        "exact": 24
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the turn, gradient, glide, and pivotal-altitude relations in FAA-H-8083-3C and FAA-H-8083-16B (tools/vectors/gen_aviation.py) (FAA-H-8083-16B (2017))",
          "count": 22
        },
        {
          "source": "FAA Instrument Procedures Handbook (FAA-H-8083-16B), worked example (FAA-H-8083-16B)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v023",
        "path": "result.path_height.value",
        "error": 2.2737367544323206e-13,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 9.419621082923635e-8
      },
      "exampleSource": "Instrument Procedures Handbook chapter 4: VDP ≈ HAT/300 NM for a 3° path (400/300 = 1.33 NM)"
    },
    {
      "id": "aviation.weather.fb-winds-decode",
      "title": "Winds aloft (FB) decoder",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 101,
        "exact": 28
      },
      "failures": [],
      "sources": [
        {
          "source": "FAA Aviation Weather Handbook (FAA-H-8083-28A), decoded example (FAA-H-8083-28A (2024))",
          "count": 9
        },
        {
          "source": "Winds encoded by an independent Python implementation of the FB coding rules (tools/vectors/gen_aviation.py) (FAA-H-8083-28A (2024))",
          "count": 8
        },
        {
          "source": "Hand-decoded per the FAA Aviation Weather Handbook FB coding rules (FAA-H-8083-28) (FAA-H-8083-28 (2022))",
          "count": 6
        },
        {
          "source": "FAA Aviation Weather Handbook (FAA-H-8083-28B) section 27.2.1.1.1: forecast speeds of 200 kt or greater are coded as 199 kt; 7799 is decoded as 270° at 199 kt or greater (FAA-H-8083-28B)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.winds.0.direction.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials FB scenario: 230° true at 119 kt, -60 °C"
    },
    {
      "id": "aviation.weather.metar-decode",
      "title": "METAR decoder",
      "version": "1.1.1",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 80,
        "exact": 41
      },
      "failures": [],
      "sources": [
        {
          "source": "Live Aviation Weather Center reports (2026-09-19), as decoded by python-metar 1.11.0 (metar 1.11.0)",
          "count": 14
        },
        {
          "source": "Hand-decoded per FAA Order JO 7900.5E Change 1 (METAR body and remarks) and the FAA Aviation Weather Handbook (flight categories) (JO 7900.5E Chg 1 (2022))",
          "count": 6
        },
        {
          "source": "FAA Aviation Weather Handbook (FAA-H-8083-28A), decoded example (FAA-H-8083-28A (2024))",
          "count": 1
        },
        {
          "source": "FAA Aviation Weather Handbook (FAA-H-8083-28B) section 24.4.3.11: the altimeter group codes tens, units, tenths, and hundredths of inches of mercury (A2992 is 29.92 inHg) (FAA-H-8083-28B)",
          "count": 1
        },
        {
          "source": "WMO Manual on Codes, FM 15 METAR group QPHPHPHPH: QNH rounded down to whole hectopascals, so no decimals are shown (WMO-No. 306, Volume I.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.wind_direction.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials weather scenario: 300° true at 15 gusting 25, 10 SM, FEW080 SCT200, 30.0/8.3 °C, 29.80 inHg, SLP 1005.2 hPa"
    },
    {
      "id": "aviation.weather.taf-decode",
      "title": "TAF decoder",
      "version": "1.2.1",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 20,
        "exact": 53
      },
      "failures": [],
      "sources": [
        {
          "source": "Live Aviation Weather Center TAFs (2026-09-19), as parsed by pytaf 1.2.1 (pytaf 1.2.1)",
          "count": 15
        },
        {
          "source": "Hand-decoded per the FAA Aviation Weather Handbook (TAF chapter) (FAA-H-8083-28 (2022))",
          "count": 5
        },
        {
          "source": "FAA Aviation Weather Handbook (FAA-H-8083-28A), decoded example (FAA-H-8083-28A (2024))",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.valid_hours",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials TAF scenario: valid 18:00Z on the 18th to 18:00Z on the 19th, each change group placed in order"
    },
    {
      "id": "aviation.wind.aloft-interpolate",
      "title": "Winds aloft between levels",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 40,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "Meteorological u/v convention and linear interpolation worked in Python (tools/vectors/gen_aloft.py) (2026)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.speed.value",
        "error": 3.061616997868382e-16,
        "abs": 1e-9,
        "rel": 0,
        "used": 3.061616997868382e-7
      },
      "exampleSource": "Hand check: u = (20 + 25.98)/2 = 22.99 kt, v = (0 - 15)/2 = -7.5 kt, so 288° at 24.2 kt; temperature 0 °C"
    },
    {
      "id": "aviation.wind.best-runway",
      "title": "Rank runways for the wind",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 9,
      "checks": {
        "numeric": 39,
        "exact": 40
      },
      "failures": [],
      "sources": [
        {
          "source": "Runway wind components ranked in Python (tools/vectors/gen_runway.py) (2026)",
          "count": 7
        },
        {
          "source": "add-aviation-suite ranking scenario (runway 18 ranks first, every runway listed) (2026)",
          "count": 1
        },
        {
          "source": "add-aviation-suite variable-wind scenario (worst case 8 kt crosswind and tailwind) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.runways.3.headwind.value",
        "error": 1.7763568394002505e-15,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.0000017763568394002503
      },
      "exampleSource": "add-aviation-suite ranking scenario: runway 18 ranks first, every runway listed"
    },
    {
      "id": "aviation.wind.course-from-heading",
      "title": "Wind triangle: course and groundspeed from a heading",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 8,
      "checks": {
        "numeric": 18,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Wind-triangle vectors worked in Python (tools/vectors/gen_triangle.py) (2026)",
          "count": 6
        },
        {
          "source": "add-aviation-suite heading-and-groundspeed scenario, solved the other way (course about 090° at 108.7 kt) (2026)",
          "count": 1
        },
        {
          "source": "add-aviation-suite mixed-reference scenario (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.groundspeed.value",
        "error": 2.842170943040401e-14,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.000028421709430404004
      },
      "exampleSource": "add-aviation-suite heading-and-groundspeed scenario solved the other way: course about 090° at 108.7 kt"
    },
    {
      "id": "aviation.wind.find-wind",
      "title": "Wind triangle: find the wind",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 10,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the ICAO Doc 7488/3 defining equations (tools/vectors/gen_aviation.py) (Doc 7488/3 (1993))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.wind_speed.value",
        "error": 3.552713678800501e-15,
        "abs": 0.000001,
        "rel": 1e-11,
        "used": 3.5520024430037e-9
      },
      "exampleSource": "add-aviation-suite wind scenario: wind about 030° at 20 kt"
    },
    {
      "id": "aviation.wind.heading-chain",
      "title": "True course to compass heading",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 8,
      "checks": {
        "numeric": 28,
        "exact": 9
      },
      "failures": [],
      "sources": [
        {
          "source": "Heading arithmetic and Bolton (1980) eq. 15 worked in Python (tools/vectors/gen_heading.py) (2026)",
          "count": 7
        },
        {
          "source": "add-aviation-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.true_heading.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-aviation-suite deviation-card scenario: magnetic 075°, between +2° at 060° and -1° at 090°, reads +0.5°; compass 074.5°"
    },
    {
      "id": "aviation.wind.heading-groundspeed",
      "title": "Wind triangle: heading and groundspeed",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 45,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the ICAO Doc 7488/3 defining equations (tools/vectors/gen_aviation.py) (Doc 7488/3 (1993))",
          "count": 20
        },
        {
          "source": "FAA Pilot's Handbook of Aeronautical Knowledge (FAA-H-8083-25C), worked example read from the published chart or table (FAA-H-8083-25C (2023))",
          "count": 1
        },
        {
          "source": "Hand computation of the PHAK wind triangle (FAA-H-8083-25C, Navigation): a direct headwind needs no correction, and groundspeed = TAS − W (FAA-H-8083-25C (2023))",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v021",
        "path": "result.heading.value",
        "error": 0.3669777746335967,
        "abs": 1,
        "rel": 0,
        "used": 0.3669777746335967
      },
      "exampleSource": "add-aviation-suite wind scenario: WCA -8.30°, heading 081.7°, groundspeed 108.7 kt"
    },
    {
      "id": "aviation.wind.one-in-sixty",
      "title": "Off-course correction (1-in-60)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 8,
      "checks": {
        "numeric": 36,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Flat-plane off-course geometry worked in Python (tools/vectors/gen_offcourse.py) (2026)",
          "count": 7
        },
        {
          "source": "add-aviation-suite 1-in-60 scenario (3.81° and 7.63° exact; 4° and 8° by the rule) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.to_destination.value",
        "error": 7.105427357601002e-15,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.000007105427357601001
      },
      "exampleSource": "add-aviation-suite 1-in-60 scenario: track error 3.81° (rule 4°), turn to the destination 7.63° (rule 8°)"
    },
    {
      "id": "aviation.wind.runway-components",
      "title": "Runway wind components",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 47,
        "exact": 27
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python implementation of the ICAO Doc 7488/3 defining equations (tools/vectors/gen_aviation.py) (Doc 7488/3 (1993))",
          "count": 20
        },
        {
          "source": "FAA Pilot's Handbook of Aeronautical Knowledge (FAA-H-8083-25C), worked example read from the published chart or table (FAA-H-8083-25C (2023))",
          "count": 1
        },
        {
          "source": "Hand computation of the PHAK wind components, headwind = W·cos θ and crosswind = W·sin θ, with θ = 90° or 180° (FAA-H-8083-25C, Aircraft Performance): a wind straight across the runway has no headwind or tailwind component (FAA-H-8083-25C (2023))",
          "count": 1
        },
        {
          "source": "Hand computation of the PHAK wind components, headwind = W·cos θ and crosswind = W·sin θ, with θ = 90° or 180° (FAA-H-8083-25C, Aircraft Performance): a wind straight down the runway from behind has no crosswind component (FAA-H-8083-25C (2023))",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v021",
        "path": "result.crosswind.value",
        "error": 0.5000000000000018,
        "abs": 1,
        "rel": 0,
        "used": 0.5000000000000018
      },
      "exampleSource": "add-aviation-suite wind scenarios: headwind 13.0 kt, crosswind 7.5 kt from the right, gust crosswind 12.5 kt"
    },
    {
      "id": "aviation.wind.tas-from-groundspeed",
      "title": "Wind triangle: airspeed and heading for a groundspeed",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 8,
      "checks": {
        "numeric": 18,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Wind-triangle vectors worked in Python (tools/vectors/gen_triangle.py) (2026)",
          "count": 7
        },
        {
          "source": "add-aviation-suite heading-and-groundspeed scenario, solved the other way (about 120 kt on heading 081.7°) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.tas.value",
        "error": 1.4210854715202004e-14,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.000014210854715202002
      },
      "exampleSource": "add-aviation-suite heading-and-groundspeed scenario solved the other way: about 120 kt on heading 081.7°"
    },
    {
      "id": "aviation.wind.uv",
      "title": "Wind components (u and v)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 15,
      "checks": {
        "numeric": 44,
        "exact": 16
      },
      "failures": [],
      "sources": [
        {
          "source": "Meteorological u/v convention and linear interpolation worked in Python (tools/vectors/gen_aloft.py) (2026)",
          "count": 15
        }
      ],
      "worst": {
        "vector": "v009",
        "path": "result.speed.value",
        "error": 3.552713678800501e-15,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.0000035527136788005005
      },
      "exampleSource": "Hand check: u = 25·sin(60°) = 21.65 kt east, v = -25·cos(60°) = -12.5 kt"
    },
    {
      "id": "drone.links.link-budget",
      "title": "Radio link budget",
      "version": "1.0.1",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 9,
        "exact": 9
      },
      "failures": [],
      "sources": [
        {
          "source": "Worked by hand in Python (tools/vectors/gen_sensing.py) (2026)",
          "count": 4
        },
        {
          "source": "add-practitioner-essentials scenarios (2.4 GHz at 5 km: about 114.0 dB) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.fspl",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials link scenario: FSPL about 114.0 dB at 2.4 GHz and 5 km"
    },
    {
      "id": "drone.mission.corridor",
      "title": "Corridor mapping lines",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 5,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Flight-line arithmetic (Wolf, Dewitt & Wilkinson 2014, ch. 18) evaluated in Python (tools/vectors/gen_drone.py) (4th edition (2014))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.line_count",
        "error": 0,
        "abs": 1e-12,
        "rel": 1e-12,
        "used": 0
      },
      "exampleSource": "add-drone-suite corridor scenario: three lines at -52.5, 0, and +52.5 m"
    },
    {
      "id": "drone.mission.export",
      "title": "Export a mission (KML, GeoJSON, CSV)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 18,
      "checks": {
        "numeric": 17,
        "exact": 51
      },
      "failures": [],
      "sources": [
        {
          "source": "OGC KML 2.3 section 9.13 altitude modes and RFC 7946, applied by hand (tools/vectors/gen_drone.py) (2026)",
          "count": 12
        },
        {
          "source": "add-drone-suite scenarios (2026)",
          "count": 5
        },
        {
          "source": "add-drone-suite scenarios (terrain following requires acknowledgment) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.waypoint_count",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0
      },
      "exampleSource": "add-drone-suite KML altitude-mode scenario (AGL writes relativeToGround)"
    },
    {
      "id": "drone.mission.facade",
      "title": "Facade scan",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 14,
      "checks": {
        "numeric": 131,
        "exact": 17
      },
      "failures": [],
      "sources": [
        {
          "source": "Coverage with the standoff as the object distance (Wolf, Dewitt & Wilkinson 2014, ch. 6), on the equator where the geodesic is closed form, evaluated in Python (tools/vectors/gen_drone.py) (4th edition (2014))",
          "count": 10
        },
        {
          "source": "add-drone-suite scenarios (2026)",
          "count": 4
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.photo_spacing.value",
        "error": 1.6697754290362354e-13,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0.000058649728559175073
      },
      "exampleSource": "add-drone-suite facade GSD scenario (30 m standoff)"
    },
    {
      "id": "drone.mission.geofence",
      "title": "Geofence around an area",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 56,
        "exact": 13
      },
      "failures": [],
      "sources": [
        {
          "source": "Geodesic distance on the equator and a meridian in closed form, and Steiner's formula for the fence area, evaluated in Python (tools/vectors/gen_drone.py) (2026)",
          "count": 7
        },
        {
          "source": "add-drone-suite scenarios (2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v007",
        "path": "result.area_enclosed.value",
        "error": 0.00025990719501423065,
        "abs": 1e-9,
        "rel": 0.001,
        "used": 0.33092369730817445
      },
      "exampleSource": "add-drone-suite waypoint-outside-fence scenario"
    },
    {
      "id": "drone.mission.orbit",
      "title": "Orbit around a point of interest",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 5,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Flight-line arithmetic (Wolf, Dewitt & Wilkinson 2014, ch. 18) evaluated in Python (tools/vectors/gen_drone.py) (4th edition (2014))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.gimbal_pitch.value",
        "error": 0,
        "abs": 1e-12,
        "rel": 1e-12,
        "used": 0
      },
      "exampleSource": "add-drone-suite orbit scenario: gimbal pitch -21.8° (atan(20/50)), heading toward the center"
    },
    {
      "id": "drone.mission.survey-grid",
      "title": "Survey grid (lawnmower pattern)",
      "version": "1.1.0",
      "stability": "experimental",
      "vectors": 8,
      "checks": {
        "numeric": 17,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "Published flight-line count (Penn State GEOG 892): ceil(width / spacing) + 1 lines, ceil(length / photo spacing) + 1 + 2 x extra photos per line, on geographiclib arc lengths (tools/vectors/gen_image_count.py) (tool version 1.1.0)",
          "count": 5
        },
        {
          "source": "King Saud University SE 321, Design of Photogrammetric Flight Plan (CLO3 example): (60,000 / 460) + 1 = 131.4, 132 + 4 = 136 photos per strip; (40,000 / 920) + 1 = 44.4, 45 lines; 136 x 45 = 6,120 photos (faculty.ksu.edu.sa, retrieved 2026-09-23)",
          "count": 1
        },
        {
          "source": "Penn State GEOG 892 (Q. Abdullah), Designing a Flight Route: (13 x 5,280 / 8,400) + 1 = 9.171, 10 lines; (105,600 / 2,800) + 1 = 38.7, 39, + 4 = 43 images per line; 430 images (390 without the extra images) (Penn State College of Earth and Mineral Sciences, online course text, retrieved 2026-09-23)",
          "count": 1
        },
        {
          "source": "Penn State GEOG 892 (Q. Abdullah), Designing a Flight Route: (13 x 5,280 / 8,400) + 1 = 9.171, 10 lines; (105,600 / 2,800) + 1 = 38.7, 39, + 4 = 43 images per line; 430 images (Penn State College of Earth and Mineral Sciences, online course text, retrieved 2026-09-23)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v011",
        "path": "result.survey_length.value",
        "error": 0.0003436990469936063,
        "abs": 0,
        "rel": 0.00001,
        "used": 0.10678236320607161
      },
      "exampleSource": "add-drone-suite survey-grid scenario: lines run along the long axis, ⌈150 / 52.5⌉ + 1 = 4 lines"
    },
    {
      "id": "drone.ops.easa-subcategory",
      "title": "EASA open subcategory",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 0,
        "exact": 12
      },
      "failures": [],
      "sources": [
        {
          "source": "data/regulations.json values (14 CFR 107.51, Regulation (EU) 2019/945 and 2019/947, EASA VLOS guidance) applied in Python (tools/vectors/gen_drone.py) (Rules as of 2026-09-18)",
          "count": 6
        }
      ],
      "worst": null,
      "exampleSource": "add-drone-suite EASA scenario: A3 only, 150 m from residential, commercial, industrial, or recreational areas"
    },
    {
      "id": "drone.ops.kinetic-energy",
      "title": "Drone impact kinetic energy",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 10,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "data/regulations.json values (14 CFR 107.51, Regulation (EU) 2019/945 and 2019/947, EASA VLOS guidance) applied in Python (tools/vectors/gen_drone.py) (Rules as of 2026-09-18)",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.energy_ft_lbf.value",
        "error": 5.684341886080802e-14,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 1.9202245012908887e-7
      },
      "exampleSource": "add-drone-suite C1 scenario: 162.5 J, above 80 J"
    },
    {
      "id": "drone.ops.part107-altitude",
      "title": "Part 107 maximum altitude",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 26,
        "exact": 30
      },
      "failures": [],
      "sources": [
        {
          "source": "14 CFR 107.51(b) as printed on eCFR (current through 2026-09-21), applied in Python (tools/vectors/gen_hold_part107.py): 400 ft AGL, or within a 400-foot radius of a structure up to 400 ft above its immediate uppermost limit (eCFR 14 CFR 107.51, last amended 2016-12-30, read 2026-09-23)",
          "count": 12
        },
        {
          "source": "data/regulations.json values (14 CFR 107.51, Regulation (EU) 2019/945 and 2019/947, EASA VLOS guidance) applied in Python (tools/vectors/gen_drone.py) (Rules as of 2026-09-18)",
          "count": 5
        },
        {
          "source": "14 CFR 107.51(b) needs both the structure and your distance from it; neither can be negative (eCFR 14 CFR 107.51, last amended 2016-12-30, read 2026-09-23)",
          "count": 4
        },
        {
          "source": "14 CFR 107.51(b), eCFR: \"cannot be higher than 400 feet above ground level\" (the rule's printed value, no structure nearby) (eCFR 14 CFR 107.51, last amended 2016-12-30, read 2026-09-23)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v015",
        "path": "result.max_hae.value",
        "error": 2.2737367544323206e-13,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 1.1363374898849278e-7
      },
      "exampleSource": "add-drone-suite altitude scenario: 700 ft AGL (300 + 400)"
    },
    {
      "id": "drone.ops.speed-check",
      "title": "Part 107 groundspeed check",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 5,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "data/regulations.json values (14 CFR 107.51, Regulation (EU) 2019/945 and 2019/947, EASA VLOS guidance) applied in Python (tools/vectors/gen_drone.py) (Rules as of 2026-09-18)",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.margin.value",
        "error": 4.468647674116255e-15,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0.000003997673814445015
      },
      "exampleSource": "14 CFR 107.51(a): 87 kt (100.1 mph) groundspeed"
    },
    {
      "id": "drone.photogrammetry.altitude-for-gsd",
      "title": "Height for a target GSD",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 36,
        "exact": 21
      },
      "failures": [],
      "sources": [
        {
          "source": "Photogrammetric formulas (Wolf, Dewitt & Wilkinson 2014, ch. 6) evaluated in Python (tools/vectors/gen_drone.py) (4th edition (2014))",
          "count": 20
        },
        {
          "source": "Alshaibani et al., Airplane Type Identification Based on Mask RCNN and Drone Images, arXiv:2108.12811, equation 1 (arXiv v1 (2021))",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v021",
        "path": "result.height.value",
        "error": 0.09080470588236267,
        "abs": 0.2,
        "rel": 0,
        "used": 0.45402352941181334
      },
      "exampleSource": "add-drone-suite scenario: 72.96 m AGL"
    },
    {
      "id": "drone.photogrammetry.asprs-accuracy",
      "title": "ASPRS accuracy (Edition 2)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 7,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "ASPRS Positional Accuracy Standards, Edition 2 (quadrature of fit and checkpoint RMSE) (Edition 2, Version 2.0)",
          "count": 5
        },
        {
          "source": "add-drone-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.horizontal.value",
        "error": 4.440892098500626e-16,
        "abs": 1e-12,
        "rel": 1e-12,
        "used": 0.00014802973661668753
      },
      "exampleSource": "add-drone-suite scenario: product accuracy 2.24 cm"
    },
    {
      "id": "drone.photogrammetry.gsd",
      "title": "Ground sampling distance (GSD)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 61,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "Photogrammetric formulas (Wolf, Dewitt & Wilkinson 2014, ch. 6) evaluated in Python (tools/vectors/gen_drone.py) (4th edition (2014))",
          "count": 20
        },
        {
          "source": "add-drone-suite scenarios (2026)",
          "count": 1
        },
        {
          "source": "Alshaibani et al., Airplane Type Identification Based on Mask RCNN and Drone Images, arXiv:2108.12811, equation 1 (arXiv v1 (2021))",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v022",
        "path": "result.gsd.value",
        "error": 0.0023702830188683244,
        "abs": 0.005,
        "rel": 0,
        "used": 0.4740566037736649
      },
      "exampleSource": "add-drone-suite scenario: 2.741 cm/px, 150.0 m across track"
    },
    {
      "id": "drone.photogrammetry.image-count",
      "title": "Image count and survey size",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 34,
        "exact": 27
      },
      "failures": [],
      "sources": [
        {
          "source": "Published flight-line count (Penn State GEOG 892): ceil(width / spacing) + 1 lines, ceil(length / photo spacing) + 1 + 2 x extra photos per line, on geographiclib arc lengths (tools/vectors/gen_image_count.py) (tool version 1.1.0)",
          "count": 9
        },
        {
          "source": "Extra photos per line end are 0 to 10 (tools/vectors/gen_image_count.py) (tool version 1.1.0)",
          "count": 2
        },
        {
          "source": "Penn State GEOG 892 (Q. Abdullah), Designing a Flight Route: (13 x 5,280 / 8,400) + 1 = 9.171, 10 lines; (105,600 / 2,800) + 1 = 38.7, 39, + 4 = 43 images per line; 430 images (Penn State College of Earth and Mineral Sciences, online course text, retrieved 2026-09-23)",
          "count": 2
        },
        {
          "source": "An area needs 3 corners (tools/vectors/gen_image_count.py) (tool version 1.1.0)",
          "count": 1
        },
        {
          "source": "Extra photos per line end must be a whole number (tools/vectors/gen_image_count.py) (tool version 1.1.0)",
          "count": 1
        },
        {
          "source": "King Saud University SE 321, Design of Photogrammetric Flight Plan (CLO3 example): (60,000 / 460) + 1 = 131.4, 132 + 4 = 136 photos per strip; (40,000 / 920) + 1 = 44.4, 45 lines; 136 x 45 = 6,120 photos (5,940 without the extra photos) (faculty.ksu.edu.sa, retrieved 2026-09-23)",
          "count": 1
        },
        {
          "source": "King Saud University SE 321, Design of Photogrammetric Flight Plan (CLO3 example): (60,000 / 460) + 1 = 131.4, 132 + 4 = 136 photos per strip; (40,000 / 920) + 1 = 44.4, 45 lines; 136 x 45 = 6,120 photos (faculty.ksu.edu.sa, retrieved 2026-09-23)",
          "count": 1
        },
        {
          "source": "Line spacing must be positive (tools/vectors/gen_image_count.py) (tool version 1.1.0)",
          "count": 1
        },
        {
          "source": "Line spacing under 0.5 m (tools/vectors/gen_image_count.py) (tool version 1.1.0)",
          "count": 1
        },
        {
          "source": "Penn State GEOG 892 (Q. Abdullah), Designing a Flight Route: (13 x 5,280 / 8,400) + 1 = 9.171, 10 lines; (105,600 / 2,800) + 1 = 38.7, 39, + 4 = 43 images per line; 430 images (390 without the extra images) (Penn State College of Earth and Mineral Sciences, online course text, retrieved 2026-09-23)",
          "count": 1
        },
        {
          "source": "Published flight-line count (Penn State GEOG 892): ceil(width / spacing) + 1 lines, ceil(length / photo spacing) + 1 + 2 x extra photos per line, on geographiclib arc lengths (tools/vectors/gen_image_count.py): spacings a third of the block, ceil(2.29) + 1 = 4 lines of ceil(10.56) + 1 + 4 = 16 photos (tool version 1.1.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v019",
        "path": "result.survey_length.value",
        "error": 0.006236706472691367,
        "abs": 0,
        "rel": 0.00001,
        "used": 0.37123379430879644
      },
      "exampleSource": "4 lines (⌈150 / 52.5⌉ + 1) of 602 m, each with ⌈602 / 30⌉ + 1 = 22 photos plus 2 past each end: 104 photos"
    },
    {
      "id": "drone.photogrammetry.motion-blur",
      "title": "Motion blur and slowest shutter",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 10,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Photogrammetric formulas (Wolf, Dewitt & Wilkinson 2014, ch. 6) evaluated in Python (tools/vectors/gen_drone.py) (4th edition (2014))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.blur",
        "error": 0,
        "abs": 1e-12,
        "rel": 1e-12,
        "used": 0
      },
      "exampleSource": "add-drone-suite scenario: 0.365 px; 1/730 s for 0.5 px"
    },
    {
      "id": "drone.photogrammetry.oblique-gsd",
      "title": "Oblique GSD and footprint",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 14,
      "checks": {
        "numeric": 111,
        "exact": 18
      },
      "failures": [],
      "sources": [
        {
          "source": "Tilted-photo geometry (Wolf, Dewitt & Wilkinson 2014, ch. 10) in closed angle form, evaluated in Python (tools/vectors/gen_drone.py) (4th edition (2014))",
          "count": 11
        },
        {
          "source": "add-drone-suite scenarios (2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.gsd_far.value",
        "error": 5.6843418860808015e-12,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0.0009723113860053913
      },
      "exampleSource": "add-drone-suite 45° oblique scenario"
    },
    {
      "id": "drone.photogrammetry.terrain-overlap",
      "title": "Overlap over high terrain",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 54,
        "exact": 33
      },
      "failures": [],
      "sources": [
        {
          "source": "Overlap at the highest relief, o_t = 1 - (1 - o) h / (h - t) (Pryor 1959, HRB Bulletin 228, pp. 36-37), evaluated in Python (tools/vectors/gen_photogrammetry_overlap.py) (Bulletin 228 (1959))",
          "count": 13
        },
        {
          "source": "Flight-planning geometry (Wolf, Dewitt & Wilkinson 2014, ch. 18): footprint and fixed photo spacing, evaluated in Python (tools/vectors/gen_drone.py) (4th edition (2014))",
          "count": 4
        },
        {
          "source": "add-drone-suite scenarios (2026)",
          "count": 2
        },
        {
          "source": "Pryor 1959, Relationship of Topographic Relief, Flight Height, and Minimum and Maximum Overlap, HRB Bulletin 228, p. 31 (Bulletin 228 (1959))",
          "count": 1
        },
        {
          "source": "Pryor 1959, Relationship of Topographic Relief, Flight Height, and Minimum and Maximum Overlap, HRB Bulletin 228, p. 32 (Bulletin 228 (1959))",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v023",
        "path": "result.min_height.value",
        "error": 0.6095999999988635,
        "abs": 1,
        "rel": 0,
        "used": 0.6095999999988635
      },
      "exampleSource": "add-drone-suite hill scenario"
    },
    {
      "id": "drone.photogrammetry.trigger",
      "title": "Overlap, trigger interval, and line spacing",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 54,
        "exact": 27
      },
      "failures": [],
      "sources": [
        {
          "source": "Flight-planning relations (Wolf, Dewitt & Wilkinson 2014, ch. 18) evaluated in Python (tools/vectors/gen_photogrammetry_overlap.py) (4th edition (2014))",
          "count": 14
        },
        {
          "source": "Photogrammetric formulas (Wolf, Dewitt & Wilkinson 2014, ch. 6) evaluated in Python (tools/vectors/gen_drone.py) (4th edition (2014))",
          "count": 5
        },
        {
          "source": "Penn State GEOG 892 (Q. Abdullah), Designing a Flight Route: air base 2,800 ft, line spacing 8,400 ft, 11.067 s between exposures (Penn State College of Earth and Mineral Sciences, retrieved 2026-09-23)",
          "count": 1
        },
        {
          "source": "Pix4D, Selecting the Image Acquisition Plan Type (forest and dense vegetation: at least 85% frontal and side overlap), with the flight-planning relations of Wolf, Dewitt & Wilkinson 2014, ch. 18: footprint 150 m × 100 m at 100 m; 100 × 0.15 = 15 m; 150 × 0.15 = 22.5 m (Pix4D support page retrieved 2026-09-23)",
          "count": 1
        },
        {
          "source": "University of Washington CEE 424 (K. M. Ahmed), Flight Planning sheet 1, problems 6 and 7 (courses.washington.edu/cee424, retrieved 2026-09-23)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.trigger_interval.value",
        "error": 0.007302375809935313,
        "abs": 0.01,
        "rel": 0,
        "used": 0.7302375809935313
      },
      "exampleSource": "add-drone-suite scenario: 25.0 m, 2.5 s, 52.5 m"
    },
    {
      "id": "drone.power.battery-energy",
      "title": "Battery energy (mAh to Wh)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 27,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "Momentum theory (Leishman 2006, ch. 2) and battery arithmetic evaluated in Python (tools/vectors/gen_drone.py) (2nd edition (2006))",
          "count": 19
        },
        {
          "source": "FAA PackSafe, Batteries Carried by Airline Passengers (Q3 worked example) (December 2024)",
          "count": 1
        },
        {
          "source": "Worked by hand: I = P / V = 150 W / 15.4 V = 9.740 A; C-rate = 9.740 A / 5.870 Ah = 1.659 (Ohm's-law power relation; checked 2026-09-23)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v013",
        "path": "result.energy.value",
        "error": 1.4210854715202004e-14,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 2.1597043640124627e-7
      },
      "exampleSource": "add-drone-suite battery scenario: about 90.4 Wh"
    },
    {
      "id": "drone.power.calibrate-hover",
      "title": "Calibrate hover power from a test flight",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 15,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Momentum theory (Leishman 2006, ch. 2) and battery arithmetic evaluated in Python (tools/vectors/gen_drone.py) (2nd edition (2006))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.fm_eta",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0
      },
      "exampleSource": "Momentum theory (Leishman 2006, chapter 2) solved for the figure of merit"
    },
    {
      "id": "drone.power.endurance",
      "title": "Drone flight time",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 29,
      "checks": {
        "numeric": 57,
        "exact": 43
      },
      "failures": [],
      "sources": [
        {
          "source": "Bauersfeld and Scaramuzza (2022) Sec. VII-E step 6, t = E / P, with the spec's reserve, derating, and range, evaluated in Python (tools/vectors/gen_endurance.py) (IEEE RA-L 7(2), 2022)",
          "count": 18
        },
        {
          "source": "Momentum theory (Leishman 2006, ch. 2) and battery arithmetic evaluated in Python (tools/vectors/gen_drone.py) (2nd edition (2006))",
          "count": 9
        },
        {
          "source": "Bauersfeld and Scaramuzza, Range, Endurance, and Optimal Speed Estimates for Multicopters, IEEE RA-L 7(2) 2022, Sec. VII-E step 6 (DJI Mavic 3: C_eff 4.89 Ah and 4.88 Ah, 4S at 3.7 V per cell, 89.5 W and 107.0 W give 2909 s and 2429 s) (IEEE RA-L 7(2), 2022)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v010",
        "path": "result.hover_time.value",
        "error": 0.034208566108006266,
        "abs": 0.06,
        "rel": 0,
        "used": 0.5701427684667711
      },
      "exampleSource": "add-drone-suite endurance scenario: about 28.8 min"
    },
    {
      "id": "drone.power.hover-power",
      "title": "Multirotor hover power",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 15,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Momentum theory (Leishman 2006, ch. 2) and battery arithmetic evaluated in Python (tools/vectors/gen_drone.py) (2nd edition (2006))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.ideal_power.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0
      },
      "exampleSource": "add-drone-suite hover scenario: disk area 0.1791 m², ideal 76.8 W, electrical 150.6 W"
    },
    {
      "id": "drone.power.max-payload",
      "title": "Maximum payload for a flight time",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 4,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Momentum theory (Leishman 2006, ch. 2) and battery arithmetic evaluated in Python (tools/vectors/gen_drone.py) (2nd edition (2006))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.max_payload.value",
        "error": 8.881784197001252e-16,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 7.786140244328299e-7
      },
      "exampleSource": "Momentum theory (Leishman 2006, chapter 2) solved for mass"
    },
    {
      "id": "drone.power.payload-impact",
      "title": "What a payload costs in flight time",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 18,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Momentum theory (Leishman 2006, ch. 2) and battery arithmetic evaluated in Python (tools/vectors/gen_drone.py) (2nd edition (2006))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.hover_time_with.value",
        "error": 3.552713678800501e-15,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 1.8349272111767565e-7
      },
      "exampleSource": "Momentum theory (Leishman 2006, chapter 2) at both masses"
    },
    {
      "id": "drone.power.rth-budget",
      "title": "Return-to-home energy budget",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 10,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Momentum theory (Leishman 2006, ch. 2) and battery arithmetic evaluated in Python (tools/vectors/gen_drone.py) (2nd edition (2006))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.margin.value",
        "error": 3.552713678800501e-15,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 2.0109700068682086e-7
      },
      "exampleSource": "add-drone-suite return scenario: return groundspeed 5 m/s"
    },
    {
      "id": "drone.sensors.dataset-size",
      "title": "Dataset size estimate",
      "version": "1.0.1",
      "stability": "experimental",
      "vectors": 9,
      "checks": {
        "numeric": 11,
        "exact": 13
      },
      "failures": [],
      "sources": [
        {
          "source": "Worked by hand in Python (tools/vectors/gen_sensing.py) (2026)",
          "count": 8
        },
        {
          "source": "add-practitioner-essentials scenarios (orthomosaic: 7.5 GB uncompressed) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.ortho_gb",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials orthomosaic scenario: 7.5 GB uncompressed, with a compressed range at the assumed ratios"
    },
    {
      "id": "drone.sensors.lidar-plan",
      "title": "Lidar mission planning",
      "version": "1.0.1",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 25,
        "exact": 12
      },
      "failures": [],
      "sources": [
        {
          "source": "Worked by hand in Python (tools/vectors/gen_sensing.py) (2026)",
          "count": 5
        },
        {
          "source": "add-practitioner-essentials scenarios (swath about 140.0 m, 171 pulses per m², beyond QL1) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.aggregate_density",
        "error": 2.842170943040401e-14,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 2.923290955523513e-7
      },
      "exampleSource": "add-practitioner-essentials lidar scenario: swath about 140.0 m and 171 pulses per m², beyond QL1"
    },
    {
      "id": "drone.sensors.thermal-footprint",
      "title": "Thermal pixel footprint",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 13,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Worked by hand in Python (tools/vectors/gen_sensing.py) (2026)",
          "count": 5
        },
        {
          "source": "add-practitioner-essentials scenarios (solar panel: 39 mm footprint, 117 mm by the 3 x 3 rule) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.footprint.value",
        "error": 1.4210854715202004e-14,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 2.1001263125914285e-7
      },
      "exampleSource": "add-practitioner-essentials solar-panel scenario: 39 mm pixel footprint, 117 mm smallest target by the 3 × 3 rule"
    },
    {
      "id": "drone.sensors.vlos",
      "title": "Visual line of sight distance",
      "version": "1.2.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 39,
        "exact": 29
      },
      "failures": [],
      "sources": [
        {
          "source": "data/regulations.json values (14 CFR 107.51, Regulation (EU) 2019/945 and 2019/947, EASA VLOS guidance) applied in Python (tools/vectors/gen_drone.py) (Rules as of 2026-09-18)",
          "count": 13
        },
        {
          "source": "Luftfahrt-Bundesamt, Guidance for Dimensioning of Flight Geography, Contingency Volume and Ground Risk Buffer, section 7.1 (maximum VLOS distance table) (LBA guidance (English), retrieved 2026-09-19)",
          "count": 10
        },
        {
          "source": "EASA, Guidelines for UAS operations in the open and specific category, Part A chapter I, VLOS distance: DLOS = 0.3 x GV, where the ground visibility \"minimum value should be at least 5 km\" (Issue 03, 17 July 2025, retrieved 2026-09-23)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.vlos.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials VLOS scenario: ALOS 134 m (327 × 0.35 + 20); beyond VLOS guidance by 266 m"
    },
    {
      "id": "geodesy.datum.helmert",
      "title": "Helmert transformation (7 or 14 parameters)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 66,
        "exact": 28
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ +proj=helmert through pyproj (PROJ 9.3 (pyproj 3.6))",
          "count": 18
        },
        {
          "source": "IOGP Guidance Note 7-2 worked example (IOGP 373-7-2, September 2019)",
          "count": 4
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.y.value",
        "error": 0.0004527084529399872,
        "abs": 0.0006,
        "rel": 0,
        "used": 0.754514088233312
      },
      "exampleSource": "IOGP GN 7-2 §4.2.3 example: 3 657 660.78, 255 778.43, 5 201 387.75 m (to the centimeter)"
    },
    {
      "id": "geodesy.datum.itrf",
      "title": "Transform between ITRF and WGS 84 realizations",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 127,
        "exact": 28
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ +proj=helmert with PROJ's ITRF2020 parameter file, through pyproj (PROJ 9.3 (pyproj 3.6); data/ITRF2020)",
          "count": 21
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 2
        },
        {
          "source": "add-geodesy-suite scenario: coincidence stated (2026-09)",
          "count": 1
        },
        {
          "source": "add-geodesy-suite scenario: unqualified WGS 84 (2026-09)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v013",
        "path": "result.height.value",
        "error": 3.6401161196408793e-8,
        "abs": 0.00001,
        "rel": 0,
        "used": 0.003640116119640879
      },
      "exampleSource": "PROJ 9.3.0 through pyproj, transforming EPSG:9988 (ITRF2020) to EPSG:7912 (ITRF2014) with PROJ's own EPSG-sourced parameters at epoch 2026.72: latitude 40.44611101524038 and longitude -79.98222202049854 identical in every digit, height 300.0011211372912 m against 300.0011211390832 m, a difference of 1.8 nanometres"
    },
    {
      "id": "geodesy.datum.legacy",
      "title": "Legacy datum to or from WGS 84",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 36,
        "exact": 40
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ applying the EPSG operation through pyproj (PROJ 9.3, EPSG v10.094)",
          "count": 18
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        },
        {
          "source": "EPSG 1173 area of use (EPSG v10.094)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v014",
        "path": "result.lon.value",
        "error": 6.445510791763809e-10,
        "abs": 1e-8,
        "rel": 0,
        "used": 0.06445510791763809
      },
      "exampleSource": "PROJ 9.3.0 asked for EPSG:1133 (ED50 to WGS 84 (1)) by code alone, through pyproj, returns 48.85568546266484 and 2.350914333016232 — identical to the tool in every digit a double carries"
    },
    {
      "id": "geodesy.datum.nad83",
      "title": "Transform between NAD 83 and ITRF or WGS 84",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 26,
      "checks": {
        "numeric": 70,
        "exact": 28
      },
      "failures": [],
      "sources": [
        {
          "source": "NGS HTDP, compiled from htdp.f and initbd.f, menu option 4 (HTDP 3.6.0 (2025-04-07))",
          "count": 23
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        },
        {
          "source": "add-geodesy-suite scenario: epoch echoed (2026-09)",
          "count": 1
        },
        {
          "source": "add-geodesy-suite scenario: unqualified WGS 84 (2026-09)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v016",
        "path": "result.height.value",
        "error": 0.0005492707080279047,
        "abs": 0.0015,
        "rel": 0,
        "used": 0.3661804720186031
      },
      "exampleSource": "NGS HTDP 3.6.0 compiled from htdp.f, menu option 4, and independently PROJ 9.3.0 through pyproj on EPSG:9988 to EPSG:6319, which agrees with the tool to 9.5 nanometres in latitude, 1.2 in longitude and 0.2 in height"
    },
    {
      "id": "geodesy.datum.nadcon5",
      "title": "Old US datums to NAD 83 (NADCON5)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 36,
      "checks": {
        "numeric": 68,
        "exact": 39
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ +proj=gridshift with the NADCON5 grid us_noaa_nadcon5_nad27_nad83_1986_conus.tif, through pyproj (PROJ 9.3; NADCON5 20160901)",
          "count": 22
        },
        {
          "source": "PROJ +proj=gridshift with the NADCON5 grid us_noaa_nadcon5_nad27_nad83_1986_alaska.tif, through pyproj (PROJ 9.3; NADCON5 20160901)",
          "count": 4
        },
        {
          "source": "PROJ +proj=gridshift with the NADCON5 grid us_noaa_nadcon5_gu63_nad83_1993_guamcnmi.tif, through pyproj (PROJ 9.3; NADCON5 20160901)",
          "count": 2
        },
        {
          "source": "PROJ +proj=gridshift with the NADCON5 grid us_noaa_nadcon5_ohd_nad83_1986_hawaii.tif, through pyproj (PROJ 9.3; NADCON5 20160901)",
          "count": 2
        },
        {
          "source": "PROJ +proj=gridshift with the NADCON5 grid us_noaa_nadcon5_pr40_nad83_1986_prvi.tif, through pyproj (PROJ 9.3; NADCON5 20160901)",
          "count": 2
        },
        {
          "source": "add-geodesy-suite scenario: outside grid (2026-09)",
          "count": 1
        },
        {
          "source": "PROJ +proj=gridshift with the NADCON5 grid us_noaa_nadcon5_as62_nad83_1993_as.tif, through pyproj (PROJ 9.3; NADCON5 20160901)",
          "count": 1
        },
        {
          "source": "PROJ +proj=gridshift with the NADCON5 grid us_noaa_nadcon5_sp1952_nad83_1986_stpaul.tif, through pyproj (PROJ 9.3; NADCON5 20160901)",
          "count": 1
        },
        {
          "source": "Regression for a reported defect (2026-09-23 fix-geodesy-indexing): Cites the NADCON 5.0 report (NOAA TR NOS NGS 63) and the biquadratic interpolation memo (NOAA TM NOS NGS 84) separately (was TM 84 alone, mislabeled as the NADCON5 report). (core 0.1.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v010",
        "path": "result.lon.value",
        "error": 2.842170943040401e-14,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.000028421709430404004
      },
      "exampleSource": "PROJ 9.3 applying the NADCON5 grid us_noaa_nadcon5_nad27_nad83_1986_conus.tif through pyproj, which the 34 grid vectors come from across all seven regions; the grid moves this point 29.815 m where the single-parameter EPSG helmert moves it 31.793 m, the 2.5 m between them being the regional variation a grid carries and a helmert cannot"
    },
    {
      "id": "geodesy.datum.plate-motion",
      "title": "Move a position between epochs (ITRF2020 plate motion)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 61,
        "exact": 25
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ +proj=helmert with the ITRF2020 plate motion rates of its data/ITRF2020, through pyproj (PROJ 9.3 (pyproj 3.6); data/ITRF2020)",
          "count": 19
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        },
        {
          "source": "add-geodesy-suite scenario: propagation in a deformation zone (2026-09)",
          "count": 1
        },
        {
          "source": "Site velocity times elapsed time (definition) (2026-09)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v012",
        "path": "result.lat.value",
        "error": 4.547473508864641e-13,
        "abs": 1e-10,
        "rel": 0,
        "used": 0.004547473508864641
      },
      "exampleSource": "PROJ 9.3.0 given the Altamimi 2023 rotation pole and origin rate bias and left to do the cross product itself: it lands within 4 nanometres in latitude, 1.2 in longitude and 2.4 in height, and 14 mm away if the origin rate bias is omitted, so the check distinguishes that term"
    },
    {
      "id": "geodesy.ellipsoid.auxiliary-latitude",
      "title": "Auxiliary latitudes",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 31,
      "checks": {
        "numeric": 130,
        "exact": 32
      },
      "failures": [],
      "sources": [
        {
          "source": "mpmath 40-digit evaluation of the defining relations (tools/vectors/gen_frames.py) (mpmath 1.3)",
          "count": 29
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        },
        {
          "source": "GeographicLib 2.7 command-line tools: CartConvert (geocentric and parametric from X and Z), GeodSolve (rectifying from the meridian arc to 45 over the arc to 90), RhumbSolve (isometric, confirmed by the rhumb from the equator making azimuth 45.00000000000), ConicProj -a 0 0 (authalic from the equal-area northing at 45 over the northing at 90) (GeographicLib 2.7)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v008",
        "path": "result.isometric.value",
        "error": 2.220303940703161e-10,
        "abs": 1e-11,
        "rel": 1e-12,
        "used": 0.32793237186112406
      },
      "exampleSource": "GeographicLib 2.7, each latitude from the shipped tool that depends on it: CartConvert for the geocentric and parametric, GeodSolve for the rectifying, RhumbSolve for the isometric, ConicProj for the authalic; all six agree within 3e-14°, except the rectifying at 1e-12° where GeodSolve's printed meters run out"
    },
    {
      "id": "geodesy.ellipsoid.parameters",
      "title": "Ellipsoid parameters",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 197,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "mpmath 40-digit evaluation of the defining relations (tools/vectors/gen_frames.py) (mpmath 1.3)",
          "count": 20
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.quarter_meridian.value",
        "error": 3.725290298461914e-9,
        "abs": 1e-9,
        "rel": 1e-14,
        "used": 0.036876885135853264
      },
      "exampleSource": "add-geodesy-suite scenario: a = 6,378,137 m, 1/f = 298.257223563, b = 6,356,752.314245… m"
    },
    {
      "id": "geodesy.ellipsoid.radii",
      "title": "Radii of curvature and degree lengths",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 165,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "mpmath 40-digit evaluation of the defining relations (tools/vectors/gen_frames.py) (mpmath 1.3)",
          "count": 16
        },
        {
          "source": "mpmath 40-digit evaluation of the defining relations (tools/vectors/gen_frames.py); meridian arcs from GeographicLib's geodesic (mpmath 1.3, geographiclib 2.x)",
          "count": 8
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.degree_lat.value",
        "error": 6.606569513678551e-9,
        "abs": 0.000001,
        "rel": 1e-13,
        "used": 0.006533593229542692
      },
      "exampleSource": "add-geodesy-suite scenario: one degree of latitude ≈ 111,131.78 m, one degree of longitude ≈ 78,846.84 m"
    },
    {
      "id": "geodesy.frame.ecef-to-geodetic",
      "title": "ECEF to latitude, longitude, and height",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 30,
      "checks": {
        "numeric": 87,
        "exact": 35
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib CartConvert (GeographicLib 2.7)",
          "count": 28
        },
        {
          "source": "add-geodesy-suite scenario: the Earth's center (2026-09)",
          "count": 1
        },
        {
          "source": "IOGP Geomatics Guidance Note 7-2, sections 4.1.1 to 4.1.3 (EPSG methods 9602, 9836, 9837), worked examples (IOGP 373-7-2, September 2019)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v030",
        "path": "result.lat.value",
        "error": 4.482323845422798e-9,
        "abs": 3e-7,
        "rel": 0,
        "used": 0.014941079484742659
      },
      "exampleSource": "GeographicLib CartConvert -r: 40.446111, -79.982222, 300 m"
    },
    {
      "id": "geodesy.frame.from-local",
      "title": "Local ENU, NED, or AER to point",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 66,
        "exact": 24
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib CartConvert (GeographicLib 2.7)",
          "count": 21
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        },
        {
          "source": "IOGP Geomatics Guidance Note 7-2, sections 4.1.1 to 4.1.3 (EPSG methods 9602, 9836, 9837), worked examples (IOGP 373-7-2, September 2019)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v023",
        "path": "result.lon.value",
        "error": 2.303733204200853e-9,
        "abs": 3e-7,
        "rel": 0,
        "used": 0.00767911068066951
      },
      "exampleSource": "GeographicLib LocalCartesian reverse of the AER offset"
    },
    {
      "id": "geodesy.frame.geodetic-to-ecef",
      "title": "Latitude, longitude, and height to ECEF",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 72,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib CartConvert (GeographicLib 2.7)",
          "count": 23
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        },
        {
          "source": "IOGP Geomatics Guidance Note 7-2, sections 4.1.1 to 4.1.3 (EPSG methods 9602, 9836, 9837), worked examples (IOGP 373-7-2, September 2019)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v025",
        "path": "result.x.value",
        "error": 0.00035821693018078804,
        "abs": 0.0005,
        "rel": 0,
        "used": 0.7164338603615761
      },
      "exampleSource": "add-geodesy-suite scenario: X ≈ 845,580.010 m, Y ≈ −4,786,836.717 m, Z ≈ 4,116,002.385 m"
    },
    {
      "id": "geodesy.frame.to-local",
      "title": "Point to local ENU, NED, and AER",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 123,
        "exact": 22
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib CartConvert (GeographicLib 2.7)",
          "count": 20
        },
        {
          "source": "IOGP Geomatics Guidance Note 7-2, sections 4.1.1 to 4.1.3 (EPSG methods 9602, 9836, 9837), worked examples (IOGP 373-7-2, September 2019)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v021",
        "path": "result.up.value",
        "error": 0.00024159800341294613,
        "abs": 0.0005,
        "rel": 0,
        "used": 0.48319600682589225
      },
      "exampleSource": "add-geodesy-suite scenario: elevation 90°, range 1,000 m, azimuth 0 with AZIMUTH_UNDEFINED"
    },
    {
      "id": "geodesy.geoid.geoid-height",
      "title": "Geoid height (EGM96)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 21,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GeoidEval 2.7 with the egm96-15 grid (tools/vectors/gen_geoid_diff.py) (egm96-15 (2009-08-29))",
          "count": 20
        },
        {
          "source": "GeographicLib GeoidEval 2.7 with the egm96-15 grid (tools/vectors/gen_geoid_diff.py), bilinear (-l) (egm96-15 (2009-08-29))",
          "count": 1
        },
        {
          "source": "Regression for a reported defect (2026-09-23 fix-geodesy-indexing): A negative geoid height reads as below the ellipsoid (was -17.21 m above). (core 0.1.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.geoid_height.value",
        "error": 0.00004694014491235521,
        "abs": 0.00005,
        "rel": 0,
        "used": 0.9388028982471042
      },
      "exampleSource": "GeographicLib GeoidEval with egm96-15 (cubic): 28.7079 m"
    },
    {
      "id": "geodesy.grid-ref.gars-forward",
      "title": "Latitude and longitude to GARS",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 0,
        "exact": 46
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GARS and Georef classes (tools/vectors/gridref_ref.cpp) (GeographicLib 2.7)",
          "count": 21
        },
        {
          "source": "NGA, Global Area Reference System description (180°E to 179°30'W is band 001, 179°30'W to 179°W band 002; 90°S to 89°30'S is band AA, 89°30'S to 89°S band AB) (earth-info.nga.mil, October 6, 2006)",
          "count": 2
        }
      ],
      "worst": null,
      "exampleSource": "GeographicLib GARS documentation: 381NH45"
    },
    {
      "id": "geodesy.grid-ref.gars-inverse",
      "title": "GARS to latitude and longitude",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 92,
        "exact": 27
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GARS and Georef classes (tools/vectors/gridref_ref.cpp) (GeographicLib 2.7)",
          "count": 21
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 2
        },
        {
          "source": "NGA, Global Area Reference System description (180°E to 179°30'W is band 001, 179°30'W to 179°W band 002; 90°S to 89°30'S is band AA, 89°30'S to 89°S band AB) (earth-info.nga.mil, October 6, 2006)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.lon.value",
        "error": 2.842170943040401e-14,
        "abs": 1e-12,
        "rel": 0,
        "used": 0.028421709430404007
      },
      "exampleSource": "GeographicLib GARS documentation"
    },
    {
      "id": "geodesy.grid-ref.georef-forward",
      "title": "Latitude and longitude to GEOREF",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 0,
        "exact": 42
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GARS and Georef classes (tools/vectors/gridref_ref.cpp) (GeographicLib 2.7)",
          "count": 20
        },
        {
          "source": "Wikipedia, World Geographic Reference System (NAS Patuxent River, 38.286108, -76.4291704, is at GJPJ3417) (retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": null,
      "exampleSource": "GeographicLib Georef: NKLN2438"
    },
    {
      "id": "geodesy.grid-ref.georef-inverse",
      "title": "GEOREF to latitude and longitude",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 82,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GARS and Georef classes (tools/vectors/gridref_ref.cpp) (GeographicLib 2.7)",
          "count": 20
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        },
        {
          "source": "Wikipedia, World Geographic Reference System (NAS Patuxent River, 38.286108, -76.4291704, is at GJPJ3417) (retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v022",
        "path": "result.lat.value",
        "error": 0.0055586666666656015,
        "abs": 0.008333333333333333,
        "rel": 0,
        "used": 0.6670399999998722
      },
      "exampleSource": "GeographicLib Georef documentation example"
    },
    {
      "id": "geodesy.grid-ref.maidenhead-forward",
      "title": "Latitude and longitude to Maidenhead locator",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 0,
        "exact": 46
      },
      "failures": [],
      "sources": [
        {
          "source": "IARU Maidenhead locator definition, independent Python implementation (tools/vectors/gen_gridref.py) (IARU Region 1 VHF Managers Handbook, version 10.03)",
          "count": 21
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        },
        {
          "source": "Wikipedia, Maidenhead Locator System (W1AW, Newington, Connecticut, is in FN31pr) (retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": null,
      "exampleSource": "add-geodesy-suite scenario: FN00ak"
    },
    {
      "id": "geodesy.grid-ref.maidenhead-inverse",
      "title": "Maidenhead locator to latitude and longitude",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 128,
        "exact": 28
      },
      "failures": [],
      "sources": [
        {
          "source": "IARU Maidenhead locator definition, independent Python implementation (tools/vectors/gen_gridref.py) (IARU Region 1 VHF Managers Handbook, version 10.03)",
          "count": 21
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 3
        },
        {
          "source": "Wikipedia, Maidenhead Locator System (W1AW, Newington, Connecticut, is in FN31pr) (retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v025",
        "path": "result.lat.value",
        "error": 0.01453666666667175,
        "abs": 0.020833333333333332,
        "rel": 0,
        "used": 0.697760000000244
      },
      "exampleSource": "add-geodesy-suite scenario: the Pittsburgh subsquare"
    },
    {
      "id": "geodesy.grid-ref.mgrs-forward",
      "title": "Latitude and longitude to MGRS",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 0,
        "exact": 50
      },
      "failures": [],
      "sources": [
        {
          "source": "NGA GEOTRANS MGRS (C) via the mgrs Python package, toMGRS and toLatLon (mgrs 1.5.4)",
          "count": 16
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) (GeographicLib 2.x)",
          "count": 5
        },
        {
          "source": "FGDC-STD-011-2001, United States National Grid, section 5.2.2 and table 1 (latitude and longitude by PROJ 9.3.0) (December 2001)",
          "count": 4
        }
      ],
      "worst": null,
      "exampleSource": "add-geodesy-suite scenario: 17TNE8630977770"
    },
    {
      "id": "geodesy.grid-ref.mgrs-inverse",
      "title": "MGRS to latitude and longitude",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 45,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "NGA GEOTRANS MGRS (C) via the mgrs Python package, toMGRS and toLatLon (mgrs 1.5.4)",
          "count": 16
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) (GeographicLib 2.x)",
          "count": 5
        },
        {
          "source": "PROJ inverse of the square's corner grid coordinates (EPSG:32761 and EPSG:32633) (PROJ 9.3.0 (pyproj 3.6.1))",
          "count": 2
        },
        {
          "source": "FGDC-STD-011-2001, United States National Grid, section 5.2.2 and table 1 (latitude and longitude by PROJ 9.3.0) (December 2001)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v014",
        "path": "result.corner_lat.value",
        "error": 1.3263398557228356e-7,
        "abs": 2e-7,
        "rel": 0,
        "used": 0.6631699278614178
      },
      "exampleSource": "add-geodesy-suite scenario: 1 m square, center offset 0.5 m"
    },
    {
      "id": "geodesy.grid-ref.usng-forward",
      "title": "Latitude and longitude to USNG",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 0,
        "exact": 46
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GeoConvert -m (MGRS, written with spaces as USNG) (GeographicLib 2.7)",
          "count": 19
        },
        {
          "source": "FGDC-STD-011-2001, United States National Grid, section 5.2.2 and table 1 (the Washington Monument) (December 2001)",
          "count": 4
        }
      ],
      "worst": null,
      "exampleSource": "add-geodesy-suite scenario: 17T NE 86309 77770"
    },
    {
      "id": "geodesy.grid-ref.usng-inverse",
      "title": "USNG to latitude and longitude",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 44,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GeoConvert -m (MGRS, written with spaces as USNG) (GeographicLib 2.7)",
          "count": 20
        },
        {
          "source": "add-geodesy-suite input rules (2026-09)",
          "count": 1
        },
        {
          "source": "FGDC-STD-011-2001, United States National Grid, section 5.2.2 and table 1 (the Washington Monument) (December 2001)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v022",
        "path": "result.corner_lat.value",
        "error": 7.105427357601002e-15,
        "abs": 1e-10,
        "rel": 0,
        "used": 0.00007105427357601002
      },
      "exampleSource": "add-geodesy-suite requirement: truncated USNG in a known grid zone"
    },
    {
      "id": "geodesy.height.convert",
      "title": "Ellipsoidal and orthometric height",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 28,
      "checks": {
        "numeric": 62,
        "exact": 31
      },
      "failures": [],
      "sources": [
        {
          "source": "h = H + N with N from GeographicLib's GeoidEval on the egm96-15 grid, as captured in core/crates/gp-geodesy/tests/data/egm96_diff.csv (GeographicLib GeoidEval 2.7, egm96-15)",
          "count": 18
        },
        {
          "source": "GeographicLib GeoidEval 2.7 with the egm96-15 grid (tools/vectors/gen_geoid_diff.py) (egm96-15 (2009-08-29))",
          "count": 8
        },
        {
          "source": "Regression for a reported defect (2026-09-23 fix-geodesy-indexing): A negative geoid height reads as below the ellipsoid (was -17.21 m above). (core 0.1.0)",
          "count": 1
        },
        {
          "source": "Regression for a reported defect (2026-09-23 fix-geodesy-indexing): A negative height above ground reads as below the ground (was -152.461 m above the ground). (core 0.1.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.orthometric.value",
        "error": 0.00004694014491235521,
        "abs": 0.00005,
        "rel": 0,
        "used": 0.9388028982471042
      },
      "exampleSource": "h − N with N = 28.7079 m from GeographicLib GeoidEval (egm96-15, cubic): 71.292 m above sea level"
    },
    {
      "id": "geodesy.magnetic.declination",
      "title": "Magnetic declination",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 29,
      "checks": {
        "numeric": 120,
        "exact": 30
      },
      "failures": [],
      "sources": [
        {
          "source": "NCEI WMM2025 test values (WMM2025_TestValues.txt, released with the WMM2025 coefficients) (WMM2025 (2024-11-13))",
          "count": 20
        },
        {
          "source": "ppigrf 2.1.0 (independent pure-Python IGRF-14 synthesis), on January 1 of coefficient epochs (tools/vectors/gen_magnetic.py) (IGRF-14 (2024-12))",
          "count": 8
        },
        {
          "source": "Regression for a reported defect (2026-09-23 fix-geodesy-indexing): The decimal year shows without digit grouping (was 2,026.71). (core 0.1.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v009",
        "path": "result.inclination.value",
        "error": 0.004914022194554946,
        "abs": 0.005,
        "rel": 0,
        "used": 0.9828044389109891
      },
      "exampleSource": "NCEI WMM2025 synthesis; checked against the published WMM2025 test values (WMM2025_TestValues.txt)"
    },
    {
      "id": "geodesy.magnetic.grivation",
      "title": "Grid variation (grivation)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 69,
        "exact": 27
      },
      "failures": [],
      "sources": [
        {
          "source": "Declination from pygeomag (an independent WMM2025 implementation) and grid convergence from PROJ's Proj.get_factors; grivation G = D - gamma and magnetic = true - variation, east positive (pygeomag / PROJ 9.3.0)",
          "count": 16
        },
        {
          "source": "NCEI WMM2025 test values (declination) and GeographicLib GeoConvert -c (convergence) (WMM2025 (2024-11-13); GeographicLib 2.x)",
          "count": 9
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.grivation.value",
        "error": 0.004602502636487316,
        "abs": 0.006,
        "rel": 0,
        "used": 0.767083772747886
      },
      "exampleSource": "add-geodesy-suite grivation scenario: WMM2025 declination minus the UPS convergence"
    },
    {
      "id": "geodesy.magnetic.true-to-magnetic",
      "title": "True and magnetic bearings",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 26,
      "checks": {
        "numeric": 58,
        "exact": 46
      },
      "failures": [],
      "sources": [
        {
          "source": "Declination from pygeomag (an independent WMM2025 implementation) and grid convergence from PROJ's Proj.get_factors; grivation G = D - gamma and magnetic = true - variation, east positive (pygeomag / PROJ 9.3.0)",
          "count": 20
        },
        {
          "source": "Arithmetic of FAA-H-8083-25C (magnetic = true - east variation; east is least, west is best) (FAA-H-8083-25C (2023))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v020",
        "path": "result.variation_used.value",
        "error": 8.002558615771704e-10,
        "abs": 0.0001,
        "rel": 0,
        "used": 0.000008002558615771704
      },
      "exampleSource": "add-geodesy-suite geomagnetism scenario: magnetic course 102°"
    },
    {
      "id": "geodesy.parse.angle-arithmetic",
      "title": "Add and subtract DMS angles",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 46,
        "exact": 48
      },
      "failures": [],
      "sources": [
        {
          "source": "Exact rational arithmetic on arcseconds (tools/vectors/gen_parse_more.py) (definition)",
          "count": 16
        },
        {
          "source": "Exact sexagesimal arithmetic with Python fractions (tools/vectors/gen_angle_arith.py) (2026)",
          "count": 8
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.seconds.value",
        "error": 0,
        "abs": 0.0001,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Sexagesimal arithmetic: 55°16'00\""
    },
    {
      "id": "geodesy.parse.bearing-difference",
      "title": "Difference between two bearings",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 23,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "Exact rational arithmetic on arcseconds (tools/vectors/gen_parse_more.py) (definition)",
          "count": 17
        },
        {
          "source": "Exact arithmetic (definition)",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.difference.value",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-geodesy-suite scenario: +20°"
    },
    {
      "id": "geodesy.parse.coordinates",
      "title": "Read any coordinate",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 39,
        "exact": 28
      },
      "failures": [],
      "sources": [
        {
          "source": "Strings written by tools/vectors/gen_parse_diff.py from integer degrees, minutes, and seconds (seed 44)",
          "count": 10
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) (GeographicLib 2.x)",
          "count": 6
        },
        {
          "source": "Regressions found by core/crates/gp-geodesy/tests/parse_parity.rs (tools/vectors/gen_parse_diff.py) (2026-09-19)",
          "count": 4
        },
        {
          "source": "Exact arithmetic (definition)",
          "count": 1
        },
        {
          "source": "Wikipedia, Decimal degrees (worked example) (retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v008",
        "path": "result.lat.value",
        "error": 0.000022222222220591448,
        "abs": 0.00005,
        "rel": 0,
        "used": 0.44444444441182895
      },
      "exampleSource": "add-geodesy-suite parsing scenario: 40.446111…, -79.982222…"
    },
    {
      "id": "geodesy.parse.format",
      "title": "Format a coordinate",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 33,
        "exact": 25
      },
      "failures": [],
      "sources": [
        {
          "source": "Exact rational arithmetic on arcseconds (tools/vectors/gen_parse_more.py) (definition)",
          "count": 16
        },
        {
          "source": "Exact arithmetic (definition)",
          "count": 3
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) (GeographicLib 2.x)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.latitude_resolution.value",
        "error": 0.003463257675100806,
        "abs": 0.05,
        "rel": 0,
        "used": 0.06926515350201612
      },
      "exampleSource": "Exact conversion of 40.446111°, -79.982222°"
    },
    {
      "id": "geodesy.projection.arc-to-chord",
      "title": "Arc-to-chord correction (t − T)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 88,
        "exact": 24
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GeoConvert and GeodSolve (tools/vectors/gen_geodesy_last.py) (GeographicLib 2.7)",
          "count": 16
        },
        {
          "source": "GeographicLib GeoConvert and GeodSolve (tools/vectors/gen_arc_chord.py) (GeographicLib 2.x)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v016",
        "path": "result.ellipsoid_distance.value",
        "error": 1.2078089639544487e-9,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.0012078089639544487
      },
      "exampleSource": "NGS Manual 5 (t − T) definition, evaluated exactly"
    },
    {
      "id": "geodesy.spcs.spcs83-forward",
      "title": "Latitude and longitude to state plane (SPCS83)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 26,
      "checks": {
        "numeric": 50,
        "exact": 28
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ 9 (via pyproj) from EPSG:4269 to the zone's EPSG meter CRS (tools/vectors/gen_spcs_diff.py) (PROJ 9.3.0)",
          "count": 25
        },
        {
          "source": "Regression for a reported defect (2026-09-23 fix-geodesy-indexing): The EPSG code is an identifier and shows without digit grouping (was 32,129). (core 0.1.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.easting.value",
        "error": 3.102468326687813e-8,
        "abs": 0.001,
        "rel": 0,
        "used": 0.00003102468326687813
      },
      "exampleSource": "add-geodesy-suite scenario: 1,347,294.025 ftUS E, 413,222.374 ftUS N (±0.003 ftUS)"
    },
    {
      "id": "geodesy.spcs.spcs83-inverse",
      "title": "State plane (SPCS83) to latitude and longitude",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 50,
        "exact": 25
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ 9 (via pyproj) from EPSG:4269 to the zone's EPSG meter CRS (tools/vectors/gen_spcs_diff.py) (PROJ 9.3.0)",
          "count": 25
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.lon.value",
        "error": 3.268496584496461e-13,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.0003268496584496461
      },
      "exampleSource": "Inverse of the add-geodesy-suite Pennsylvania South scenario: about 40.446111°, -79.982222°"
    },
    {
      "id": "geodesy.spcs.zone-lookup",
      "title": "State plane zone lookup",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 30,
      "checks": {
        "numeric": 40,
        "exact": 30
      },
      "failures": [],
      "sources": [
        {
          "source": "The EPSG registry through pyproj: NAD83 State Plane projected CRSs and their areas of use (tools/vectors/gen_spcs_zones.py) (PROJ 9.3.0 EPSG database)",
          "count": 24
        },
        {
          "source": "SPCS83 zone list, NOAA Manual NOS NGS 5 (NOS NGS 5 (1990))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 0,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "NOAA Manual NOS NGS 5: Colorado North (0501), Central (0502), and South (0503)"
    },
    {
      "id": "geodesy.ups.forward",
      "title": "Latitude and longitude to UPS",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 29,
      "checks": {
        "numeric": 77,
        "exact": 53
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ through pyproj: EPSG:32661 and EPSG:32761, WGS 84 / UPS North and South (polar stereographic, k0 = 0.994, false easting and northing 2,000,000 m); the anchor point agrees with GeographicLib's GeoConvert (pyproj 3.6.1 / PROJ 9.3.0)",
          "count": 23
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) (GeographicLib 2.x)",
          "count": 2
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) by rotational symmetry (GeographicLib 2.x)",
          "count": 2
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) by polar symmetry (GeographicLib 2.x)",
          "count": 1
        },
        {
          "source": "Exact arithmetic (definition)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.easting.value",
        "error": 0.0003826781176030636,
        "abs": 0.001,
        "rel": 0,
        "used": 0.3826781176030636
      },
      "exampleSource": "add-geodesy-suite scenario: 2,000,000 m E, 1,444,542.609 m N (±1 mm)"
    },
    {
      "id": "geodesy.ups.inverse",
      "title": "UPS to latitude and longitude",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 26,
      "checks": {
        "numeric": 48,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ through pyproj: EPSG:32661 and EPSG:32761, WGS 84 / UPS North and South (polar stereographic, k0 = 0.994, false easting and northing 2,000,000 m); the anchor point agrees with GeographicLib's GeoConvert (pyproj 3.6.1 / PROJ 9.3.0)",
          "count": 21
        },
        {
          "source": "Exact arithmetic (definition)",
          "count": 2
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) (GeographicLib 2.x)",
          "count": 1
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) by polar symmetry (GeographicLib 2.x)",
          "count": 1
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) by rotational symmetry (GeographicLib 2.x)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.lat.value",
        "error": 3.440518980823981e-9,
        "abs": 1e-8,
        "rel": 0,
        "used": 0.3440518980823981
      },
      "exampleSource": "add-geodesy-suite scenario inverse"
    },
    {
      "id": "geodesy.utm.forward",
      "title": "Latitude and longitude to UTM",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 64,
        "exact": 24
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib TMcoords.dat, point sample (Karney, exact transverse Mercator) (TMcoords 2009)",
          "count": 12
        },
        {
          "source": "Meridian arc M(lat) by Simpson integration of a(1-e^2)/(1-e^2 sin^2)^1.5 (tools/vectors/gen_geodesy.py) (WGS 84)",
          "count": 6
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) (GeographicLib 2.x)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.northing.value",
        "error": 0.0002788528800010681,
        "abs": 0.001,
        "rel": 0,
        "used": 0.2788528800010681
      },
      "exampleSource": "add-geodesy-suite scenario: 17N 586,309.953 m E, 4,477,770.428 m N (±1 mm)"
    },
    {
      "id": "geodesy.utm.inverse",
      "title": "UTM to latitude and longitude",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 72,
        "exact": 21
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib TMcoords.dat, point sample (Karney, exact transverse Mercator) (TMcoords 2009)",
          "count": 15
        },
        {
          "source": "Meridian arc M(lat) by Simpson integration of a(1-e^2)/(1-e^2 sin^2)^1.5 (tools/vectors/gen_geodesy.py) (WGS 84)",
          "count": 5
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) (GeographicLib 2.x)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.lat.value",
        "error": 2.492804185294517e-9,
        "abs": 1e-8,
        "rel": 0,
        "used": 0.2492804185294517
      },
      "exampleSource": "add-geodesy-suite scenario: 40.446111°, -79.982222°"
    },
    {
      "id": "geodesy.utm.zone",
      "title": "UTM zone and band lookup",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 39,
      "checks": {
        "numeric": 72,
        "exact": 78
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib's GeoConvert: -u for the UTM zone and -m for the MGRS grid zone, both carrying the Norway and Svalbard exceptions; central meridian 6z - 183 by definition (GeographicLib 2.7)",
          "count": 33
        },
        {
          "source": "add-geodesy-suite scenarios (GeographicLib values) (GeographicLib 2.x)",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.zone",
        "error": 0,
        "abs": 0,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-geodesy-suite scenario: zone 32, not 31"
    },
    {
      "id": "geometry.area.polygon",
      "title": "Polygon area and perimeter on the ellipsoid",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 29,
      "checks": {
        "numeric": 57,
        "exact": 59
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib Planimeter (Karney 2013 geodesic polygon area), WGS 84 (GeographicLib 2.7)",
          "count": 23
        },
        {
          "source": "GeographicLib Planimeter -R (Karney 2024, the area of rhumb polygons), WGS 84 (GeographicLib 2.x)",
          "count": 5
        },
        {
          "source": "add-navigation-and-geometry shoelace-warning scenario (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v008",
        "path": "result.area.value",
        "error": 4.5993660269250114e-11,
        "abs": 1e-9,
        "rel": 1e-8,
        "used": 0.037612427342829984
      },
      "exampleSource": "add-navigation-and-geometry area scenario: 269,154.55 km², perimeter 2,099.854 km, clockwise"
    },
    {
      "id": "geometry.buffer.geodesic",
      "title": "Buffer a point, line, or polygon",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 30,
      "checks": {
        "numeric": 61,
        "exact": 35
      },
      "failures": [],
      "sources": [
        {
          "source": "Steiner's formula and plane closed forms on small near-equator shapes, evaluated in Python (tools/vectors/gen_buffer.py) (2026)",
          "count": 23
        },
        {
          "source": "add-navigation-and-geometry scenarios (2026)",
          "count": 6
        },
        {
          "source": "GeographicLib 2.7 GeodSolve against 8,004 points sampled along the input rectangle: every one of the 157 boundary vertices lies 500 m from it within 61 nanometres, and the deepest chord midpoint sags 0.124103 m inside, which is what max_deviation reports (GeographicLib 2.7)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v030",
        "path": "result.max_deviation.value",
        "error": 3.6770517460038565e-7,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.36770517460038565
      },
      "exampleSource": "GeographicLib 2.7 GeodSolve, against 8,004 points sampled along the input rectangle: all 157 boundary vertices lie 500 m from it within 61 nanometres, and the worst chord midpoint sags 0.124103 m inside, which is the max_deviation of 0.1241033677 m the tool reports"
    },
    {
      "id": "geometry.distance.tracks",
      "title": "Compare two tracks",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 57,
        "exact": 21
      },
      "failures": [],
      "sources": [
        {
          "source": "Distances by GeographicLib's GeodSolve (C++), couplings worked by hand (tools/vectors/gen_distance.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 4
        },
        {
          "source": "add-navigation-and-geometry scenarios (2026)",
          "count": 1
        },
        {
          "source": "add-navigation-and-geometry scenarios (GeodSolve: GeographicLib version 2.7)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a curving track against a straight one (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a high-latitude pair (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a pair across the antimeridian (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a pair near the equator (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a southern-hemisphere pair (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a track against a coarser version of itself (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a two-point track against a many-point one (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: one track much shorter than the other (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: the same track against itself (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: tracks running opposite ways along the same ground (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: tracks that diverge along their length (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: tracks with different vertex counts (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: two tracks running beside each other (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: two tracks that cross (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v017",
        "path": "result.frechet.value",
        "error": 0.0000027652909011521842,
        "abs": 0.000001,
        "rel": 5e-8,
        "used": 0.11953437064979613
      },
      "exampleSource": "checked against GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane — GEOS's own Fréchet implementation, and its point-to-segment distance for the Hausdorff — over fourteen pairs of tracks, agreeing to 6.3e-9 relative at worst"
    },
    {
      "id": "geometry.mesh.delaunay",
      "title": "Delaunay triangulation of points",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 20,
        "exact": 40
      },
      "failures": [],
      "sources": [
        {
          "source": "Qhull via SciPy (tools/vectors/gen_mesh_diff.py) (SciPy 1.x)",
          "count": 5
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a dozen points (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a high-latitude scatter (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a jittered 3x3 grid (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a jittered 4x4 grid (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a long thin scatter (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a nudged ring (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a nudged ring with a centre (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a scatter across the antimeridian (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a small scatter (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a southern scatter (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: a wider scatter (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: an equatorial scatter (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: five points (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: sixteen scattered points (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, delaunay_triangles on PROJ's azimuthal equidistant plane: two clusters (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.triangle_count",
        "error": 0,
        "abs": 0,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "de Berg et al. (2008), the lifting map. Checked against GEOS 3.11.4's own delaunay_triangles over fifteen point sets — scatters, jittered grids, rings, two clusters, and sets at the equator, at 70 north and across the antimeridian — agreeing triangle for triangle on every one, which a unique triangulation permits demanding"
    },
    {
      "id": "geometry.mesh.voronoi",
      "title": "Voronoi cells around points",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 20,
        "exact": 40
      },
      "failures": [],
      "sources": [
        {
          "source": "Qhull via SciPy (tools/vectors/gen_mesh_diff.py) (SciPy 1.x)",
          "count": 5
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a dozen points (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a high-latitude scatter (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a jittered 3x3 grid (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a jittered 4x4 grid (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a long thin scatter (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a nudged ring (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a nudged ring with a centre (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a scatter across the antimeridian (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a small scatter (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a southern scatter (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: a wider scatter (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: an equatorial scatter (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: five points (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: sixteen scattered points (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, voronoi_polygons in the tool's own clip box on PROJ's azimuthal equidistant plane: two clusters (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.cell_count",
        "error": 0,
        "abs": 0,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "The Delaunay dual; checked against Qhull via SciPy, and against GEOS 3.11.4's voronoi_polygons over fifteen point sets in the same clip box, agreeing on every cell's corner count and on its area to 4.4e-7 relative"
    },
    {
      "id": "geometry.overlay.boolean",
      "title": "Overlap, union, or difference of two polygons",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 61,
        "exact": 24
      },
      "failures": [],
      "sources": [
        {
          "source": "Areas by GeographicLib's Planimeter, crossings by Clairaut's relation with GeodSolve (C++), via tools/vectors/gen_overlay.py (GeodSolve: GeographicLib version 2.7)",
          "count": 10
        },
        {
          "source": "add-navigation-and-geometry scenarios (GeodSolve: GeographicLib version 2.7)",
          "count": 2
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: difference of a square inside another, leaving a hole (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: difference of two overlapping squares (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: difference of two squares that do not meet (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: intersection of a square inside another (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: intersection of two squares across the antimeridian (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: symmetric-difference of two overlapping squares (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: union of a square inside another (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: union of two overlapping squares (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: union of two squares across the antimeridian (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane, with the result measured back on the ellipsoid by geographiclib's PolygonArea: union of two squares that do not meet (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v016",
        "path": "result.area.value",
        "error": 4.969857858583282e-12,
        "abs": 1e-12,
        "rel": 1e-10,
        "used": 0.2092156895917884
      },
      "exampleSource": "GEOS 3.11.4 through shapely, the reference implementation for this operation, run on the same azimuthal equidistant plane and measured back on the ellipsoid by geographiclib: over ten cases across all four operations the areas agree to 2.2e-11 relative and the part counts exactly"
    },
    {
      "id": "geometry.predicate.point-in-polygon",
      "title": "Point in polygon",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 83,
        "exact": 157
      },
      "failures": [],
      "sources": [
        {
          "source": "Points built with GeographicLib's GeodSolve (C++), classified by hand (tools/vectors/gen_predicate.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 6
        },
        {
          "source": "add-navigation-and-geometry scenarios (GeodSolve: GeographicLib version 2.7)",
          "count": 2
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a square (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a square, points outside (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a square, scattered points 1 (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a square, scattered points 2 (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a square, scattered points 3 (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a triangle (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a triangle, points outside (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a triangle, scattered points 1 (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a triangle, scattered points 2 (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: a triangle, scattered points 3 (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: an L, points in the arm and in the notch (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: an L, scattered points 1 (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: an L, scattered points 2 (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: an L, scattered points 3 (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v012",
        "path": "result.results.1.distance.value",
        "error": 0.0027466573951642204,
        "abs": 0.001,
        "rel": 0.00005,
        "used": 0.10117089302105689
      },
      "exampleSource": "inside, in a hole, and on the boundary. The verdicts are checked against GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane over 51 points and five shapes — a planar test against a geodesic winding number, agreeing on every point — with the edge distances matching to 7.4e-6 relative"
    },
    {
      "id": "geometry.shape.bbox",
      "title": "Bounding box, antimeridian-aware",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 103,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "Hand-checked longitude boxes; edge vertices by Clairaut's relation with GeodSolve azimuths (tools/vectors/gen_envelope.py) (2026)",
          "count": 6
        },
        {
          "source": "Hand-checked longitude boxes; edge vertices by Clairaut's relation with GeodSolve azimuths (tools/vectors/gen_envelope.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 4
        },
        {
          "source": "add-navigation-and-geometry scenarios (2026)",
          "count": 2
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: a box across the antimeridian (geographiclib 2.1; RFC 7946)",
          "count": 1
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: a high-latitude quadrilateral (geographiclib 2.1; RFC 7946)",
          "count": 1
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: a long mid-latitude line, which bulges poleward (geographiclib 2.1; RFC 7946)",
          "count": 1
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: a narrow equatorial strip (geographiclib 2.1; RFC 7946)",
          "count": 1
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: a southern-hemisphere line (geographiclib 2.1; RFC 7946)",
          "count": 1
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: a transatlantic line (geographiclib 2.1; RFC 7946)",
          "count": 1
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: a triangle in the northern mid-latitudes (geographiclib 2.1; RFC 7946)",
          "count": 1
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: points either side of the antimeridian (geographiclib 2.1; RFC 7946)",
          "count": 1
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: points spread over more than half the world (geographiclib 2.1; RFC 7946)",
          "count": 1
        },
        {
          "source": "latitude extremes by bisecting Karney's geographiclib for where the azimuth passes due east or west; longitude box by RFC 7946 section 5.2's largest-gap rule: the same pair as bare points, which does not (geographiclib 2.1; RFC 7946)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.east.value",
        "error": 2.842170943040401e-14,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.000028421709430404004
      },
      "exampleSource": "RFC 7946 §5.2 writes a box crossing the antimeridian with west > east, so 170 to -170 is the 20° box and not the 340° one. Checked over ten shapes against Karney's geographiclib bisected for where each edge's azimuth passes due east or west, which agrees with the tool exactly in every coordinate"
    },
    {
      "id": "geometry.shape.centroid",
      "title": "Polygon centroid and interior point",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 60,
        "exact": 36
      },
      "failures": [],
      "sources": [
        {
          "source": "Symmetry and local-plane centroids, evaluated in Python (tools/vectors/gen_shape.py) (2026)",
          "count": 9
        },
        {
          "source": "add-navigation-and-geometry scenarios (2026)",
          "count": 3
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a C shape, centroid outside (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a long thin strip (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a narrow wedge (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a rectangle straddling the equator (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a shape across the antimeridian (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a southern-hemisphere quadrilateral (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a square at 70 north (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a square in Colorado (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a square on the equator (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a triangle (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: a twelve-sided ring (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "PROJ's ellipsoidal Lambert azimuthal equal-area (pyproj) with GEOS's planar centroid (shapely), over edges walked by Karney's geographiclib: an L in Colorado (PROJ 9.3.0 / GEOS 3.11.4 / geographiclib 2.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.centroid_lat.value",
        "error": 1.8613243213394526e-7,
        "abs": 3e-7,
        "rel": 0,
        "used": 0.6204414404464842
      },
      "exampleSource": "a C shape, whose centre of mass falls outside it: CENTROID_OUTSIDE is raised and the interior point returned. Checked against PROJ 9.3.0's ellipsoidal Lambert azimuthal equal-area with GEOS 3.11.4's planar centroid over twelve shapes, which agree with the tool to 23 mm and to 4.6e-9 of the area"
    },
    {
      "id": "geometry.shape.densify",
      "title": "Add vertices along geodesic edges (densify)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 132,
        "exact": 21
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GeodSolve inverse and direct on WGS 84 (tools/vectors/gen_densify.py) (GeographicLib 2.x)",
          "count": 6
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a high-latitude line at 10000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a line across the antimeridian at 20000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a line of exactly two pieces at 1000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a meridian line at 60000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a short line at 2000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a southern triangle at 15000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a square as a polygon at 2500 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a three-leg route at 3000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a transatlantic line at 500000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: a very long route at 40000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: an equatorial line at 50000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: the same line cut finer at 500 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: the same line, no cut needed at 50000 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: the same route cut finer at 900 m (geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "Karney's geographiclib: ceil(length / max) pieces per edge, placed by the direct problem: the same square cut finer at 700 m (geographiclib 2.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v013",
        "path": "result.longest_piece.value",
        "error": 1.0902567737502977e-10,
        "abs": 0,
        "rel": 1e-9,
        "used": 0.00015955877450041142
      },
      "exampleSource": "Karney (2013) inverse and direct on WGS 84. Checked against his own geographiclib over fifteen cases — lines, polygons, a meridian, the equator, the antimeridian and high latitudes — agreeing on every vertex count, on the lengths to 1.6e-13 relative, and placing the interior vertices within 2.1e-14 deg"
    },
    {
      "id": "geometry.shape.enclosing",
      "title": "Hull, bounding rectangle, and enclosing circle",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 104,
        "exact": 22
      },
      "failures": [],
      "sources": [
        {
          "source": "Circles and rectangles built with GeographicLib's GeodSolve (C++), evaluated in Python (tools/vectors/gen_envelope.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 8
        },
        {
          "source": "add-navigation-and-geometry scenarios (2026)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: a long thin spread (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: a loose cluster (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: a quadrilateral (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: a scatter at 70 north (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: a scatter at the equator (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: a southern scatter (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: a square, where the rectangle is the hull (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: a tight cluster (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: a triangle (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: points either side of the antimeridian (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: three points in a line (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely on PROJ's azimuthal equidistant plane: minimum_bounding_circle, convex_hull and minimum_rotated_rectangle, with the hull's area measured on the ellipsoid by geographiclib's PolygonArea: two points (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v008",
        "path": "result.rect_azimuth.value",
        "error": 0.00004673741770133688,
        "abs": 0.0001,
        "rel": 0,
        "used": 0.4673741770133688
      },
      "exampleSource": "checked against GEOS 3.11.4 through shapely — its own minimum_bounding_circle, convex_hull and minimum_rotated_rectangle — over twelve point sets, agreeing on every hull corner count, on the circle radius to 2.5e-8 relative, on the hull area to 5.7e-7, and placing the circle's centre within 0.8 m over a 20 km scatter"
    },
    {
      "id": "geometry.simplify.rdp",
      "title": "Simplify a line or polygon (Douglas-Peucker)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 29,
      "checks": {
        "numeric": 181,
        "exact": 29
      },
      "failures": [],
      "sources": [
        {
          "source": "Douglas-Peucker (1973) and Visvalingam-Whyatt (1993) in Python on GeographicLib GeodesicProj -z (tools/vectors/gen_simplify.py) (GeographicLib 2.x)",
          "count": 5
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a gentle curve at 100 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a gentle curve at 25 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a gentle curve at 400 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a gentle curve at 5 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a high-latitude track at 100 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a high-latitude track at 25 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a high-latitude track at 400 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a high-latitude track at 5 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a long wandering track at 100 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a long wandering track at 25 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a long wandering track at 400 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a long wandering track at 5 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a near-straight line at 100 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a near-straight line at 25 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a near-straight line at 400 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a near-straight line at 5 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a sharp dogleg at 100 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a sharp dogleg at 25 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a sharp dogleg at 400 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a sharp dogleg at 5 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a zigzag at 100 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a zigzag at 25 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a zigzag at 400 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely, LineString.simplify on PROJ's azimuthal equidistant plane: a zigzag at 5 m (GEOS 3.11.4 / PROJ 9.3.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v024",
        "path": "result.max_deviation.value",
        "error": 0.00001194969418349956,
        "abs": 0.000001,
        "rel": 0.000001,
        "used": 0.13197420722731665
      },
      "exampleSource": "Douglas and Peucker (1973) with geodesic deviations (Karney 2013). Checked against GEOS 3.11.4's own LineString.simplify on the same plane over six shapes at four tolerances each: the two implementations kept the same vertices in all twenty-four, with the deviations agreeing to 1.3e-7 relative"
    },
    {
      "id": "geometry.simplify.visvalingam",
      "title": "Simplify a line or polygon (Visvalingam)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 29,
      "checks": {
        "numeric": 111,
        "exact": 29
      },
      "failures": [],
      "sources": [
        {
          "source": "Douglas-Peucker (1973) and Visvalingam-Whyatt (1993) in Python on GeographicLib GeodesicProj -z (tools/vectors/gen_simplify.py) (GeographicLib 2.x)",
          "count": 5
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a gentle curve at 1000 m2, keeping vertices [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a gentle curve at 20000 m2, keeping vertices [1, 4, 8, 12] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a gentle curve at 200000 m2, keeping vertices [1, 8, 12] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a gentle curve at 2e+06 m2, keeping vertices [1, 12] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a high-latitude track at 1000 m2, keeping vertices [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a high-latitude track at 20000 m2, keeping vertices [1, 2, 4, 6, 8, 10] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a high-latitude track at 200000 m2, keeping vertices [1, 4, 8, 10] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a high-latitude track at 2e+06 m2, keeping vertices [1, 10] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a long wandering track at 1000 m2, keeping vertices [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a long wandering track at 20000 m2, keeping vertices [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a long wandering track at 200000 m2, keeping vertices [1, 5, 9, 13, 17, 20] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a long wandering track at 2e+06 m2, keeping vertices [1, 13, 20] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a near-straight line at 1000 m2, keeping vertices [1, 9] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a near-straight line at 20000 m2, keeping vertices [1, 9] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a near-straight line at 200000 m2, keeping vertices [1, 9] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a near-straight line at 2e+06 m2, keeping vertices [1, 9] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a sharp dogleg at 1000 m2, keeping vertices [1, 2, 3, 4, 5] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a sharp dogleg at 20000 m2, keeping vertices [1, 2, 4, 5] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a sharp dogleg at 200000 m2, keeping vertices [1, 2, 4, 5] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a sharp dogleg at 2e+06 m2, keeping vertices [1, 5] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a zigzag at 1000 m2, keeping vertices [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a zigzag at 20000 m2, keeping vertices [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a zigzag at 200000 m2, keeping vertices [1, 14] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        },
        {
          "source": "the simplification package (urschrei), Visvalingam-Whyatt on PROJ's azimuthal equidistant plane: a zigzag at 2e+06 m2, keeping vertices [1, 14] (simplification 0.7 / PROJ 9.5.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.max_deviation.value",
        "error": 0.000020423656827972536,
        "abs": 0.05,
        "rel": 0,
        "used": 0.0004084731365594507
      },
      "exampleSource": "Visvalingam and Whyatt (1993) with geodesic deviations (Karney 2013). Checked against urschrei's simplification crate, an unrelated implementation of the same paper, over six shapes at four area thresholds each: the two kept exactly the same vertices in all twenty-four"
    },
    {
      "id": "geometry.validity.make-valid",
      "title": "Check and repair a polygon",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 40,
        "exact": 46
      },
      "failures": [],
      "sources": [
        {
          "source": "Areas by GeographicLib's Planimeter and crossings by GeodSolve (C++), via tools/vectors/gen_validity.py (GeodSolve: GeographicLib version 2.7)",
          "count": 5
        },
        {
          "source": "add-navigation-and-geometry scenarios (GeodSolve: GeographicLib version 2.7)",
          "count": 2
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a bow tie (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a bow tie across the antimeridian (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a bow tie at the equator (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a crossed quadrilateral (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a ring pinched to a point (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a square with a repeated corner (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a square with a spike (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a valid L (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a valid square (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a valid square across the antimeridian (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a valid square at 70 north (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a valid square at the equator (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a valid square, wound the other way (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        },
        {
          "source": "GEOS 3.11.4 through shapely: is_valid and make_valid on PROJ's azimuthal equidistant plane, with the repaired area measured on the ellipsoid by geographiclib's PolygonArea: a valid triangle (GEOS 3.11.4 / PROJ 9.3.0 / geographiclib 2.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.area.value",
        "error": 3.73016062482634e-11,
        "abs": 0,
        "rel": 1e-9,
        "used": 0.06147343945426694
      },
      "exampleSource": "a bow tie: two triangles, with the crossing located. Checked against GEOS 3.11.4 through shapely over fourteen polygons — valid and crossed, at the equator, at 70 north and across the antimeridian — agreeing on every verdict and part count except two degenerate rings, where the repaired areas still agree to 6.2e-11 relative"
    },
    {
      "id": "indexing.convert.cross-index",
      "title": "One place in every index, at a matched cell size",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 63,
        "exact": 163
      },
      "failures": [],
      "sources": [
        {
          "source": "Cell-size tables for each system worked independently in Python (tools/vectors/gen_cross.py) (2026-09-22)",
          "count": 21
        }
      ],
      "worst": {
        "vector": "v010",
        "path": "result.cells.3.cell_size.value",
        "error": 3.637978807091713e-12,
        "abs": 0.000001,
        "rel": 1e-9,
        "used": 1.4346119268006414e-7
      },
      "exampleSource": "add-spatial-indexing-and-raster hierarchical-cells scenario: a 150 m target gives geohash precision 7 and H3 resolution 10"
    },
    {
      "id": "indexing.geohash.cover",
      "title": "Geohashes covering an area",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 55
      },
      "failures": [],
      "sources": [
        {
          "source": "Slippy-map and geohash arithmetic in Python (tools/vectors/gen_cover.py) (2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 0,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Geohash cell arithmetic (Niemeyer 2008)"
    },
    {
      "id": "indexing.geohash.decode",
      "title": "Geohash decoder",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 85,
        "exact": 25
      },
      "failures": [],
      "sources": [
        {
          "source": "Geohash algorithm implemented in Python (tools/vectors/gen_indexing.py) (2026)",
          "count": 22
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 1
        },
        {
          "source": "Wikipedia, Geohash (worked example) (retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v024",
        "path": "result.lon.value",
        "error": 0.000027343750000241585,
        "abs": 0.0005,
        "rel": 0,
        "used": 0.05468750000048317
      },
      "exampleSource": "Inverse of the encode scenario"
    },
    {
      "id": "indexing.geohash.encode",
      "title": "Geohash encoder",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 44,
        "exact": 46
      },
      "failures": [],
      "sources": [
        {
          "source": "Geohash algorithm implemented in Python (tools/vectors/gen_indexing.py) (2026)",
          "count": 21
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 1
        },
        {
          "source": "Wikipedia, Geohash (worked example) (retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.south.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: dppn5fyxx"
    },
    {
      "id": "indexing.geohash.neighbors",
      "title": "Geohash neighbors",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 0,
        "exact": 110
      },
      "failures": [],
      "sources": [
        {
          "source": "Geohash algorithm implemented in Python (tools/vectors/gen_indexing.py) (2026)",
          "count": 21
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 2
        },
        {
          "source": "Chris Veness, latlon-geohash test suite (test.js) (2.0.0)",
          "count": 1
        }
      ],
      "worst": null,
      "exampleSource": "Geohash neighbor definition"
    },
    {
      "id": "indexing.h3.cell-info",
      "title": "H3 cell inspector",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 122,
        "exact": 57
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 19
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 3
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (H3 4.4.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.boundary.0.lat",
        "error": 4.746425474877469e-12,
        "abs": 5e-11,
        "rel": 1e-11,
        "used": 0.005004335803768098
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: center about (40.444866°, -79.981847°)"
    },
    {
      "id": "indexing.h3.cell-to-local-ij",
      "title": "H3 local IJ for a cell (cellToLocalIj)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 44,
        "exact": 66
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.i",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "H3 cellToLocalIj"
    },
    {
      "id": "indexing.h3.cells-to-polygon",
      "title": "H3 cell set outline (cellsToMultiPolygon)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 144,
        "exact": 24
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 24
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.area.value",
        "error": 1.7884204339679854e-8,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0.2435598837299411
      },
      "exampleSource": "H3 cellsToMultiPolygon"
    },
    {
      "id": "indexing.h3.children",
      "title": "H3 children cells",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 20,
        "exact": 40
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 19
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (H3 4.4.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 5e-11,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: 7 children"
    },
    {
      "id": "indexing.h3.compact",
      "title": "H3 compact",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 20,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 20
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 5e-11,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "H3 compactCells: the 7 children compact to their parent, 892a8471487ffff"
    },
    {
      "id": "indexing.h3.edges",
      "title": "H3 edges and vertexes",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 26,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 20
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.edges.0.length.value",
        "error": 3.0184901333996095e-7,
        "abs": 0.000001,
        "rel": 1e-11,
        "used": 0.2904647152423416
      },
      "exampleSource": "H3 originToDirectedEdges"
    },
    {
      "id": "indexing.h3.grid-disk",
      "title": "H3 grid disk (k-ring)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 21
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 5e-11,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: 6 cells, not 7"
    },
    {
      "id": "indexing.h3.grid-path",
      "title": "H3 grid path and distance",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 20,
        "exact": 59
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 20
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.distance",
        "error": 0,
        "abs": 5e-11,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "H3 gridPathCells"
    },
    {
      "id": "indexing.h3.grid-ring",
      "title": "H3 grid ring",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 20,
        "exact": 20
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 20
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 5e-11,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "H3 gridRing: 6k cells away from pentagons"
    },
    {
      "id": "indexing.h3.lat-lng-to-cell",
      "title": "H3 cell for a point",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 72,
        "exact": 50
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 23
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 1
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (H3 4.4.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.area.value",
        "error": 9.557865610076988e-10,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0.6865086396196585
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: 892a8471487ffff"
    },
    {
      "id": "indexing.h3.local-ij-to-cell",
      "title": "H3 cell at local IJ (localIjToCell)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 44,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.lon.value",
        "error": 6.22002449546244e-14,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0.00006212103184214247
      },
      "exampleSource": "H3 localIjToCell"
    },
    {
      "id": "indexing.h3.parent",
      "title": "H3 parent cell",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 20,
        "exact": 40
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 19
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (H3 4.4.1)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.child_position",
        "error": 0,
        "abs": 5e-11,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: 852a8473fffffff"
    },
    {
      "id": "indexing.h3.polygon-to-cells",
      "title": "H3 polygon fill (polygonToCells)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 22,
        "exact": 60
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 20
        },
        {
          "source": "H3 C test suite, testPolygonToCells.c (sfGeoPolygon, holeGeoPolygon) (H3 v4.4.1)",
          "count": 2
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 5e-11,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "H3 polygonToCells"
    },
    {
      "id": "indexing.h3.resolution-chooser",
      "title": "H3 resolution chooser",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 24,
        "exact": 22
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 average hexagon areas (h3.average_hexagon_area) (H3 4.4.1)",
          "count": 13
        },
        {
          "source": "H3 average hexagon edge lengths (h3.average_hexagon_edge_length) (H3 4.4.1)",
          "count": 7
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (H3 4.4.1)",
          "count": 1
        },
        {
          "source": "H3 documentation, Tables of cell statistics across resolutions (h3geo.org, retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v022",
        "path": "result.average_area.value",
        "error": 4.2720670057061483e-10,
        "abs": 5e-10,
        "rel": 1e-11,
        "used": 0.8526172348218118
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: resolution 8 (≈ 0.74 km²), 7 is ≈ 5.16 km²"
    },
    {
      "id": "indexing.h3.uncompact",
      "title": "H3 uncompact",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 20,
        "exact": 20
      },
      "failures": [],
      "sources": [
        {
          "source": "H3 C 4.4.1 via h3-py 4.4.2 (H3 4.4.1)",
          "count": 20
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 5e-11,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "H3 uncompactCells"
    },
    {
      "id": "indexing.plus-code.decode",
      "title": "Plus Code decoder",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 49,
      "checks": {
        "numeric": 168,
        "exact": 57
      },
      "failures": [],
      "sources": [
        {
          "source": "Open Location Code test data, decoding.csv (open-location-code main)",
          "count": 42
        },
        {
          "source": "Open Location Code test data, encoding.csv (open-location-code main)",
          "count": 5
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 1
        },
        {
          "source": "Open Location Code specification (recover nearest) (open-location-code main)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v046",
        "path": "result.east.value",
        "error": 5.115907697472721e-13,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.0005115907697472721
      },
      "exampleSource": "Open Location Code documentation example"
    },
    {
      "id": "indexing.plus-code.encode",
      "title": "Plus Code encoder",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 35,
      "checks": {
        "numeric": 0,
        "exact": 70
      },
      "failures": [],
      "sources": [
        {
          "source": "Open Location Code test data, encoding.csv (open-location-code main)",
          "count": 35
        }
      ],
      "worst": null,
      "exampleSource": "Open Location Code documentation example: 8FVC9G8F+6X"
    },
    {
      "id": "indexing.plus-code.shorten",
      "title": "Shorten a Plus Code",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 0,
        "exact": 42
      },
      "failures": [],
      "sources": [
        {
          "source": "Open Location Code test data, shortCodeTests.csv (open-location-code main)",
          "count": 15
        },
        {
          "source": "Open Location Code specification (shorten) (open-location-code main)",
          "count": 5
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 1
        }
      ],
      "worst": null,
      "exampleSource": "Open Location Code shortening rule"
    },
    {
      "id": "indexing.s2.cell-info",
      "title": "S2 cell details",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 264,
        "exact": 154
      },
      "failures": [],
      "sources": [
        {
          "source": "s2sphere, an independent Python implementation of the S2 algorithms (tools/vectors/gen_s2.py) (s2sphere 0.2.5)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v016",
        "path": "result.lat.value",
        "error": 1.7905676941154525e-11,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.017905676941154525
      },
      "exampleSource": "The cell from the token scenario, with its geometry checked against s2sphere"
    },
    {
      "id": "indexing.s2.covering",
      "title": "S2 cells covering a region",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 66,
        "exact": 60
      },
      "failures": [],
      "sources": [
        {
          "source": "The covering this implementation produces, pinned so a change in the refinement is visible; containment is checked independently against s2sphere in tests/s2_cover_parity.rs (2026-09-23)",
          "count": 16
        },
        {
          "source": "The covering this implementation produces, pinned so a change in the refinement is visible; containment, budget, and level range are checked against sampled points by the core tests (2026-09-22)",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 0,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-spatial-indexing-and-raster hierarchical-cells scenario: at most 8 cells, all between levels 10 and 16, together covering the region"
    },
    {
      "id": "indexing.s2.lat-lng-to-cell",
      "title": "S2 cell for a point",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 88,
        "exact": 66
      },
      "failures": [],
      "sources": [
        {
          "source": "s2sphere, an independent Python implementation of the S2 algorithms (tools/vectors/gen_s2.py) (s2sphere 0.2.5)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v016",
        "path": "result.lat.value",
        "error": 1.7905676941154525e-11,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.017905676941154525
      },
      "exampleSource": "add-spatial-indexing-and-raster hierarchical-cells scenario: the token is 8834f3dec"
    },
    {
      "id": "indexing.s2.neighbors",
      "title": "S2 edge neighbours",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 44,
        "exact": 132
      },
      "failures": [],
      "sources": [
        {
          "source": "s2sphere, an independent Python implementation of the S2 algorithms (tools/vectors/gen_s2.py) (s2sphere 0.2.5)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.level",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Checked against s2sphere's get_edge_neighbors, in the same order"
    },
    {
      "id": "indexing.tile.bounds",
      "title": "Map tile bounds",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 26,
      "checks": {
        "numeric": 83,
        "exact": 52
      },
      "failures": [],
      "sources": [
        {
          "source": "OpenStreetMap slippy-map formulas and Bing quadkeys in Python (tools/vectors/gen_indexing.py) (2026)",
          "count": 21
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 3
        },
        {
          "source": "mercantile README (Mapbox), worked examples (mercantile 1.2.1)",
          "count": 1
        },
        {
          "source": "Microsoft, Bing Maps Tile System (worked quadkey example and ground-resolution table) (2018-02-28)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.south.value",
        "error": 1.4210854715202004e-14,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.000014210854715202002
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: tile y convention confusion"
    },
    {
      "id": "indexing.tile.cover",
      "title": "Map tiles covering a box",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 20,
        "exact": 60
      },
      "failures": [],
      "sources": [
        {
          "source": "Slippy-map and geohash arithmetic in Python (tools/vectors/gen_cover.py) (2026)",
          "count": 21
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 0,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Slippy map tile arithmetic"
    },
    {
      "id": "indexing.tile.family",
      "title": "Map tile parent and children",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 0,
        "exact": 230
      },
      "failures": [],
      "sources": [
        {
          "source": "Slippy-map and geohash arithmetic in Python (tools/vectors/gen_cover.py) (2026)",
          "count": 23
        }
      ],
      "worst": null,
      "exampleSource": "Slippy map tile arithmetic: parent 11/568/772"
    },
    {
      "id": "indexing.tile.from-point",
      "title": "Map tile for a point (XYZ, TMS, quadkey)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 44,
        "exact": 71
      },
      "failures": [],
      "sources": [
        {
          "source": "OpenStreetMap slippy-map formulas and Bing quadkeys in Python (tools/vectors/gen_indexing.py) (2026)",
          "count": 20
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 2
        },
        {
          "source": "mercantile README (Mapbox), worked examples (mercantile 1.2.1)",
          "count": 1
        },
        {
          "source": "Microsoft, Bing Maps Tile System (worked quadkey example and ground-resolution table) (2018-02-28)",
          "count": 1
        },
        {
          "source": "Regression for a reported defect (2026-09-23 fix-geodesy-indexing): tile_size given as the JSON number 512 is accepted like the string \"512\" (was rejected as not a string). (core 0.1.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v024",
        "path": "result.ground_resolution.value",
        "error": 0.00003597952309064567,
        "abs": 0.00005,
        "rel": 0,
        "used": 0.7195904618129134
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: 12/1137/1544, TMS y 2551, quadkey 032001112001, about 29.08 m/px"
    },
    {
      "id": "indexing.tile.ground-resolution",
      "title": "Map ground resolution and scale",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 30,
      "checks": {
        "numeric": 30,
        "exact": 30
      },
      "failures": [],
      "sources": [
        {
          "source": "OpenStreetMap slippy-map formulas and Bing quadkeys in Python (tools/vectors/gen_indexing.py) (2026)",
          "count": 20
        },
        {
          "source": "Microsoft, Bing Maps Tile System (worked quadkey example and ground-resolution table) (2018-02-28)",
          "count": 9
        },
        {
          "source": "add-spatial-indexing-and-raster scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v029",
        "path": "result.resolution.value",
        "error": 0.00004553543474243582,
        "abs": 0.00005,
        "rel": 0,
        "used": 0.9107086948487164
      },
      "exampleSource": "add-spatial-indexing-and-raster scenario: about 29.08 m/px"
    },
    {
      "id": "navigation.geodesic.direct",
      "title": "Destination from a start, course, and distance (geodesic)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 28,
      "checks": {
        "numeric": 79,
        "exact": 28
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GeodTest-short.dat, line sample (Karney, high-precision reference) (GeodTest 2010)",
          "count": 18
        },
        {
          "source": "GeographicLib GeodSolve -E (GeodesicExact), custom ellipsoids (GeographicLib 2.x)",
          "count": 5
        },
        {
          "source": "Closed form on WGS 84: equatorial arc s = a * dlon; meridian quadrant 10,001,965.729313 m (GeographicLib 2.x)",
          "count": 4
        },
        {
          "source": "add-navigation-and-geometry geodesic scenarios (GeographicLib GeodSolve values) (GeographicLib 2.x)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.lat2.value",
        "error": 3.9676969265656226e-8,
        "abs": 1e-7,
        "rel": 0,
        "used": 0.39676969265656226
      },
      "exampleSource": "add-navigation-and-geometry geodesic scenario: (45.8920808°, -63.7549563°), final course 57.886373°"
    },
    {
      "id": "navigation.geodesic.haversine",
      "title": "Haversine distance (spherical)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 21,
        "exact": 20
      },
      "failures": [],
      "sources": [
        {
          "source": "Haversine evaluated in Python with R1 = 6,371,008.771 m (Moritz 2000)",
          "count": 19
        },
        {
          "source": "Rosetta Code, Haversine formula (task description) (retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.difference.value",
        "error": 0.15440114494413137,
        "abs": 1,
        "rel": 0,
        "used": 0.15440114494413137
      },
      "exampleSource": "add-navigation-and-geometry scenario: about 5,540,019 m, 14,890 m (0.27%) shorter than the geodesic"
    },
    {
      "id": "navigation.geodesic.intermediate-point",
      "title": "Point part way along a great circle",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 48,
      "checks": {
        "numeric": 109,
        "exact": 49
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib's GeodSolve, called per quantity (tools/vectors/gen_nav_geodesic.py) (GeographicLib 2.7)",
          "count": 42
        },
        {
          "source": "Spherical formulas in Python and GeographicLib GeodSolve (tools/vectors/gen_sphere.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v011",
        "path": "result.ellipsoidal_lon.value",
        "error": 7.0054517742335065e-12,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.007005451774233506
      },
      "exampleSource": "Worked by spherical interpolation, with the ellipsoidal point from the geodesic direct at a quarter of the distance"
    },
    {
      "id": "navigation.geodesic.intersection",
      "title": "Where two geodesic segments cross",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 62,
      "checks": {
        "numeric": 246,
        "exact": 124
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib IntersectTool -i (Karney 2024, geodesic intersections) (GeographicLib 2.x)",
          "count": 61
        },
        {
          "source": "GeographicLib IntersectTool -i (Karney 2024); found by the differential runner, where the Wasm build once kept the far crossing (GeographicLib 2.x)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v012",
        "path": "result.along_b.value",
        "error": 0.000004696659743785858,
        "abs": 0.000001,
        "rel": 5e-12,
        "used": 0.354187327436974
      },
      "exampleSource": "GeographicLib IntersectTool -i (Karney 2023)"
    },
    {
      "id": "navigation.geodesic.inverse",
      "title": "Distance between two points (geodesic)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 31,
      "checks": {
        "numeric": 118,
        "exact": 35
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib GeodTest-short.dat, line sample (Karney, high-precision reference) (GeodTest 2010)",
          "count": 18
        },
        {
          "source": "GeographicLib GeodSolve -E (GeodesicExact), custom ellipsoids (GeographicLib 2.x)",
          "count": 5
        },
        {
          "source": "Closed form on WGS 84: equatorial arc s = a * dlon; meridian quadrant 10,001,965.729313 m (GeographicLib 2.x)",
          "count": 4
        },
        {
          "source": "add-navigation-and-geometry geodesic scenarios (GeographicLib GeodSolve values) (GeographicLib 2.x)",
          "count": 2
        },
        {
          "source": "add-navigation-and-geometry high-flattening scenario (GeodSolve -E) (GeographicLib 2.x)",
          "count": 1
        },
        {
          "source": "Regression for a reported defect (2026-09-23 fix-geodesy-indexing): A 0.859 m distance keeps three significant digits (was 0.001 km). (core 0.1.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.distance.value",
        "error": 4.524999894783832e-7,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.4524999894783832
      },
      "exampleSource": "add-navigation-and-geometry geodesic scenario: 5,554,908.791 m, 51.3816479°, 107.9828291°"
    },
    {
      "id": "navigation.geodesic.midpoint",
      "title": "Midpoint on the geodesic",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 58,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib's GeodSolve, called per quantity (tools/vectors/gen_nav_geodesic.py) (GeographicLib 2.7)",
          "count": 18
        },
        {
          "source": "Closed form on WGS 84: equatorial arc s = a * dlon; meridian quadrant 10,001,965.729313 m (GeographicLib 2.x)",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v018",
        "path": "result.lon.value",
        "error": 6.224354365258478e-12,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.006224354365258478
      },
      "exampleSource": "Karney direct at half the inverse distance"
    },
    {
      "id": "navigation.geodesic.spherical-direct",
      "title": "Great-circle destination (spherical)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 67,
        "exact": 21
      },
      "failures": [],
      "sources": [
        {
          "source": "The great-circle formulas on a sphere of 6,371.008771 km, transcribed from their definitions (tools/vectors/gen_nav_sphere_vincenty.py) (definition)",
          "count": 16
        },
        {
          "source": "Spherical formulas in Python and GeographicLib GeodSolve (tools/vectors/gen_sphere.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v016",
        "path": "result.final_course.value",
        "error": 3.069544618483633e-12,
        "abs": 1e-8,
        "rel": 0,
        "used": 0.0003069544618483633
      },
      "exampleSource": "Worked from the spherical formulas on R1, with the ellipsoidal end from the geodesic direct"
    },
    {
      "id": "navigation.geodesic.spherical-inverse",
      "title": "Great-circle distance and course (spherical)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 78,
        "exact": 21
      },
      "failures": [],
      "sources": [
        {
          "source": "The great-circle formulas on a sphere of 6,371.008771 km, transcribed from their definitions (tools/vectors/gen_nav_sphere_vincenty.py) (definition)",
          "count": 16
        },
        {
          "source": "Spherical formulas in Python and GeographicLib GeodSolve (tools/vectors/gen_sphere.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 4
        },
        {
          "source": "add-navigation-and-geometry geodesic scenarios (JFK to Heathrow: 5,540,019 m on R1, about 14,890 m shorter than the geodesic) (GeodSolve: GeographicLib version 2.7)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.course_difference.value",
        "error": 3.743139131984208e-11,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.03743139131984208
      },
      "exampleSource": "Worked from the spherical formulas; the distance equals the haversine scenario's 5,540,019 m"
    },
    {
      "id": "navigation.geodesic.vertex",
      "title": "Highest point of a geodesic (vertex)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 63,
        "exact": 38
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib's GeodSolve, called per quantity (tools/vectors/gen_nav_geodesic.py) (GeographicLib 2.7)",
          "count": 14
        },
        {
          "source": "GeographicLib GeodSolve -a (Karney 2013), checked against Clairaut's relation (GeographicLib 2.x)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.along.value",
        "error": 4.842877388000488e-8,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.04842877388000488
      },
      "exampleSource": "Karney (2013) auxiliary sphere; GeographicLib GeodSolve -a"
    },
    {
      "id": "navigation.geodesic.vincenty-direct",
      "title": "Vincenty direct (legacy)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 58,
        "exact": 21
      },
      "failures": [],
      "sources": [
        {
          "source": "Vincenty's 1975 inverse and direct methods, implemented from the paper's own formulas (tools/vectors/gen_nav_sphere_vincenty.py) (Vincenty (1975), Survey Review XXIII no. 176)",
          "count": 16
        },
        {
          "source": "Closed form on WGS 84: equatorial arc s = a * dlon; meridian quadrant 10,001,965.729313 m (Vincenty agrees within 1 mm) (GeographicLib 2.x)",
          "count": 4
        },
        {
          "source": "add-navigation-and-geometry geodesic scenarios (GeographicLib GeodSolve values) (Vincenty agrees within 1 mm) (GeographicLib 2.x)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.lat2.value",
        "error": 3.967752348899012e-8,
        "abs": 1e-7,
        "rel": 0,
        "used": 0.3967752348899012
      },
      "exampleSource": "Compared with the Karney direct solution for the same inputs"
    },
    {
      "id": "navigation.geodesic.vincenty-inverse",
      "title": "Vincenty inverse (legacy)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 52,
        "exact": 22
      },
      "failures": [],
      "sources": [
        {
          "source": "Vincenty's 1975 inverse and direct methods, implemented from the paper's own formulas (tools/vectors/gen_nav_sphere_vincenty.py) (Vincenty (1975), Survey Review XXIII no. 176)",
          "count": 16
        },
        {
          "source": "Closed form on WGS 84: equatorial arc s = a * dlon; meridian quadrant 10,001,965.729313 m (GeographicLib 2.x)",
          "count": 3
        },
        {
          "source": "add-navigation-and-geometry geodesic scenarios (GeographicLib GeodSolve values) (GeographicLib 2.x)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.distance.value",
        "error": 4.4073385652154684e-7,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.44073385652154684
      },
      "exampleSource": "add-navigation-and-geometry scenario: sub-millimeter from Karney"
    },
    {
      "id": "navigation.geodesic.waypoints",
      "title": "Waypoints along a route line",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 176,
        "exact": 22
      },
      "failures": [],
      "sources": [
        {
          "source": "Karney's geographiclib (Python): points along the geodesic by the direct problem (2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v013",
        "path": "result.length.value",
        "error": 5.4569682106375694e-12,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.005456968210637569
      },
      "exampleSource": "navigation geodesic scenario: 11 points, each 555,490.879 m apart along the geodesic"
    },
    {
      "id": "navigation.los.dip",
      "title": "Dip of the horizon",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 46,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "Spherical Earth with effective radius R/(1 - k), evaluated in Python (tools/vectors/gen_los.py) (2026)",
          "count": 22
        },
        {
          "source": "Bowditch (NGA Pub. 9, 2024) Table 12's horizon rule 1.17 sqrt(h ft) and the printed dip rule 1.76' sqrt(h m), which together fix the effective radius at 7666208 m, i.e. k = 0.1689; the rule value is that printed coefficient evaluated directly, and the dip is held only to the 0.25% the two rules agree to (NGA Pub. 9, 2024 edition)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v013",
        "path": "result.dip.value",
        "error": 3.552713678800501e-15,
        "abs": 1e-9,
        "rel": 1e-10,
        "used": 0.0000013653068015555794
      },
      "exampleSource": "Bowditch (NGA Pub. 9) Table 12 and the 1.76′√h dip rule, which are the same rule: together they fix the effective radius at 7,666,208 m, and the exact dip on it is 5.5526′ against the rule's 5.5656′"
    },
    {
      "id": "navigation.los.fresnel",
      "title": "Fresnel zone and radio link clearance",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 68,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "Spherical Earth with effective radius R/(1 - k), evaluated in Python (tools/vectors/gen_los.py) (2026)",
          "count": 22
        },
        {
          "source": "ITU-R P.530's printed working form F1 = 17.3 sqrt(d1 d2 / (f d)) and the microwave-path Earth bulge d1 d2 / (12.75 K), K = 4/3; each published constant is short of the exact form by its own rounding, 0.084% and 0.063% (ITU-R P.530)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v023",
        "path": "result.fresnel_radius.value",
        "error": 0.009530101184914486,
        "abs": 0,
        "rel": 0.001,
        "used": 0.8390646046269769
      },
      "exampleSource": "ITU-R P.530's printed form F1 = 17.3 √(d1 d2 / (f d)) gives 11.3580 m against the tool's 11.3675 m, and the microwave-path Earth bulge d1 d2 / (12.75 K) gives 1.4706 m against 1.4715 m; each published constant is short by its own rounding, 0.084% and 0.063%, at every frequency and distance alike"
    },
    {
      "id": "navigation.los.horizon",
      "title": "Distance to the horizon",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 29,
      "checks": {
        "numeric": 95,
        "exact": 29
      },
      "failures": [],
      "sources": [
        {
          "source": "Spherical Earth with effective radius R/(1 - k), evaluated in Python (tools/vectors/gen_los.py) (2026)",
          "count": 22
        },
        {
          "source": "Bowditch, The American Practical Navigator (NGA Pub. 9), Volume II, Table 12, Distance of the Horizon (2024 edition)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v025",
        "path": "result.rule_visual.value",
        "error": 0.05000000000000071,
        "abs": 0.051,
        "rel": 0,
        "used": 0.980392156862759
      },
      "exampleSource": "navigation line-of-sight scenario: geometric 35.70 km, optical (k = 0.13) 38.27 km, radio 41.22 km"
    },
    {
      "id": "navigation.los.visibility",
      "title": "Can two points see each other?",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 67,
        "exact": 46
      },
      "failures": [],
      "sources": [
        {
          "source": "Spherical Earth with effective radius R/(1 - k), evaluated in Python (tools/vectors/gen_los.py) (2026)",
          "count": 22
        },
        {
          "source": "Bowditch (NGA Pub. 9, 2024) Table 12: 700 ft (213.36 m) has a horizon of 31.0 nmi, and the range at which two objects see each other is the two horizon distances added (NGA Pub. 9, 2024 edition)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v023",
        "path": "result.max_range.value",
        "error": 0.23639491972408422,
        "abs": 0.2432,
        "rel": 0,
        "used": 0.9720185843917937
      },
      "exampleSource": "Bowditch's own procedure, the distance to each horizon added together: the tool's range is that sum over 115 pairs of heights printed in NGA Pub. 9 Table 12, within the tenth of a nautical mile the table rounds to plus the 0.231% by which its square-root rule sits above the exact horizon"
    },
    {
      "id": "navigation.rhumb.direct",
      "title": "Destination on a constant course (rhumb line)",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 50,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib RhumbSolve (Karney's Rhumb), WGS 84 (GeographicLib 2.7)",
          "count": 24
        },
        {
          "source": "Bowditch, The American Practical Navigator (NGA Pub. 9), Art. 910, Mercator sailing (2024 edition)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v025",
        "path": "result.lat2.value",
        "error": 0.01702699200016866,
        "abs": 0.02,
        "rel": 0,
        "used": 0.8513496000084331
      },
      "exampleSource": "GeographicLib RhumbSolve on WGS 84"
    },
    {
      "id": "navigation.rhumb.inverse",
      "title": "Rhumb line distance and course",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 91,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib RhumbSolve (Karney's Rhumb), WGS 84 (GeographicLib 2.7)",
          "count": 22
        },
        {
          "source": "Bowditch, The American Practical Navigator (NGA Pub. 9), Art. 910, Mercator sailing (2024 edition)",
          "count": 1
        },
        {
          "source": "Regression for a reported defect (2026-09-23 fix-geodesy-indexing): A short rhumb distance keeps three significant digits; the rhumb-minus-geodesic difference stays at millimeter decimals. (core 0.1.0)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v023",
        "path": "result.distance.value",
        "error": 2.5473804979795887,
        "abs": 2.778,
        "rel": 0,
        "used": 0.9169836205830053
      },
      "exampleSource": "add-navigation-and-geometry rhumb scenario: course 77.968°, 5,774,190 m, 219.3 km (3.9%) longer than the geodesic"
    },
    {
      "id": "navigation.route.closest-point",
      "title": "Closest point on a route",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 71,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "Karney's geographiclib (Python): per-leg perpendicularity bisection, clamped to each leg (2026)",
          "count": 22
        },
        {
          "source": "GeographicLib GeodSolve: the five legs by the inverse problem, the closest point by the course to the position being 90 deg from the leg, the along-route distance as the first leg plus the run to it (GeographicLib 2.7)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v023",
        "path": "result.along_route.value",
        "error": 7.877929419919383e-10,
        "abs": 1e-8,
        "rel": 0,
        "used": 0.07877929419919383
      },
      "exampleSource": "GeographicLib 2.7 GeodSolve: the closest point sits where the course to the position is 90.00000000000 from the leg, 8476.774536 m away, with the first leg and the run up to it summing to the along-route distance"
    },
    {
      "id": "navigation.route.course-intersection",
      "title": "Where two courses cross",
      "version": "1.0.1",
      "stability": "experimental",
      "vectors": 8,
      "checks": {
        "numeric": 28,
        "exact": 9
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib IntersectTool, GeodSolve, and RhumbSolve (tools/vectors/gen_intersect.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 8
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.distance1.value",
        "error": 1.30385160446167e-8,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.0130385160446167
      },
      "exampleSource": "Worked on the ellipsoid: both runs checked by carrying each course its distance with the geodesic direct problem"
    },
    {
      "id": "navigation.route.cpa",
      "title": "Closest point of approach",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 27,
      "checks": {
        "numeric": 64,
        "exact": 27
      },
      "failures": [],
      "sources": [
        {
          "source": "Relative motion in a flat plane: t = -(r.v)/|v|^2, evaluated in Python (2026)",
          "count": 22
        },
        {
          "source": "Relative motion in a local east-north-up frame: t = -(r.v)/|v|^2, evaluated in Python (2026)",
          "count": 4
        },
        {
          "source": "exactly solvable by hand: r = (1000, 1200) m and v = (-10, -10) m/s give t = -(r.v)/|v|^2 = 22000/200 = 110 s, relative position (-100, +100) m, separation 100*sqrt(2) on a bearing of 315 deg, present separation sqrt(1000^2 + 1200^2) (closed form)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v027",
        "path": "result.separation.value",
        "error": 1.7053025658242404e-13,
        "abs": 0,
        "rel": 1e-12,
        "used": 0.0012058310082691392
      },
      "exampleSource": "exactly solvable by hand: with r = (1000, 1200) m and a relative velocity of (−10, −10) m/s, t = −(r·v)/|v|² = 22000/200 = 110 s exactly, the relative position is then (−100, +100) m, so the separation is 100√2 = 141.4213562373095 m on a bearing of exactly 315°, and the present separation is √(1000² + 1200²) = 1562.0499351813308 m"
    },
    {
      "id": "navigation.route.cross-track",
      "title": "Cross-track and along-track distance",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 112,
        "exact": 45
      },
      "failures": [],
      "sources": [
        {
          "source": "Karney's geographiclib (Python): perpendicularity bisection along the geodesic (geographiclib 2.1)",
          "count": 22
        },
        {
          "source": "Ed Williams, Aviation Formulary, Cross track error worked example (LAX to JFK) (version 1.47)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v023",
        "path": "result.along_track.value",
        "error": 0.06773499920466008,
        "abs": 0.08,
        "rel": 0,
        "used": 0.8466874900582511
      },
      "exampleSource": "navigation route-geometry scenario: a point south-east of the JFK-LHR geodesic near the start is right of course"
    },
    {
      "id": "navigation.route.fly-by",
      "title": "Fly-by turn anticipation",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 72,
        "exact": 45
      },
      "failures": [],
      "sources": [
        {
          "source": "Coordinated turn: R = V^2/(g tan bank), lead = R tan(dpsi/2), evaluated in Python (2026)",
          "count": 22
        },
        {
          "source": "the FAA's standard-rate turn (Instrument Flying Handbook, FAA-H-8083-15B): 3 deg/s is 360 deg in two minutes, so at 120 kt the radius is V*T/(2 pi) and the bank that holds it is atan(V*omega/g); a 90 deg turn then takes 30 s and covers 120 kt * 30 s = one nautical mile of arc (FAA-H-8083-15B)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.lead_distance.value",
        "error": 2.7284841053187847e-12,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.0004605476871555693
      },
      "exampleSource": "exact by hand, and tied to the FAA's published standard-rate turn: at 120 kt and 25° of bank R = V²/(g tan 25°) = 833.3860599902922 m and the lead for a 90° turn is R tan 45° = R; at the standard 3°/s instead, the radius is 1179.0198184247606 m, identical to the V·T/(2π) the two-minute definition gives, and the 90° arc is 1852.0000000000002 m — one nautical mile exactly"
    },
    {
      "id": "navigation.route.intercept",
      "title": "Intercept a moving target",
      "version": "1.0.1",
      "stability": "experimental",
      "vectors": 17,
      "checks": {
        "numeric": 80,
        "exact": 18
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib's GeodSolve: the intercept time found by bracketing and bisecting range(t) - v.t (tools/vectors/gen_nav_route.py) (GeographicLib 2.7)",
          "count": 12
        },
        {
          "source": "GeographicLib IntersectTool, GeodSolve, and RhumbSolve (tools/vectors/gen_intersect.py) (GeodSolve: GeographicLib version 2.7)",
          "count": 4
        },
        {
          "source": "add-navigation-and-geometry route-geometry scenarios (unreachable: the target opens faster than the pursuer closes) (GeodSolve: GeographicLib version 2.7)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v013",
        "path": "result.meet_lon.value",
        "error": 3.3166633883752183e-9,
        "abs": 1e-8,
        "rel": 0,
        "used": 0.33166633883752183
      },
      "exampleSource": "Worked in the plane first (t = 10 ÷ √(20² − 12²) = 0.625 h) and refined on the ellipsoid; checked by running both to the meeting point"
    },
    {
      "id": "navigation.route.legs",
      "title": "Route legs, courses, and totals",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 138,
        "exact": 22
      },
      "failures": [],
      "sources": [
        {
          "source": "Karney's geographiclib (Python) geodesic inverse per leg (2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v014",
        "path": "result.total_distance.value",
        "error": 9.094947017729282e-13,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.0009094947017729281
      },
      "exampleSource": "navigation route-geometry scenario: a 4-waypoint route shows true and magnetic courses per leg, with the declination and model"
    },
    {
      "id": "navigation.route.range-rings",
      "title": "Range rings",
      "version": "1.0.1",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 43,
        "exact": 27
      },
      "failures": [],
      "sources": [
        {
          "source": "GeographicLib's GeodSolve, called per quantity (tools/vectors/gen_nav_geodesic.py) (GeographicLib 2.7)",
          "count": 10
        },
        {
          "source": "Ring points by GeodSolve and areas by Planimeter (GeographicLib, C++), via tools/vectors/gen_rings.py (GeodSolve: GeographicLib version 2.7)",
          "count": 7
        },
        {
          "source": "add-navigation-and-geometry scenarios (2026)",
          "count": 4
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.summary.0.area.value",
        "error": 6.605205271625891e-11,
        "abs": 1e-9,
        "rel": 1e-9,
        "used": 0.0008310940237595958
      },
      "exampleSource": "add-navigation-and-geometry range rings"
    },
    {
      "id": "navigation.route.time-speed-distance",
      "title": "Time, speed, and distance",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 29,
      "checks": {
        "numeric": 29,
        "exact": 36
      },
      "failures": [],
      "sources": [
        {
          "source": "distance = speed x time, evaluated in Python (2026)",
          "count": 22
        },
        {
          "source": "Bowditch, The American Practical Navigator (NGA Pub. 9), Volume II, Table 11, Speed, Time, and Distance (2024 edition)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v028",
        "path": "result.distance.value",
        "error": 0.04166666666666696,
        "abs": 0.051,
        "rel": 0,
        "used": 0.8169934640522934
      },
      "exampleSource": "navigation route-geometry scenario: 250 NM at 125 kt is 2 h 00 min"
    },
    {
      "id": "navigation.vector.distance-3d",
      "title": "3D distance between two points",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 65,
        "exact": 22
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ through pyproj, EPSG:4979 to EPSG:4978 (WGS 84 geodetic to geocentric), with the east-north-up rotation applied from its own definition (tools/vectors/gen_nav_vector.py) (pyproj 3.6.1 / PROJ 9.3.0)",
          "count": 12
        },
        {
          "source": "GeographicLib CartConvert -l, GeodSolve -i, and GeoidEval (egm96-15) (tools/vectors/gen_vector3d.py) (GeographicLib 2.x)",
          "count": 6
        },
        {
          "source": "add-navigation-and-geometry scenarios (2026)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.slant_range.value",
        "error": 5.374408829084132e-8,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.05374408829084132
      },
      "exampleSource": "add-navigation-and-geometry drone scenario: straight-line 2,003.694 m, elevation 3.4245°; flat Earth 2,003.597 m and 3.4336°"
    },
    {
      "id": "navigation.vector.look-angles",
      "title": "Look angles to a target",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 85,
        "exact": 22
      },
      "failures": [],
      "sources": [
        {
          "source": "PROJ through pyproj, EPSG:4979 to EPSG:4978 (WGS 84 geodetic to geocentric), with the east-north-up rotation applied from its own definition (tools/vectors/gen_nav_vector.py) (pyproj 3.6.1 / PROJ 9.3.0)",
          "count": 16
        },
        {
          "source": "GeographicLib CartConvert -l, GeodSolve -i, and GeoidEval (egm96-15) (tools/vectors/gen_vector3d.py) (GeographicLib 2.x)",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.slant_range.value",
        "error": 1.0477378964424133e-9,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.0010477378964424133
      },
      "exampleSource": "Local east-north-up from GeographicLib LocalCartesian conventions"
    },
    {
      "id": "navigation.vector.operations",
      "title": "Vector sum, dot, and cross product",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 104,
        "exact": 24
      },
      "failures": [],
      "sources": [
        {
          "source": "Exact trigonometry and vector algebra from the definitions (tools/vectors/gen_nav_vector.py) (definition)",
          "count": 16
        },
        {
          "source": "Vector algebra evaluated in Python (tools/vectors/gen_vector3d.py) (2026)",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.magnitude",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Component-wise sum: (4, 3), magnitude 5, direction 053.1301° from north"
    },
    {
      "id": "navigation.vector.polar-cartesian",
      "title": "Vector components and direction",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 75,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "Exact trigonometry and vector algebra from the definitions (tools/vectors/gen_nav_vector.py) (definition)",
          "count": 16
        },
        {
          "source": "Vector algebra evaluated in Python (tools/vectors/gen_vector3d.py) (2026)",
          "count": 8
        },
        {
          "source": "add-navigation-and-geometry scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.y",
        "error": 6.123233995736766e-16,
        "abs": 1e-12,
        "rel": 0,
        "used": 0.0006123233995736767
      },
      "exampleSource": "add-navigation-and-geometry navigational-convention scenario: (10, 0)"
    },
    {
      "id": "raster.index.band-math",
      "title": "Band math",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 12,
      "checks": {
        "numeric": 12,
        "exact": 12
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 12
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.value",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "The NDVI definition written as band math: it gives the same 0.6981 as the NDVI tool"
    },
    {
      "id": "raster.index.dnbr",
      "title": "dNBR (burn severity)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 10,
        "exact": 20
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 10
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.dnbr",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Key and Benson 2006: a drop of 0.48 falls in the moderate-high range (0.44 to 0.66)"
    },
    {
      "id": "raster.index.evi",
      "title": "EVI",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 10,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 10
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.evi",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Huete and others 2002: NIR 0.45, red 0.08, blue 0.04 give 0.5675"
    },
    {
      "id": "raster.index.evi2",
      "title": "EVI2",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 10,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 10
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.evi2",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Jiang and others 2008 formula: NIR 0.45 and red 0.08 give 0.5633"
    },
    {
      "id": "raster.index.mndwi",
      "title": "MNDWI",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 10,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 10
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.mndwi",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Xu 2006: green 0.12 and SWIR1 0.03 give 0.6"
    },
    {
      "id": "raster.index.nbr",
      "title": "NBR",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 10,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 10
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.nbr",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Key and Benson 2006: NIR 0.33 and SWIR2 0.08 give 0.6098"
    },
    {
      "id": "raster.index.ndbi",
      "title": "NDBI",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 10,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 10
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.ndbi",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Zha and others 2003: SWIR1 0.31 and NIR 0.26 give 0.0877"
    },
    {
      "id": "raster.index.ndvi",
      "title": "NDVI",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 10,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 10
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.ndvi",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-spatial-indexing-and-raster imagery-indices scenario: NIR 0.45 and red 0.08 give 0.6981"
    },
    {
      "id": "raster.index.ndwi-gao",
      "title": "NDWI (Gao, vegetation water)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 10,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 10
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.ndwi",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Gao 1996: NIR 0.38 and SWIR1 0.22 give 0.2667"
    },
    {
      "id": "raster.index.ndwi-mcfeeters",
      "title": "NDWI (McFeeters, open water)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 10,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 10
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.ndwi",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "McFeeters 1996: green 0.12 and NIR 0.04 give 0.5"
    },
    {
      "id": "raster.index.savi",
      "title": "SAVI",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 30,
      "checks": {
        "numeric": 30,
        "exact": 30
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 30
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.savi",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Huete 1988 formula with L = 0.5: NIR 0.45 and red 0.08 give 0.5388"
    },
    {
      "id": "raster.scale.reflectance",
      "title": "Digital number to reflectance",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 17,
      "checks": {
        "numeric": 17,
        "exact": 17
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 17
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.reflectance",
        "error": 0,
        "abs": 1e-12,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-spatial-indexing-and-raster imagery-indices scenario: (1450 - 1000) / 10000 = 0.045"
    },
    {
      "id": "raster.terrain.ruggedness",
      "title": "Terrain ruggedness and position",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 28,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.tri.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "The definitions worked independently in Python (tools/vectors/gen_raster.py)"
    },
    {
      "id": "raster.terrain.slope-aspect",
      "title": "Slope, aspect, and hillshade",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 19,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Index formulas transcribed from their papers in Python (tools/vectors/gen_raster.py) (2026-09-22)",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.slope.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "Horn's formulas worked independently in Python (tools/vectors/gen_raster.py)"
    },
    {
      "id": "survey.cogo.angular-closure",
      "title": "Angular closure of a loop traverse",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 8,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.misclosure.value",
        "error": 7.275957614183426e-11,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.0723975882008301
      },
      "exampleSource": "add-survey-suite angular-misclosure scenario: +25\""
    },
    {
      "id": "survey.cogo.area-by-coordinates",
      "title": "Area by coordinates (acreage)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 74,
        "exact": 40
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 17
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 2
        },
        {
          "source": "Wikipedia, Shoelace formula (worked example) (retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v017",
        "path": "result.perimeter.value",
        "error": 3.637978807091713e-12,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0.00002142840305822545
      },
      "exampleSource": "add-survey-suite scenario: 5,000 ft², 0.1148 ac"
    },
    {
      "id": "survey.cogo.forward",
      "title": "Coordinates from a bearing and distance",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 10,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.northing.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "Inverse of the add-survey-suite inverse scenario"
    },
    {
      "id": "survey.cogo.intersection",
      "title": "Intersection (bearings and distances)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 12,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.solutions.0.easting.value",
        "error": 1.4210854715202004e-14,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.00001353414734781143
      },
      "exampleSource": "add-survey-suite two-solution scenario"
    },
    {
      "id": "survey.cogo.inverse",
      "title": "Inverse between two coordinates",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 10,
        "exact": 12
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 4
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.distance.value",
        "error": 5.684341886080802e-14,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.00004294840945103892
      },
      "exampleSource": "add-survey-suite scenario: N 45°00'00\" E, 141.421"
    },
    {
      "id": "survey.cogo.least-squares-2d",
      "title": "Least-squares network adjustment (2D)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 57,
        "exact": 14
      },
      "failures": [],
      "sources": [
        {
          "source": "Weighted least squares with numerical Jacobians, NumPy and SciPy (tools/vectors/gen_lsq.py) (NumPy 2.x, SciPy 1.x)",
          "count": 5
        },
        {
          "source": "add-survey-suite least-squares scenarios (chi-square failure) (NumPy 2.x, SciPy 1.x)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.adjusted.1.semi_major.value",
        "error": 1.2853735437134972e-11,
        "abs": 0.000001,
        "rel": 0.00001,
        "used": 0.000010910820246277518
      },
      "exampleSource": "Weighted least squares after Ghilani and Wolf (2021), chapter 16"
    },
    {
      "id": "survey.cogo.offset-shot",
      "title": "Total-station offset shot",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 15,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.distance.value",
        "error": 2.2737367544323206e-13,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.00019758737818225685
      },
      "exampleSource": "add-survey-suite tree-center scenario"
    },
    {
      "id": "survey.cogo.resection",
      "title": "Three-point resection",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 8,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 4
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.northing.value",
        "error": 7.787548383930698e-12,
        "abs": 1e-9,
        "rel": 1e-8,
        "used": 0.0000015571982371387118
      },
      "exampleSource": "Angles computed from a station at (500, 1350)"
    },
    {
      "id": "survey.cogo.station-offset",
      "title": "Station and offset from a line",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 14,
        "exact": 16
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.offset.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "Plane geometry"
    },
    {
      "id": "survey.cogo.traverse-closure",
      "title": "Traverse closure and adjustment",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 26,
      "checks": {
        "numeric": 172,
        "exact": 32
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 22
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 2
        },
        {
          "source": "University of Memphis CIVL 1112, Surveying - Traverse Calculations (latitudes and departures example, group example 1) (course notes, retrieved 2026-09-19)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v022",
        "path": "result.misclosure.value",
        "error": 0.00048324062259985645,
        "abs": 0.0005,
        "rel": 0,
        "used": 0.9664812451997129
      },
      "exampleSource": "add-survey-suite scenario: ΣLat 0.1198, ΣDep 0.0200, misclosure 0.1215, precision about 1:11,525"
    },
    {
      "id": "survey.curves.circular-curve",
      "title": "Horizontal circular curve",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 93,
        "exact": 25
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 12
        },
        {
          "source": "Headquarters, Department of the Army, FM 5-233 Construction Surveying, chapter 3 (simple curves) (FM 5-233 (1985))",
          "count": 4
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 3
        },
        {
          "source": "Arc definition D = 18000/(πR) with stationing (15th edition (2018))",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v020",
        "path": "result.length.value",
        "error": 0.004480712166241574,
        "abs": 0.005,
        "rel": 0,
        "used": 0.8961424332483148
      },
      "exampleSource": "add-survey-suite scenario: T 133.975, L 261.799, C 258.819, E 17.638, M 17.037 ft"
    },
    {
      "id": "survey.curves.curve-layout",
      "title": "Circular curve layout table",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 13,
        "exact": 14
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.tangent.value",
        "error": 1.4210854715202004e-14,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.000012808135719464313
      },
      "exampleSource": "add-survey-suite layout-table scenario"
    },
    {
      "id": "survey.curves.sight-distance",
      "title": "Vertical curve length for sight distance",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 6,
        "exact": 16
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 6
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.min_length.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0
      },
      "exampleSource": "add-survey-suite crest SSD scenario: about 368.3 ft, S > L"
    },
    {
      "id": "survey.curves.spiral",
      "title": "Spiral-curve-spiral transition",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 24,
        "exact": 16
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.total_tangent.value",
        "error": 4.320099833421409e-12,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.000004320099833421409
      },
      "exampleSource": "add-survey-suite spiral-curve-spiral scenario"
    },
    {
      "id": "survey.curves.unequal-vertical-curve",
      "title": "Unequal-tangent vertical curve",
      "version": "1.0.1",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 18,
        "exact": 14
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        },
        {
          "source": "Worked by hand: curve elevation at the PVI station = 100 + 300 x 300 x (-0.03 - 0.02) / (2 x 600) = 96.25 ft, 3.75 ft below the PVI (Ghilani and Wolf 2021, ch. 25) (Elementary Surveying, 16th edition (2021))",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.turning_elevation.value",
        "error": 1.4210854715202004e-14,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.000012961377886904417
      },
      "exampleSource": "Two-parabola unequal-tangent curve"
    },
    {
      "id": "survey.curves.vertical-curve",
      "title": "Vertical curve",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 77,
        "exact": 79
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 19
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        },
        {
          "source": "Indiana Department of Transportation, Indiana Design Manual chapter 44, example 44-3.1 (figure 44-3G) (Chapter 44 (current), retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.pvc_elevation.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0
      },
      "exampleSource": "add-survey-suite scenario: PVC 7+00 at 94.00 ft; high point 9+40 at 96.40 ft; K = 120"
    },
    {
      "id": "survey.earthwork.average-end-area",
      "title": "Average end area volume",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 10,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 4
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.volume_ft3.value",
        "error": 3.637978807091713e-12,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0.000024092574881402074
      },
      "exampleSource": "add-survey-suite scenario: 15,000 ft³ = 555.56 yd³"
    },
    {
      "id": "survey.earthwork.borrow-pit",
      "title": "Grid (borrow-pit) volume",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 14,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.cut_volume.value",
        "error": 3.410605131648481e-13,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0.000035566430508579494
      },
      "exampleSource": "add-survey-suite corner-weights scenario"
    },
    {
      "id": "survey.earthwork.grade",
      "title": "Side slope and grade (H:V)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 23,
        "exact": 12
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 8
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v010",
        "path": "result.slope_length.value",
        "error": 2.842170943040401e-14,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.000022736458176923776
      },
      "exampleSource": "add-survey-suite scenario: 3H:1V is about 18.43° and 33.3%"
    },
    {
      "id": "survey.earthwork.prismoidal",
      "title": "Prismoidal volume",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 15,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 4
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.difference.value",
        "error": 7.958078640513122e-13,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0.0006382221483975888
      },
      "exampleSource": "add-survey-suite scenario: 14,866.7 ft³"
    },
    {
      "id": "survey.earthwork.profile-grades",
      "title": "Profile grade analysis",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 20,
        "exact": 9
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.segments.1.grade",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0
      },
      "exampleSource": "add-survey-suite grade-threshold scenario: the 11% segment is flagged"
    },
    {
      "id": "survey.earthwork.section-area",
      "title": "Cross-section cut and fill areas",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 11,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.cut_area.value",
        "error": 2.9023894398960692e-9,
        "abs": 0.000001,
        "rel": 0.000001,
        "used": 0.00006609190403352275
      },
      "exampleSource": "add-survey-suite mixed-section scenario"
    },
    {
      "id": "survey.earthwork.shrink-swell",
      "title": "Swell, shrink, and truck loads",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 13,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 4
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.loose_volume.value",
        "error": 4.547473508864641e-13,
        "abs": 1e-9,
        "rel": 1e-11,
        "used": 0.000015900257024002244
      },
      "exampleSource": "add-survey-suite scenario: 1,250 loose yd³, 105 loads"
    },
    {
      "id": "survey.earthwork.slope-stake",
      "title": "Slope stake (catch point)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 8,
        "exact": 13
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.catch_offset.value",
        "error": 1.7763568394002505e-14,
        "abs": 1e-9,
        "rel": 0.000001,
        "used": 6.410099882057334e-10
      },
      "exampleSource": "add-survey-suite catch-point scenario on planar ground"
    },
    {
      "id": "survey.earthwork.solid-volume",
      "title": "Cone, frustum, and prism volumes",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 6,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.volume.value",
        "error": 9.094947017729282e-13,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.00015091469688561295
      },
      "exampleSource": "πr²h/3 = 5,026.55 ft³"
    },
    {
      "id": "survey.earthwork.stockpile",
      "title": "Stockpile volume (TIN)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 12,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.volume.value",
        "error": 9.094947017729282e-13,
        "abs": 1e-9,
        "rel": 1e-10,
        "used": 0.0000028333168279530474
      },
      "exampleSource": "A square pyramid: base area × height / 3 = 8,333.33 ft³"
    },
    {
      "id": "survey.gnss.antenna-height",
      "title": "Antenna height from a slant measurement",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 8,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Worked by hand in Python (tools/vectors/gen_gnss.py) (2026)",
          "count": 4
        },
        {
          "source": "add-practitioner-essentials GNSS scenarios (1.800 m slant, 0.100 m radius: about 1.7972 m) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.vertical.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials antenna scenario: √(1.8² − 0.1²) ≈ 1.7972 m, with the formula shown"
    },
    {
      "id": "survey.gnss.localization",
      "title": "Site localization (calibration)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 18,
        "exact": 11
      },
      "failures": [],
      "sources": [
        {
          "source": "Least squares by NumPy lstsq (tools/vectors/gen_localize.py) (NumPy 2.x)",
          "count": 4
        },
        {
          "source": "add-practitioner-essentials localization scenarios (feet entered as meters) (NumPy 2.x)",
          "count": 1
        },
        {
          "source": "add-practitioner-essentials localization scenarios (two points: no redundancy) (NumPy 2.x)",
          "count": 1
        },
        {
          "source": "Least squares by NumPy lstsq (tools/vectors/gen_localize.py) (three points: no redundancy) (NumPy 2.x)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.rms.value",
        "error": 5.8165925977517675e-11,
        "abs": 0.000001,
        "rel": 0,
        "used": 0.000058165925977517675
      },
      "exampleSource": "Built at scale 0.99997 and 1.5° rotation with a few millimeters of noise; least squares after Ghilani and Wolf (2021)"
    },
    {
      "id": "survey.gnss.opus-plan",
      "title": "OPUS session planning",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 3,
        "exact": 19
      },
      "failures": [],
      "sources": [
        {
          "source": "Worked by hand in Python (tools/vectors/gen_gnss.py) (2026)",
          "count": 5
        },
        {
          "source": "add-practitioner-essentials GNSS scenarios (a one-hour session gets rapid-static processing) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.day_of_year",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials OPUS scenario: a one-hour session gets rapid-static processing, with NGS's requirements stated"
    },
    {
      "id": "survey.gnss.rtk-budget",
      "title": "RTK and PPK precision budget",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 5,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "Worked by hand in Python (tools/vectors/gen_gnss.py) (2026)",
          "count": 4
        },
        {
          "source": "add-practitioner-essentials GNSS scenarios (8 mm + 1 ppm at 15 km: 23 mm) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.horizontal.value",
        "error": 7.105427357601002e-15,
        "abs": 1e-9,
        "rel": 0,
        "used": 0.000007105427357601001
      },
      "exampleSource": "add-practitioner-essentials RTK scenario: 23 mm horizontal (a + b·d, as manufacturers state it)"
    },
    {
      "id": "survey.land.alta-rpp",
      "title": "ALTA/NSPS relative positional precision",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 6,
        "exact": 11
      },
      "failures": [],
      "sources": [
        {
          "source": "Worked by hand in Python (tools/vectors/gen_gnss.py) (2026)",
          "count": 3
        },
        {
          "source": "add-practitioner-essentials GNSS scenarios (0.12 ft allowable at 1,000 ft) (2026)",
          "count": 1
        },
        {
          "source": "add-practitioner-essentials GNSS scenarios (a misclosure is refused: RPP comes from the error ellipse) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.allowable.value",
        "error": 2.7755575615628914e-17,
        "abs": 1e-12,
        "rel": 0,
        "used": 0.000027755575615628914
      },
      "exampleSource": "add-practitioner-essentials RPP scenario: 0.12 ft allowable at 1,000 ft"
    },
    {
      "id": "survey.land.basis-rotation",
      "title": "Basis-of-bearing rotation",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 5,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python arithmetic on the BLM Manual unit definitions and latitudes and departures (tools/vectors/gen_survey.py) (BLM Manual of Surveying Instructions (2009))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.rotation.value",
        "error": 7.57900686654267e-15,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.000007578943708678431
      },
      "exampleSource": "add-practitioner-essentials rotation scenario: every call rotates by +0°02'30\""
    },
    {
      "id": "survey.land.deed-parse",
      "title": "Deed parser (metes and bounds)",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 5,
        "exact": 10
      },
      "failures": [],
      "sources": [
        {
          "source": "Hand-parsed call forms (Brown's Boundary Control, ch. 5) (7th edition (2014))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.count",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0
      },
      "exampleSource": "Constructed example exercising symbol, word, and dash bearings and a natural-boundary call (Brown's Boundary Control, ch. 5 call forms)"
    },
    {
      "id": "survey.land.deed-plot",
      "title": "Deed plot, closure, and area",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 55,
        "exact": 28
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python arithmetic on the BLM Manual unit definitions and latitudes and departures (tools/vectors/gen_survey.py) (Ghilani and Wolf, 15th ed. (2018))",
          "count": 17
        },
        {
          "source": "Independent Python arithmetic on the BLM Manual unit definitions and latitudes and departures (tools/vectors/gen_survey.py) (BLM Manual of Surveying Instructions (2009))",
          "count": 2
        },
        {
          "source": "University of Memphis CIVL 1112, Surveying - Traverse Calculations (latitudes and departures example, group example 1) (course notes, retrieved 2026-09-19)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v018",
        "path": "result.misclosure.value",
        "error": 0.00046608085224797424,
        "abs": 0.0005,
        "rel": 0,
        "used": 0.9321617044959485
      },
      "exampleSource": "Hand-computed latitudes and departures (Ghilani and Wolf, ch. 10): misclosure about 0.42 ft over 1,850 ft, precision about 1:4,400"
    },
    {
      "id": "survey.land.legacy-units",
      "title": "Legacy land units",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 7,
      "checks": {
        "numeric": 7,
        "exact": 7
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python arithmetic on the BLM Manual unit definitions and latitudes and departures (tools/vectors/gen_survey.py) (BLM Manual of Surveying Instructions (2009))",
          "count": 7
        }
      ],
      "worst": {
        "vector": "v007",
        "path": "result.us_survey_feet.value",
        "error": 3.552713678800501e-15,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.0000035039906882799676
      },
      "exampleSource": "add-practitioner-essentials legacy-units scenario: 814.44 US survey feet (1 chain = 66 ftUS; 1 link = 0.66 ftUS)"
    },
    {
      "id": "survey.land.plss-parse",
      "title": "PLSS legal description reader",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 5,
      "checks": {
        "numeric": 5,
        "exact": 5
      },
      "failures": [],
      "sources": [
        {
          "source": "Independent Python arithmetic on the BLM Manual unit definitions and latitudes and departures (tools/vectors/gen_survey.py) (BLM Manual of Surveying Instructions (2009))",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.nominal_area.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials PLSS scenario: the northeast quarter of the southwest quarter of section 12, nominal 40 acres"
    },
    {
      "id": "survey.reduction.combined-factor",
      "title": "Combined scale factor (grid and ground)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 63,
        "exact": 23
      },
      "failures": [],
      "sources": [
        {
          "source": "NOAA Manual NOS NGS 5 (Stem 1990), section 4, evaluated in Python (1990)",
          "count": 16
        },
        {
          "source": "NOAA Manual NOS NGS 5, State Plane Coordinate System of 1983 (Stem), section 4.4 example, steps 4 and 5 (1990)",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v022",
        "path": "result.grid_distance.value",
        "error": 0.00044501887532533146,
        "abs": 0.0005,
        "rel": 0,
        "used": 0.8900377506506629
      },
      "exampleSource": "NOAA Manual NOS NGS 5 formula with R = 20,906,000 ft"
    },
    {
      "id": "survey.reduction.curvature-refraction",
      "title": "Curvature and refraction correction",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 11,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 4
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 2
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.correction.value",
        "error": 2.168404344971009e-19,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 2.1684010137475081e-10
      },
      "exampleSource": "add-survey-suite scenario: ≈ 0.0675 m with k = 0.14, ≈ 0.0683 m with k = 0.13"
    },
    {
      "id": "survey.reduction.edm-correction",
      "title": "EDM atmospheric and prism corrections",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 9,
      "checks": {
        "numeric": 21,
        "exact": 12
      },
      "failures": [],
      "sources": [
        {
          "source": "IAG 1999 closed formula worked in Python (tools/vectors/gen_edm.py) (2026)",
          "count": 8
        },
        {
          "source": "add-survey-suite ppm scenario (1,000.000 + 0.012 - 0.030 = 999.982 m) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.corrected.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-survey-suite ppm scenario: 1,000.000 + 0.012 − 0.030 = 999.982 m, each correction listed"
    },
    {
      "id": "survey.reduction.inaccessible-height",
      "title": "Height of an inaccessible object",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 13,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 5
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v005",
        "path": "result.distance_used.value",
        "error": 1.4210854715202004e-13,
        "abs": 1e-9,
        "rel": 1e-10,
        "used": 0.000014210854715202004
      },
      "exampleSource": "One-station trigonometric height"
    },
    {
      "id": "survey.reduction.level-run",
      "title": "Level run reduction and closure",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 16,
        "exact": 8
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.sum_backsights.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0
      },
      "exampleSource": "A level loop in the textbook's note form"
    },
    {
      "id": "survey.reduction.slope",
      "title": "Slope distance to horizontal and vertical",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 10,
      "checks": {
        "numeric": 17,
        "exact": 12
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 7
        },
        {
          "source": "add-survey-suite scenarios (2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.horizontal_distance.value",
        "error": 0,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0
      },
      "exampleSource": "add-survey-suite scenario: HD ≈ 498.097 m, VD ≈ 43.578 m"
    },
    {
      "id": "survey.reduction.stadia",
      "title": "Stadia reduction",
      "version": "1.0.0",
      "stability": "experimental",
      "vectors": 6,
      "checks": {
        "numeric": 16,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "Surveying formulas (Ghilani & Wolf 2018) evaluated in Python (tools/vectors/gen_survey.py) (15th edition (2018))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v006",
        "path": "result.horizontal_distance.value",
        "error": 2.842170943040401e-14,
        "abs": 1e-9,
        "rel": 1e-12,
        "used": 0.00002471692144105509
      },
      "exampleSource": "Stadia formulas with K = 100, C = 0"
    },
    {
      "id": "time.scale.block-time",
      "title": "Block time (out to in)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 23,
        "exact": 48
      },
      "failures": [],
      "sources": [
        {
          "source": "Exact integer arithmetic on minutes, adding 24 h when a clock-only in time precedes out (definition)",
          "count": 18
        },
        {
          "source": "Clock arithmetic with Python datetime (tools/vectors/gen_time.py) (2026)",
          "count": 5
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.minutes",
        "error": 0,
        "abs": 0.000001,
        "rel": 1e-15,
        "used": 0
      },
      "exampleSource": "Across-midnight arithmetic: 3 h 25 min"
    },
    {
      "id": "time.scale.decimal-hours",
      "title": "Decimal hours to hours and minutes",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 50,
        "exact": 55
      },
      "failures": [],
      "sources": [
        {
          "source": "Exact integer arithmetic on minutes: minutes = round(hours x 60); hours = h + mm/60 (definition)",
          "count": 20
        },
        {
          "source": "Hours-to-minutes arithmetic (tools/vectors/gen_time.py) (2026)",
          "count": 4
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.minutes",
        "error": 0,
        "abs": 0.000001,
        "rel": 1e-15,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials scenario: 1.3 h is 1 h 18 min"
    },
    {
      "id": "time.scale.gps-to-utc",
      "title": "GPS week and seconds to UTC",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 21,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "TAI - UTC accumulated from the IANA tzdb leapseconds file (10 s at 1972-01-01); GPS - UTC = TAI - UTC - 19 s; week and seconds of week from the GPS epoch 1980-01-06 (IANA tzdb 2026c)",
          "count": 16
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 3
        },
        {
          "source": "Python datetime and the IERS Bulletin C 72 leap-second table (tools/vectors/gen_time.py) (Bulletin C 72 (2026-07-06))",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.gps_week",
        "error": 0,
        "abs": 0.000001,
        "rel": 1e-15,
        "used": 0
      },
      "exampleSource": "Inverse of the add-practitioner-essentials GPS week scenario"
    },
    {
      "id": "time.scale.gps-week",
      "title": "UTC to GPS week and seconds",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 123,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "TAI - UTC accumulated from the IANA tzdb leapseconds file (10 s at 1972-01-01); GPS - UTC = TAI - UTC - 19 s; week and seconds of week from the GPS epoch 1980-01-06 (IANA tzdb 2026c)",
          "count": 16
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 4
        },
        {
          "source": "Python datetime and the IERS Bulletin C 72 leap-second table (tools/vectors/gen_time.py) (Bulletin C 72 (2026-07-06))",
          "count": 4
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.gps_week",
        "error": 0,
        "abs": 0.000001,
        "rel": 1e-15,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials scenario: week 2436, seconds of week 432018, GPS − UTC 18 s"
    },
    {
      "id": "time.scale.julian-date",
      "title": "Julian date, MJD, and day of year",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 84,
        "exact": 31
      },
      "failures": [],
      "sources": [
        {
          "source": "JD = 2440587.5 + (POSIX seconds)/86400, with the calendar and day of year from Python's datetime (proleptic Gregorian); MJD = JD - 2400000.5 (CPython 3.13 datetime)",
          "count": 17
        },
        {
          "source": "USNO Julian date definition evaluated with Python datetime (tools/vectors/gen_time.py) (2024)",
          "count": 4
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 2
        },
        {
          "source": "USNO Julian date definition (2024)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.jd",
        "error": 0,
        "abs": 0.000001,
        "rel": 1e-15,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials scenario: JD 2461301.5, MJD 61301, day 261"
    },
    {
      "id": "time.scale.utc-offset",
      "title": "Local time to UTC (Zulu)",
      "version": "1.1.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 5,
        "exact": 81
      },
      "failures": [],
      "sources": [
        {
          "source": "Python zoneinfo on tzdata 2026d (core/crates/gp-time/tests/data/tz_diff.csv) (2026d)",
          "count": 7
        },
        {
          "source": "Python zoneinfo documentation, America/Los_Angeles examples (docs.python.org/3/library/zoneinfo.html) (retrieved 2026-09-19)",
          "count": 5
        },
        {
          "source": "Python datetime with fixed offsets (tools/vectors/gen_time.py) (2026)",
          "count": 4
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 3
        },
        {
          "source": "IANA tzdb 2026d (US DST: second Sunday in March to first Sunday in November, 2:00 local) (2026d)",
          "count": 3
        },
        {
          "source": "IANA tzdb 2026d America/Anchorage: AKDT is UTC−8 in July, so 0300Z on July 2 is 19:00 on July 1 local (2026d)",
          "count": 1
        },
        {
          "source": "IANA tzdb 2026d America/Anchorage: AKDT is UTC−8 in July, so 2300Z is 15:00 local (2026d)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.day_shift",
        "error": 0,
        "abs": 0.000001,
        "rel": 1e-15,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials Zulu scenario: 1905Z"
    },
    {
      "id": "time.scale.zone-info",
      "title": "Time zone rules at a date",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 26,
      "checks": {
        "numeric": 0,
        "exact": 129
      },
      "failures": [],
      "sources": [
        {
          "source": "Python zoneinfo on the system IANA release: offset, abbreviation, DST state, and the next transition by bisection (IANA tzdb 2026c)",
          "count": 20
        },
        {
          "source": "IANA tzdb 2026d (checked with Python zoneinfo on tzdata 2026d) (2026d)",
          "count": 5
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 1
        }
      ],
      "worst": null,
      "exampleSource": "IANA tzdb 2026d: MDT (-06:00) until 2026-11-01 08:00 UTC"
    },
    {
      "id": "time.sun.aviation-nights",
      "title": "The four aviation nights",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 0,
        "exact": 67
      },
      "failures": [],
      "sources": [
        {
          "source": "USNO sunset and civil twilight (retrieved 2026-09-19, tools/vectors/gen_usno_sun.py --nights) with 14 CFR 61.57(b) and 1.1 (API 4.0.1)",
          "count": 16
        },
        {
          "source": "USNO sunset and civil twilight (retrieved 2026-09-18) with the 14 CFR 61.57(b) and 1.1 definitions (API 4.0.1)",
          "count": 4
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 2
        }
      ],
      "worst": null,
      "exampleSource": "add-practitioner-essentials scenario: loggable night that does not count toward §61.57(b)"
    },
    {
      "id": "time.sun.events",
      "title": "Sunrise, sunset, and twilight",
      "version": "1.0.2",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 13,
        "exact": 57
      },
      "failures": [],
      "sources": [
        {
          "source": "USNO Astronomical Applications API rstt/oneday, retrieved 2026-09-19 (tools/vectors/gen_usno_sun.py) (API 4.0.1)",
          "count": 13
        },
        {
          "source": "USNO Astronomical Applications API rstt/oneday, retrieved 2026-09-18 (API 4.0.1)",
          "count": 7
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 1
        },
        {
          "source": "Hand computation of the sun's lowest altitude, latitude + declination − 90°: at Anchorage (61.22° N) on the June solstice (declination 23.44°) it is −5.34°, above the −6° civil twilight limit, so civil twilight neither begins nor ends (Meeus, Astronomical Algorithms, 2nd edition)",
          "count": 1
        },
        {
          "source": "Hand computation of the sun's lowest altitude, latitude + declination − 90°: at Utqiagvik (71.29° N) on the June solstice (declination 23.44°) it is +4.73°, above the −0.833° sunrise altitude, so the sun does not set (Meeus, Astronomical Algorithms, 2nd edition)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v014",
        "path": "result.day_minutes",
        "error": 1,
        "abs": 2,
        "rel": 0,
        "used": 0.5
      },
      "exampleSource": "add-practitioner-essentials scenario: evening events after 00:00Z are dated on the next UTC day"
    },
    {
      "id": "time.sun.hotspot",
      "title": "Sun hotspot in a camera frame",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 23,
      "checks": {
        "numeric": 86,
        "exact": 46
      },
      "failures": [],
      "sources": [
        {
          "source": "Sun position from pvlib's NREL SPA (sea level, 101325 Pa, 12 C); antisolar point and hotspot angle by vector geometry (tools/vectors/gen_sun_pvlib.py) (pvlib 0.13.0)",
          "count": 17
        },
        {
          "source": "NOAA solar equations (tools/vectors/gen_sun.py) and vector geometry (tools/vectors/gen_hotspot.py) (NOAA GML 2023)",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.sun_azimuth.value",
        "error": 0.008227782667262318,
        "abs": 0.02,
        "rel": 0,
        "used": 0.4113891333631159
      },
      "exampleSource": "NREL SPA sun position; with the sun near 73° up, the antisolar point is 17° off nadir, inside an 84° field of view"
    },
    {
      "id": "time.sun.mapping-window",
      "title": "Mapping light window",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 21,
      "checks": {
        "numeric": 19,
        "exact": 53
      },
      "failures": [],
      "sources": [
        {
          "source": "Sun position from pvlib's NREL SPA (sea level, 101325 Pa, 12 C); threshold crossings by bisection (tools/vectors/gen_sun_pvlib.py) (pvlib 0.13.0)",
          "count": 16
        },
        {
          "source": "NOAA solar calculator equations transcribed in Python (tools/vectors/gen_sun.py) (NOAA GML 2023)",
          "count": 5
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.max_elevation.value",
        "error": 0.0025277700576680218,
        "abs": 0.01,
        "rel": 0,
        "used": 0.2527770057668022
      },
      "exampleSource": "add-practitioner-essentials mapping-window scenario"
    },
    {
      "id": "time.sun.night-currency",
      "title": "Night passenger currency",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 54,
        "exact": 114
      },
      "failures": [],
      "sources": [
        {
          "source": "Sun position from pvlib's NREL SPA (sea level, 101325 Pa, 12 C); 14 CFR 61.57(b) applied by hand (tools/vectors/gen_sun_pvlib.py) (pvlib 0.13.0)",
          "count": 16
        },
        {
          "source": "Counting worked by hand (tools/vectors/gen_currency.py) (2026)",
          "count": 5
        },
        {
          "source": "add-practitioner-essentials currency scenario (May 1, May 10, and June 2 give currency through July 30, 2026) (2026)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.aircraft.0.takeoffs",
        "error": 0,
        "abs": 0,
        "rel": 0,
        "used": 0
      },
      "exampleSource": "add-practitioner-essentials currency scenario: landings on May 1, May 10, and June 2 give currency through July 30, 2026"
    },
    {
      "id": "time.sun.position",
      "title": "Sun position (azimuth and elevation)",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 28,
      "checks": {
        "numeric": 103,
        "exact": 30
      },
      "failures": [],
      "sources": [
        {
          "source": "pvlib.solarposition.spa_python (NREL SPA port) (pvlib 0.13.0)",
          "count": 25
        },
        {
          "source": "add-practitioner-essentials scenarios (2026)",
          "count": 2
        },
        {
          "source": "NREL/TP-560-34302 Table A5.1 (published to 1e-5) (2008)",
          "count": 1
        }
      ],
      "worst": {
        "vector": "v029",
        "path": "result.equation_of_time.value",
        "error": 0.000007770820786845434,
        "abs": 0.00001,
        "rel": 0,
        "used": 0.7770820786845433
      },
      "exampleSource": "NREL SPA"
    },
    {
      "id": "units.acceleration.convert",
      "title": "Acceleration converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v011",
        "path": "result.converted.value",
        "error": 5.551115123125783e-17,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.36291895414800973
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.angle.convert",
      "title": "Angle converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 110,
      "checks": {
        "numeric": 110,
        "exact": 220
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 110
        }
      ],
      "worst": {
        "vector": "v029",
        "path": "result.converted.value",
        "error": 3.3881317890172014e-21,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.4065758146820641
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.angle.deg-to-rad",
      "title": "Degrees to radians",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 2e-15,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.angle.rad-to-deg",
      "title": "Radians to degrees",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 2e-15,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.angular-rate.convert",
      "title": "Angular rate converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 40,
      "checks": {
        "numeric": 40,
        "exact": 80
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 40
        }
      ],
      "worst": {
        "vector": "v024",
        "path": "result.converted.value",
        "error": 3.2311742677852644e-27,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.2936681426104135
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.area.ac-to-ha",
      "title": "Acres to hectares",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.converted.value",
        "error": 5.684341886080802e-14,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.438947334421807
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.area.convert",
      "title": "Area converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 75,
      "checks": {
        "numeric": 75,
        "exact": 150
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 75
        }
      ],
      "worst": {
        "vector": "v002",
        "path": "result.converted.value",
        "error": 3.552713678800501e-15,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.438947334421807
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.area.ft2-to-ac",
      "title": "Square feet to acres",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.area.ha-to-ac",
      "title": "Hectares to acres",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 3.552713678800501e-15,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.28754644336004276
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.charge.convert",
      "title": "Battery charge converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.data-rate.convert",
      "title": "Data rate converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v012",
        "path": "result.converted.value",
        "error": 1.3234889800848443e-23,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.44116299336161474
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.density.convert",
      "title": "Density converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v004",
        "path": "result.converted.value",
        "error": 2.2737367544323206e-13,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.4549511168789484
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.energy.convert",
      "title": "Energy converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 34,
      "checks": {
        "numeric": 34,
        "exact": 68
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 34
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 5.684341886080802e-14,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.31898663782720543
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.frequency.convert",
      "title": "Frequency converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 40,
      "checks": {
        "numeric": 40,
        "exact": 80
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 40
        }
      ],
      "worst": {
        "vector": "v015",
        "path": "result.converted.value",
        "error": 4.235164736271502e-22,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.3388131789017201
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.fuel.convert",
      "title": "Fuel volume and weight",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 20,
      "checks": {
        "numeric": 19,
        "exact": 41
      },
      "failures": [],
      "sources": [
        {
          "source": "FAA-H-8083-25C Chapter 10 nominal fuel weights (avgas 6 lb/gal, jet fuel 6.7 lb/gal); mass = volume x density in SI from the exact gallon, litre and pound, by rational arithmetic (FAA-H-8083-25C (2023))",
          "count": 14
        },
        {
          "source": "FAA-H-8083-25C Chapter 10 nominal fuel weights (avgas 6 lb/gal, jet fuel 6.7 lb/gal); mass = volume x density by exact rational arithmetic (FAA-H-8083-25C (2023))",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v018",
        "path": "result.volume.value",
        "error": 7.105427357601002e-15,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.35527136788005004
      },
      "exampleSource": "FAA-H-8083-25C Chapter 10 (6 lb/gal)"
    },
    {
      "id": "units.length.convert",
      "title": "Length converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 135,
      "checks": {
        "numeric": 135,
        "exact": 270
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 135
        }
      ],
      "worst": {
        "vector": "v101",
        "path": "result.converted.value",
        "error": 1.8189894035458565e-12,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.44354237616062164
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.ft-to-m",
      "title": "Feet to meters",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.ftus-to-ft",
      "title": "US survey feet to international feet",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.converted.value",
        "error": 2.3283064365386963e-10,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.2328301779925823
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.ftus-to-m",
      "title": "US survey feet to meters",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.in-to-mm",
      "title": "Inches to millimeters",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.km-to-mi",
      "title": "Kilometers to miles",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.km-to-nm",
      "title": "Kilometers to nautical miles",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.m-to-ft",
      "title": "Meters to feet",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.m-to-ftus",
      "title": "Meters to US survey feet",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 1.1641532182693481e-10,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.23283064365480094
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.mi-to-km",
      "title": "Miles to kilometers",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.mi-to-nm",
      "title": "Statute miles to nautical miles",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.mm-to-in",
      "title": "Millimeters to inches",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 1.1102230246251565e-16,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.22204460492503128
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.nm-to-km",
      "title": "Nautical miles to kilometers",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 2.842170943040401e-14,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.3069299074557668
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.length.nm-to-mi",
      "title": "Nautical miles to statute miles",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.mass.convert",
      "title": "Mass converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 24,
        "exact": 48
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 24
        }
      ],
      "worst": {
        "vector": "v012",
        "path": "result.converted.value",
        "error": 4.547473508864641e-13,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.42972901799961005
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.mass.kg-to-lb",
      "title": "Kilograms to pounds",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.mass.lb-to-kg",
      "title": "Pounds to kilograms",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 2.2737367544323206e-13,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.39315541058435366
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.power.convert",
      "title": "Power converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v012",
        "path": "result.converted.value",
        "error": 2.220446049250313e-16,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.3311572667562635
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.pressure.convert",
      "title": "Pressure converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 73,
      "checks": {
        "numeric": 73,
        "exact": 146
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 73
        }
      ],
      "worst": {
        "vector": "v069",
        "path": "result.converted.value",
        "error": 8.881784197001252e-16,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.4293979623136615
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.pressure.hpa-to-inhg",
      "title": "HPa to inHg",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.pressure.inhg-to-hpa",
      "title": "InHg to hPa",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 1.1368683772161603e-13,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.2244097635633817
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.pressure.kpa-to-psi",
      "title": "KPa to psi",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 3.552713678800501e-15,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.24495098547448751
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.pressure.psi-to-kpa",
      "title": "Psi to kPa",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 2.842170943040401e-14,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.2748146958807433
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.quantity.normalize",
      "title": "Normalize a unit-tagged value",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 24,
      "checks": {
        "numeric": 23,
        "exact": 46
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 24
        }
      ],
      "worst": {
        "vector": "v007",
        "path": "result.normalized.value",
        "error": 2.2737367544323206e-13,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.39315541058435366
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.slope.convert",
      "title": "Slope and grade converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 84,
        "exact": 26
      },
      "failures": [],
      "sources": [
        {
          "source": "Definition of grade: ratio = rise/run = tan(angle); angles from Python math.tan and math.atan (definition)",
          "count": 19
        },
        {
          "source": "Definition of grade: ratio = rise/run = tan(angle); angles from Python math.atan (definition)",
          "count": 6
        }
      ],
      "worst": {
        "vector": "v021",
        "path": "result.percent.value",
        "error": 1.4210854715202004e-14,
        "abs": 1e-15,
        "rel": 2e-15,
        "used": 0.12201294879606768
      },
      "exampleSource": "Definition of grade: angle = atan(0.0833) = 4.76°; a 1:12 ramp is 8.33%"
    },
    {
      "id": "units.speed.convert",
      "title": "Speed converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 47,
      "checks": {
        "numeric": 47,
        "exact": 94
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 47
        }
      ],
      "worst": {
        "vector": "v022",
        "path": "result.converted.value",
        "error": 4.547473508864641e-13,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.4065805114805698
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.speed.kmh-to-kt",
      "title": "Km/h to knots",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.speed.kt-to-kmh",
      "title": "Knots to km/h",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.converted.value",
        "error": 1.4210854715202004e-14,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.4384712963653812
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.speed.kt-to-mph",
      "title": "Knots to mph",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.speed.kt-to-mps",
      "title": "Knots to m/s",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.speed.mph-to-kt",
      "title": "Mph to knots",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.speed.mps-to-kt",
      "title": "M/s to knots",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 3.552713678800501e-15,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.3655347629521404
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.temperature-difference.convert",
      "title": "Temperature difference converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.temperature.c-to-f",
      "title": "Celsius to Fahrenheit",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.temperature.convert",
      "title": "Temperature converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.temperature.f-to-c",
      "title": "Fahrenheit to Celsius",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.time.convert",
      "title": "Time converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 25,
      "checks": {
        "numeric": 25,
        "exact": 50
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 25
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.vertical-speed.convert",
      "title": "Vertical speed converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 22,
      "checks": {
        "numeric": 22,
        "exact": 44
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 22
        }
      ],
      "worst": {
        "vector": "v011",
        "path": "result.converted.value",
        "error": 1.1102230246251565e-16,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.24283093277015672
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.vertical-speed.fpm-to-mps",
      "title": "Ft/min to m/s",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.volume.convert",
      "title": "Volume converter",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 45,
      "checks": {
        "numeric": 45,
        "exact": 90
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 45
        }
      ],
      "worst": {
        "vector": "v011",
        "path": "result.converted.value",
        "error": 8.673617379884035e-19,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.4420970869389862
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.volume.gal-to-l",
      "title": "US gallons to liters",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v001",
        "path": "result.converted.value",
        "error": 0,
        "abs": 0,
        "rel": 5e-16,
        "used": 0
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    },
    {
      "id": "units.volume.l-to-gal",
      "title": "Liters to US gallons",
      "version": "1.0.0",
      "stability": "stable",
      "vectors": 3,
      "checks": {
        "numeric": 3,
        "exact": 6
      },
      "failures": [],
      "sources": [
        {
          "source": "NIST SP 811 (2008) Appendix B.8 and NIST Handbook 44 Appendix C exact definitions; expected value by exact rational arithmetic (tools/vectors/gen_units.py) (SP 811 2008; HB44 2026)",
          "count": 3
        }
      ],
      "worst": {
        "vector": "v003",
        "path": "result.converted.value",
        "error": 1.1102230246251565e-16,
        "abs": 0,
        "rel": 5e-16,
        "used": 0.22204460492503128
      },
      "exampleSource": "Exact unit definitions (NIST SP 811 Appendix B)"
    }
  ]
}
