Overview G Core Inequality S Composite Scoring H Harmonization DataFrames CLI Reference
Docs / Core Engines / Harmonization

Cross-Country Harmonization Registry

The moveq_catalogue module provides a formal questionnaire contract registry for cross-country and cross-jurisdictional transport equity comparisons.

The Comparative Transit Problem

When an equity methodology designed for the United Kingdom (based on UK Index of Multiple Deprivation deciles and LSOA polygons) is applied to France (INSEE IRIS units) or the United States (Census Tracts), research teams often silently skip unavailable variables or quietly substitute metrics without documentation.

Zero Silent Methodology Drift
moveq-catalogue prevents silent omission. A base study defines a questionnaire of metric section IDs. Any adapted study must explicitly register one of three actions for every base section: SAME, REPLACE, or OMIT.

Tri-State Section Actions (SectionAction)

Action Requirements Description
SectionAction.SAME None The metric definition is preserved verbatim and calculated against local demographic data.
SectionAction.REPLACE replacement_title (str) The metric is substituted with a locally meaningful equivalent (e.g. replacing UK IMD with French INSEE IRIS deprivation index).
SectionAction.OMIT note (str) The section is dropped because no local data exists. Requires an explicit justification note explaining why.

Python Usage

harmonize_country.py Python 3.10+
from moveq_catalogue import Catalogue, SectionAction

# 1. Define base questionnaire established by lead study
base_sections = [
    "bus_stop_coverage_400m",
    "peak_hour_frequency",
    "evening_night_service",
    "socioeconomic_deprivation_rank"
]

# 2. Initialize catalogue for adapted study (e.g. France)
cat = Catalogue(base_sections, country="France")

# 3. Register explicit decisions for each section
cat.register("bus_stop_coverage_400m", SectionAction.SAME)
cat.register("peak_hour_frequency", SectionAction.SAME)
cat.register("evening_night_service", SectionAction.SAME)
cat.register(
    "socioeconomic_deprivation_rank",
    SectionAction.REPLACE,
    replacement_title="French INSEE IRIS Deprivation Decile"
)

# 4. Validate completeness (fails if any base section was forgotten)
issues = cat.validate()
if issues:
    print("Incomplete catalogue! Missing mappings:", issues)
else:
    print("✓ Catalogue valid and fully harmonized.")
    print("Summary:", cat.summary())
    # Output: Summary: {'same': 3, 'replace': 1, 'omit': 0}

Validation Rules

  • Duplicate Base Sections: Initializing Catalogue with duplicate base section IDs raises ValueError.
  • Unknown Section ID: Registering an action for an ID not present in base_sections raises ValueError.
  • Replace Without Title: Calling register(id, SectionAction.REPLACE) without replacement_title raises ValueError.
  • Omit Without Note: Calling register(id, SectionAction.OMIT) without note raises ValueError.
  • Incomplete Catalogue: validate() returns a list of error strings for any section IDs that remain unmapped.