{
  "contract_version": "1.0.0",
  "build": {
    "method_version": "1.0.0",
    "source_revision": "96262e1e48ed26a7b8286a9bfaabed006548a74d",
    "generator": "scripts/generate_data_quality.py"
  },
  "dataset": {
    "record_count": 1989,
    "data_as_of": "2026-08-06",
    "version": "2026.08.06",
    "revision": "96262e1e48ed26a7b8286a9bfaabed006548a74d"
  },
  "sources": {
    "canonical_dataset": {
      "source_id": "canonical_dataset",
      "type": "canonical_csv",
      "path": "gaapitchfinder_data.csv",
      "url": "https://github.com/ryanmcg2203/gaapitchfinder/blob/96262e1e48ed26a7b8286a9bfaabed006548a74d/gaapitchfinder_data.csv",
      "data_as_of": "2026-08-06",
      "revision": "96262e1e48ed26a7b8286a9bfaabed006548a74d",
      "available": true,
      "limitation": null
    },
    "osm_coverage_snapshot": {
      "source_id": "osm_coverage_snapshot",
      "type": "derived_csv",
      "path": "data/derived/osm_coverage_report.csv",
      "url": "https://github.com/ryanmcg2203/gaapitchfinder/blob/26268d1155e795149a1b69ea9be432d69b087463/data/derived/osm_coverage_report.csv",
      "data_as_of": "2026-07-05",
      "revision": "26268d1155e795149a1b69ea9be432d69b087463",
      "available": true,
      "limitation": "The snapshot is refreshed manually and can predate the canonical dataset."
    }
  },
  "metrics": [
    {
      "metric_id": "record_count",
      "label": "Pitch records",
      "value": 1989,
      "unit": "records",
      "numerator": null,
      "denominator": null,
      "percentage": null,
      "status": "informational",
      "threshold": null,
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Count data rows in the canonical CSV, excluding the header.",
      "summary": "1,989 pitch records are published in the current dataset.",
      "limitation": null,
      "details": {}
    },
    {
      "metric_id": "valid_coordinates",
      "label": "Valid coordinates",
      "value": 1989,
      "unit": "records",
      "numerator": 1989,
      "denominator": 1989,
      "percentage": 100.0,
      "status": "pass",
      "threshold": {
        "operator": "gte",
        "value": 100,
        "unit": "percent"
      },
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Parse finite WGS 84 latitude and longitude values and enforce world bounds.",
      "summary": "1,989 of 1,989 records have valid coordinate pairs.",
      "limitation": null,
      "details": {
        "missing_records": 0,
        "invalid_records": 0
      }
    },
    {
      "metric_id": "missing_coordinates",
      "label": "Missing coordinates",
      "value": 0,
      "unit": "records",
      "numerator": null,
      "denominator": null,
      "percentage": null,
      "status": "pass",
      "threshold": {
        "operator": "eq",
        "value": 0,
        "unit": "records"
      },
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Count rows where latitude or longitude is blank.",
      "summary": "0 records have a blank latitude or longitude.",
      "limitation": "Malformed nonblank coordinates are reported under valid coordinates rather than this metric.",
      "details": {}
    },
    {
      "metric_id": "missing_required_identity_location",
      "label": "Missing required identity or location",
      "value": 0,
      "unit": "records",
      "numerator": null,
      "denominator": null,
      "percentage": null,
      "status": "pass",
      "threshold": {
        "operator": "eq",
        "value": 0,
        "unit": "records"
      },
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Count rows missing any required identity or location field: File, Club, Province, Country, Division, or County.",
      "summary": "0 records are missing a required identity or location field.",
      "limitation": "Pitch name is intentionally optional and is not included in this metric.",
      "details": {}
    },
    {
      "metric_id": "shared_coordinate_groups",
      "label": "Shared coordinate groups",
      "value": 21,
      "unit": "groups",
      "numerator": null,
      "denominator": null,
      "percentage": null,
      "status": "review",
      "threshold": {
        "operator": "review_above",
        "value": 0,
        "unit": "groups"
      },
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Group records that have exactly equal numeric latitude and longitude values.",
      "summary": "21 coordinate groups are shared by more than one record.",
      "limitation": "Shared coordinates are review prompts, not errors; multiple clubs can legitimately use one ground.",
      "details": {
        "affected_records": 76
      }
    },
    {
      "metric_id": "likely_duplicate_groups",
      "label": "Likely duplicate groups",
      "value": 0,
      "unit": "groups",
      "numerator": null,
      "denominator": null,
      "percentage": null,
      "status": "pass",
      "threshold": {
        "operator": "review_above",
        "value": 0,
        "unit": "groups"
      },
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Group normalized club, pitch, county, and country names at coordinates rounded to five decimal places.",
      "summary": "0 groups match the duplicate-candidate rule.",
      "limitation": "Candidates require human review because a club can have multiple records at one complex.",
      "details": {
        "affected_records": 0
      }
    },
    {
      "metric_id": "valid_directions_links",
      "label": "Valid directions links",
      "value": 1989,
      "unit": "records",
      "numerator": 1989,
      "denominator": 1989,
      "percentage": 100.0,
      "status": "pass",
      "threshold": {
        "operator": "gte",
        "value": 100,
        "unit": "percent"
      },
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Require an allowed Google Maps host, one finite daddr pair, and coordinates matching the canonical point within 0.00001 degrees.",
      "summary": "1,989 of 1,989 directions links are valid and coordinate-aligned.",
      "limitation": null,
      "details": {}
    },
    {
      "metric_id": "elevation_coverage",
      "label": "Elevation coverage",
      "value": 1985,
      "unit": "records",
      "numerator": 1985,
      "denominator": 1989,
      "percentage": 99.8,
      "status": "pass",
      "threshold": {
        "operator": "gte",
        "value": 95,
        "unit": "percent"
      },
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Count nonblank finite elevation values between -500 and 9,000 metres.",
      "summary": "1,985 of 1,989 records include a valid elevation value.",
      "limitation": "Elevation values are enrichment estimates and are not surveyed ground heights.",
      "details": {}
    },
    {
      "metric_id": "rainfall_coverage",
      "label": "Rainfall coverage",
      "value": 1985,
      "unit": "records",
      "numerator": 1985,
      "denominator": 1989,
      "percentage": 99.8,
      "status": "pass",
      "threshold": {
        "operator": "gte",
        "value": 95,
        "unit": "percent"
      },
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Count rows with valid annual rainfall and rain-days values within the published schema ranges.",
      "summary": "1,985 of 1,989 records include both rainfall fields.",
      "limitation": "Rainfall fields are modelled annual estimates rather than observations at each pitch.",
      "details": {}
    },
    {
      "metric_id": "wikipedia_link_coverage",
      "label": "Reviewed Wikipedia links",
      "value": 1126,
      "unit": "records",
      "numerator": 1126,
      "denominator": 1989,
      "percentage": 56.6,
      "status": "informational",
      "threshold": null,
      "source_id": "canonical_dataset",
      "data_as_of": "2026-08-06",
      "method": "Count nonblank Wikipedia URLs that use an allowed Wikipedia hostname.",
      "summary": "1,126 of 1,989 records include a reviewed Wikipedia link.",
      "limitation": "Not every club has a suitable Wikipedia article, so no completeness target is applied.",
      "details": {}
    },
    {
      "metric_id": "osm_geometry_match_coverage",
      "label": "OSM geometry-match coverage",
      "value": 96.3,
      "unit": "percent",
      "numerator": 1621,
      "denominator": 1683,
      "percentage": 96.3,
      "status": "informational",
      "threshold": null,
      "source_id": "osm_coverage_snapshot",
      "data_as_of": "2026-07-05",
      "method": "Treat matched_gaa and matched_generic as matches, no_match as evaluated nonmatches, and exclude unavailable statuses from the denominator.",
      "summary": "1,621 of 1,683 evaluated snapshot rows have a nearby OSM pitch match.",
      "limitation": "This is a historical proximity check against OSM pitch geometry, not proof that every match is correctly tagged. The snapshot contains 1,683 rows while the current canonical dataset contains 1,686 Ireland records.",
      "details": {
        "snapshot_records": 1683,
        "current_ireland_records": 1686,
        "unavailable_records": 0,
        "county_breakdown": [
          {
            "county": "Antrim",
            "matched": 45,
            "evaluated": 48,
            "percentage": 93.8,
            "unavailable": 0
          },
          {
            "county": "Armagh",
            "matched": 44,
            "evaluated": 50,
            "percentage": 88.0,
            "unavailable": 0
          },
          {
            "county": "Carlow",
            "matched": 28,
            "evaluated": 28,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Cavan",
            "matched": 43,
            "evaluated": 43,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Clare",
            "matched": 47,
            "evaluated": 53,
            "percentage": 88.7,
            "unavailable": 0
          },
          {
            "county": "Cork",
            "matched": 157,
            "evaluated": 167,
            "percentage": 94.0,
            "unavailable": 0
          },
          {
            "county": "Derry",
            "matched": 37,
            "evaluated": 40,
            "percentage": 92.5,
            "unavailable": 0
          },
          {
            "county": "Donegal",
            "matched": 43,
            "evaluated": 44,
            "percentage": 97.7,
            "unavailable": 0
          },
          {
            "county": "Down",
            "matched": 51,
            "evaluated": 51,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Dublin",
            "matched": 104,
            "evaluated": 106,
            "percentage": 98.1,
            "unavailable": 0
          },
          {
            "county": "Fermanagh",
            "matched": 22,
            "evaluated": 23,
            "percentage": 95.7,
            "unavailable": 0
          },
          {
            "county": "Galway",
            "matched": 83,
            "evaluated": 84,
            "percentage": 98.8,
            "unavailable": 0
          },
          {
            "county": "Kerry",
            "matched": 68,
            "evaluated": 70,
            "percentage": 97.1,
            "unavailable": 0
          },
          {
            "county": "Kildare",
            "matched": 49,
            "evaluated": 49,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Kilkenny",
            "matched": 42,
            "evaluated": 43,
            "percentage": 97.7,
            "unavailable": 0
          },
          {
            "county": "Laois",
            "matched": 45,
            "evaluated": 45,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Leitrim",
            "matched": 23,
            "evaluated": 25,
            "percentage": 92.0,
            "unavailable": 0
          },
          {
            "county": "Limerick",
            "matched": 59,
            "evaluated": 68,
            "percentage": 86.8,
            "unavailable": 0
          },
          {
            "county": "Longford",
            "matched": 25,
            "evaluated": 25,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Louth",
            "matched": 40,
            "evaluated": 40,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Mayo",
            "matched": 58,
            "evaluated": 58,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Meath",
            "matched": 67,
            "evaluated": 68,
            "percentage": 98.5,
            "unavailable": 0
          },
          {
            "county": "Monaghan",
            "matched": 30,
            "evaluated": 31,
            "percentage": 96.8,
            "unavailable": 0
          },
          {
            "county": "Offaly",
            "matched": 45,
            "evaluated": 46,
            "percentage": 97.8,
            "unavailable": 0
          },
          {
            "county": "Roscommon",
            "matched": 34,
            "evaluated": 34,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Sligo",
            "matched": 25,
            "evaluated": 26,
            "percentage": 96.2,
            "unavailable": 0
          },
          {
            "county": "Tipperary",
            "matched": 76,
            "evaluated": 76,
            "percentage": 100.0,
            "unavailable": 0
          },
          {
            "county": "Tyrone",
            "matched": 52,
            "evaluated": 55,
            "percentage": 94.5,
            "unavailable": 0
          },
          {
            "county": "Waterford",
            "matched": 49,
            "evaluated": 50,
            "percentage": 98.0,
            "unavailable": 0
          },
          {
            "county": "Westmeath",
            "matched": 41,
            "evaluated": 45,
            "percentage": 91.1,
            "unavailable": 0
          },
          {
            "county": "Wexford",
            "matched": 50,
            "evaluated": 51,
            "percentage": 98.0,
            "unavailable": 0
          },
          {
            "county": "Wicklow",
            "matched": 39,
            "evaluated": 41,
            "percentage": 95.1,
            "unavailable": 0
          }
        ]
      }
    }
  ]
}
