{
 "release_id": "ve-audit-sample-r3-2026-09-12",
 "release_number": 3,
 "previous_release_id": "ve-audit-sample-r2-2026-09-12",
 "title": "Sample release (Databricks-ready): visitor product inventory, illustrative prototype",
 "snapshot_date": "2026-09-12",
 "generated": "2026-09-12T19:49:37+00:00",
 "generated_note": "Taken from data/processed/meta.json generated (pipeline run); no wall-clock time is written by the export.",
 "publisher": "Hestia Forge (illustrative prototype for VisitBritain/VisitEngland tender BTA2235)",
 "prototype_url": "https://visitengland-tender.hestiaforge.com/",
 "page_url": "https://visitengland-tender.hestiaforge.com/sample-release/",
 "unity_catalog": {
  "catalog": "ve_audit",
  "schema": "sample",
  "example_volume_path": "/Volumes/ve_audit/sample/release/"
 },
 "files": [
  {
   "path": "product.parquet",
   "table": "product",
   "format": "parquet",
   "rows": 19846,
   "bytes": 1875004,
   "sha256": "e5606b71d95f3fb603a8465f768f434392ace9632f0b40d2af8b837038d98f28"
  },
  {
   "path": "product.csv",
   "table": "product",
   "format": "csv",
   "rows": 19846,
   "bytes": 8779409,
   "sha256": "44ab879f5a5fd895622315226cb0be4ef7c151d5edd5485b66016e34839f1414"
  },
  {
   "path": "product_attribute_provenance.parquet",
   "table": "product_attribute_provenance",
   "format": "parquet",
   "rows": 95921,
   "bytes": 970765,
   "sha256": "4b37d16c25ff112b25c5363337cc2c563a49ce0144f5b961ecd0cef82f4f8961"
  },
  {
   "path": "product_attribute_provenance.csv",
   "table": "product_attribute_provenance",
   "format": "csv",
   "rows": 95921,
   "bytes": 14228330,
   "sha256": "9ba6f4012d9edc92a0a193253e15f2e946026b1005a12d1e4a6959daa95bd4c2"
  },
  {
   "path": "product_source_xref.parquet",
   "table": "product_source_xref",
   "format": "parquet",
   "rows": 22316,
   "bytes": 1040346,
   "sha256": "d244f981a53a413a53b5a619500e21313cb9c64070affb2f1d03ce2ec01725a2"
  },
  {
   "path": "product_source_xref.csv",
   "table": "product_source_xref",
   "format": "csv",
   "rows": 22316,
   "bytes": 6426494,
   "sha256": "d148980030b22fe6ec2d129b4bca9fd42e51f5d786a62205bcc2d3ddc8edffc9"
  },
  {
   "path": "product_relationship.parquet",
   "table": "product_relationship",
   "format": "parquet",
   "rows": 3043,
   "bytes": 180436,
   "sha256": "0b642ccf62a69bcf0760cd9dfeeeace43b8ae26869095e0c773b852ab24c226f"
  },
  {
   "path": "product_relationship.csv",
   "table": "product_relationship",
   "format": "csv",
   "rows": 3043,
   "bytes": 776264,
   "sha256": "42deba8c60beecb038609429bd44afec94cf7652f5cd7e89dffdbd97d58d60d8"
  },
  {
   "path": "product_lineage_event.parquet",
   "table": "product_lineage_event",
   "format": "parquet",
   "rows": 2808,
   "bytes": 245137,
   "sha256": "b2ef9cc448b161af4644b7af0575d70020a8cb201539f0764059229ddd6a5773"
  },
  {
   "path": "product_lineage_event.csv",
   "table": "product_lineage_event",
   "format": "csv",
   "rows": 2808,
   "bytes": 1000476,
   "sha256": "62d20e70bcec4a4ef5cd3739e80592064f3767334d791810703d35eed22f8a59"
  },
  {
   "path": "product_change_set.parquet",
   "table": "product_change_set",
   "format": "parquet",
   "rows": 93,
   "bytes": 13246,
   "sha256": "f42f27c8ce3c9356c19e4f981b9e48cb0885834538e0aeb67f3645017fbc293b"
  },
  {
   "path": "product_change_set.csv",
   "table": "product_change_set",
   "format": "csv",
   "rows": 93,
   "bytes": 77597,
   "sha256": "56370f5a1216d0a4b7ddac3bc44e6ad64732ec465b487168c702b627ca5e339a"
  },
  {
   "path": "lvep_membership.parquet",
   "table": "lvep_membership",
   "format": "parquet",
   "rows": 13,
   "bytes": 5640,
   "sha256": "821e5ca741f7c77dc45e47273a0c09e4a4332db1b38bbf0a34e7a7001857bcc6"
  },
  {
   "path": "lvep_membership.csv",
   "table": "lvep_membership",
   "format": "csv",
   "rows": 13,
   "bytes": 2411,
   "sha256": "5e3a1c502de2cf9670d3b84b8f606fa096e2d21a1ca34e7df6c76ddf65f683a3"
  },
  {
   "path": "ve_product_id_registry.csv",
   "table": null,
   "format": "csv",
   "rows": 19846,
   "bytes": 3433440,
   "sha256": "47c9f259dd98787d471d836fbd16f0b9d749c6d0201cf176a9907b37a7c67f3d",
   "description": "ve_product_id registry: every id ever published, the release that minted it, status and replacing id"
  },
  {
   "path": "match_precision_pairs.csv",
   "table": null,
   "format": "csv",
   "rows": 819,
   "bytes": 127800,
   "sha256": "4e025bfb2c095772047607d3fdfd89a698393a46f135db8c8ee7dbfdf183052b",
   "description": "Match precision test: the 819 identifier hold-out pairs, the rule's best candidate, score and band"
  },
  {
   "path": "same_name_pairs.csv",
   "table": null,
   "format": "csv",
   "rows": 197,
   "bytes": 29958,
   "sha256": "c6e64a8c6bd20d59fc4078d56e74bac3b44f393c0e98bfa67d02828d18151c6d",
   "description": "Same-name pairs within 150 m, marked for the 100 m text rule and the release rule"
  },
  {
   "path": "match_precision_summary.json",
   "table": null,
   "format": "json",
   "rows": null,
   "bytes": 1545,
   "sha256": "873e11c0192f3fe2a2b1ae6364d561d69deef6dab984d5cdaf10273a9d87c5dd",
   "description": "Match precision test and same-name check: figures computed by the script"
  },
  {
   "path": "match_precision_test.py",
   "table": null,
   "format": "python",
   "rows": null,
   "bytes": 11627,
   "sha256": "737f761df487044a04dee5447a92f14ba53f9751fda266fe6f8f5f5b3c71586a",
   "description": "Script that produced the match test files (reads the raw source downloads)"
  },
  {
   "path": "data_dictionary.json",
   "table": null,
   "format": "json",
   "rows": null,
   "bytes": 56945,
   "sha256": "0114ccf80a96ee3228b539204dd83fff59ffc5fa96a634489cc6d571c766229c",
   "description": "Data dictionary: tables, keys, columns, types, derivations, examples, enums"
  },
  {
   "path": "ddl.sql",
   "table": null,
   "format": "sql",
   "rows": null,
   "bytes": 20591,
   "sha256": "7ced54343801ba00f7a564cb733e79b0b60b842847db06669e71cb95a7d34f94",
   "description": "Databricks SQL DDL for Unity Catalog, with commented load example"
  },
  {
   "path": "spark-read-log.txt",
   "table": null,
   "format": "text",
   "rows": null,
   "bytes": 34834,
   "sha256": "1bf5d7a8c62671a6c3da669237ad2eaa7f3d9668b15e26855dfcdd7a6cba99ac",
   "description": "Log of the local Spark read check (real output)"
  }
 ],
 "checksums_cover": "Every data file, ve_product_id_registry.csv, the match test files, data_dictionary.json, ddl.sql and spark-read-log.txt. Not covered: manifest.json itself, and index.html and release.css (the web page for this release).",
 "row_counts": {
  "product": 19846,
  "product_attribute_provenance": 95921,
  "product_source_xref": 22316,
  "product_relationship": 3043,
  "product_lineage_event": 2808,
  "product_change_set": 93,
  "lvep_membership": 13
 },
 "lineage_event_counts": {
  "merge": 2470,
  "review_candidate_kept_separate": 228,
  "same_name_candidate": 108,
  "unit_group": 2,
  "split": 0,
  "product_merge": 0,
  "retire": 0
 },
 "change_set_counts": {
  "inserted": 0,
  "updated": 93,
  "retired": 0
 },
 "change_set_updated_products": 72,
 "change_set_updated_columns": {
  "nearest_product_m": 72,
  "checks": 21
 },
 "changes_since_previous_release": [
  {
   "attributes": [
    "checks",
    "nearest_product_m"
   ],
   "change": "Latent heritage rule for area designations: World Heritage Sites, registered parks and gardens and registered battlefields are now measured from their Historic England boundary (boundaries retrieved 13 September 2026, pipeline/fetch_nhle_areas.py and area_rule.py) instead of one representative point. A visitor product record inside the site or within 500 m of its boundary counts, so the check latent_asset is removed where one exists (for example the Cornwall and West Devon Mining Landscape, with East Pool Mine and Heartlands inside), and nearest_product_m is the distance to the boundary (0 inside). Other sources keep the 12 September 2026 snapshot; no other rule changed."
  }
 ],
 "identifiers": {
  "ve_product_id": "Persistent surrogate key, read from the id registry (ve_product_id_registry.csv) and never recomputed. Minted once when a product is first published; all its source records are stored against it, so it stays when survivorship picks a different primary record. Merges keep one id and retire the other (product_merge); splits keep the id on the larger part and mint one (split). Release 1 ids were minted from the SHA-256 of the then-primary source key; the formula is not applied again.",
  "registry": {
   "ids_in_registry": 19846,
   "active": 19846,
   "retired": 0,
   "minted_in_this_release": 0,
   "carried_from_earlier_releases": 19846
  },
  "prototype_id": "Identifier shown in the web prototype. Renumbered at every build: do not store or join on it across releases."
 },
 "match_test": {
  "match_precision": {
   "pairs": 819,
   "auto_merge": 690,
   "auto_merge_correct": 688,
   "precision_pct": 99.7,
   "precision_wilson_95_pct": [
    98.95,
    99.92
   ],
   "review": 115,
   "review_with_tagged_item_first": 112,
   "no_match": 14,
   "auto_merge_recall_pct": 84.0,
   "merged_correctly_or_sent_to_review_pct": 98.0,
   "wrong_auto_merges": [
    "Radisson (way/29450342) -> The Edwardian Manchester, A Radisson Collection Hotel (Q111368147), tagged Free Trade Hall",
    "Hyatt Regency Manchester (way/452432847) -> Hyatt House Manchester (Q111873746), tagged Hyatt Regency Manchester"
   ]
  },
  "same_name_nearby": {
   "rows_in_file": 197,
   "pairs_under_both_rules": 72,
   "text_rule_within_100m": {
    "pairs": 161,
    "same_category_candidates": 94,
    "different_category": 67,
    "of_which_review_band_pairs": 23,
    "rule": "names equal after build.py slug_name (stop words such as the, st, ltd dropped), within 100 m, every pair of records"
   },
   "release_rule_within_150m": {
    "pairs": 108,
    "within_100m": 72,
    "rule": "names equal after postprocess_review.py norm, within 150 m, not a review-band pair, names used 5+ times in one LVEP skipped (check same_name_nearby)"
   }
  }
 },
 "seasonality_by_lvep": [
  {
   "lvep_id": "cornwall",
   "lvep_name": "Cornwall",
   "product_records": 4198,
   "stated": 24,
   "inferred": 379,
   "no_month_evidence": 3795,
   "with_month_limits": 18
  },
  {
   "lvep_id": "greater-manchester",
   "lvep_name": "Greater Manchester",
   "product_records": 5674,
   "stated": 3,
   "inferred": 726,
   "no_month_evidence": 4945,
   "with_month_limits": 2
  },
  {
   "lvep_id": "york-north-yorkshire",
   "lvep_name": "York & North Yorkshire",
   "product_records": 6687,
   "stated": 26,
   "inferred": 488,
   "no_month_evidence": 6173,
   "with_month_limits": 14
  }
 ],
 "spark_read_check": {
  "all_checks_passed": true,
  "checks_failed": 0,
  "checks_total": 107,
  "counts": {
   "lvep_membership": {
    "csv": 13,
    "manifest": 13,
    "parquet": 13
   },
   "product": {
    "csv": 19846,
    "manifest": 19846,
    "parquet": 19846
   },
   "product_attribute_provenance": {
    "csv": 95921,
    "manifest": 95921,
    "parquet": 95921
   },
   "product_change_set": {
    "csv": 93,
    "manifest": 93,
    "parquet": 93
   },
   "product_lineage_event": {
    "csv": 2808,
    "manifest": 2808,
    "parquet": 2808
   },
   "product_relationship": {
    "csv": 3043,
    "manifest": 3043,
    "parquet": 3043
   },
   "product_source_xref": {
    "csv": 22316,
    "manifest": 22316,
    "parquet": 22316
   }
  },
  "counts_match": true,
  "csv_ok": true,
  "ddl_check": {
   "comments_match": true,
   "constraints_accepted_locally": false,
   "constraints_note": "Local Spark rejected the informational PRIMARY KEY / FOREIGN KEY clauses (they need Unity Catalog), so they were removed for this check; their syntax was not validated locally.",
   "executed": true,
   "first_error_with_constraints": "lvep_membership: AnalysisException: [UNSUPPORTED_FEATURE.TABLE_OPERATION] The feature is not supported: Table `spark_catalog`.`ve_audit_sample_local`.`lvep_membership` does not support CONSTRAINT. Please check the current catalog and namespace to make sure the qualified table name is expected, and also check the catalog implementation which is configured by \"spark.sql.catalog\". SQLSTATE: 0A000",
   "insert_ok": true,
   "local_database": "ve_audit_sample_local",
   "schemas_match": true,
   "substitutions": [
    "'ve_audit.sample.' -> 've_audit_sample_local.' (local Spark has no Unity Catalog three-part names)",
    "'USING DELTA' -> 'USING PARQUET' (Delta Lake is not installed in local Spark)",
    "'CREATE CATALOG IF NOT EXISTS ve_audit' not run (not supported by the local session catalog)",
    "'CREATE SCHEMA IF NOT EXISTS ve_audit.sample' -> 'CREATE DATABASE IF NOT EXISTS ve_audit_sample_local'",
    "CONSTRAINT ... PRIMARY KEY / FOREIGN KEY ... NOT ENFORCED clauses removed (attempt 1 failed in local Spark, see log)"
   ]
  },
  "failed_checks": [],
  "files_sha256": {
   "ddl.sql": "7ced54343801ba00f7a564cb733e79b0b60b842847db06669e71cb95a7d34f94",
   "lvep_membership.csv": "5e3a1c502de2cf9670d3b84b8f606fa096e2d21a1ca34e7df6c76ddf65f683a3",
   "lvep_membership.parquet": "821e5ca741f7c77dc45e47273a0c09e4a4332db1b38bbf0a34e7a7001857bcc6",
   "product.csv": "44ab879f5a5fd895622315226cb0be4ef7c151d5edd5485b66016e34839f1414",
   "product.parquet": "e5606b71d95f3fb603a8465f768f434392ace9632f0b40d2af8b837038d98f28",
   "product_attribute_provenance.csv": "9ba6f4012d9edc92a0a193253e15f2e946026b1005a12d1e4a6959daa95bd4c2",
   "product_attribute_provenance.parquet": "4b37d16c25ff112b25c5363337cc2c563a49ce0144f5b961ecd0cef82f4f8961",
   "product_change_set.csv": "56370f5a1216d0a4b7ddac3bc44e6ad64732ec465b487168c702b627ca5e339a",
   "product_change_set.parquet": "f42f27c8ce3c9356c19e4f981b9e48cb0885834538e0aeb67f3645017fbc293b",
   "product_lineage_event.csv": "62d20e70bcec4a4ef5cd3739e80592064f3767334d791810703d35eed22f8a59",
   "product_lineage_event.parquet": "b2ef9cc448b161af4644b7af0575d70020a8cb201539f0764059229ddd6a5773",
   "product_relationship.csv": "42deba8c60beecb038609429bd44afec94cf7652f5cd7e89dffdbd97d58d60d8",
   "product_relationship.parquet": "0b642ccf62a69bcf0760cd9dfeeeace43b8ae26869095e0c773b852ab24c226f",
   "product_source_xref.csv": "d148980030b22fe6ec2d129b4bca9fd42e51f5d786a62205bcc2d3ddc8edffc9",
   "product_source_xref.parquet": "d244f981a53a413a53b5a619500e21313cb9c64070affb2f1d03ce2ec01725a2",
   "ve_product_id_registry.csv": "47c9f259dd98787d471d836fbd16f0b9d749c6d0201cf176a9907b37a7c67f3d"
  },
  "finished": "2026-09-13T12:27:03+00:00",
  "foreign_keys_ok": true,
  "java_version": "21.0.12",
  "master": "local[*]",
  "pyarrow_version": "25.0.1",
  "pyspark_version": "4.2.0",
  "python_version": "3.12.3",
  "release_id": "ve-audit-sample-r3-2026-09-12",
  "spark_version": "4.2.0",
  "ve_product_id_in_registry": true,
  "ve_product_id_unique": true,
  "log_matches_current_files": true
 },
 "licences": [
  {
   "source": "osm",
   "name": "OpenStreetMap",
   "publisher": "OpenStreetMap contributors",
   "licence": "Open Database Licence (ODbL) 1.0",
   "licence_url": "https://opendatacommons.org/licenses/odbl/1-0/",
   "attribution": "© OpenStreetMap contributors",
   "copyright_url": "https://www.openstreetmap.org/copyright",
   "statement": "The OpenStreetMap-derived layer of this release is a Derivative Database of OpenStreetMap and is made available under the Open Database Licence (ODbL) 1.0, with the attribution © OpenStreetMap contributors. Rows and values in that layer are identified by product.osm_derived = true, product.primary_source = 'osm', the product *_source columns with value osm, and product_source_xref rows with source = 'osm'. If you publicly use an adapted version of this layer, the ODbL share-alike terms apply to it.",
   "retrieved": "2026-09-12"
  },
  {
   "source": "wd",
   "name": "Wikidata",
   "publisher": "Wikimedia Foundation and Wikidata contributors",
   "licence": "Creative Commons CC0 1.0",
   "licence_url": "https://creativecommons.org/publicdomain/zero/1.0/",
   "attribution": "Wikidata, CC0 1.0 (attribution not required; given as a courtesy)",
   "statement": "Wikidata values (identifiers, descriptions, websites, classes) are dedicated to the public domain under CC0 1.0.",
   "retrieved": "2026-09-12"
  },
  {
   "source": "nhle",
   "name": "National Heritage List for England",
   "publisher": "Historic England",
   "licence": "Open Government Licence v3.0",
   "licence_url": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
   "attribution": "© Historic England 2026. Contains Ordnance Survey data © Crown copyright and database right 2026",
   "statement": "NHLE list entry numbers, names, designations, grades and locations are used under the Open Government Licence v3.0.",
   "retrieved": "2026-09-12"
  },
  {
   "source": "ons",
   "name": "ONS local authority boundaries (May 2026), mid-year population estimates, LSOA (2021) population-weighted centroids and Census 2021 residents",
   "publisher": "Office for National Statistics",
   "licence": "Open Government Licence v3.0",
   "licence_url": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/",
   "attribution": "Source: Office for National Statistics, licensed under the Open Government Licence v3.0. Contains OS data © Crown copyright and database right 2026",
   "statement": "Local authority codes and names (boundaries used to assign records) and mid-year population estimates are used under the Open Government Licence v3.0.",
   "retrieved": "2026-09-12"
  }
 ],
 "caveats": [
  "Illustrative sample built for the VisitBritain/VisitEngland tender BTA2235 response. It is not the production tool.",
  "Open data only: OpenStreetMap, Wikidata, Historic England NHLE and ONS. It contains no BTA or VisitEngland data and does not follow VisitEngland's schema.",
  "Covers 3 of 38 LVEPs (Cornwall, Greater Manchester, York & North Yorkshire). The LVEP to local authority membership is illustrative; Cornwall excludes the Isles of Scilly.",
  "prototype_id is not stable between builds. Use ve_product_id.",
  "Matching and classification are rules only: no machine learning and no human review. Some merges may be wrong, and pairs in the review band are kept separate rather than resolved. Category confidence is fixed per rule, not calibrated.",
  "Opening months are stated for only 53 of 16,559 visitor product records (0.3%): the source states the months. A further 1,593 are inferred to open all year only because their opening hours have no month rules; the rest have no month evidence. By LVEP, stated / inferred: Cornwall 24 / 379 of 4,198; Greater Manchester 3 / 726 of 5,674; York & North Yorkshire 26 / 488 of 6,687. 34 records show months closed.",
  "Open data coverage differs between places and categories. Missing records are not evidence that a product does not exist.",
  "Values are as retrieved on 2026-09-12 and may have changed at source since."
 ]
}
