apiVersion: v3.1.0
kind: DataContract
id: education.ccrpi_graduation_rate
name: ccrpi_graduation_rate
version: 1.1.0
status: active
domain: education
tenant: georgia-public-data
description:
  purpose: 'Georgia high school graduation rates at the school, district, and state level by demographic
    subgroup, 2012-2025. A single `graduation_rate` column (0-1 scale) carries three distinct methodologies
    discriminated by `rate_type`: the federal adjusted 4-year cohort rate (2012-2025), the 5-year cohort
    variant (2018-2024), and the Senate Bill 431 on-time rate (2021-2024, school-level only). `num_cohort`
    and `num_graduates` carry the published denominator/numerator where a source ships them; CCRPI accountability
    years add an improvement `indicator_target` and color `ccrpi_flag`. Sources span six release families
    (CCRPI workbooks, legacy 2012-2014 releases, standalone 4-year and 5-year cohort releases, SB 431
    on-time releases, and a GOSA-portal CSV that fills the 2023 4-year count gap), merged by source precedence.
    This topic publishes the underlying graduation rates by methodology and demographic; the CCRPI Graduation
    Rate component score as it feeds the accountability index (a distinct benchmarked value, not equal
    to the raw 4-year rate) — alongside the overall CCRPI score and the other four component scores —
    lives in the `ccrpi_scoring_by_component` topic (the CCRPI overview).'
  usage: Star-schema fact table. Join the districts dimension on district_code; the schools dimension
    on district_code + school_code; the demographics dimension on demographic. 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.
tags:
- education
- georgia insights
- ccrpi_graduation_rate
servers:
- server: s3_gold
  type: s3
  location: s3://georgia-data-gold/education/ccrpi_graduation_rate/**/*.parquet
  format: parquet
- server: local_gold
  type: local
  path: data/gold/education/ccrpi_graduation_rate/**/*.parquet
  format: parquet
schema:
- name: ccrpi_graduation_rate
  logicalType: object
  physicalType: parquet
  physicalName: ccrpi_graduation_rate
  description: ccrpi_graduation_rate fact table, year-partitioned Parquet (split by detail level where
    present).
  dataGranularityDescription: One row per year, district_code, school_code, demographic, rate_type (geography
    columns are NULL at higher aggregation levels).
  customProperties:
  - property: sub_topic
    value: georgiainsights
  - property: detail_levels
    value:
    - schools
    - districts
    - states
  - property: default_detail
    value: schools
  - property: grain
    value:
    - year
    - district_code
    - school_code
    - demographic
    - rate_type
  - property: key_metric
    value: graduation_rate
  - property: null_semantics
    value:
      suppressed_to_null: true
      zero_is_real: true
  - property: partition_columns
    value:
    - year
  - property: path_template
    value: education/ccrpi_graduation_rate/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
    - column: demographic
      target_object: demographics
      target_columns:
      - demographic
      attribute_columns:
      - demographic_label
      - demographic_category
      scope: global
  - property: example_queries
    value:
    - description: Latest year (2025), schools detail
      query: SELECT * FROM ccrpi_graduation_rate WHERE year = 2025 LIMIT 100
    - description: District 601 in 2025
      query: SELECT * FROM ccrpi_graduation_rate WHERE district_code = '601' AND year = 2025 LIMIT 100
    - description: Filter by rate_type = 4_year
      query: SELECT * FROM ccrpi_graduation_rate WHERE rate_type = '4_year' AND year = 2025 LIMIT 100
  properties:
  - name: year
    logicalType: integer
    physicalType: int
    required: true
    description: Graduation (cohort end) calendar year. For `4_year` rows, the spring the cohort was due
      to graduate; for `5_year` rows, the cohort's 4-year year + 1 had already passed (the rate is published
      one year later but keyed to the cohort year measured); for `on_time` rows, the SB 431 graduation
      year. Sourced from the bronze year column where one exists (CCRPI/legacy/on-time files; cross-checked
      against the filename) and from the filename for the standalone cohort releases. The February 2018
      standalone release carries 2017-cohort data and lands in 2017.
    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) for standard districts; 7-digit code for state-charter/state-school
      operators; the allowlisted pseudo-district code `RTC` (Residential Treatment Center aggregate, data
      years 2015-2018 only). NULL for state-level rows. FK to the 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; later bronze years strip leading zeros). NULL
      for district- and state-level rows. FK to the schools dimension (composite key with district_code).
    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: demographic
    logicalType: string
    physicalType: string
    required: true
    description: Canonical demographic code (FK to demographics dimension). 10 subgroups are reported
      across every era (all, asian_pacific_islander, black, hispanic, white, multiracial, native_american,
      economically_disadvantaged, english_learners, students_with_disabilities); 8 more (active_duty,
      female, male, foster_care, homeless, migrant, not_economically_disadvantaged, students_without_disabilities)
      appear ONLY in 2023 via the GOSA 4-year cohort CSV's wider breakdown. Race uses the combined `asian_pacific_islander`
      bucket — no source file publishes separate Asian or Pacific Islander rows. `American Indian/Alaskan
      [Native]` label drift folds to `native_american`; the GOSA CSV's `Limited English Proficient` folds
      to `english_learners`.
    examples:
    - 'black'
    relationships:
    - to: demographics.demographic
    enum:
    - 'active_duty'
    - 'all'
    - 'asian_pacific_islander'
    - 'black'
    - 'economically_disadvantaged'
    - 'english_learners'
    - 'female'
    - 'foster_care'
    - 'hispanic'
    - 'homeless'
    - 'male'
    - 'migrant'
    - 'multiracial'
    - 'native_american'
    - 'not_economically_disadvantaged'
    - 'students_with_disabilities'
    - 'students_without_disabilities'
    - 'white'
    customProperties:
    - property: column_role
      value: fk_demographic
    - property: label
      value: Demographic
    - property: short_description
      value: Student subgroup the row reports — race, gender, economic status, disability, and more; 'all'
        is the total.
    - property: has_total
      value: true
    - property: total_value
      value: 'all'
    - property: key_metric_grain_contributor
      value: true
    primaryKey: true
    primaryKeyPosition: 4
  - name: rate_type
    logicalType: string
    physicalType: string
    required: true
    description: 'Graduation-rate methodology: `4_year` (federal adjusted 4-year cohort rate, 2012-2025),
      `5_year` (5-year cohort variant, 2018-2024), or `on_time` (SB 431 statutory measure — continuous
      enrollment from Oct 1 of 9th grade — 2021-2024, school-level rows only). Denominator semantics differ
      per type (see num_cohort).'
    examples:
    - '4_year'
    enum:
    - '4_year'
    - '5_year'
    - 'on_time'
    customProperties:
    - property: column_role
      value: categorical
    - property: label
      value: Rate Type
    - property: short_description
      value: 'Which graduation-rate methodology the row uses: 4-year cohort, 5-year cohort, or the SB
        431 on-time rate.'
    - property: has_total
      value: false
    - property: key_metric_grain_contributor
      value: true
    - property: value_coverage
      value:
      - value: '4_year'
        first_year: 2012
        last_year: 2025
        rows: 52384
      - value: '5_year'
        first_year: 2018
        last_year: 2024
        rows: 25489
      - value: 'on_time'
        first_year: 2021
        last_year: 2024
        rows: 8548
    primaryKey: true
    primaryKeyPosition: 5
  - name: graduation_rate
    logicalType: number
    physicalType: double
    required: false
    description: 'Graduation rate on the 0-1 decimal scale (bronze ships 0-100; divided by 100). Interpretation
      follows rate_type. For overlapping 4-year keys the CCRPI accountability value wins by source precedence;
      standalone cohort releases fill years CCRPI does not cover, and ~200 small-cell 2023 keys carry
      the GOSA CSV rate that the CCRPI workbook suppressed. CAVEAT: the rate and the count pair can come
      from releases published at different cutoffs — do NOT assume num_graduates / num_cohort equals graduation_rate
      for `4_year` rows (it reconciles only to ~0.4pp even within one release). For `on_time` rows the
      identity holds to published rounding and is enforced as a quality check.'
    examples:
    - 0.8544
    customProperties:
    - property: column_role
      value: metric
    - property: label
      value: Graduation Rate
    - property: short_description
      value: Share of the cohort that graduated, on a 0-1 scale; which methodology applies is set by rate_type.
    - property: unit
      value: proportion
    - property: null_meaning
      value: Suppressed by GaDOE/GOSA (`TFS`/`Too Few Students`, `No Data`, `No Data Found`) or not published
        for this key by any source.
    - property: key_metric
      value: true
  - name: num_cohort
    logicalType: integer
    physicalType: bigint
    required: false
    description: 'Published cohort denominator. For `4_year` rows: the federal adjusted cohort (first-time
      9th graders four years prior, adjusted for transfers) from the standalone cohort releases — ALL-Students
      demographic only in 2015-2022/2024-2025, all 18 demographics in 2023 via the GOSA CSV. For `on_time`
      rows: `Total Enrolled` per SB 431 (continuous enrollment from Oct 1). Never published for `5_year`
      rows or the 2012-2014 legacy years.'
    examples:
    - 134822
    customProperties:
    - property: column_role
      value: metric
    - property: label
      value: Number Cohort
    - property: unit
      value: count
    - property: null_meaning
      value: 'Source published no denominator for this key: all 2012-2014 and `5_year` rows, non-`all`
        demographics in standalone 4-year years (counts ship for ALL Students only, except 2023''s GOSA
        CSV), or suppressed (TFS).'
    - property: metric_component
      value: denominator
  - name: num_graduates
    logicalType: integer
    physicalType: bigint
    required: false
    description: 'Published count of graduates (cohort numerator). Same source coverage as num_cohort.
      Never exceeds num_cohort (0 violations source-wide; enforced as a quality check). CAVEAT: published
      at a different cutoff than the CCRPI graduation_rate for 4-year rows — see graduation_rate.'
    examples:
    - 113735
    customProperties:
    - property: column_role
      value: metric
    - property: label
      value: Number Graduates
    - property: unit
      value: count
    - property: null_meaning
      value: Source published no numerator for this key (same coverage as num_cohort) or suppressed (TFS).
    - property: metric_component
      value: numerator
  - name: indicator_target
    logicalType: number
    physicalType: double
    required: false
    description: 'CCRPI improvement target on the same 0-1 scale as graduation_rate (observed range [0.022,
      0.9]). Published for 4-year and 5-year rows in 2018-2019 and 2023-2025 releases: years 2018, 2019,
      2023, 2024 carry both rate types, 2022 carries 5-year only (the 2023 workbook''s prior-year slice;
      the 2022 release itself omitted the column), 2025 carries 4-year only (its 5-year slice lands in
      2024). 2020 is all NULL (COVID CCRPI suspension). NOT cross-topic comparable: each CCRPI topic''s
      target inherits its companion metric''s scale (§16).'
    examples:
    - 0.8454
    customProperties:
    - property: column_role
      value: metric
    - property: label
      value: Indicator Target
    - property: unit
      value: proportion
    - property: null_meaning
      value: Row outside CCRPI flag-bearing coverage (see description), suppressed (`TFS`), or the 2020
        COVID suspension (all `NA` at source).
  - name: ccrpi_flag
    logicalType: string
    physicalType: string
    required: false
    description: 'CCRPI performance color flag: `green` (met the improvement target), `yellow` (improved
      but short of target), or `red` (did not improve); bronze G/Y/R recoded per §16. The graduation indicator
      never awards `green_star` in any bronze year (2018-2025, verified). Same publication coverage as
      indicator_target. A derived performance attribute functionally determined by the rest of the row
      key, so it is excluded from the contract grain.'
    examples:
    - 'green'
    enum:
    - 'green'
    - 'red'
    - 'yellow'
    customProperties:
    - property: column_role
      value: categorical
    - property: label
      value: CCRPI Flag
    - property: short_description
      value: CCRPI performance color (green/yellow/red) for whether the school met its graduation improvement
        target.
    - property: null_meaning
      value: Row outside CCRPI flag-bearing coverage (same years as indicator_target), bronze `NA` (no
        indicator_target to compare), or a non-CCRPI rate_type (`on_time`).
    - property: has_total
      value: false
  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: demographic_in_allowed_values
    description: demographic is one of the 18 canonical codes.
    dimension: conformity
    query: SELECT COUNT(*) FROM {object} WHERE demographic IS NOT NULL AND demographic NOT IN ('active_duty',
      'all', 'asian_pacific_islander', 'black', 'economically_disadvantaged', 'english_learners', 'female',
      'foster_care', 'hispanic', 'homeless', 'male', 'migrant', 'multiracial', 'native_american', 'not_economically_disadvantaged',
      'students_with_disabilities', 'students_without_disabilities', 'white')
    mustBe: 0
  - type: sql
    name: rate_type_in_allowed_values
    description: rate_type is one of the 3 canonical codes.
    dimension: conformity
    query: SELECT COUNT(*) FROM {object} WHERE rate_type IS NOT NULL AND rate_type NOT IN ('4_year', '5_year',
      'on_time')
    mustBe: 0
  - type: sql
    name: graduation_rate_within_unit_interval
    description: graduation_rate is a bounded proportion on the [0, 1] scale.
    dimension: accuracy
    query: SELECT COUNT(*) FROM {object} WHERE graduation_rate IS NOT NULL AND (graduation_rate < 0 OR
      graduation_rate > 1)
    mustBe: 0
  - type: sql
    name: num_cohort_non_negative
    description: num_cohort is a count (>= 0).
    dimension: accuracy
    query: SELECT COUNT(*) FROM {object} WHERE num_cohort IS NOT NULL AND num_cohort < 0
    mustBe: 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: indicator_target_within_unit_interval
    description: indicator_target is a bounded proportion on the [0, 1] scale.
    dimension: accuracy
    query: SELECT COUNT(*) FROM {object} WHERE indicator_target IS NOT NULL AND (indicator_target < 0
      OR indicator_target > 1)
    mustBe: 0
  - type: sql
    name: ccrpi_flag_in_allowed_values
    description: ccrpi_flag is one of the 3 canonical codes.
    dimension: conformity
    query: SELECT COUNT(*) FROM {object} WHERE ccrpi_flag IS NOT NULL AND ccrpi_flag NOT IN ('green',
      'red', 'yellow')
    mustBe: 0
  - type: sql
    name: num_graduates_not_exceeding_num_cohort
    description: 'The numerator never exceeds the denominator on rows where both counts are published.
      Verified against bronze: 0 violations in every release family.'
    dimension: accuracy
    query: SELECT COUNT(*) FROM {object} WHERE num_graduates IS NOT NULL AND num_cohort IS NOT NULL AND
      num_graduates > num_cohort
    mustBe: 0
  - type: sql
    name: on_time_rate_reconciles_with_counts
    description: 'For on_time rows the rate and both counts ship in one file and reconcile exactly to
      published rounding: |graduation_rate - num_graduates/num_cohort| <= 0.0001 (bronze max deviation
      0.005 on the 0-100 scale = half the last published decimal). Scoped to on_time — 4-year rows mix
      sources at different cutoffs and legitimately do not reconcile.'
    dimension: consistency
    query: SELECT COUNT(*) FROM {object} WHERE rate_type = 'on_time' AND graduation_rate IS NOT NULL AND
      num_graduates IS NOT NULL AND num_cohort IS NOT NULL AND num_cohort > 0 AND ABS(graduation_rate
      - CAST(num_graduates AS DOUBLE) / num_cohort) > 0.0001
    mustBe: 0
  - type: sql
    name: on_time_counts_co_null
    description: 'On-time suppression is all-or-nothing: rate, num_cohort, and num_graduates are either
      all published or all NULL on every on_time row (verified against bronze 2021-2024: 0 partial rows).'
    dimension: consistency
    query: SELECT COUNT(*) FROM {object} WHERE rate_type = 'on_time' AND ((num_cohort IS NULL) <> (num_graduates
      IS NULL) OR (num_cohort IS NULL) <> (graduation_rate IS NULL))
    mustBe: 0
  - type: sql
    name: on_time_rows_are_school_level
    description: 'Structural: the SB 431 on-time release publishes school-level rows only — every on_time
      row carries both geography keys (self-scoped via geography NULL-ness; there are no district or state
      on_time aggregates).'
    dimension: consistency
    query: SELECT COUNT(*) FROM {object} WHERE rate_type = 'on_time' AND (district_code IS NULL OR school_code
      IS NULL)
    mustBe: 0
  - type: sql
    name: five_year_rows_never_carry_counts
    description: 'Structural: no source publishes 5-year cohort counts — num_cohort and num_graduates
      are NULL on every 5_year row.'
    dimension: consistency
    query: SELECT COUNT(*) FROM {object} WHERE rate_type = '5_year' AND (num_cohort IS NOT NULL OR num_graduates
      IS NOT NULL)
    mustBe: 0
  - type: sql
    name: indicator_target_flag_publication_coverage
    description: 'indicator_target and ccrpi_flag are non-NULL only in the CCRPI flag-bearing (year, rate_type)
      slices: 2018/2019/2023/2024 both cohort types, 2022 5-year only (the 2022 release omitted the columns;
      its 5-year slice arrives via the 2023 workbook), 2025 4-year only. This also pins the 2020 COVID
      suppression (all NA at source) and that on_time rows never carry CCRPI constructs.'
    dimension: consistency
    query: SELECT COUNT(*) FROM {object} WHERE (indicator_target IS NOT NULL OR ccrpi_flag IS NOT NULL)
      AND NOT ((year IN (2018, 2019, 2023, 2024) AND rate_type IN ('4_year', '5_year')) OR (year = 2022
      AND rate_type = '5_year') OR (year = 2025 AND rate_type = '4_year'))
    mustBe: 0
customProperties:
- property: title
  value: High School Graduation Rates
- property: summary
  value: Georgia high school graduation rates by school, district, and demographic subgroup, 2012-2025.
- property: source
  value: Georgia Insights (GaDOE) / GOSA
- property: source_url
  value: https://georgiainsights.gadoe.org/data-downloads/
- property: update_frequency
  value: annual
- property: year_range
  value: 2012-2025
- property: schema_hash
  value: cf373e5d8659c44afb7259a01d4ee2a163cca28d3b0665bc3675780b73b39e37
- property: available_years
  value:
  - 2012
  - 2013
  - 2014
  - 2015
  - 2016
  - 2017
  - 2018
  - 2019
  - 2020
  - 2021
  - 2022
  - 2023
  - 2024
  - 2025
- property: year_gaps
  value: []
