How andifathulms/paribus works
Purpose and System Shape
Paribus is a research pipeline and publication system estimating performance differences associated with competing under untested powerlifting rules. Its core product is a guarded identification workflow, not athlete-level analytics. The backend processes public competition records through reproducible stages; the frontend presents aggregate findings, methodology, and downloadable data.
Entry points are Django management commands in backend/manage.py, the versioned DRF API at backend/apps/api/urls.py, and Next.js routes under frontend/src/app/.
Runtime and Storage Boundaries
The backend is Django 5/Python 3.11 with DRF, Polars and statistical/ML libraries; it runs with PostgreSQL 16 for pipeline metadata and estimates, Redis/Celery for asynchronous work, and local parquet for row-level competition records. Deployment is containerized through docker-compose.yml, backend/Dockerfile, and frontend/Dockerfile.
Postgres deliberately does not become a raw-data warehouse: data paths and shared settings are centralized in backend/apps/common/paths.py and backend/apps/common/config.py.
1. Acquisition, Validation, and Cleaning
The ingest domain downloads either the OpenPowerlifting corpus or synthetic data, validates its schema, and writes cleaned analytical records. Its commands establish the first pipeline boundary:
• backend/apps/ingest/management/commands/fetch_data.py
• backend/apps/ingest/management/commands/validate_schema.py
• backend/apps/ingest/cleaning.py
Cleaning rules are externally frozen in config/cleaning.yml; raw-to-clean transformation should remain reproducible and separate from downstream inference.
2. Privacy-Preserving Identity Resolution
Identity resolution links records into lifter-level panels while avoiding publication of names. It combines linkage, similarity/plausibility checks, optional hand-labeled classifier candidates, and validation/reporting:
• backend/apps/identity/linkage.py
• backend/apps/identity/services.py
• backend/apps/identity/models.py
Published identifiers use a configured salt, and API serialization is structurally constrained from returning lifter names. Identity definitions are controlled by config/identity.yml; alternative identity sets feed sensitivity analysis.
3. Cohort Construction and Feasibility
Cohort builders convert linked clean records into design-eligible populations, partitioning incompatible equipment and event categories rather than pooling them. They also make and persist the same-meet/RQ2 feasibility decision before estimation:
• backend/apps/cohorts/builders.py
• backend/apps/cohorts/services.py
• backend/apps/cohorts/models.py
Definitions are frozen via config/cohorts.yml, creating a boundary between population specification and statistical execution.
4. Event-Study Identification Gate
The event-study stage centers switchers on first untested competition and evaluates pre-switch trends. Its recorded verdict is a hard dependency: estimation cannot proceed without it.
• backend/apps/eventstudy/gate.py
• backend/apps/eventstudy/services.py
• backend/apps/eventstudy/management/commands/event_study.py
This is the primary control-flow gate between cohort assembly and causal-style reporting.
5. Estimation and Stored Results
Estimation executes naive, within-lifter fixed-effects, and eligible same-meet designs, with clustered lifter standard errors and intervals/sample counts required on persisted estimates:
• backend/apps/estimation/design.py
• backend/apps/estimation/services.py
• backend/apps/estimation/models.py
Specification definitions reside in config/specs.yml. Heterogeneity and spline-related analysis are adjacent but remain within the estimation domain.
6. Robustness as Validity Enforcement
Robustness procedures test placebo behavior, propensity matching, federation exclusion, and identity sensitivity:
• backend/apps/robustness/placebo.py
• backend/apps/robustness/propensity.py
• backend/apps/robustness/sensitivity.py
The placebo command is a material quality gate: failure exits non-zero and invalidates the within-lifter headline rather than merely annotating it.
7. Publication API and Dashboard
DRF exposes aggregate estimates, downloads, and health/framing information; serializers and routes enforce the no-athlete-surface boundary:
• backend/apps/api/views.py
• backend/apps/api/viewsets.py
• backend/apps/api/downloads.py
The Next.js frontend consumes this API through frontend/src/lib/api.ts and presents findings/data/methodology routes, notably frontend/src/app/findings/page.tsx and frontend/src/app/data/page.tsx. Charts visualize aggregate uncertainty and event-study outputs, not individual careers.
Main entry points: estimation/services.py Estimation · identity/services.py Identity resolution · cohorts/services.py Cohort construction · gate.py Event-study gate
Components 17
Research pipeline
Reproducible identification and estimation stages.
- Ingest and clean · Downloads, validates, and cleans competition records.
backend/apps/ingest/management/commands/fetch_data.py - Cleaning rules
config/cleaning.yml - Identity resolution · Builds privacy-preserving lifter panels and validation reports.
backend/apps/identity/services.py - Identity definitions
config/identity.yml - Cohort construction · Partitions compatible populations and records feasibility.
backend/apps/cohorts/services.py - Cohort definitions
config/cohorts.yml - Event-study gate · Records the pre-trend verdict required before estimation.
backend/apps/eventstudy/gate.py - Estimation · Runs naive, within-lifter, and eligible same-meet designs.
backend/apps/estimation/services.py - Specifications
config/specs.yml - Robustness enforcement · Placebo failure invalidates the within-lifter headline.
backend/apps/robustness/placebo.py
Publication surface
Aggregate-only API and dashboard.
- Aggregate publication API · Routes and serializers exclude lifter names and athlete-level surfaces.
backend/apps/api/urls.py - Data downloads · Publishes aggregate downloadable outputs.
backend/apps/api/downloads.py - API client
frontend/src/lib/api.ts - Findings and data dashboard · Presents aggregate uncertainty, event studies, methods, and data.
frontend/src/app/findings/page.tsx
Storage and execution
Runtime persistence boundaries.
- Competition records · Raw and cleaned row-level records remain outside Postgres.
backend/apps/common/paths.py - Pipeline metadata and estimates · Stores workflow metadata, verdicts, cohorts, and aggregate estimates.
- Async workers
Connections 21
- Cleaning rules → Ingest and clean: governs
- Ingest and clean → Competition records: writes cleaned records
- Competition records → Identity resolution: clean records
- Identity definitions → Identity resolution: governs
- Identity resolution → Cohort construction: linked panels
- Cohort definitions → Cohort construction: governs
- Cohort construction → Event-study gate: eligible switchers
- Event-study gate → Estimation: passing verdict required
- Specifications → Estimation: defines designs
- Estimation → Robustness enforcement: headline estimates
- Identity resolution → Pipeline metadata and estimates: panel metadata
- Cohort construction → Pipeline metadata and estimates: cohorts and feasibility
- Event-study gate → Pipeline metadata and estimates: recorded verdict
- Estimation → Pipeline metadata and estimates: persisted estimates
- Robustness enforcement → Pipeline metadata and estimates: validity status
- Async workers → Ingest and clean: runs async work
- Async workers → Estimation: runs async work
- Pipeline metadata and estimates → Aggregate publication API: aggregate results
- Aggregate publication API → Data downloads: serves download outputs
- Aggregate publication API → API client: aggregate API responses
- API client → Findings and data dashboard: findings and data