| from __future__ import annotations |
|
|
| from dataclasses import dataclass |
|
|
|
|
| @dataclass(frozen=True) |
| class BaselineAssumptions: |
| total_reference_population: int = 10_000_000 |
| uncertainty_low: float = 0.72 |
| uncertainty_high: float = 1.28 |
|
|
|
|
| BASELINE = BaselineAssumptions() |
|
|
| BASELINE_REFERENCE_OPTIONS = { |
| "demo_reference_pool": { |
| "label": "Demo working pool (10M)", |
| "value": 10_000_000, |
| "note": "Synthetic starting universe for scenario testing; not the full Ukraine population.", |
| }, |
| "sssu_jan_2022_total": { |
| "label": "SSSU Jan 2022 total population", |
| "value": 41_167_335, |
| "note": "Official pre-full-scale-invasion total population estimate cited by ACAPS.", |
| }, |
| "custom": { |
| "label": "Custom starting pool", |
| "value": 1_000_000, |
| "note": "Editable starting universe for a narrower adult, regional, platform, or pre-filtered pool.", |
| }, |
| } |
|
|
| SALARY_ANCHORS_UAH = { |
| "official_pfu_2025_average": 20_654, |
| "kse_workua_jan_2026_median": 27_500, |
| "workua_current_average": 28_600, |
| } |
|
|
| INCOME_THRESHOLD_OPTIONS_UAH = [ |
| 0, |
| 20_000, |
| 25_000, |
| 30_000, |
| 35_000, |
| 40_000, |
| 45_000, |
| 50_000, |
| 60_000, |
| 70_000, |
| 80_000, |
| 90_000, |
| 100_000, |
| 125_000, |
| 150_000, |
| 200_000, |
| 250_000, |
| 300_000, |
| 400_000, |
| 500_000, |
| 750_000, |
| 1_000_000, |
| ] |
|
|
| INCOME_CURVE_POINTS_UAH = [ |
| (0, 1.0), |
| (SALARY_ANCHORS_UAH["official_pfu_2025_average"], 0.55), |
| (SALARY_ANCHORS_UAH["workua_current_average"], 0.42), |
| (45_000, 0.25), |
| (70_000, 0.10), |
| (100_000, 0.055), |
| (200_000, 0.015), |
| (500_000, 0.002), |
| (750_000, 0.001), |
| (1_000_000, 0.0005), |
| ] |
|
|
| SOURCE_LINKS = [ |
| { |
| "label": "Work.ua salary statistics", |
| "url": "https://www.work.ua/en/salary-all/", |
| "note": "Current salary benchmark from job postings; Work.ua states that the median is calculated from recent vacancies.", |
| }, |
| { |
| "label": "KSE Ukraine Monthly Economic Update, February 2026", |
| "url": "https://institute.kse.ua/wp-content/uploads/2026/02/ukraine_monthly_economic_update_eng_february_2026.pdf", |
| "note": "Cites Work.ua January 2026 offered median salary of UAH 27,500.", |
| }, |
| { |
| "label": "Pension Fund of Ukraine average wage indicator, 2025", |
| "url": "https://www.pfu.gov.ua/2170600-pokaznyk-serednoyi-zarobitnoyi-platy-za-2025-rik/", |
| "note": "Official average wage indicator used for pension calculations; annual 2025 value is UAH 20,653.55.", |
| }, |
| { |
| "label": "DOU developer salary statistics", |
| "url": "https://jobs.dou.ua/salaries/?switch_lang=en", |
| "note": "IT salary survey and CSV-backed salary analytics for Ukrainian tech roles.", |
| }, |
| { |
| "label": "Djinni salary guide", |
| "url": "https://guide.djinni.co/salaries", |
| "note": "Tech salary benchmarks for Ukraine-focused hiring; useful for high-income scenario context.", |
| }, |
| { |
| "label": "ACAPS Ukraine population data sources report", |
| "url": "https://www.acaps.org/fileadmin/Data_Product/Main_media/20230818_ACAPS_Thematic_report_Ukraine_estimates_and_sources_of_population_data.pdf", |
| "note": "Explains baseline population datasets and cites SSSU January 2022 total population estimate.", |
| }, |
| { |
| "label": "State Statistics Service of Ukraine 2022 overview", |
| "url": "https://www.ukrstat.gov.ua/operativ/infografika/2022/o_soc_ek_Ukr/01_2022_e.pdf", |
| "note": "Official population-statistics context and methodology notes.", |
| }, |
| ] |
|
|
| AGE_BAND_FACTORS = { |
| "18-24": 0.12, |
| "25-34": 0.22, |
| "35-44": 0.20, |
| "45-54": 0.18, |
| "55-70": 0.28, |
| } |
|
|
| REGION_FACTORS = { |
| "all_ukraine": 1.0, |
| "large_cities": 0.34, |
| "kyiv_region": 0.13, |
| "western_regions": 0.24, |
| } |
|
|
| TARGET_POPULATION_FACTORS = { |
| "all_adults": 1.0, |
| "women": 0.53, |
| "men": 0.47, |
| } |
|
|
| RELATIONSHIP_STATUS_FACTORS = { |
| "any": 1.0, |
| "not_married": 0.46, |
| "single_or_divorced": 0.32, |
| } |
|
|
| HEIGHT_FACTORS = { |
| 150: 1.0, |
| 160: 0.92, |
| 165: 0.82, |
| 170: 0.67, |
| 175: 0.48, |
| 180: 0.28, |
| 185: 0.13, |
| 190: 0.04, |
| } |
|
|
| EDUCATION_FACTORS = { |
| "any": 1.0, |
| "higher_education": 0.38, |
| "graduate_plus": 0.16, |
| } |
|
|
| CHILDREN_STATUS_FACTORS = { |
| "any": 1.0, |
| "no_children": 0.62, |
| "has_children": 0.31, |
| "co_parenting_ready": 0.18, |
| } |
|
|
| FUTURE_CHILDREN_FACTORS = { |
| "any": 1.0, |
| "wants_children": 0.48, |
| "does_not_want_children": 0.22, |
| "open_or_undecided": 0.58, |
| } |
|
|
| MILITARY_STATUS_FACTORS = { |
| "any": 1.0, |
| "civilian_or_not_serving": 0.91, |
| "active_service": 0.07, |
| "veteran_or_service_history": 0.15, |
| } |
|
|
| RELOCATION_FACTORS = { |
| "any": 1.0, |
| "same_city_only": 0.22, |
| "open_to_relocation": 0.36, |
| "remote_or_long_distance_ok": 0.44, |
| } |
|
|
| HOUSING_FACTORS = { |
| "any": 1.0, |
| "independent_living": 0.48, |
| "own_or_stable_housing": 0.29, |
| } |
|
|
| SMOKING_FACTORS = { |
| "any": 1.0, |
| "non_smoker": 0.72, |
| "ok_with_smoking": 1.0, |
| } |
|
|
| ALCOHOL_FACTORS = { |
| "any": 1.0, |
| "rare_or_none": 0.46, |
| "moderate_ok": 0.76, |
| } |
|
|
| LANGUAGE_FACTORS = { |
| "any": 1.0, |
| "ukrainian_comfortable": 0.82, |
| "english_comfortable": 0.38, |
| "ukrainian_and_english": 0.31, |
| } |
|
|
| PETS_FACTORS = { |
| "any": 1.0, |
| "pet_friendly": 0.54, |
| "no_pets_preferred": 0.42, |
| } |
|
|
| DATA_QUALITY_NOTES = [ |
| { |
| "label": "Population", |
| "note": "Replace demo baseline with current age-sex population estimates before publication.", |
| }, |
| { |
| "label": "Relationship status", |
| "note": "Official marital status does not equal real availability; label as estimated.", |
| }, |
| { |
| "label": "Income", |
| "note": "Income thresholds above public medians are scenario cutoffs. Open sources do not provide a universal real maximum salary.", |
| }, |
| { |
| "label": "Height", |
| "note": "Height currently requires proxy distribution unless a Ukraine-specific source is validated.", |
| }, |
| { |
| "label": "Military status", |
| "note": "War-related filters are sensitive, time-changing, and should stay scenario-only until sourced.", |
| }, |
| { |
| "label": "Children", |
| "note": "Children and co-parenting filters are preference-context assumptions, not value judgments.", |
| }, |
| { |
| "label": "Independence", |
| "note": "Multiplying many filters assumes independence; use results as a stress test, not a factual census.", |
| }, |
| ] |
|
|