fix(admissions): correct first_preference_offer_pct in dbt staging
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 18s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 49s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 1m12s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
Build and Push Docker Images / Build Backend (FastAPI) (push) Successful in 18s
Build and Push Docker Images / Build Frontend (Next.js) (push) Successful in 49s
Build and Push Docker Images / Build Pipeline (Meltano + dbt + Airflow) (push) Successful in 1m12s
Build and Push Docker Images / Trigger Portainer Update (push) Successful in 1s
The staging model was mapping EES column ``proportion_1stprefs_v_totaloffers`` straight onto ``first_preference_offer_pct``. That raw column is not a percentage — it is a ratio of first-preference applications to total offers (an oversubscription indicator, >1 means oversubscribed), so OLQH rendered as "1%" when the true first-choice success rate is 27/42 = 64%. The frontend display code is not at fault and is not patched here — data-quality issues must be fixed at the source. - stg_ees_admissions: compute ``first_preference_offer_pct`` as ``100 * number_1st_preference_offers / times_put_as_1st_preference`` — of families who listed this school first, the % that received an offer (0–100). Guard against divide-by-zero. - stg_ees_admissions: expose the legitimate EES ratio as the new column ``oversubscription_ratio`` (1st-preference applications per place) for future use, clearly named. - fact_admissions, FactAdmissions model, data_loader: propagate the new ``oversubscription_ratio`` column. - SchoolAdmissions type: document both columns inline. - buildSchoolSummary: reword the oversubscription clause so it reads sensibly across the whole 0–100 range (no more "just 64%"). - Hero chip subtitle: clearer phrasing "X% of first-choice applicants offered a place". Requires a dbt run of stg_ees_admissions and fact_admissions on deploy so the new column materialises. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -414,6 +414,7 @@ def get_supplementary_data(db: Session, urn: int) -> dict:
|
||||
"first_preference_applications": a.first_preference_applications,
|
||||
"first_preference_offers": a.first_preference_offers,
|
||||
"first_preference_offer_pct": a.first_preference_offer_pct,
|
||||
"oversubscription_ratio": a.oversubscription_ratio,
|
||||
"oversubscribed": a.oversubscribed,
|
||||
}
|
||||
if a
|
||||
|
||||
@@ -184,6 +184,7 @@ class FactAdmissions(Base):
|
||||
first_preference_applications = Column(Integer)
|
||||
first_preference_offers = Column(Integer)
|
||||
first_preference_offer_pct = Column(Float)
|
||||
oversubscription_ratio = Column(Float)
|
||||
oversubscribed = Column(Boolean)
|
||||
admissions_policy = Column(String(100))
|
||||
|
||||
|
||||
@@ -226,7 +226,7 @@ export function SchoolDetailView({
|
||||
<div className={styles.heroChipTitle}>Oversubscribed</div>
|
||||
<div className={styles.heroChipSub}>
|
||||
{admissions.first_preference_offer_pct != null
|
||||
? `${Math.round(admissions.first_preference_offer_pct)}% got first choice`
|
||||
? `${Math.round(admissions.first_preference_offer_pct)}% of first-choice applicants offered a place`
|
||||
: 'More applicants than places'}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -134,7 +134,10 @@ export interface SchoolAdmissions {
|
||||
total_applications: number | null;
|
||||
first_preference_applications?: number | null;
|
||||
first_preference_offers?: number | null;
|
||||
/** Of families who listed this school as 1st preference, the % that received an offer (0–100). */
|
||||
first_preference_offer_pct: number | null;
|
||||
/** 1st-preference applications per place offered (>1 means oversubscribed). */
|
||||
oversubscription_ratio?: number | null;
|
||||
oversubscribed: boolean | null;
|
||||
}
|
||||
|
||||
|
||||
@@ -557,11 +557,12 @@ export function buildSchoolSummary(
|
||||
// Admissions clause
|
||||
if (admissions?.oversubscribed) {
|
||||
if (admissions.first_preference_offer_pct != null) {
|
||||
const pct = Math.round(admissions.first_preference_offer_pct);
|
||||
parts.push(
|
||||
`heavily oversubscribed — just ${Math.round(admissions.first_preference_offer_pct)}% of applicants get a first-choice offer`,
|
||||
`oversubscribed — ${pct}% of first-choice applicants are offered a place`,
|
||||
);
|
||||
} else {
|
||||
parts.push('heavily oversubscribed');
|
||||
parts.push('oversubscribed');
|
||||
}
|
||||
} else if (admissions?.first_preference_offer_pct != null && admissions.first_preference_offer_pct >= 90) {
|
||||
parts.push('most families get their first-choice offer');
|
||||
|
||||
@@ -9,6 +9,7 @@ select
|
||||
first_preference_applications,
|
||||
first_preference_offers,
|
||||
first_preference_offer_pct,
|
||||
oversubscription_ratio,
|
||||
oversubscribed,
|
||||
admissions_policy
|
||||
from {{ ref('stg_ees_admissions') }}
|
||||
|
||||
@@ -29,7 +29,25 @@ renamed as (
|
||||
{{ safe_numeric('times_put_as_1st_preference') }}::integer as first_preference_applications,
|
||||
|
||||
-- Proportions
|
||||
{{ safe_numeric('proportion_1stprefs_v_totaloffers') }} as first_preference_offer_pct,
|
||||
-- first_preference_offer_pct: of families who listed this school FIRST,
|
||||
-- the percentage that received an offer. 0–100 scale.
|
||||
-- The raw EES column `proportion_1stprefs_v_totaloffers` stores a
|
||||
-- different, misleading figure (first-preference applications divided
|
||||
-- by total offers, i.e. an oversubscription ratio) — do not use it.
|
||||
case
|
||||
when {{ safe_numeric('times_put_as_1st_preference') }} > 0
|
||||
then 100.0
|
||||
* {{ safe_numeric('number_1st_preference_offers') }}
|
||||
/ {{ safe_numeric('times_put_as_1st_preference') }}
|
||||
end as first_preference_offer_pct,
|
||||
|
||||
-- Oversubscription ratio: 1st-preference applications per place offered.
|
||||
-- >1 means the school is oversubscribed on first preferences.
|
||||
case
|
||||
when {{ safe_numeric('total_number_places_offered') }} > 0
|
||||
then {{ safe_numeric('times_put_as_1st_preference') }}::numeric
|
||||
/ {{ safe_numeric('total_number_places_offered') }}
|
||||
end as oversubscription_ratio,
|
||||
|
||||
-- Derived: oversubscribed if 1st-preference applications > places offered
|
||||
-- Use already-cast columns to avoid repeating the regex expression
|
||||
|
||||
Reference in New Issue
Block a user