{"region":"Riyadh","generated_at":"2026-08-31T04:31:46.990003+00:00","title":"How the Riyadh data is built","audience":"Written for the analyst who has to defend a site decision to someone else. Every figure on this page is measured from the live baseline at the moment you loaded it.","model":{"current_tier":1,"current_model":"Weighted MCDA","honesty_rule":"A Tier 1 score is an index, not a forecast. It ranks locations against each other on the factors you weighted; it does not predict revenue and is never denominated in SAR. Revenue forecasting is Tier 4 and requires your own stores' sales history.","ladder":[{"tier":1,"model":"Weighted MCDA","requires":"nothing beyond the regional baseline","output":"0–100 suitability index","answers":"which of these locations is most suitable, and why","available":true},{"tier":2,"model":"Huff / gravity — distance-decay market share","requires":"a competitor set and an attractiveness proxy","output":"% share captured per competing site","answers":"how much of this trade area would we actually capture, and how much of it comes out of our own stores","available":false},{"tier":3,"model":"Analog — nearest neighbour to top-performing stores","requires":"roughly 20–30 of the tenant's own stores","output":"“this site resembles your Store 12 and Store 27”","answers":"which of our existing stores does this site behave like","available":false},{"tier":4,"model":"ML regression on trade-area features","requires":"roughly 50+ stores with sales history","output":"revenue forecast with a confidence band","answers":"what will this site turn over","available":false}]},"grid":{"table":"region_baseline_h3","cells":{"8":6217,"9":42682},"total_cells":48899,"scoring_resolution":9,"source_zone_resolution":8,"explanation":"The region is tiled with H3 hexagons. A resolution-9 cell is about 0.1 km² — roughly a city block — and is the only resolution any score reads. Resolution 8 is seven times larger and holds the population source's own figures. The two layers are each a complete cover of the region, so their totals are compared against each other and never added together."},"reconciliation":{"sources":[{"key":"kontur","label":"Kontur Population Dataset (H3-native, 2023-11-01 release)","licence":"CC-BY-4.0","total":7033492.0,"cells":4835,"kind":"gridded model","deviation_vs_census":0.00347718401168763,"published_in_plan":7033492.0,"drift_vs_plan":0.0,"is_baseline_source":true,"deviation_pct":0.348,"credit_line":"Kontur Population Dataset, © Kontur (kontur.io), CC BY 4.0"},{"key":"ghsl","label":"GHSL GHS-POP R2023A (100 m raster, epoch 2020)","licence":"EC-JRC-Free","total":8216348.199391308,"cells":6207,"kind":"gridded model","deviation_vs_census":0.17223677143369043,"published_in_plan":8216348.0,"drift_vs_plan":2.4267631828714226e-8,"is_baseline_source":false,"deviation_pct":17.224,"credit_line":"European Commission, Joint Research Centre (JRC): Global Human Settlement Layer GHS-BUILT-S and GHS-POP, release R2023A (epoch 2020, 100 m, Mollweide)"},{"key":"worldpop","label":"WorldPop 2020 unconstrained age/sex (SAU)","licence":"CC-BY-4.0","total":6437776.755819415,"cells":7008,"kind":"gridded model","deviation_vs_census":-0.08151426201585724,"published_in_plan":6437777.0,"drift_vs_plan":-3.7929332634185534e-8,"is_baseline_source":false,"deviation_pct":-8.151,"credit_line":"WorldPop (www.worldpop.org), School of Geography and Environmental Science, University of Southampton — Global High Resolution Population Denominators Project. Licensed CC BY 4.0."}],"census_reference":{"label":"GASTAT 2022 census — Ar Riyadh governorate","total":7009120.0,"scope":"governorate","scope_note":"GOVERNORATE SCOPE ONLY — this is not the DEVELOPMENT_PLAN §4 M1 exit gate, which is specified per district and cannot be evaluated (blocker SS-1-13: district polygons now exist but carry NO population; there are no per-district GASTAT figures to compare against)"},"spread":0.12301292349765768,"normal_spread_threshold":0.15,"baseline_source":"kontur","baseline_deviation_pct":0.348,"findings":[{"check":"cross_source_agreement","verdict":"PASS","statement":"The independent population products agree to ±12.3% — inside the ±15% that gridded models normally disagree by. No sign of a units or clipping error.","evidence":["Kontur Population Dataset (H3-native, 2023-11-01 release): 7,033,492 (+0.35% vs census)","GHSL GHS-POP R2023A (100 m raster, epoch 2020): 8,216,348 (+17.22% vs census)","WorldPop 2020 unconstrained age/sex (SAU): 6,437,777 (-8.15% vs census)","GASTAT 2022 census — Ar Riyadh governorate: 7,009,120"],"action":"","column":"population"}],"explanation":"Three independent gridded population products and one census, over the same governorate. They disagree — they always do, because each models the same people from different inputs — and the size of that disagreement is the honest error bar on any population figure in this product. The baseline is built on the one that lands closest to the census.","caveat":"The census reference is a governorate total: it tests how many people the model has, not whether it has them in the right places. The district-level test that would answer the second question is blocked — see the validation section."},"conservation":{"resolutions":[{"resolution":8,"composed_total":7033492.0,"source_total":7033492.0,"source":"Kontur Population Dataset (staging.stg_kontur_population)","source_cells":4835,"residual":0.0,"relative_deviation":0.0,"cells_with_population":4835},{"resolution":9,"composed_total":7033492.002697733,"source_total":7033492.0,"source":"Kontur Population Dataset (staging.stg_kontur_population)","source_cells":4835,"residual":0.0026977332308888435,"relative_deviation":3.83555313760056e-10,"cells_with_population":33410}],"findings":[{"check":"population_conservation","verdict":"PASS","statement":"Population is conserved at res 8: +0.0000% against the Kontur source total.","evidence":["res 8: composed 7,033,492 vs Kontur 7,033,492 — residual +0 (+0.0000%) over 4,835 populated cells","float32 (REAL) storage accounts for ~1e-6 of this."],"action":"","column":"population"},{"check":"population_conservation","verdict":"PASS","statement":"Population is conserved at res 9: +0.0000% against the Kontur source total.","evidence":["res 9: composed 7,033,492 vs Kontur 7,033,492 — residual +0 (+0.0000%) over 33,410 populated cells","float32 (REAL) storage accounts for ~1e-6 of this."],"action":"","column":"population"}],"explanation":"Redistribution moves people around inside a source zone; it must never create or destroy any. This compares what the baseline holds, at each resolution, against what the population source published."},"dasymetric":{"method":"siteselect.dasymetric_v1","ticket":"SS-1-03","cap_sqm":559.346,"cap_basis":"pooled mean footprint of Overture-classified residential buildings in this region at res 9","cap_residential_buildings":59626,"cap_residential_cells":1492,"context_p75_mean_footprint_sqm":480.1,"context_p90_mean_footprint_sqm":893.4,"input_licences":["CC-BY-4.0","ODbL-1.0"],"weighting_tiers":[{"tier":"buildings","cells":32778,"population":7026484.5,"population_share":0.999004},{"tier":"ghsl_builtup","cells":400,"population":6281.001,"population_share":0.000893},{"tier":"uniform","cells":232,"population":725.0,"population_share":0.000103}],"example":{"landmark":"King Khalid International Airport","why_this_place":"Nobody lives on an airport apron. A gridded population product that reports residents here is showing you its disaggregation error, and every trade area that overlaps the cell inherits it.","available":true,"source_zone":{"h3_index":"613957636391436287","resolution":8,"population":6279.0},"children":[{"h3_index":"618461236018020351","population":1712.4546,"building_count":3,"footprint_area_sqm":92553.93760463642,"weighting_tier":"buildings"},{"h3_index":"618461236016971775","population":1141.6364,"building_count":2,"footprint_area_sqm":33966.62601923989,"weighting_tier":"buildings"},{"h3_index":"618461236017758207","population":1141.6364,"building_count":2,"footprint_area_sqm":47193.75767607428,"weighting_tier":"buildings"},{"h3_index":"618461236017233919","population":1141.6364,"building_count":2,"footprint_area_sqm":25577.667250262573,"weighting_tier":"buildings"},{"h3_index":"618461236018282495","population":570.8182,"building_count":1,"footprint_area_sqm":22133.025632489007,"weighting_tier":"buildings"},{"h3_index":"618461236017496063","population":570.8182,"building_count":1,"footprint_area_sqm":784.7680001584813,"weighting_tier":"buildings"},{"h3_index":"618461236018544639","population":0.0,"building_count":0,"footprint_area_sqm":0.0,"weighting_tier":"buildings"}],"child_count":7,"children_with_population":7,"empty_children":1,"max_child_population":1712.4546,"min_nonzero_child_population":570.8182,"children_total":6279.0002,"residual":0.00020000000040454324,"reading":"The larger source cell keeps its total. Inside it, the people move onto the sub-cells that carry building evidence, and a sub-cell with no mapped building goes to exactly zero — which is a result, not missing data. Read the resolution-9 row for placement; the resolution-8 row is still the source's own figure, smear included."},"explanation":"The population source publishes on the larger resolution-8 grid, which spreads residents evenly across land nobody lives on. Each cell's total is kept — it is the best local measurement available — but where inside the cell those people sit is decided from building evidence: each building is counted, and credited with at most a residential-sized floorplate. That cap is what stops one airport terminal or warehouse outweighing a street of houses, and it is measured from this region's own classified residential buildings rather than assumed.","limit":"Redistribution works strictly inside a source zone. It never moves people between resolution-8 cells, because doing so would discard the only real population measurement available and substitute our building model for it. The resolution-8 layer therefore still carries the source's own smear, by design — which is why every trade area reads resolution 9."},"columns":{"resolution":9,"null_policy":{"statement":"A blank is not a zero. Where no source covers a cell the value is left empty, and every rollup in the product is written to know the difference: a zero would state that nobody lives there, which is a measurement, and nothing downstream could tell it apart from one.","cells_without_population":9272,"cells_with_population":33410,"cells_total":42682,"source_reason":"Kontur publishes only populated hexagons. No Kontur cell covers this grid cell, so nothing is known here. SS-1-02 deliberately declined to write a 0 for such cells because 'Kontur reported nothing here' is information a 0 would destroy; this composition honours that. Aggregations must COALESCE or filter explicitly.","columns_affected":["population","pop_age_0_14","pop_age_15_29","pop_age_30_44","pop_age_45_64","pop_age_65_plus"],"consequence":"In a score, a factor with no value for a location is excluded and the remaining weights are renormalised, so scores stay comparable — and the score reports what share of its intended weight it was actually computed from."},"rows":[{"column":"population","tier":"Tier 1 — demand","description":"Residents per hex, Kontur redistributed onto building footprints.","ticket":"SS-1-03","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":33410,"cells_total":42682,"coverage_pct":78.28,"spatial_signal":null,"modeled":true,"withheld_by_composer":false,"calibrated":null,"licence":"derived","share_alike":true,"source":"Kontur Population Dataset (SA extract, release 20231101)","unit":null,"method":"siteselect.dasymetric_v1","why_not":"","unblocked_by":""},{"column":"pop_age_0_14","tier":"Tier 1 — demand","description":"Residents aged 0–14, population × WorldPop band share.","ticket":"SS-1-03","registry_status":"composed","state":"no_spatial_signal","usable_as_a_factor":false,"cells_with_a_value":33410,"cells_total":42682,"coverage_pct":78.28,"spatial_signal":false,"modeled":true,"withheld_by_composer":false,"calibrated":null,"licence":"CC-BY-4.0","share_alike":false,"source":"WorldPop 2020 unconstrained age/sex structure (SAU) share × dasymetric population","unit":null,"method":"siteselect.dasymetric_v1","why_not":"the composer flagged this column as spatially constant across the region: a real quantity, but identical in every location, so it cannot rank one against another","unblocked_by":""},{"column":"pop_age_15_29","tier":"Tier 1 — demand","description":"Residents aged 15–29, population × WorldPop band share.","ticket":"SS-1-03","registry_status":"composed","state":"no_spatial_signal","usable_as_a_factor":false,"cells_with_a_value":33410,"cells_total":42682,"coverage_pct":78.28,"spatial_signal":false,"modeled":true,"withheld_by_composer":false,"calibrated":null,"licence":"CC-BY-4.0","share_alike":false,"source":"WorldPop 2020 unconstrained age/sex structure (SAU) share × dasymetric population","unit":null,"method":"siteselect.dasymetric_v1","why_not":"the composer flagged this column as spatially constant across the region: a real quantity, but identical in every location, so it cannot rank one against another","unblocked_by":""},{"column":"pop_age_30_44","tier":"Tier 1 — demand","description":"Residents aged 30–44, population × WorldPop band share.","ticket":"SS-1-03","registry_status":"composed","state":"no_spatial_signal","usable_as_a_factor":false,"cells_with_a_value":33410,"cells_total":42682,"coverage_pct":78.28,"spatial_signal":false,"modeled":true,"withheld_by_composer":false,"calibrated":null,"licence":"CC-BY-4.0","share_alike":false,"source":"WorldPop 2020 unconstrained age/sex structure (SAU) share × dasymetric population","unit":null,"method":"siteselect.dasymetric_v1","why_not":"the composer flagged this column as spatially constant across the region: a real quantity, but identical in every location, so it cannot rank one against another","unblocked_by":""},{"column":"pop_age_45_64","tier":"Tier 1 — demand","description":"Residents aged 45–64, population × WorldPop band share.","ticket":"SS-1-03","registry_status":"composed","state":"no_spatial_signal","usable_as_a_factor":false,"cells_with_a_value":33410,"cells_total":42682,"coverage_pct":78.28,"spatial_signal":false,"modeled":true,"withheld_by_composer":false,"calibrated":null,"licence":"CC-BY-4.0","share_alike":false,"source":"WorldPop 2020 unconstrained age/sex structure (SAU) share × dasymetric population","unit":null,"method":"siteselect.dasymetric_v1","why_not":"the composer flagged this column as spatially constant across the region: a real quantity, but identical in every location, so it cannot rank one against another","unblocked_by":""},{"column":"pop_age_65_plus","tier":"Tier 1 — demand","description":"Residents aged 65+, population × WorldPop band share.","ticket":"SS-1-03","registry_status":"composed","state":"no_spatial_signal","usable_as_a_factor":false,"cells_with_a_value":33410,"cells_total":42682,"coverage_pct":78.28,"spatial_signal":false,"modeled":true,"withheld_by_composer":false,"calibrated":null,"licence":"CC-BY-4.0","share_alike":false,"source":"WorldPop 2020 unconstrained age/sex structure (SAU) share × dasymetric population","unit":null,"method":"siteselect.dasymetric_v1","why_not":"the composer flagged this column as spatially constant across the region: a real quantity, but identical in every location, so it cannot rank one against another","unblocked_by":""},{"column":"households","tier":"Tier 1 — demand","description":"Households per hex.","ticket":"SS-1-02","registry_status":"deferred","state":"unavailable","usable_as_a_factor":false,"cells_with_a_value":0,"cells_total":42682,"coverage_pct":0.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":null,"share_alike":false,"source":null,"unit":null,"method":null,"why_not":"The only household source available is a GASTAT governorate total. Distributing it by a constant households-per-person ratio yields a column that is a scalar multiple of `population` — no spatial signal, no information, but it looks like a measurement and would be weighted as one. A NULL column is honest; a constant-ratio one is not.","unblocked_by":"SS-1-04 (district calibration), blocked on SS-1-13"},{"column":"daytime_pop_index","tier":"Tier 1 — demand","description":"Daytime vs residential population (DATA_STRATEGY §2.2).","ticket":"SS-2-04","registry_status":"pending","state":"unavailable","usable_as_a_factor":false,"cells_with_a_value":0,"cells_total":42682,"coverage_pct":0.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":null,"share_alike":false,"source":null,"unit":null,"method":null,"why_not":"DATA_STRATEGY §2.2 needs five inputs. SS-2-04 delivered two (transit_stops, traffic_exposure); retail GLA is unavailable (SS-1-15) and school/university capacity is not ingested.","unblocked_by":"a workplace/education capacity source, plus SS-1-15 for GLA"},{"column":"affluence_index","tier":"Tier 1 — demand","description":"MODELLED affluence, 0–100 (DATA_STRATEGY §2.3). Land value + POI affluence mix + plot spaciousness + dwelling scale. NOT income and NOT a measurement — there is no open income dataset for KSA at usable granularity.","ticket":"SS-1-08","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":12636,"cells_total":42682,"coverage_pct":29.6,"spatial_signal":true,"modeled":true,"withheld_by_composer":false,"calibrated":false,"licence":"derived","share_alike":true,"source":"siteselect affluence model (modelled composite)","unit":"relative index, 0-100, region-normalised. NOT a currency, NOT a percentile of income, NOT comparable to another region's index until both are rescaled together.","method":"weighted sum of four normalised terms, renormalised per cell over the terms that cell has an input for, published on 0-100. land_value is ln(1+SAR/m²) min-max scaled between the region's q0.02 and q0.98 of that transform; poi_affluence_mix is 0.5 + 3·(affluent − deprivation)/all open countable venues in an h3_grid_disk of radius k=2, clipped to [0,1]; plot_spaciousness is 1 − min(footprint coverage / 0.4, 1); dwelling_scale is a log-space trapezoid on mean footprint per building with corners [60.0, 220.0, 900.0, 2600.0] m².","why_not":"","unblocked_by":""},{"column":"spend_potential","tier":"Tier 1 — demand","description":"SAR/year spend potential = population × age propensity × affluence × HES basket.","ticket":"SS-1-09","registry_status":"deferred","state":"unavailable","usable_as_a_factor":false,"cells_with_a_value":0,"cells_total":42682,"coverage_pct":0.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":null,"share_alike":false,"source":null,"unit":null,"method":null,"why_not":"Two of its four factors are still unavailable. The GASTAT Household Expenditure Survey category basket was not obtained, so there is no basket to multiply by; and the age propensity term would multiply through a spatially constant age structure (SS-1-12 — exactly one distinct 65+ share across all 55,230 hexes). What is left is population × affluence × a constant, published in SAR — a currency-denominated restatement of two columns that already exist, and the currency is what would make it read as a measurement.","unblocked_by":"a GASTAT HES category basket, and SS-1-04 district age structure"},{"column":"poi_counts","tier":"Tier 2 — competition & supply","description":"{category: count} of open, countable POIs.","ticket":"SS-1-05","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":"ODbL-1.0","share_alike":true,"source":"staging.poi_unified (SS-1-05) + staging.poi_brand (SS-1-06)","unit":null,"method":null,"why_not":"","unblocked_by":""},{"column":"brand_presence","tier":"Tier 2 — competition & supply","description":"{brand_id: count} after Arabic/English brand normalization.","ticket":"SS-1-06","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":"ODbL-1.0","share_alike":true,"source":"staging.poi_unified (SS-1-05) + staging.poi_brand (SS-1-06)","unit":null,"method":null,"why_not":"","unblocked_by":""},{"column":"retail_gla_sqm","tier":"Tier 2 — competition & supply","description":"Gross leasable retail area.","ticket":"SS-1-05","registry_status":"deferred","state":"unavailable","usable_as_a_factor":false,"cells_with_a_value":0,"cells_total":42682,"coverage_pct":0.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":true,"calibrated":null,"licence":null,"share_alike":false,"source":null,"unit":null,"method":null,"why_not":"Requires building height or storey count. 169 of 756,675 Overture buildings carry a height and 397 carry explicit levels — 0.06% of the stock. Extrapolating GLA from that is fiction, not sparsity (SS-1-15).","unblocked_by":"SS-1-15 — a height/levels source, or a commercial GLA dataset"},{"column":"road_class_mix","tier":"Tier 3 — accessibility","description":"{osm highway class: metres in the hex}, from OSM ways clipped to the cell polygon.","ticket":"SS-2-04","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":"ODbL-1.0","share_alike":true,"source":"OpenStreetMap (Geofabrik gcc-states extract)","unit":"metres","method":"geodesic length of ST_Intersection(way, cell) per OSM highway class, rounded to 0.1 m. Keys are raw OSM highway values; links kept distinct. highway=construction and =proposed are not ingested. {} means covered and roadless.","why_not":"","unblocked_by":""},{"column":"junction_density","tier":"Tier 3 — accessibility","description":"Street intersections per km² — OSM nodes with ≥3 incident edges on the public street network, over the true cell area.","ticket":"SS-2-04","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":"ODbL-1.0","share_alike":true,"source":"OpenStreetMap (Geofabrik gcc-states extract)","unit":"junctions per km2","method":"OSM nodes with >= 3 incident edges on the public street network, divided by the true geodesic cell area. Junction network excludes highway=service and =track.","why_not":"","unblocked_by":""},{"column":"traffic_exposure","tier":"Tier 3 — accessibility","description":"MODELED. Σ(clipped length × class weight × carriageway factor), in primary-arterial-equivalent metres. See baseline.road_classes.","ticket":"SS-2-04","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":true,"withheld_by_composer":false,"calibrated":null,"licence":"ODbL-1.0","share_alike":true,"source":"OpenStreetMap (Geofabrik gcc-states extract)","unit":"primary-arterial-equivalent metres","method":"sum(clipped length m * class weight * carriageway factor). Weights are typical two-way AADT per OSM class divided by the anchor; one-way ways are multiplied by the carriageway factor so a dual carriageway does not score twice a single one.","why_not":"","unblocked_by":""},{"column":"transit_stops","tier":"Tier 3 — accessibility","description":"Public transport stop places whose point falls in the hex.","ticket":"SS-2-04","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":"ODbL-1.0","share_alike":true,"source":"OpenStreetMap (Geofabrik gcc-states extract)","unit":"count","method":"count of stop_class='stop_place' features whose point falls in the cell. public_transport=stop_position and railway=subway_entrance are staged but never counted. A stop place within 25 m of a higher-ranked one is suppressed as the same stop mapped twice.","why_not":"","unblocked_by":""},{"column":"footfall_value","tier":"Tier 4 — footfall","description":"MODELED, UNCALIBRATED. 0–100 footfall proxy index (DATA_STRATEGY §5 option A): category-weighted POI density, traffic exposure, junction density, built-up intensity and anchor proximity. Res 9 only — the index is normalised against the cell population it is computed over, so a res-8 value would not be comparable. Not a visitor count. See baseline.footfall_weights.","ticket":"SS-2-07","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":true,"withheld_by_composer":false,"calibrated":false,"licence":"ODbL-1.0","share_alike":true,"source":"siteselect footfall proxy (proxy)","unit":"relative index, 0-100, region-normalised (NOT a visitor count)","method":"weighted sum of five normalised terms, published on 0-100. poi_density, traffic_exposure and junction_density are ln(1+x) divided by the region's q=0.999 of that transform and clipped to 1; built_up_pct is divided by 100; anchor_proximity is a weight-summed exp(-d/d0) to the nearest anchor of each type and is already in [0, 1]. The weights are renormalised per cell over the terms that cell has an input for, so a missing input does not act as a zero.","why_not":"","unblocked_by":""},{"column":"footfall_source","tier":"Tier 4 — footfall","description":"'proxy' | 'telco' | 'card' | 'sdk'. Which of DATA_STRATEGY §5's options produced footfall_value; 'proxy' until a panel is purchased.","ticket":"SS-2-07","registry_status":"composed","state":"provenance_label","usable_as_a_factor":false,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":false,"licence":"ODbL-1.0","share_alike":true,"source":"siteselect.compose_footfall","unit":"enum: proxy | telco | card | sdk","method":"constant 'proxy' on every composed cell. The column exists so purchased data (DATA_STRATEGY 5 options B/C/D) replaces the proxy as a column swap rather than a rewrite; see compose_footfall.SUPERSEDE_SQL.","why_not":"this column records where a value came from rather than measuring the place; it is not a factor","unblocked_by":""},{"column":"footfall_confidence","tier":"Tier 4 — footfall","description":"Weight of evidence behind footfall_value, not probability of correctness. Capped at 0.5 while footfall_source='proxy' so an uncalibrated model cannot be mistaken for a purchased panel.","ticket":"SS-2-07","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":true,"withheld_by_composer":false,"calibrated":false,"licence":"ODbL-1.0","share_alike":true,"source":"siteselect.compose_footfall","unit":"0-0.5 for footfall_source='proxy'","method":"ceiling * input_coverage * (1 - poi_share * (1 - poi_evidence)). input_coverage is the share of renormalised term weight the cell has an input for; poi_evidence is 0.7 * n/(n+5) + 0.3 * (share of the cell's open countable POIs seen by >= 2 independent sources); poi_share scales that penalty by how much this cell's value depends on the POI term. It measures weight of evidence, not probability of correctness: an empty desert cell is a well-founded 0 with low confidence, because nothing distinguishes it from the 20,000 other near-zero cells.","why_not":"","unblocked_by":""},{"column":"land_value_sqm","tier":"Land & built form","description":"SAR/m² land value from srem.moj.gov.sa — the median of a district's monthly transaction prices over a trailing 12-month window, inherited by every res-9 cell in that district. ⚠️ DISTRICT granularity stored per hex: within-district variation is absent, and 46.4% of res-9 cells are NULL because no SREM transaction in the window reached them. Uncovered cells are NOT imputed. See baseline.compose_land_value.","ticket":"SS-1-14","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":19817,"cells_total":42682,"coverage_pct":46.43,"spatial_signal":true,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":"Saudi-Open-Data","share_alike":false,"source":"SREM — Saudi Real Estate Market (Ministry of Justice)","unit":null,"method":"median of the district's monthly volume-weighted transaction prices over the recency window, inherited unchanged by every res-9 cell in the district; a cell straddling districts takes the mean of their prices weighted by the share of the CELL in each","why_not":"","unblocked_by":""},{"column":"built_up_pct","tier":"Land & built form","description":"Percent of sampled GHS-BUILT-S pixel area that is built surface.","ticket":"SS-1-03","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":"EC-JRC-Free","share_alike":false,"source":"GHSL GHS-BUILT-S R2023A (E2020, 100 m)","unit":null,"method":null,"why_not":"","unblocked_by":""},{"column":"building_count","tier":"Land & built form","description":"Overture building footprints whose centroid falls in the hex.","ticket":"SS-1-03","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":"ODbL-1.0","share_alike":true,"source":"Overture Maps — buildings","unit":null,"method":null,"why_not":"","unblocked_by":""},{"column":"footprint_area_sqm","tier":"Land & built form","description":"Total building footprint area in the hex.","ticket":"SS-1-03","registry_status":"composed","state":"usable","usable_as_a_factor":true,"cells_with_a_value":42682,"cells_total":42682,"coverage_pct":100.0,"spatial_signal":null,"modeled":false,"withheld_by_composer":false,"calibrated":null,"licence":"ODbL-1.0","share_alike":true,"source":"Overture Maps — buildings","unit":null,"method":null,"why_not":"","unblocked_by":""}],"usable_count":14,"usable":["population","affluence_index","poi_counts","brand_presence","road_class_mix","junction_density","traffic_exposure","transit_stops","footfall_value","footfall_confidence","land_value_sqm","built_up_pct","building_count","footprint_area_sqm"],"no_spatial_signal":["pop_age_0_14","pop_age_15_29","pop_age_30_44","pop_age_45_64","pop_age_65_plus"],"unavailable":["households","daytime_pop_index","spend_potential","retail_gla_sqm"],"provenance_labels":["footfall_source"],"undocumented_deferrals":[],"explanation":"Every column the scoring engine can see, and the state it is actually in. Only the columns marked usable can carry weight in a score: a column with no value would otherwise be scored as a zero, and a column with no spatial signal would rank locations on a constant."},"limitations":[{"key":"footfall_is_modeled","severity":"material","headline":"Footfall is a modeled proxy, not a measurement","statement":"The footfall figure is an index this platform computes from POI density, traffic exposure, junction density, built-up surface and proximity to anchors. It is not a count of people, it does not come from mobile-device data, and it has not been calibrated against any observed visit counts. It is useful for comparing one location with another and must not be read as a visitor volume.","affects":["footfall_value","footfall_confidence"],"evidence":{"unit":"relative index, 0-100, region-normalised (NOT a visitor count)","method":"weighted sum of five normalised terms, published on 0-100. poi_density, traffic_exposure and junction_density are ln(1+x) divided by the region's q=0.999 of that transform and clipped to 1; built_up_pct is divided by 100; anchor_proximity is a weight-summed exp(-d/d0) to the nearest anchor of each type and is already in [0, 1]. The weights are renormalised per cell over the terms that cell has an input for, so a missing input does not act as a zero.","calibrated":false,"source_labels":[{"label":"proxy","cells":42682}],"inputs":["region_baseline_h3.poi_counts","region_baseline_h3.traffic_exposure","region_baseline_h3.junction_density","region_baseline_h3.built_up_pct","staging.poi_unified_open","staging.stg_osm_transit_stops","app.siteselect.baseline.footfall_weights"]},"unblocked_by":"calibration against a tenant's own transaction or door-count data, or a purchased mobility dataset"},{"key":"affluence_is_modelled_and_is_not_income","severity":"material","headline":"Affluence is a modelled index — it is not income","statement":"There is no open income dataset for Saudi Arabia at any sub-governorate granularity, so nothing in this platform has observed a household income. The affluence figure is an index computed from real-estate transaction prices, the mix of venues in the surrounding neighbourhood, and building typology. It orders neighbourhoods within one city; it is not a currency, not a percentile of income, and not comparable to another city's index. Its largest single input is a district-level land price, so it is coarser than the hexagon it is stored on.","affects":["affluence_index"],"evidence":{"unit":"relative index, 0-100, region-normalised. NOT a currency, NOT a percentile of income, NOT comparable to another region's index until both are rescaled together.","method":"weighted sum of four normalised terms, renormalised per cell over the terms that cell has an input for, published on 0-100. land_value is ln(1+SAR/m²) min-max scaled between the region's q0.02 and q0.98 of that transform; poi_affluence_mix is 0.5 + 3·(affluent − deprivation)/all open countable venues in an h3_grid_disk of radius k=2, clipped to [0,1]; plot_spaciousness is 1 − min(footprint coverage / 0.4, 1); dwelling_scale is a log-space trapezoid on mean footprint per building with corners [60.0, 220.0, 900.0, 2600.0] m².","calibrated":false,"coverage_pct":29.6,"term_weights":{"land_value":0.45,"dwelling_scale":0.1,"plot_spaciousness":0.15,"poi_affluence_mix":0.3},"excluded_inputs":{"age_structure":"WorldPop's unconstrained age/sex product has spatially constant shares in Riyadh — exactly one distinct 65+ share across all 55,230 hexes (SS-1-12). Nothing derived from it can vary in space.","nationality_mix":"DATA_STRATEGY §2.3 lists it; it is available only as a governorate share. A district composition approximated from one region-wide number is region-constant, and a constant term multiplied through a weighted index reconciles perfectly while distinguishing nothing (the SS-1-12 failure mode). NOT approximated.","household_income":"no open income dataset exists for Saudi Arabia at any sub-governorate granularity, and Meta's Relative Wealth Index does not cover KSA (DATA_STRATEGY §2.3). This absence is why the column is modelled.","population_density":"available and deliberately unused. SS-1-03 redistributes Kontur by capped building footprint, so population is a transform of the same footprint data plot_spaciousness and dwelling_scale read; a fifth term on it would count one input three times.","building_height_or_storeys":"169 of 756,675 Overture buildings in Riyadh carry a height (SS-1-15). Apartment-vs-villa is exactly what height would settle and 0.02% coverage cannot settle it."},"granularity_warning":"the land_value term (45% of the weight) is DISTRICT-CONSTANT — SS-1-14 stores one district price on every res-9 cell in that district. Within-district variation in this index comes entirely from the POI mix and the two building terms.","null_means":"not composed, for one of four reasons recorded per cell in source_flags._affluence_null.reason: no_land_value (the required term is missing), insufficient_inputs (a priced cell with no buildings and no nearby venues), outside_aoi, or resolution_not_composed (res 8). There is no default of 50, no zero-fill and no imputation — a NULL here means the model declined to guess, not that the area is poor.","inputs":["region_baseline_h3.land_value_sqm","region_baseline_h3.building_count","region_baseline_h3.footprint_area_sqm","staging.poi_unified_open","app.siteselect.baseline.affluence_weights"]},"unblocked_by":"a household income or wealth survey published below governorate level, which would make the index calibratable rather than only arguable"},{"key":"land_value_is_district_granularity","severity":"material","headline":"Land value resolves to a district, not to a hexagon","statement":"Every square metre price on this platform is the median of one district's monthly transaction prices, and every hexagon inside that district carries the same number. The prices themselves are measured — they are real recorded sales, not a model — but the geography is coarse: a corner plot on an arterial and an interior street two blocks away are indistinguishable here. Districts with no transaction in the window are left empty and are not filled in from their neighbours, which is why a large part of the surface has no price at all.","affects":["land_value_sqm","affluence_index"],"evidence":{"granularity":"district","coverage_pct":46.43,"districts_priced":131,"recency_window":{"end":"2026-07-01","start":"2025-08-01","months":12,"rationale":"staged transactions span 2006-2026 and Riyadh land prices moved by 2-4x over that span; widening to 3 years would add 203 res-9 cells (0.48% of the grid) at the cost of mixing 2024 prices into a current-value column","anchored_to":"latest staged monthly period, not wall-clock now()"},"estimator":"median_of_monthly_prices","estimator_rejected":"volume-weighted mean — rejected because two single deals of ~7.1bn SAR in Oct 2025 put King Faisal at 83,752 and King Abdulaziz at 68,752 SAR/m², which is one transaction, not a district land value. Per-district volume-weighted means are kept in staging.stg_district_land_value for comparison.","within_district_modulation":"none — deliberately not modulated by building density or POI mix, which would make a measured price partly modelled and would feed the affluence model a reflection of its own inputs (SS-1-08)","null_means":"no SREM transaction in the recency window reached any district polygon overlapping this cell. NOT imputed from neighbouring districts."},"unblocked_by":"parcel-level or street-level transaction geography, which SREM does not publish"},{"key":"district_geometry_provenance_is_unknown","severity":"blocking","headline":"The district boundaries have no established licence or attribution","statement":"Land value and the affluence index are placed on the map by a district boundary layer that arrived without a source, a licence, or an attribution line. Its schema resembles Saudi National Address / SPL lineage, and that resemblance is not evidence — this platform does not assert a licence it cannot produce. The layer is recorded as needs-review, every cell composed through it is tagged in the data so the dependency can be found and the columns withdrawn wholesale, and neither the boundaries themselves nor anything derived from them is cleared for redistribution until the question is resolved. The transaction prices carried on that geography are SREM's under the Saudi Open Data Licence; that is a separate and settled question.","affects":["land_value_sqm","affluence_index"],"evidence":[{"source":"KSA district boundaries (user-supplied, provenance unverified)","licence":"unknown","provenance_verified":false,"credit_line":"District boundaries: source unverified. Supplied without attribution or licence; provenance not established. Not cleared for redistribution or client-facing display.","staging_tables":["staging.stg_ksa_districts","staging.stg_district_h3","staging.stg_district_srem_bridge"],"compliance_state":"needs-review"}],"unblocked_by":"an identified publisher and licence for the boundary layer, or a replacement layer whose licence permits commercial use"},{"key":"age_structure_has_no_spatial_signal","severity":"blocking","headline":"Age and sex structure does not vary within the city","statement":"The age bands are real counts and they sum correctly to the total population, but the shares behind them come from an unconstrained national product: every hexagon in the region carries the same age profile. The counts are usable as a magnitude. The shares cannot distinguish one location from another, so the scoring engine refuses to place weight on them — a weight there would rank candidates on a constant.","affects":["pop_age_0_14","pop_age_15_29","pop_age_30_44","pop_age_45_64","pop_age_65_plus"],"evidence":{"distinct_65_plus_shares":1,"measured_over_cells":55230,"stddev_65_plus_share":1.107425428147326e-10,"shares":{"pop_age_0_14":0.24180048,"pop_age_15_29":0.2190024,"pop_age_30_44":0.30597054,"pop_age_45_64":0.20383618,"pop_age_65_plus":0.0293904},"safe_use":"counts are usable as a magnitude (they sum to `population`); age *shares* are identical in every hex and must never be used as an MCDA factor or presented as a differentiator between candidate locations","ticket":"SS-1-12"},"unblocked_by":"district-level census tables, which need a Riyadh district polygon layer"},{"key":"census_calibration_is_still_unevaluable","severity":"blocking","headline":"Having district boundaries is not having a district census — the ±5 % population check still cannot be run","statement":"The milestone's exit gate asks whether the hexagon populations sum to within ±5 % of the official population of each district. Answering it needs two things: district boundaries, and an official population per district. The boundaries now exist. The per-district counts do not — the boundary file carries an id, a city, a region, two names and a centroid, and no population field of any kind. Nothing has been substituted for the missing counts and no version of this check has been run and passed. The population surface remains a redistribution of Kontur's own totals, validated against the governorate total it was built from, which is a weaker statement than the gate asks for. For the same reason the age and sex structure still carries no within-city signal, and the banking and clinic weight profiles still refuse to produce a score.","affects":["population","pop_age_0_14","pop_age_15_29","pop_age_30_44","pop_age_45_64","pop_age_65_plus"],"evidence":{"district_polygons_staged":3731,"district_polygons_reaching_this_region":173,"population_field_in_the_boundary_layer":"none — 0 of the population-like column names exist on staging.stg_ksa_districts, checked against the catalogue","boundary_layer_columns":["district_id","city_id","region_id","name_ar","name_en","X","Y"],"profiles_still_refusing_to_score":["banking","clinic"],"note":"the exit gate's own state is measured by the SS-1-11 harness and reported under `validation.exit_gate`; it is not restated here"},"unblocked_by":"GASTAT population counts published per district, which would make the gate evaluable and would give the age columns real spatial variation"},{"key":"some_columns_are_unavailable","severity":"blocking","headline":"`households`, `daytime_pop_index`, `spend_potential` and `retail_gla_sqm` are unavailable — not estimated","statement":"These columns are empty. They could each have been filled with a plausible-looking number derived from the data that does exist, and they were not, because every available method produces a rescaling of a column we already have wearing a different label. An empty column is visibly empty; a fabricated one is not, and it would be weighted as a measurement in every score built on top of it. The scoring engine drops these factors and renormalises the remaining weights, and every score says what share of its intended weight was dropped.","affects":["households","daytime_pop_index","spend_potential","retail_gla_sqm"],"evidence":[{"column":"households","why":"The only household source available is a GASTAT governorate total. Distributing it by a constant households-per-person ratio yields a column that is a scalar multiple of `population` — no spatial signal, no information, but it looks like a measurement and would be weighted as one. A NULL column is honest; a constant-ratio one is not.","unblocked_by":"SS-1-04 (district calibration), blocked on SS-1-13","cells_with_a_value":0},{"column":"daytime_pop_index","why":"DATA_STRATEGY §2.2 needs five inputs. SS-2-04 delivered two (transit_stops, traffic_exposure); retail GLA is unavailable (SS-1-15) and school/university capacity is not ingested.","unblocked_by":"a workplace/education capacity source, plus SS-1-15 for GLA","cells_with_a_value":0},{"column":"spend_potential","why":"Two of its four factors are still unavailable. The GASTAT Household Expenditure Survey category basket was not obtained, so there is no basket to multiply by; and the age propensity term would multiply through a spatially constant age structure (SS-1-12 — exactly one distinct 65+ share across all 55,230 hexes). What is left is population × affluence × a constant, published in SAR — a currency-denominated restatement of two columns that already exist, and the currency is what would make it read as a measurement.","unblocked_by":"a GASTAT HES category basket, and SS-1-04 district age structure","cells_with_a_value":0},{"column":"retail_gla_sqm","why":"Requires building height or storey count. 169 of 756,675 Overture buildings carry a height and 397 carry explicit levels — 0.06% of the stock. Extrapolating GLA from that is fiction, not sparsity (SS-1-15).","unblocked_by":"SS-1-15 — a height/levels source, or a commercial GLA dataset","cells_with_a_value":0}],"unblocked_by":"SS-1-04 (district calibration), blocked on SS-1-13; SS-1-15 — a height/levels source, or a commercial GLA dataset; a GASTAT HES category basket, and SS-1-04 district age structure; a workplace/education capacity source, plus SS-1-15 for GLA"},{"key":"tier_1_is_an_index","severity":"material","headline":"The score is a suitability index, not a revenue forecast","statement":"A Tier 1 score is an index, not a forecast. It ranks locations against each other on the factors you weighted; it does not predict revenue and is never denominated in SAR. Revenue forecasting is Tier 4 and requires your own stores' sales history.","affects":["score"],"evidence":[{"tier":1,"model":"Weighted MCDA","requires":"nothing beyond the regional baseline","output":"0–100 suitability index","available":true},{"tier":2,"model":"Huff / gravity — distance-decay market share","requires":"a competitor set and an attractiveness proxy","output":"% share captured per competing site","available":false},{"tier":3,"model":"Analog — nearest neighbour to top-performing stores","requires":"roughly 20–30 of the tenant's own stores","output":"“this site resembles your Store 12 and Store 27”","available":false},{"tier":4,"model":"ML regression on trade-area features","requires":"roughly 50+ stores with sales history","output":"revenue forecast with a confidence band","available":false}],"unblocked_by":"your own store network and sales history — Tiers 2 to 4 unlock on data you already hold"}],"sources":{"region":"Riyadh","live_state":"ok","count":12,"share_alike_count":3,"sources":[{"key":"foursquare_places","source":"Foursquare OS Places","role":"Competition tier — POI inventory (DATA_STRATEGY §3).","licence":"Apache-2.0","licence_name":"Apache License 2.0","licence_url":"https://www.apache.org/licenses/LICENSE-2.0","source_url":"https://huggingface.co/datasets/foursquare/fsq-os-places","url":"https://huggingface.co/datasets/foursquare/fsq-os-places","credit_line":"© Foursquare Labs, Inc. Foursquare OS Places, licensed under the Apache License 2.0.","notice_text":"Copyright 2024 Foursquare Labs, Inc. All rights reserved.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.","notice_exempt_reason":"","share_alike":false,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"dt=2025-02-06","ledger_ingestor":"foursquare_places","secondary_payload_of":"","staging_tables":["staging.stg_foursquare_places"],"notes":"Apache-2.0 §4(d) requires the NOTICE itself to be redistributed, not merely a credit line — see notice_text.","provenance_candidates":[],"retrieved_at":"2026-08-15T04:33:16.133635+00:00","rows_written_last_run":179127},{"key":"osm","source":"OpenStreetMap","role":"Competition tier — POIs; accessibility tier — road class mix, junction density, traffic exposure and transit stops (SS-2-04). The ODbL anchor for §9 trap #2.","licence":"ODbL-1.0","licence_name":"Open Database License 1.0","licence_url":"https://opendatacommons.org/licenses/odbl/1-0/","source_url":"https://www.openstreetmap.org/copyright","url":"https://www.openstreetmap.org/copyright","credit_line":"© OpenStreetMap contributors, ODbL 1.0","notice_text":"","notice_exempt_reason":"","share_alike":true,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"Overpass API live query; Geofabrik gcc-states-latest.osm.pbf","ledger_ingestor":"osm_overpass","secondary_payload_of":"","staging_tables":["staging.stg_osm_pois","staging.stg_osm_roads","staging.stg_osm_junctions","staging.stg_osm_transit_stops"],"notes":"","provenance_candidates":[],"retrieved_at":"2026-08-15T04:24:28.403416+00:00","rows_written_last_run":14399},{"key":"overture_places","source":"Overture Maps Foundation — places","role":"Competition tier — POIs.","licence":"CDLA-Permissive-2.0","licence_name":"Community Data License Agreement — Permissive 2.0","licence_url":"https://cdla.dev/permissive-2-0/","source_url":"https://overturemaps.org/","url":"https://overturemaps.org/","credit_line":"© Overture Maps Foundation","notice_text":"","notice_exempt_reason":"","share_alike":false,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"release 2026-07-22.0, theme=places","ledger_ingestor":"overture_places","secondary_payload_of":"","staging_tables":["staging.stg_overture_places"],"notes":"The places theme is CDLA-Permissive-2.0 on the extract we hold. This is *not* transferable to the buildings theme — see overture_buildings.","provenance_candidates":[],"retrieved_at":"2026-08-15T04:30:41.507272+00:00","rows_written_last_run":41656},{"key":"overture_buildings","source":"Overture Maps Foundation — buildings","role":"Supply tier — building_count and footprint_area_sqm.","licence":"ODbL-1.0","licence_name":"Open Database License 1.0","licence_url":"https://opendatacommons.org/licenses/odbl/1-0/","source_url":"https://docs.overturemaps.org/guides/buildings/","url":"https://docs.overturemaps.org/guides/buildings/","credit_line":"© Overture Maps Foundation; contains data © OpenStreetMap contributors (ODbL)","notice_text":"","notice_exempt_reason":"","share_alike":true,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"release 2026-07-22.0, theme=buildings","ledger_ingestor":"overture_buildings","secondary_payload_of":"","staging_tables":["staging.stg_overture_buildings"],"notes":"Share-alike, despite the theme commonly being assumed permissive. Building-derived columns must stay tagged and separable in source_flags (§9 trap #2). Earlier runs are recorded in the ledger under CDLA-Permissive-2.0, before the per-extract check existed.","provenance_candidates":[],"retrieved_at":"2026-08-15T04:36:00.391205+00:00","rows_written_last_run":29328},{"key":"worldpop","source":"WorldPop","role":"Demand tier — age/sex structure.","licence":"CC-BY-4.0","licence_name":"Creative Commons Attribution 4.0 International","licence_url":"https://creativecommons.org/licenses/by/4.0/","source_url":"https://www.worldpop.org/","url":"https://www.worldpop.org/","credit_line":"WorldPop (www.worldpop.org), School of Geography and Environmental Science, University of Southampton — Global High Resolution Population Denominators Project. Licensed CC BY 4.0.","notice_text":"","notice_exempt_reason":"","share_alike":false,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"Global 2000-2020, SAU, 2020, 100 m (unconstrained)","ledger_ingestor":"worldpop_agesex","secondary_payload_of":"","staging_tables":["staging.stg_worldpop_agesex"],"notes":"Unconstrained product: the age/sex shares are spatially constant across the AOI and must never be presented as a differentiator between hexes.","provenance_candidates":[],"retrieved_at":"2026-08-15T05:44:44.019409+00:00","rows_written_last_run":55230},{"key":"kontur","source":"Kontur Population","role":"Demand tier — H3 population, input to dasymetric redistribution.","licence":"CC-BY-4.0","licence_name":"Creative Commons Attribution 4.0 International","licence_url":"https://creativecommons.org/licenses/by/4.0/","source_url":"https://data.humdata.org/dataset/kontur-population-dataset","url":"https://data.humdata.org/dataset/kontur-population-dataset","credit_line":"Kontur Population Dataset, © Kontur (kontur.io), CC BY 4.0","notice_text":"","notice_exempt_reason":"","share_alike":false,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"kontur_population_SA_20231101","ledger_ingestor":"kontur_population","secondary_payload_of":"","staging_tables":["staging.stg_kontur_population"],"notes":"","provenance_candidates":[],"retrieved_at":"2026-08-15T06:21:53.655796+00:00","rows_written_last_run":4835},{"key":"ghsl","source":"GHSL — Global Human Settlement Layer","role":"Supply tier — built-up surface, the dasymetric weighting surface.","licence":"EC-JRC-Free","licence_name":"European Commission JRC free reuse (GHSL)","licence_url":"https://eur-lex.europa.eu/eli/dec/2011/833/oj","source_url":"https://ghsl.jrc.ec.europa.eu/","url":"https://ghsl.jrc.ec.europa.eu/","credit_line":"European Commission, Joint Research Centre (JRC): Global Human Settlement Layer GHS-BUILT-S and GHS-POP, release R2023A (epoch 2020, 100 m, Mollweide)","notice_text":"","notice_exempt_reason":"","share_alike":false,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"R2023A, GHS-BUILT-S, epoch 2020, 100 m, Mollweide (ESRI:54009)","ledger_ingestor":"ghsl_builtup","secondary_payload_of":"","staging_tables":["staging.stg_ghsl_builtup"],"notes":"","provenance_candidates":[],"retrieved_at":"2026-08-15T04:35:45.178591+00:00","rows_written_last_run":48889},{"key":"geoboundaries","source":"geoBoundaries — SAU ADM2 (administrative boundaries)","role":"Base geography — governorate polygons carrying the census join.","licence":"ODbL-1.0","licence_name":"Open Database License 1.0","licence_url":"https://opendatacommons.org/licenses/odbl/1-0/","source_url":"https://www.geoboundaries.org/","url":"https://www.geoboundaries.org/","credit_line":"Boundaries © geoBoundaries (gbOpen, SAU ADM2), derived from OpenStreetMap contributors — © OpenStreetMap contributors, ODbL 1.0","notice_text":"","notice_exempt_reason":"","share_alike":true,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"gbOpen SAU ADM2 @ 9469f09","ledger_ingestor":"gastat_census","secondary_payload_of":"gastat_census","staging_tables":["staging.stg_gastat_districts"],"notes":"Share-alike. Upstream label says CC BY-SA 2.0; the operative licence is ODbL 1.0 via OpenStreetMap. Riyadh district (ADM3) polygons do not exist in this release, which is why the district-level baseline columns are deferred rather than approximated.","provenance_candidates":[],"retrieved_at":"2026-08-15T06:22:18.147647+00:00","rows_written_last_run":2},{"key":"gastat","source":"GASTAT — Saudi General Authority for Statistics","role":"Demand tier — governorate population and household counts.","licence":"Saudi-Open-Data","licence_name":"Saudi Open Data Licence","licence_url":"https://open.data.gov.sa/en/pages/termsofuse","source_url":"https://www.stats.gov.sa/","url":"https://www.stats.gov.sa/","credit_line":"General Authority for Statistics (GASTAT), Saudi Census 2022; republished by the Royal Commission for Riyadh City open-data portal under the KSA Open Data Licence","notice_text":"","notice_exempt_reason":"","share_alike":false,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"Saudi Census 2022 (via RCRC open-data portal)","ledger_ingestor":"gastat_census","secondary_payload_of":"","staging_tables":["staging.stg_gastat_districts"],"notes":"Redistribution terms under the Saudi Open Data Licence are an open §9 checklist item and need a KSA-side legal read: the terms page is behind the same F5 WAF that blocks open.data.gov.sa to non-KSA clients.","provenance_candidates":[],"retrieved_at":"2026-08-15T06:22:18.147647+00:00","rows_written_last_run":2},{"key":"srem","source":"SREM — Saudi Real Estate Market (Ministry of Justice)","role":"Affluence tier — real-estate transaction values.","licence":"Saudi-Open-Data","licence_name":"Saudi Open Data Licence","licence_url":"https://open.data.gov.sa/en/pages/termsofuse","source_url":"https://srem.moj.gov.sa/","url":"https://srem.moj.gov.sa/","credit_line":"Ministry of Justice — Saudi Real Estate Market (البورصة العقارية), Saudi Open Data Licence","notice_text":"","notice_exempt_reason":"","share_alike":false,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"Dashboard/GetAreaInfo transactions extract","ledger_ingestor":"srem_landvalue","secondary_payload_of":"","staging_tables":["staging.stg_srem_transactions","staging.stg_district_land_value"],"notes":"Same Saudi Open Data Licence review item as GASTAT — still open, and composition does not close it. Composed into land_value_sqm by SS-1-14 (baseline.compose_land_value) as the median of each district's monthly prices over a trailing 12-month window. Two caveats travel with every value and belong here too: the figure has DISTRICT granularity stored per hex, and the geography that places it on hexes is the `ksa_districts` layer, whose provenance is NOT established. Crediting SREM for these values is correct; treating the column as cleared for redistribution is not, until `ksa_districts` is resolved.","provenance_candidates":[],"retrieved_at":"2026-08-15T06:02:08.974021+00:00","rows_written_last_run":7528},{"key":"ksa_districts","source":"KSA district boundaries (user-supplied, provenance unverified)","role":"Base geography — district polygons carrying the SREM land-value join. NEEDS-REVIEW: now composed into land_value_sqm (SS-1-14) and, through it, into the modelled affluence_index (SS-1-08), with the licence question still open.","licence":"unknown","licence_name":"Unknown — provenance not established","licence_url":"","source_url":"file:pipelines/data/raw/districts/districts_ksa.geojson","url":"file:pipelines/data/raw/districts/districts_ksa.geojson","credit_line":"District boundaries: source unverified. Supplied without attribution or licence; provenance not established. Not cleared for redistribution or client-facing display.","notice_text":"","notice_exempt_reason":"","share_alike":false,"commercial_use":true,"attribution_required":true,"provenance_verified":false,"data_version":"user-supplied GeoJSON, 3,732 features, no version identifier","ledger_ingestor":"ksa_districts","secondary_payload_of":"","staging_tables":["staging.stg_ksa_districts","staging.stg_district_h3","staging.stg_district_srem_bridge"],"notes":"⚠️ NEEDS REVIEW BEFORE ANY USE BEYOND STAGING. No attribution, licence text or upstream URL accompanied this file. The property schema (district_id / city_id / region_id / name_ar / name_en) resembles Saudi National Address / SPL lineage but that is a resemblance, not a provenance. This layer supplies the geography that lands land_value_sqm on hexes and it carries NO population field — it is a district polygon layer, not a district census, so SS-1-04 census calibration and the ±5% district exit gate remain unevaluable and the banking and clinic profiles must keep refusing to score. SS-1-14 has since composed land_value_sqm through these polygons, and SS-1-08 composed the modelled affluence_index on top of that column, which it requires; both widened the exposure and resolved none of it. Withdrawing the layer means NULLing those two columns — `compose_land_value`'s reset path and `compose_affluence.ODBL_DROP_SQL` do exactly that, and no third column reads this geography. \n\nPROVENANCE RESEARCH (see provenance_candidates): the file is now traced, by measurement, to a public GeoJSON whose own README says it was scraped from the Saudi National Address portal. That identifies the lineage and closes NOTHING — the stated licence is a software copyleft over data the publisher did not own. The question is still open and this entry still carries UNKNOWN_PROVENANCE. \n\nThe layer's third and most visible consumer is not a column at all: district NAMES, which every client-facing deliverable prints. That exposure is now gated on the `district_names_cleared` capability (`baseline.clearance`), default False, so a deliverable renders reference ids and coordinates instead of names and stays releasable while this item is open.","provenance_candidates":[{"name":"homaily/Saudi-Arabia-Regions-Cities-and-Districts — geojson/districts.geojson","url":"https://github.com/homaily/Saudi-Arabia-Regions-Cities-and-Districts/blob/master/geojson/districts.geojson","stated_licence":"GPL-2.0 (repository LICENSE file)","stated_licence_url":"https://github.com/homaily/Saudi-Arabia-Regions-Cities-and-Districts/blob/master/LICENSE","match_evidence":["Feature count identical: 3,732 in both files.","Property blocks identical for all 3,732 features, in the same order, after dropping the two extra keys our copy carries (X, Y): district_id, city_id, region_id, name_ar, name_en all match byte-for-byte under a canonical JSON hash.","Geometry byte-identical on 3,663 of 3,732 features. The 69 that differ are all upstream Polygon rewritten as GeometryCollection (37), MultiPolygon (25), Polygon (6) or LineString (1) — the exact signature of a validity-repair pass over our copy, so our file is downstream of this one rather than a sibling of it.","Upstream README states the data was 'collected from https://maps.address.gov.sa/' — the Saudi National Address (Saudi Post / SPL) web map."],"blocks_clearance":"Two independent reasons, either one sufficient. (1) GPL-2.0 is a software copyleft licence with no database-rights grant; what it means applied to a GeoJSON, and what it would require of a hosted product rendering those names, is undetermined — and if it does reach, it reaches as copyleft. (2) The repository states the data was collected from a Saudi government address portal. A third party cannot grant terms it never held, so the operative licence is SPL's, which is not stated anywhere we can read. This is the GADM shape exactly: the best-matching dataset carrying terms that may forbid this use.","is_not_a_licence":true},{"name":"Saudi National Address (Saudi Post / SPL) — maps.address.gov.sa","url":"https://maps.address.gov.sa/","stated_licence":"not established — no public terms page located","stated_licence_url":"","match_evidence":["Named by the candidate above as its own upstream, so it is the root of the only lineage we have evidence for.","district_id is an 11-digit composite that decomposes exactly as 1 + region_id(2) + city_id(5) + sequence(3) — e.g. 10100003001 is region 01, city 00003, district 001 — a national identifier scheme, not an export artefact.","13 region_id values, matching the 13 administrative regions of Saudi Arabia; 152 distinct city_id values across 3,731 staged districts.","3,439 of 3,732 name_en values end in the literal 'Dist.', the transliteration convention of the National Address gazetteer."],"blocks_clearance":"No terms of use for bulk reuse or redistribution of National Address boundary data have been located. SPL publishes commercial API products, which implies the bulk geometry is licensed rather than open. Absence of a prohibition is not a permission.","is_not_a_licence":true}],"retrieved_at":"2026-08-16T11:28:50.049212+00:00","rows_written_last_run":3731},{"key":"h3_grid","source":"H3 — Uber hierarchical hexagonal grid (h3-pg)","role":"Base geography — the H3 res-8/res-9 cell grid itself.","licence":"Apache-2.0","licence_name":"Apache License 2.0","licence_url":"https://www.apache.org/licenses/LICENSE-2.0","source_url":"https://h3geo.org/","url":"https://h3geo.org/","credit_line":"H3 © Uber Technologies, Apache License 2.0","notice_text":"","notice_exempt_reason":"Software dependency, not redistributed. The deliverable carries H3 cell identifiers computed by the library, not the library or any part of its source, so nothing is distributed for §4(d) to attach to. The credit line is given anyway. If h3-pg is ever shipped inside a container image we hand to a client, this exemption stops holding and the upstream NOTICE must be obtained and set here.","share_alike":false,"commercial_use":true,"attribution_required":true,"provenance_verified":true,"data_version":"h3 4.5.0 / h3_postgis 4.5.0","ledger_ingestor":"h3_grid","secondary_payload_of":"","staging_tables":["region_baseline_h3"],"notes":"Software, not data: Apache-2.0 applies to the H3 library that generates the cell identifiers. Listed because every row of the baseline is keyed by one, and the ledger records it as a source.","provenance_candidates":[],"retrieved_at":"2026-08-16T21:49:54.866457+00:00","rows_written_last_run":0}],"notes":"retrieved_at is read from staging.baseline_ingest_runs, not declared in the registry: a date in source code is a claim about a run, a date in the ledger is a record of one. null means the source has never been successfully ingested here."},"attribution":{"endpoint":"/api/v1/attribution","page":"/api/v1/attribution/page","notice":"/api/v1/attribution/notice","compliance":"/api/v1/attribution/compliance"},"cache":{"hit":true,"ttl_seconds":900},"validation":{"harness":"SS-1-11","command":"python -m app.siteselect.baseline.validate --region Riyadh","region":"Riyadh","generated_at":"2026-08-31T02:40:06.718652+00:00","ok":false,"verdict_counts":{"INFO":6,"PASS":74,"FAIL":5,"N/A":1,"WARN":1},"exit_gate":{"specification":"DEVELOPMENT_PLAN §4 M1 — hex population sums within ±5% of GASTAT *district* totals","evaluable":false,"blocker":"SS-1-13 — no per-district population (polygons exist, census does not)"},"cells":{"8":6217,"9":42682},"held_out":[{"column":"households","ticket":"SS-1-02","reason":"The only household source is a GASTAT *governorate* total. Spreading it by a constant households-per-person ratio produces a column that is arithmetically a copy of `population` — no spatial signal, no new information — but that looks like a measurement and would be weighted as one in every downstream score.","unblocked_by":"SS-1-04 district calibration, itself blocked on SS-1-13","tier":"Tier 1 — demand"},{"column":"spend_potential","ticket":"SS-1-09","reason":"Two of its four factors are still unavailable. The GASTAT Household Expenditure Survey category basket was not obtained, so there is no basket to multiply by; and the age propensity term would multiply through a spatially constant age structure (SS-1-12 — exactly one distinct 65+ share across all 55,230 hexes). What is left is population × affluence × a constant, published in SAR — a currency-denominated restatement of two columns that already exist, and the currency is what would make it read as a measurement.","unblocked_by":"a GASTAT HES category basket, and SS-1-04 district age structure","tier":"Tier 1 — demand"},{"column":"retail_gla_sqm","ticket":"SS-1-05","reason":"Requires building height or storey count. 169 of 756,675 Overture buildings carry a height and 397 carry explicit levels — 0.06% of the stock. Extrapolating GLA from that is fiction, not sparsity (SS-1-15).","unblocked_by":"SS-1-15 — a height/levels source, or a commercial GLA dataset","tier":"Tier 2 — competition & supply"}],"licences":[{"licence":"Apache-2.0","name":"Apache License 2.0","share_alike":false,"attribution_required":true,"columns":[],"inherited_by":["affluence_index","poi_counts","brand_presence"]},{"licence":"CC-BY-4.0","name":"Creative Commons Attribution 4.0 International","share_alike":false,"attribution_required":true,"columns":["population","pop_age_0_14","pop_age_15_29","pop_age_30_44","pop_age_45_64","pop_age_65_plus"],"inherited_by":[]},{"licence":"CDLA-Permissive-2.0","name":"Community Data License Agreement — Permissive 2.0","share_alike":false,"attribution_required":true,"columns":[],"inherited_by":["affluence_index","poi_counts","brand_presence"]},{"licence":"EC-JRC-Free","name":"European Commission JRC free reuse (GHSL)","share_alike":false,"attribution_required":true,"columns":["built_up_pct"],"inherited_by":["population"]},{"licence":"ODbL-1.0","name":"Open Database License 1.0","share_alike":true,"attribution_required":true,"columns":["poi_counts","brand_presence","road_class_mix","junction_density","traffic_exposure","transit_stops","footfall_value","footfall_source","footfall_confidence","building_count","footprint_area_sqm"],"inherited_by":["population","affluence_index"]},{"licence":"Saudi-Open-Data","name":"Saudi Open Data Licence","share_alike":false,"attribution_required":true,"columns":["land_value_sqm"],"inherited_by":["affluence_index"]},{"licence":"derived","name":"Derived in-house from tagged inputs","share_alike":false,"attribution_required":false,"columns":["population","affluence_index"],"inherited_by":[]},{"licence":"unknown","name":"Unknown — provenance not established","share_alike":false,"attribution_required":true,"columns":[],"inherited_by":["affluence_index"]}],"findings":[{"check":"spatial_signal","verdict":"FAIL","statement":"`pop_age_0_14` is a fixed multiple of `population` (ratio CV 2.94e-08 < 1e-04). Its values vary between hexes, but every bit of that variation comes from `population` — as a differentiator it carries no information of its own.","evidence":["res 8: 4,835 cells, 2 distinct ratios (6 dp), ratio mean=0.24180048, ratio CV=2.94e-08","res 9: 24,425 cells, 2 distinct ratios (6 dp), ratio mean=0.24180048, ratio CV=3.98e-08"],"action":"Never present `pop_age_0_14` as a spatial differentiator, and never give it MCDA weight alongside `population` — that double-counts `population` under a second name.","column":"pop_age_0_14"},{"check":"spatial_signal","verdict":"FAIL","statement":"`pop_age_15_29` is a fixed multiple of `population` (ratio CV 3.01e-08 < 1e-04). Its values vary between hexes, but every bit of that variation comes from `population` — as a differentiator it carries no information of its own.","evidence":["res 8: 4,835 cells, 1 distinct ratios (6 dp), ratio mean=0.21900240, ratio CV=3.01e-08","res 9: 24,425 cells, 1 distinct ratios (6 dp), ratio mean=0.21900240, ratio CV=4.08e-08"],"action":"Never present `pop_age_15_29` as a spatial differentiator, and never give it MCDA weight alongside `population` — that double-counts `population` under a second name.","column":"pop_age_15_29"},{"check":"spatial_signal","verdict":"FAIL","statement":"`pop_age_30_44` is a fixed multiple of `population` (ratio CV 4.77e-08 < 1e-04). Its values vary between hexes, but every bit of that variation comes from `population` — as a differentiator it carries no information of its own.","evidence":["res 8: 4,835 cells, 1 distinct ratios (6 dp), ratio mean=0.30597054, ratio CV=4.77e-08","res 9: 24,425 cells, 2 distinct ratios (6 dp), ratio mean=0.30597054, ratio CV=4.86e-08"],"action":"Never present `pop_age_30_44` as a spatial differentiator, and never give it MCDA weight alongside `population` — that double-counts `population` under a second name.","column":"pop_age_30_44"},{"check":"spatial_signal","verdict":"FAIL","statement":"`pop_age_45_64` is a fixed multiple of `population` (ratio CV 3.57e-08 < 1e-04). Its values vary between hexes, but every bit of that variation comes from `population` — as a differentiator it carries no information of its own.","evidence":["res 8: 4,835 cells, 1 distinct ratios (6 dp), ratio mean=0.20383618, ratio CV=3.57e-08","res 9: 24,425 cells, 1 distinct ratios (6 dp), ratio mean=0.20383618, ratio CV=4.05e-08"],"action":"Never present `pop_age_45_64` as a spatial differentiator, and never give it MCDA weight alongside `population` — that double-counts `population` under a second name.","column":"pop_age_45_64"},{"check":"spatial_signal","verdict":"FAIL","statement":"`pop_age_65_plus` is a fixed multiple of `population` (ratio CV 3.13e-08 < 1e-04). Its values vary between hexes, but every bit of that variation comes from `population` — as a differentiator it carries no information of its own.","evidence":["res 8: 4,835 cells, 1 distinct ratios (6 dp), ratio mean=0.02939040, ratio CV=3.13e-08","res 9: 24,425 cells, 1 distinct ratios (6 dp), ratio mean=0.02939040, ratio CV=3.99e-08"],"action":"Never present `pop_age_65_plus` as a spatial differentiator, and never give it MCDA weight alongside `population` — that double-counts `population` under a second name.","column":"pop_age_65_plus"},{"check":"share_alike_separability","verdict":"WARN","statement":"18 populated column(s) rest on ODbL-1.0 data; 8 of them carry the `odbl_derived` flag that makes the share-alike subset selectable in one query.","evidence":["population: licence=CC-BY-4.0, derived, input licences=CC-BY-4.0, EC-JRC-Free, ODbL-1.0, odbl_derived=False, share_alike=True","pop_age_0_14: licence=CC-BY-4.0, input licences=—, odbl_derived=False, share_alike=False — reached via an upstream baseline column","pop_age_15_29: licence=CC-BY-4.0, input licences=—, odbl_derived=False, share_alike=False — reached via an upstream baseline column","pop_age_30_44: licence=CC-BY-4.0, input licences=—, odbl_derived=False, share_alike=False — reached via an upstream baseline column","pop_age_45_64: licence=CC-BY-4.0, input licences=—, odbl_derived=False, share_alike=False — reached via an upstream baseline column","pop_age_65_plus: licence=CC-BY-4.0, input licences=—, odbl_derived=False, share_alike=False — reached via an upstream baseline column","affluence_index: licence=derived, input licences=Apache-2.0, CDLA-Permissive-2.0, ODbL-1.0, Saudi-Open-Data, unknown, odbl_derived=True, share_alike=True","poi_counts: licence=ODbL-1.0, input licences=Apache-2.0, CDLA-Permissive-2.0, ODbL-1.0, odbl_derived=True, share_alike=True","brand_presence: licence=ODbL-1.0, input licences=Apache-2.0, CDLA-Permissive-2.0, ODbL-1.0, odbl_derived=True, share_alike=True","road_class_mix: licence=ODbL-1.0, input licences=—, odbl_derived=False, share_alike=True","junction_density: licence=ODbL-1.0, input licences=—, odbl_derived=False, share_alike=True","traffic_exposure: licence=ODbL-1.0, input licences=—, odbl_derived=False, share_alike=True","transit_stops: licence=ODbL-1.0, input licences=—, odbl_derived=False, share_alike=True","footfall_value: licence=ODbL-1.0, input licences=—, odbl_derived=True, share_alike=True","footfall_source: licence=ODbL-1.0, input licences=—, odbl_derived=True, share_alike=True","footfall_confidence: licence=ODbL-1.0, input licences=—, odbl_derived=True, share_alike=True","building_count: licence=ODbL-1.0, input licences=—, odbl_derived=True, share_alike=True","footprint_area_sqm: licence=ODbL-1.0, input licences=—, odbl_derived=True, share_alike=True"],"action":"Add `odbl_derived: true` to population, pop_age_0_14, pop_age_15_29, pop_age_30_44, pop_age_45_64, pop_age_65_plus, road_class_mix, junction_density, traffic_exposure, transit_stops — ODbL reaches them through an input, and separability has to be provable by query, not by reading prose (DATA_STRATEGY §9).","column":""},{"check":"exit_gate","verdict":"N/A","statement":"The M1 exit gate — hex population sums within ±5% of GASTAT DISTRICT totals — CANNOT BE EVALUATED. It is neither passed nor failed.","evidence":["Blocker SS-1-13: district POPULATION is missing. A user-supplied Riyadh district POLYGON layer was staged (189 districts) and SS-1-14 composes land_value_sqm through it — but it carries no population field, so it cannot supply the other half of this comparison.","open.data.gov.sa is F5 WAF-blocked to non-KSA clients, portal.saudicensus.sa no longer resolves, geoBoundaries has no ADM3 for SAU.","Only ADM2 governorate rows landed, so there is nothing to compare per district."],"action":"Obtain per-district GASTAT population for Riyadh (RCRC opendata.rcrc.gov.sa publishes districtcode/district/districtar attributes; likely needs a KSA network path), join it to staging.stg_ksa_districts, then run SS-1-04 calibration and re-run this harness. A polygon layer alone does NOT unblock this gate.","column":"population"}],"passing_checks":74,"explanation":"The baseline is measured by a re-runnable harness, not signed off by hand. It profiles every column, re-derives the population totals against their sources, and looks for columns that vary too little to carry information. Findings below are everything that is not a pass.","state":"fresh","age_seconds":7417},"scoring_engine":{"available":true,"schema":{"id":"siteselect.mcda_score.v1","version":"1.0.0"},"model":{"tier":1,"name":"weighted MCDA","output":"suitability index, 0-100","requires":"region baseline only","is_forecast":false,"currency_units":null,"honesty_note":"This is a relative suitability index, not a revenue forecast. It has no monetary interpretation and must never be labelled in SAR. Revenue estimation requires Tier 2 (Huff) for share and Tier 4 (ML) for value, neither of which is in this number."},"calibration":{"weights_calibrated":false,"weights_source":"PRD §4.4 placeholder profiles — direction and rough ranking per vertical, not fitted to observed store performance","calibrates_at":"SS-4-04, from tenant store performance"},"factors":[{"key":"population_density","label":"Resident population density","family":"demand","unit":"people per km2","description":"Resident population of the trade area per km2 of baseline-covered area. A density, not a total: the total scales with the trade area and would make the same site score differently at 10 and 15 minutes.","status":"available","dormant_reason":null,"unlocks_with":null,"notes":["9,272 of the region's res-9 cells have population NULL rather than 0 (Kontur never mentions them). SS-2-06 excludes them from the total and reports the coverage; a low-coverage value here is a floor, not a total."],"column":"population"},{"key":"daytime_pop_index","label":"Daytime vs resident population","family":"demand","unit":"index","description":"Ratio of daytime to resident population in the trade area.","status":"dormant","dormant_reason":"the column is NULL for Riyadh by design — no daytime-population source has been composed. It is not approximated from anything, because every available approximation would be a guess wearing a number's clothes.","unlocks_with":"SS-1-04 (district layer) plus a workplace/commute source","notes":[],"column":"daytime_pop_index"},{"key":"age_structure","label":"Age structure of the catchment","family":"demand","unit":"share of residents","description":"Share of the catchment in the age bands a vertical serves. Real as a count, useless as a differentiator today — see Gate 1.","status":"gated","dormant_reason":"the pop_age_* columns are WorldPop's national age pyramid applied through a spatially uniform share: every hex in Riyadh has the same age composition, and there is exactly one distinct 65+ share across all 55,230 cells. The counts are real; as a ranking factor they are a constant. The baseline says so itself, per cell, in source_flags->'<col>'->>'spatial_signal', and this engine reads that flag at runtime rather than hardcoding the verdict.","unlocks_with":"SS-1-04 — GASTAT district boundaries and counts, which give the age columns real spatial variation. On that day the flag flips to true and this factor becomes weightable with no change to this file.","notes":[],"column":"pop_age_30_44"},{"key":"affluence_index","label":"Household affluence","family":"spending_power","unit":"index","description":"Relative household affluence across the trade area.","status":"available","dormant_reason":null,"unlocks_with":null,"notes":["MODELLED, not measured. There is no open income dataset for Saudi Arabia at any sub-governorate granularity (DATA_STRATEGY §2.3), so nothing in this pipeline has observed a household income. SS-1-08 composes this from four normalised terms — SREM land value, the affluent-vs-deprivation venue mix in a k=2 hex disk, plot spaciousness and dwelling scale — renormalised per cell over the terms that cell has an input for. Any surface presenting it must carry the modelled flag and must never render it as income, in SAR, or as a percentile of income.","its largest single term is land value, which is a DISTRICT figure. A profile weighting both affluence_index and land_value is weighting the same SREM prices twice, once with each sign.","composed on 12,636 of 42,682 res-9 cells (29.6%) — every cell that has a land value and enough building or venue context to renormalise against. NULL means the model declined to guess, not that the area is poor; there is no default of 50 and no imputation."],"column":"affluence_index"},{"key":"spend_potential","label":"Addressable spend","family":"spending_power","unit":"currency per period","description":"Spend the catchment can direct at this category.","status":"dormant","dormant_reason":"NULL for Riyadh by design. SS-1-09 derives it from affluence and an HES basket, and affluence does not exist yet.","unlocks_with":"SS-1-08 affluence, then SS-1-09","notes":[],"column":"spend_potential"},{"key":"land_value","label":"Land cost","family":"spending_power","unit":"SAR per m2","description":"Land value per m2 — an input cost, so profiles weight it negatively. This is a cost the site carries, not an output of the score; the score itself remains an index and is never expressed in SAR.","status":"available","dormant_reason":null,"unlocks_with":null,"notes":["measured, not modelled: every number is the median of a district's monthly volume-weighted SREM transaction prices over a trailing 12-month window. Nothing is estimated or imputed.","DISTRICT granularity stored per hex. Every res-9 cell in a district carries that district's single price, so within-district variation — arterial frontage against interior streets — is absent. It ranks districts, not hexes.","priced on 19,817 of 42,682 res-9 cells (46.4%), from 131 priced districts. A catchment falling entirely in unpriced districts drops this factor through Gate 2 rather than borrowing a neighbour's price.","the SAR/m2 values are SREM's under the Saudi Open Data Licence, but the geography placing them on hexes is a user-supplied district layer with NO established licence or attribution (attribution.SOURCES['ksa_districts'], provenance_verified=False). That review is open and composing this column did not close it."],"column":"land_value_sqm"},{"key":"footfall_index","label":"Footfall (modelled proxy)","family":"footfall","unit":"relative index 0-100, region-normalised","description":"SS-2-08's footfall index. Modelled from POI, road and built-up inputs — NOT observed visitor counts, and NOT calibrated against any. It ranks cells against each other and estimates nobody.","status":"available","dormant_reason":null,"unlocks_with":null,"notes":["a modelled proxy: any surface presenting this factor must say so (PRODUCT_PLAN §6). It is the single largest weight in the F&B profile, so the score inherits its uncertainty."],"column":"footfall_value"},{"key":"traffic_exposure","label":"Traffic exposure","family":"accessibility","unit":"primary-arterial-equivalent metres per km2","description":"Class-weighted road length per km2 — how much through-traffic passes the trade area. Modelled from road class, not measured counts.","status":"available","dormant_reason":null,"unlocks_with":null,"notes":[],"column":"traffic_exposure"},{"key":"arterial_access","label":"Arterial road access","family":"accessibility","unit":"arterial metres per km2","description":"Metres of motorway, trunk, primary and secondary road (including links) per km2. Correlated with traffic_exposure by construction — both read road_class_mix — so a profile weighting both is weighting the road network twice, deliberately or otherwise.","status":"available","dormant_reason":null,"unlocks_with":null,"notes":[],"column":"road_class_mix"},{"key":"junction_density","label":"Street permeability","family":"accessibility","unit":"junctions per km2","description":"Street-network junction density: how many ways there are to reach the site on foot or by car. A local-access measure — the drive-time half of 'accessibility' is structural here, because the score is computed over an isochrone in the first place.","status":"available","dormant_reason":null,"unlocks_with":null,"notes":[],"column":"junction_density"},{"key":"transit_access","label":"Public transport access","family":"accessibility","unit":"stops per km2","description":"Public transport stop places per km2 of the trade area.","status":"available","dormant_reason":null,"unlocks_with":null,"notes":["Riyadh's OSM transit coverage is thin — 446 of 42,682 res-9 cells carry a stop at all. The factor discriminates the metro/BRT corridors from everywhere else and says little in between."],"column":"transit_stops"},{"key":"competitor_density","label":"Competitor density","family":"supply","unit":"competing outlets per km2","description":"Outlets in the vertical's own POI categories, per km2. The sign is the profile's to choose: positive where clustering helps (QSR), negative where a rival across the road takes the basket (grocery).","status":"available","dormant_reason":null,"unlocks_with":null,"notes":["counted from open POI data (Overture/Foursquare/OSM, SS-1-05), not from a licensed outlet register: it is a floor on the competitor set, not a census of it."],"column":"poi_counts"},{"key":"poi_density","label":"Commercial activity density","family":"supply","unit":"POIs per km2","description":"All countable POIs per km2 — general commercial vitality. Available and unweighted by every shipped seed, because footfall_index is already modelled from POI density and weighting both would count the same evidence twice.","status":"available","dormant_reason":null,"unlocks_with":null,"notes":[],"column":"poi_counts"},{"key":"built_up_pct","label":"Built-up surface share","family":"built_form","unit":"percent","description":"Share of the trade area's surface that is built (GHS-BUILT-S).","status":"available","dormant_reason":null,"unlocks_with":null,"notes":[],"column":"built_up_pct"},{"key":"building_density","label":"Building density","family":"built_form","unit":"buildings per km2","description":"Mapped building footprints per km2 (Overture).","status":"available","dormant_reason":null,"unlocks_with":null,"notes":[],"column":"building_count"},{"key":"network_gap","label":"Gap in the existing network","family":"network","unit":"index","description":"How far this site is from the tenant's own existing outlets — the factor that stops a recommendation landing 200 m from the client's own store (PRD §3 E4).","status":"dormant","dormant_reason":"not derivable from the region baseline at all: it is a function of the tenant's own store network, which is tenant-scoped data this engine is not given. Approximating it from competitor POIs would answer a different question and look identical.","unlocks_with":"M4 — tenant store upload (SS-4-01) and network analysis","notes":[],"column":null}],"factor_count":16,"factors_by_status":{"available":["population_density","affluence_index","land_value","footfall_index","traffic_exposure","arterial_access","junction_density","transit_access","competitor_density","poi_density","built_up_pct","building_density"],"dormant":["daytime_pop_index","spend_potential","network_gap"],"gated":["age_structure"]},"status_meanings":{"available":"the baseline carries this column and the engine will score it wherever a trade area has coverage. Whether a particular candidate got a value is a per-candidate question, answered by that score's dropped_factors.","dormant":"the column is empty, or the quantity is not derivable from the region baseline at all. The engine excludes the factor and reports the weight it dropped; it is never defaulted to zero.","gated":"the column has values but the baseline reports them as spatially constant. A weight here would rank candidates on a number that is identical everywhere, so the engine refuses to score the profile rather than producing a ranking that means nothing."},"seed_key_reconciliation":{"population":{"action":"renamed","to":"population_density","why":"the factor is people per km2, not people. A total scales with the trade area, so weighting it would score the analyst's isochrone dropdown as much as the site."},"accessibility":{"action":"renamed","to":"junction_density","why":"'accessibility' named two different things across the seeds — drive-time reach (grocery, logistics) and local permeability. The drive-time half is already structural: the score is computed over an isochrone. What is left, and what the baseline actually measures, is junction density. The rename makes the score's real content visible instead of borrowing the authority of a broader word."},"road_class":{"action":"renamed","to":"arterial_access","why":"names the quantity — arterial metres per km2 — rather than the column."},"land_cost":{"action":"renamed","to":"land_value","why":"matches the baseline column land_value_sqm. The cost framing lives in the sign of the weight, which is negative in every profile. Live since SS-1-14 — measured SREM prices at DISTRICT granularity, on 46.4% of res-9 cells. This is the factor whose absence made the logistics profile degenerate toward dense and central."},"footfall_index":{"action":"kept","to":"footfall_index","why":"reads footfall_value, which SS-2-08 publishes as a 0-100 region-normalised index. The seed key was already the honest name."},"traffic_exposure":{"action":"kept","to":"traffic_exposure","why":"normalised to per-km2 inside the engine; the key is unchanged."},"competitor_density":{"action":"kept","to":"competitor_density","why":"now resolved per vertical against the SS-1-06 unified POI taxonomy."},"transit_access":{"action":"kept","to":"transit_access","why":"reads transit_stops."},"daytime_pop_index":{"action":"kept","to":"daytime_pop_index","why":"column exists in the schema and is NULL by design — dormant, not dropped."},"affluence_index":{"action":"kept","to":"affluence_index","why":"live since SS-1-08. MODELLED, not measured — no income data for KSA exists at usable granularity, so the index is composed from land value, venue mix, plot spaciousness and dwelling scale. Weighted wherever a catchment has coverage (29.6% of res-9 cells); dropped through Gate 2 where it does not."},"spend_potential":{"action":"kept","to":"spend_potential","why":"dormant, NULL by design."},"age_structure":{"action":"kept","to":"age_structure","why":"kept at its authored weight on purpose. It trips Gate 1 today, which is the correct behaviour and makes the banking and clinic profiles refuse rather than rank on a constant. Moving the weight elsewhere would need a human to move it back the day SS-1-04 lands; leaving it means those profiles start working on their own."},"network_gap":{"action":"kept","to":"network_gap","why":"dormant — needs the tenant's own store network (M4)."}},"contract_endpoint":"/api/v1/scoring/contract","note":"The full refusal contract — what the scoring API declines to do and the HTTP status it declines with — is served from the running system at /api/v1/scoring/contract."}}