Phase 4.5 Verification Report
Phase 4.5 Verification Report
Detail card renderer location
- File:
app.py - Function:
render_detail_card - Lines: 1644–1766
- Helper called by it:
_render_program_outcomes— Lines 1588–1641
FoS data in detail card?
Found. _render_program_outcomes is called at the bottom of render_detail_card (line 1766) and does exactly what Phase 8.5 requires:
# app.py lines 1588–1641
def _render_program_outcomes(school_row: pd.Series, name: str) -> None:
"""
Phase 8 — Step 8.5. Render the school's program-level outcomes for the
major currently selected on the Major Explorer tab. Three cases:
Case 1: school does not offer the major at all
Case 2: school offers the major but reports no values for it
Case 3: at least one value is reported — render metric tiles
"""
cip_code = st.session_state.get("selected_cip") # ← reads the bridge key
if cip_code is None or cip_code == 0:
return
unit_id_val = school_row.get("unit_id")
if pd.isna(unit_id_val):
return
fos_df = major_explorer.load_field_of_study() # ← loads field_of_study_cleaned.csv
major_label = major_explorer.get_selected_major_label(fos_df, int(cip_code))
if major_label is None:
return
program = major_explorer.get_school_program_outcomes(
fos_df, int(unit_id_val), int(cip_code) # ← per-school FoS lookup
)
st.markdown(f"**Program-level outcomes — {major_label}**")
# Case 1: school does not offer this major
if program is None:
st.caption(f"_{name} does not offer this major._")
return
# Case 2: offers but all four metrics are NaN (cohort below n=30)
all_missing = all(pd.isna(v) for v in program.values())
if all_missing:
st.caption(
f"_{name} offers this major, but the program's cohort size fell "
"below the Scorecard's reporting threshold (n < 30)._"
)
return
# Case 3: render metric tiles
cols = st.columns(4)
tiles = [
("median_earnings_1yr", "Earnings, 1yr"),
("median_earnings_4yr", "Earnings, 4yr"),
("median_earnings_5yr", "Earnings, 5yr"),
("median_debt", "Median debt"),
]
for col_widget, (col_name, label) in zip(cols, tiles):
val = program[col_name]
display = "—" if pd.isna(val) else f"${val:,.0f}"
col_widget.metric(label, display)
The call site in render_detail_card:
# app.py line 1764–1766
# Phase 8 — Step 8.5: Program-level outcomes for the major
# currently selected on the Major Explorer tab.
_render_program_outcomes(school_row, name)
Session_state bridge from Major Explorer?
Found. pages/major_explorer.py defines the key constant and writes it on every render:
# major_explorer.py lines 41–44
# Session-state key for the currently selected CIP code (stored as int to
# match the dtype in the source CSV). Read by Steps 8.3-8.5 and by the
# School Finder tab in Step 8.5.
SELECTED_CIP_KEY = "selected_cip"
# major_explorer.py line 872 (inside render())
st.session_state[SELECTED_CIP_KEY] = int(selected_row["cip_code"])
Additionally, app.py wires selected_cip into the URL parameter system so
the selection survives page shares/bookmarks (line 166):
# app.py line 166
"cip": ("selected_cip", int, 0),
Verdict: A — Fully shipped
Phase 4.5 is fully implemented. The Major Explorer tab writes
st.session_state["selected_cip"] whenever a user picks a major (or on
first load, defaulting to 0). The School Finder’s render_detail_card
function calls _render_program_outcomes, which reads that same key, loads
field_of_study_cleaned.csv via the cached major_explorer.load_field_of_study()
helper, looks up the specific school–major combination, and renders four
st.metric tiles (1yr earnings, 4yr earnings, 5yr earnings, median debt)
directly inside each pinned school’s detail card. All three required cases
are handled: major not offered, offered but below reporting threshold, and
offered with reportable data. No missing code — both sides of the bridge
exist and are connected.
If verdict is B or C — what’s missing
N/A — verdict is A.