Phase 11.1A Completion Report — Major Description Infrastructure

Test count

105/105 passing

  • 100 pre-existing tests (unchanged)
  • 5 new tests in test_major_descriptions.py

Files created or modified

  • data/major_descriptions.yaml — New YAML data file; 3 authored entries keyed by CIP4 string: Computer Science (11.07), Mechanical Engineering (14.19), Psychology (42.01). Each entry has name, overview, what_youll_learn, typical_classes, and related_majors fields.

  • major_descriptions.py — New loader module at repo root. Provides load_major_descriptions() (LRU-cached, returns the full dict) and get_description(cip_code) (normalizes CIP4/CIP6 input, returns the entry dict or None).

  • requirements.txt — Added pyyaml>=6.0 (was not a project dependency; required by the new YAML loader).

  • pages/major_explorer.py — Two changes:
    1. Added from major_descriptions import get_description import.
    2. Added _render_major_description(cip_code, fallback_name) render function (inline Streamlit rendering, no return value).
    3. Called _render_major_description inside render() between the selectbox resolution and the outcomes panel, separated by st.divider().
  • test_major_descriptions.py — New test file at repo root. Five tests covering: dict return type, key presence on a hit, CIP6→CIP4 normalization, miss returning None, and bad-input safety (None, "", "not.a.code").

Deviations from spec

None. The implementation matches the spec exactly.


Decisions not covered by spec — notes for Phase 11.1B

  1. YAML scalar style for overview: The spec didn’t specify YAML scalar style. The overview paragraphs are written as folded block scalars (>) which collapses newlines to spaces, producing clean single-paragraph strings. Phase 11.1B authors should use the same style for consistency.

  2. related_majors includes 4 entries per sample, not 3: The spec shows 3 in the schema example but doesn’t cap the list. All three sample entries use 4 related majors. Phase 11.1B can use any count.

  3. st.divider() before the description block: The spec says to insert the description “immediately after the major is resolved from session state and before the outcomes panel.” A st.divider() is added before the description to visually separate it from the picker widget above, consistent with how other panels are separated throughout the page. This is minor and can be removed if the design direction changes.

  4. No try/except wrapper: The spec says to wrap the function call in a try/except “if the function is straightforward enough to be obviously safe” — the function is fully safe (it reads a cached dict and renders static Streamlit elements, with no I/O or network calls at render time), so the try/except was omitted per the spec’s own guidance.

  5. Placement relative to existing cip4_str variable: The existing code computes cip4_str = _cip_int_to_cip4_str(cip_code) later in the render function (at the wages/projections section). The description call uses selected_row["cip_code_display"] (already in XX.XX format) rather than duplicating the conversion or moving cip4_str earlier. Both produce the same string; this avoids touching variable layout in the existing render flow.