Compliance Mapping Frameworks for Spatial Epidemiology Pipelines

This guide is part of the Spatial Epidemiology Fundamentals & Data Standards foundation, and it covers how to encode legal, privacy, and statistical constraints as deterministic gates that every geospatial output must clear before reaching a dashboard or an agency report. A compliance mapping framework is the governance layer that sits between raw spatial ingestion and analytical routines: it enforces field-level metadata, validates coordinate references, applies statistical disclosure control, and writes an audit trail that survives a statutory review without watering down the underlying epidemiology.

Compliance Framework as a Governance Layer A three-tier stack. The top tier is raw spatial ingestion (case points, boundary polygons, environmental rasters). It flows down into the compliance mapping framework, the governance layer, which holds four responsibilities side by side: field-level metadata, coordinate-reference validation, statistical disclosure control, and an append-only audit trail. Only data that clears that layer flows down to the bottom tier of analytical routines and agency-facing dashboards. A side rail shows the audit trail capturing every approve or reject decision for statutory review. Raw spatial ingestion case points · boundary polygons · environmental rasters Compliance mapping framework — governance layer Field-level metadata CRS validation Disclosure control Audit trail approved only Analytical routines & dashboards clustering · exposure models · agency reports Append- only log approve / reject statutory review The framework is executable policy between ingestion and analysis — not a document

Concept & Epidemiological Alignment

A compliance mapping framework is not a document — it is executable policy. In disease surveillance, environmental exposure assessment, and health-resource allocation, the same geometry can be lawful at one aggregation level and a reportable privacy breach at another. The framework’s job is to make the difference deterministic: given a dataset and a target use, it either approves the data or rejects it with a logged reason, never silently degrades it.

Use a framework like this when datasets carry protected health information, when outputs feed inter-agency handoffs, or when longitudinal analyses must reconcile shifting administrative boundaries. The controlling assumptions that must hold in public health surveillance data are concrete:

  • Minimum population thresholds apply to every geographic identifier. The HIPAA Privacy Rule restricts geographic units smaller than a state, permitting the first three ZIP digits only when the aggregated population exceeds 20,000 (HHS Safe Harbor guidance).
  • k-anonymity holds at the geometry level, not just the attribute level — a polygon that isolates a single household re-identifies it regardless of how the attributes are masked.
  • Coordinate references are explicit and authorized, because an undeclared or unexpected projection silently biases distance decay, buffer radii, and spatial autocorrelation statistics.
  • Transformations are reproducible, so that an auditor can replay ingestion and obtain a byte-identical result.

Where a generic GIS validation script stops at “is the geometry valid?”, a compliance framework adds the regulatory and statistical predicates above and refuses to pass anything it cannot defend. It complements rather than replaces method-level rigor: downstream code in the Disease Clustering & Spatial Statistical Modeling topic area assumes the data it receives has already cleared these gates.

Decision Flow: From Raw Dataset to Approved Layer

Every dataset passes through layered compliance gates before it can reach analytical routines. A record only becomes “approved” when it satisfies the disclosure threshold and carries an authorized coordinate reference with valid topology; failing either branch routes the record to suppression/aggregation or to a logged rejection rather than into the analytical set.

Compliance Mapping Governance Flow A vertical governance flow: a raw spatial dataset enters a metadata registry with schema and lineage checks; if it does not meet the disclosure threshold it is suppressed or aggregated for k-anonymity and re-checked; once it does, CRS and topology validation runs; if geometry is invalid or the CRS is not authorized the record is rejected and logged; otherwise it is approved for analysis and dashboards. Raw spatial dataset Metadata registry schema & lineage checks Meets disclosure threshold? Suppress / aggregate k-anonymity No CRS & topology validation Yes Geometry valid & CRS authorized? Reject + log validation failure No Approved for analysis & dashboards Yes Governance flow — datasets clear disclosure and CRS gates before reaching analysis

The same logic expressed as a gate-by-gate contract clarifies what each stage owns and what a failure does:

Gate Validates On failure
Metadata registry Schema version, controlled vocabularies, lineage fields present Reject, log missing fields
Disclosure threshold k-anonymity ≥ k, population ≥ statutory minimum Suppress or aggregate, re-check
CRS authorization EPSG code is recognized and on the allow-list Reject, log unauthorized datum
Topology validation is_valid, no slivers below area floor Repair if safe, else reject
Lineage export Deterministic ordering, hashed config written Block release until written

Spatial Data Prerequisites

Before the framework can issue an approval, inputs must satisfy structural prerequisites:

  • Geometry type — vector polygons for aggregated rates, points for case locations; mixed-type layers are split, never silently coerced.
  • Coordinate reference — a defined CRS on the allow-list. Enforce canonical Coordinate Reference Systems for Public Health so distance, buffer, and weights operations run in a metric projection rather than raw degrees.
  • Topology — geometries pass is_valid; self-intersections, sliver polygons, and duplicate vertices are repaired or rejected before any spatial join.
  • Format — an interoperable, schema-preserving container. Standardize ingestion on the options described in Spatial Data Types & Formats — GeoPackage or GeoParquet — which retain attribute typing and spatial indexing without proprietary lock-in.
  • Precision — a fixed coordinate-rounding tolerance (commonly 6 decimal places for decimal degrees) applied consistently, so that precision itself never becomes an unlogged re-identification vector. Aggressive precision reduction is governed by the Precision Standards in Epi Mapping rules.
  • Minimum sample size — small-area denominators must clear the disclosure floor; cells below it are merged upward before rate calculation.

Coordinate validation should verify EPSG codes against the allow-list, restrict datum transformations to explicitly authorized pipelines, and reject layers lacking a defined spatial reference. Using pyproj and shapely, the framework programmatically confirms CRS consistency and flags topology violations before any join executes. Mixed vector formats are read through GDAL/OGR drivers so translation preserves the spatial reference rather than dropping it.

Production Implementation

The framework below integrates validation gates, parameterized thresholds, deterministic ordering, and centralized audit logging. It enforces CRS authorization, repairs or rejects invalid geometry, applies a statistical-disclosure area floor, and writes a hashed lineage record for replay.

# Pinned: geopandas==0.14.4, pyproj==3.6.1, shapely==2.0.4 (Python 3.11)
import json
import hashlib
import logging
from datetime import datetime, timezone

import geopandas as gpd
import pyproj
from shapely.validation import make_valid

# Audit logger — one structured line per compliance event
logging.basicConfig(
    filename="compliance_audit.log",
    level=logging.INFO,
    format="%(asctime)s | %(levelname)s | %(message)s",
)

TARGET_CRS = "EPSG:4326"          # storage/output reference
METRIC_CRS = "EPSG:5070"          # CONUS Albers — equal-area, for areal filtering
AUTHORIZED_CRS = {4326, 5070, 4269, 3857}  # allow-list of EPSG codes
MIN_AREA_KM2 = 0.001              # statistical-disclosure floor on tiny polygons


def _config_hash() -> str:
    """Hash the compliance configuration so a run is reproducible and auditable."""
    cfg = {
        "target_crs": TARGET_CRS,
        "metric_crs": METRIC_CRS,
        "authorized_crs": sorted(AUTHORIZED_CRS),
        "min_area_km2": MIN_AREA_KM2,
    }
    return hashlib.sha256(json.dumps(cfg, sort_keys=True).encode()).hexdigest()


def validate_and_transform(input_path: str, output_path: str, stable_id: str = "geoid") -> dict:
    gdf = gpd.read_file(input_path)

    # 1. CRS authorization — reject undeclared or off-allow-list references
    if not gdf.crs:
        logging.error("Rejected: input layer lacks a defined CRS")
        raise ValueError("Input layer lacks defined CRS. Rejecting for compliance.")
    src_epsg = gdf.crs.to_epsg()
    if src_epsg not in AUTHORIZED_CRS:
        logging.error("Rejected: unauthorized CRS EPSG:%s", src_epsg)
        raise ValueError(f"Unauthorized CRS EPSG:{src_epsg}. Not on allow-list.")
    if src_epsg != pyproj.CRS(TARGET_CRS).to_epsg():
        logging.info("Transforming EPSG:%s -> %s", src_epsg, TARGET_CRS)
        gdf = gdf.to_crs(TARGET_CRS)

    # 2. Geometry validation & topology repair (logged, never silent)
    invalid = ~gdf.geometry.is_valid
    if invalid.any():
        logging.warning("Repairing %d invalid geometries", int(invalid.sum()))
        gdf.loc[invalid, "geometry"] = gdf.loc[invalid, "geometry"].apply(make_valid)

    # 3. Statistical disclosure control — drop sub-floor polygons (area in equal-area CRS)
    gdf["area_km2"] = gdf.to_crs(METRIC_CRS).geometry.area / 1e6
    before = len(gdf)
    gdf = gdf[gdf["area_km2"] >= MIN_AREA_KM2].copy()

    # 4. Deterministic ordering — stable sort so output is byte-reproducible
    if stable_id in gdf.columns:
        gdf = gdf.sort_values(stable_id, kind="mergesort").reset_index(drop=True)

    # 5. Lineage metadata + export
    metadata = {
        "ingestion_timestamp": datetime.now(timezone.utc).isoformat(),
        "source_crs": f"EPSG:{src_epsg}",
        "target_crs": TARGET_CRS,
        "config_sha256": _config_hash(),
        "records_before": before,
        "records_after": len(gdf),
        "validation_status": "PASS",
    }
    gdf.to_file(output_path, driver="GPKG")
    with open(f"{output_path}.metadata.json", "w") as fh:
        json.dump(metadata, fh, indent=2)
    logging.info("Pipeline complete: %d records -> %s", len(gdf), output_path)
    return metadata

The metadata registry that backs the stable_id and controlled vocabularies above is built out in Building a HIPAA-Compliant Spatial Metadata Schema, which extends ISO 19115-2 and FGDC CSDGM fields so lineage is machine-readable rather than free text. For deployment, wrap each gate in a pytest fixture, parameterize the constants via environment variables, and run the suite in CI so a merge is blocked whenever a compliance check fails.

Parameter Selection & Tuning

The framework’s behavior is governed by a small set of parameters that must be chosen deliberately and version-controlled:

  • AUTHORIZED_CRS allow-list — keep it minimal: a storage CRS (EPSG:4326), the jurisdiction’s analytical projection (UTM zone or State Plane), and an equal-area CRS for areal computations. Every code not on the list is a rejection, not a silent reprojection.
  • METRIC_CRS for area — never compute area in EPSG:4326. Use an equal-area projection (EPSG:5070 for CONUS) so the disclosure floor means a real square-kilometre value.
  • MIN_AREA_KM2 disclosure floor — set from the smallest defensible reporting unit, not an arbitrary epsilon. Document the population that the floor corresponds to.
  • k for k-anonymity — choose per data-use agreement (commonly k ≥ 11 for cell-suppression regimes); record the chosen k alongside the output.
  • Precision tolerance — coordinate rounding is a tuning knob, not a default; tighter precision raises re-identification risk and must be logged.

When the approved data later feeds spatial autocorrelation, the same discipline applies to analytical parameters — minimum neighbor thresholds and false-discovery-rate correction are tuned in Global & Local Moran’s I Implementation, and every sensitivity sweep is logged beside the model output.

Edge Cases & Failure Modes

  • Transboundary CRS drift — datasets spanning two UTM zones or State Plane zones cannot share a single analytical projection without distortion; detect the span and route each partition through its zone-appropriate CRS before merging.
  • Island and sliver polygonsmake_valid can emit GeometryCollection fragments; filter to the intended geometry type after repair so a repaired multipolygon does not smuggle in zero-area lines.
  • Zero and sub-floor denominators — small-area rates with near-zero populations explode under division; merge cells upward to the disclosure floor before computing rates, and log every merge.
  • Boundary version drift — administrative zones change between census vintages, breaking longitudinal denominators. Pin the boundary vintage in lineage metadata and reconcile updates with an explicit crosswalk rather than a spatial overlay.
  • Memory at scale (N > 50k) — read in chunks or use a spatially partitioned GeoParquet layout, and build a spatial index before joins so predicate evaluation stays on indexed bounding boxes.
  • Silent attribute-key duplication — verify that attribute merges preserve primary keys without fan-out; a duplicated key inflates case counts and corrupts every downstream rate.

Compliance & Audit Controls

Defensibility depends on the run being reproducible and the decisions being recorded:

  • Deterministic execution — sort by a stable identifier before export (the kind="mergesort" stable sort above) so two runs on identical input produce byte-identical output.
  • Configuration logging with SHA-256 — hash the compliance configuration (CRS allow-list, thresholds, precision) into the lineage record so an auditor can prove which policy produced a given release.
  • Append-only audit log — every transform, repair, suppression, and rejection writes a timestamped line; the log is the evidence trail for a statutory review.
  • Output schema — export a documented column set (geoid, area_km2, rate fields) with ISO 19115 metadata, including source and target CRS, record counts before and after suppression, and the validation status.
  • Provenance for handoff — the .metadata.json sidecar travels with the layer so a receiving agency inherits the full lineage rather than reconstructing it.

Treating compliance as a parameterized, testable component of the data lifecycle removes manual audit overhead while preserving the statistical rigor that high-stakes public health decisions demand.