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
Cataloguewith duplicate base section IDs raisesValueError. - Unknown Section ID: Registering an action for an ID not present in
base_sectionsraisesValueError. - Replace Without Title: Calling
register(id, SectionAction.REPLACE)withoutreplacement_titleraisesValueError. - Omit Without Note: Calling
register(id, SectionAction.OMIT)withoutnoteraisesValueError. - Incomplete Catalogue:
validate()returns a list of error strings for any section IDs that remain unmapped.