apiVersion: v3.1.0
kind: DataContract
id: education.hope_eligible_graduates
name: hope_eligible_graduates
version: 1.0.0
status: active
domain: education
tenant: georgia-public-data
description:
  purpose: 'Governor''s Office of Student Achievement (GOSA) HOPE Eligibility dataset. For every Georgia
    public high school, school district, and the state as a whole, reports the number of graduating seniors
    who met the academic eligibility criteria for Georgia''s HOPE scholarship program. Three metrics:
    num_graduates (regular graduates), num_hope_eligible (subset that met HOPE academic eligibility),
    and hope_eligible_rate (the share that met eligibility, on a 0-1 decimal scale). Coverage: spring
    2004 through spring 2024 (21 files; filename year = spring graduation year). No demographic / gender
    / race breakdowns — every row is the all-students total. There is a substantive series break between
    2006 and 2007: state-level percent eligible drops from ~62% (2006) to ~38% (2007+). This reflects
    a real methodology change in HOPE eligibility determination, not a data-processing artifact: beginning
    with the high school graduating class of 2007, the Georgia Student Finance Commission (GSFC) began
    computing each student''s HOPE GPA directly from electronic high-school transcript data (the GSFC-calculated
    HOPE GPA) rather than relying on the school-reported GPA used previously. The break is preserved as
    published, not ''fixed''. Treat 2004-2006 and 2007-2024 as separate eras when comparing percentages.'
  usage: Star-schema fact table. Join the districts dimension on district_code; the schools dimension
    on district_code + school_code. Read directly with DuckDB over Parquet.
  limitations: 'Suppressed cells are NULL (not zero). State rows have NULL district_code and school_code;
    district rows have NULL school_code. Derived-aggregate caveat: for 2008 the bronze ships only school-level
    rows, so all district and state aggregate rows are derived here (sum of counts, graduate-count-weighted
    mean for hope_eligible_rate); the derived 2008 state total matches the bronze State Level sheet exactly
    (Renaissance Academy, fully orphaned, is excluded by both). For 2004 the bronze has school + state
    rows but no district rollups, so the 2004 district rows are likewise derived from the school rows.
    A separate known 2004 bronze artifact means the official state total (68,163 graduates / 42,233 eligible)
    is ~0.2% higher than the sum of itemized 2004 school rows, so a user roll-up from schools/districts
    to state will be ~0.2% short for 2004 only.'
tags:
- education
- governor's office of student achievement
- hope_eligible_graduates
servers:
- server: s3_gold
  type: s3
  location: s3://georgia-data-gold/education/hope_eligible_graduates/**/*.parquet
  format: parquet
- server: local_gold
  type: local
  path: data/gold/education/hope_eligible_graduates/**/*.parquet
  format: parquet
schema:
- name: hope_eligible_graduates
  logicalType: object
  physicalType: parquet
  physicalName: hope_eligible_graduates
  description: hope_eligible_graduates fact table, year-partitioned Parquet (split by detail level where
    present).
  dataGranularityDescription: One row per year, district_code, school_code (geography columns are NULL
    at higher aggregation levels).
  customProperties:
  - property: sub_topic
    value: gosa
  - property: detail_levels
    value:
    - schools
    - districts
    - states
  - property: default_detail
    value: schools
  - property: grain
    value:
    - year
    - district_code
    - school_code
  - property: key_metric
    value: hope_eligible_rate
  - property: null_semantics
    value:
      suppressed_to_null: true
      zero_is_real: true
  - property: partition_columns
    value:
    - year
  - property: path_template
    value: education/hope_eligible_graduates/year={year}/{detail}.parquet
  - property: foreign_keys
    value:
    - column: district_code
      target_object: districts
      target_columns:
      - district_code
      attribute_columns:
      - district_name
      - district_census_id
      - district_type
      scope: domain
    - column: school_code
      target_object: schools
      target_columns:
      - district_code
      - school_code
      attribute_columns:
      - school_name
      scope: domain
  - property: example_queries
    value:
    - description: Latest year (2024), schools detail
      query: SELECT * FROM hope_eligible_graduates WHERE year = 2024 LIMIT 100
    - description: District 601 in 2024
      query: SELECT * FROM hope_eligible_graduates WHERE district_code = '601' AND year = 2024 LIMIT 100
  properties:
  - name: year
    logicalType: integer
    physicalType: int
    required: true
    description: Spring graduation year (e.g., 2024 = spring-2024 graduating class, 2023-2024 school year).
      For Era 1 and Era 2 files the filename year is cross-checked against the LONG_SCHOOL_YEAR column's
      ending year and must match.
    examples:
    - 2024
    customProperties:
    - property: column_role
      value: year
    - property: label
      value: Year
    primaryKey: true
    primaryKeyPosition: 1
  - name: district_code
    logicalType: string
    physicalType: string
    required: false
    description: 3-digit GOSA district code (zero-padded). 7-digit charter / state-school codes pass through
      unchanged (e.g., 7820412). NULL for state-level aggregate rows. FK to districts dimension.
    examples:
    - '601'
    relationships:
    - to: districts.district_code
    customProperties:
    - property: column_role
      value: fk_district
    - property: label
      value: District Code
    primaryKey: true
    primaryKeyPosition: 2
  - name: school_code
    logicalType: string
    physicalType: string
    required: false
    description: 4-digit GOSA school code (zero-padded). NULL for district- and state-level aggregate
      rows. FK to schools dimension (composite PK with district_code). Bronze padding is inconsistent
      across eras (the composite-key eras ship unpadded 3-digit codes; Era 2 mixes by year; 2008 mixes
      within the file); the transform normalizes to 4 digits via zfill.
    examples:
    - '0103'
    relationships:
    - to: schools.district_code
    - to: schools.school_code
    customProperties:
    - property: column_role
      value: fk_school
    - property: label
      value: School Code
    primaryKey: true
    primaryKeyPosition: 3
  - name: num_graduates
    logicalType: integer
    physicalType: bigint
    required: false
    description: Number of regular high-school graduates in the cohort. NULL when suppressed in bronze
      (TFS = Too Few Students, applied per the 2009 source SQL when graduates <= 9; affects 2009 and 2011-2024)
      or when the bronze cell is genuinely blank — a value GOSA left unreported (all 2014 and 2020 NULLs
      are blank cells; those files contain no TFS markers). The 2004-2008 and 2010 files have no suppression,
      so their values are uncensored.
    examples:
    - 335
    customProperties:
    - property: column_role
      value: metric
    - property: label
      value: Number Graduates
    - property: unit
      value: count
    - property: metric_component
      value: denominator
  - name: num_hope_eligible
    logicalType: integer
    physicalType: bigint
    required: false
    description: Number of graduates in this cohort who met HOPE academic eligibility (GPA + required-course
      requirements). NULL when TFS-suppressed or when the bronze cell is genuinely blank (both occur in
      2011-2020; see the suppression note). May be 0 (e.g., Renaissance Academy in 2008 had 28 graduates
      and 0 HOPE-eligible — a real zero, not suppression). Never exceeds num_graduates (enforced by a
      quality check; 0 violations in bronze).
    examples:
    - 170
    customProperties:
    - property: column_role
      value: metric
    - property: label
      value: Number HOPE Eligible
    - property: unit
      value: count
    - property: metric_component
      value: numerator
  - name: hope_eligible_rate
    logicalType: number
    physicalType: double
    required: false
    description: Share of graduates that met HOPE academic eligibility, on a 0-1 decimal scale (bronze
      0-100 divided by 100). NULL when TFS-suppressed or genuinely blank in bronze (see the suppression
      note). For derived district + state aggregates (2008 all levels above school; 2004 district level)
      and bronze rows merged under one school code (the 2004 trailing-x pairs, the 2008 Westside pair),
      this is computed as num_hope_eligible / num_graduates — a graduate-count weighted mean across the
      contributing rows. Reconciles with the published counts within 0.005 everywhere (measured max deviation
      0.0005, from 1-decimal bronze rounding).
    examples:
    - 0.5075
    customProperties:
    - property: column_role
      value: metric
    - property: label
      value: HOPE Eligible Rate
    - property: short_description
      value: Share of graduates that met HOPE academic eligibility, on a 0-1 scale; NULL when suppressed
        (too few students).
    - property: unit
      value: proportion
    - property: key_metric
      value: true
  quality:
  - type: sql
    name: non_empty
    description: The dataset has at least one row.
    dimension: completeness
    query: SELECT COUNT(*) FROM {object}
    mustBeGreaterThan: 0
  - type: sql
    name: num_graduates_non_negative
    description: num_graduates is a count (>= 0).
    dimension: accuracy
    query: SELECT COUNT(*) FROM {object} WHERE num_graduates IS NOT NULL AND num_graduates < 0
    mustBe: 0
  - type: sql
    name: num_hope_eligible_non_negative
    description: num_hope_eligible is a count (>= 0).
    dimension: accuracy
    query: SELECT COUNT(*) FROM {object} WHERE num_hope_eligible IS NOT NULL AND num_hope_eligible < 0
    mustBe: 0
  - type: sql
    name: hope_eligible_rate_within_unit_interval
    description: hope_eligible_rate is a bounded proportion on the [0, 1] scale.
    dimension: accuracy
    query: SELECT COUNT(*) FROM {object} WHERE hope_eligible_rate IS NOT NULL AND (hope_eligible_rate
      < 0 OR hope_eligible_rate > 1)
    mustBe: 0
  - type: sql
    name: num_hope_eligible_not_exceeding_num_graduates
    description: The HOPE-eligible subset (num_hope_eligible) never exceeds the graduating cohort (num_graduates)
      where both are present. Verified 0 violations across all 21 bronze files.
    dimension: consistency
    query: SELECT COUNT(*) FROM {object} WHERE num_hope_eligible IS NOT NULL AND num_graduates IS NOT
      NULL AND num_hope_eligible > num_graduates
    mustBe: 0
  - type: sql
    name: hope_eligible_rate_reconciles_with_count_over_graduates
    description: Where all three metrics are present and num_graduates > 0, the published rate equals
      num_hope_eligible / num_graduates within 0.005 (0.5pp). Measured max bronze deviation is 0.0005
      — half-ulp of the 1-decimal rounding used in 2004-2007 and 2010; derived/merged rows are exact by
      construction.
    dimension: consistency
    query: SELECT COUNT(*) FROM {object} WHERE hope_eligible_rate IS NOT NULL AND num_hope_eligible IS
      NOT NULL AND num_graduates IS NOT NULL AND num_graduates > 0 AND ABS(hope_eligible_rate - (CAST(num_hope_eligible
      AS DOUBLE) / num_graduates)) > 0.005
    mustBe: 0
  - type: sql
    name: suppression_nulls_graduates_last
    description: 'Co-null structure of TFS suppression: whenever num_graduates is NULL, num_hope_eligible
      and hope_eligible_rate are NULL too (full suppression censors all three together; partial suppression
      censors only the eligible count and/or the rate, never the graduate count alone). Verified 0 violations
      across all bronze years.'
    dimension: consistency
    query: SELECT COUNT(*) FROM {object} WHERE num_graduates IS NULL AND (num_hope_eligible IS NOT NULL
      OR hope_eligible_rate IS NOT NULL)
    mustBe: 0
  - type: sql
    name: exactly_one_state_row_per_year
    description: 'Structural fact: every published year carries exactly one statewide rollup row (both
      geography keys NULL) — from bronze in 20 years, derived from school rows in 2008. More or fewer
      means a level-classification or aggregation bug.'
    dimension: completeness
    query: SELECT COUNT(*) FROM (SELECT year FROM {object} WHERE district_code IS NULL AND school_code
      IS NULL GROUP BY year HAVING COUNT(*) <> 1) AS bad_years
    mustBe: 0
customProperties:
- property: title
  value: HOPE-Eligible Graduates
- property: summary
  value: Georgia high school graduates who met the academic eligibility criteria for the HOPE scholarship,
    by school, district, and state, 2004-2024.
- property: source
  value: Governor's Office of Student Achievement (GOSA)
- property: source_url
  value: https://gosa.georgia.gov/dashboards-data-report-card/downloadable-data
- property: update_frequency
  value: annual
- property: year_range
  value: 2004-2024
- property: schema_hash
  value: 09bef34719e284141e0b1b30494b268f25cc91bf4d8295935c38624d7e371346
- property: available_years
  value:
  - 2004
  - 2005
  - 2006
  - 2007
  - 2008
  - 2009
  - 2010
  - 2011
  - 2012
  - 2013
  - 2014
  - 2015
  - 2016
  - 2017
  - 2018
  - 2019
  - 2020
  - 2021
  - 2022
  - 2023
  - 2024
- property: year_gaps
  value: []
