Note: These are different from Risk Alerts above. This chart shows pure retention probability, while Risk Alerts combine retention with GPA and completion metrics.
>
}
/>
diff --git a/codebenders-dashboard/components/readiness-assessment-chart.tsx b/codebenders-dashboard/components/readiness-assessment-chart.tsx
index 6f580f5..ee0247a 100644
--- a/codebenders-dashboard/components/readiness-assessment-chart.tsx
+++ b/codebenders-dashboard/components/readiness-assessment-chart.tsx
@@ -1,10 +1,12 @@
'use client';
+import Link from 'next/link';
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { AlertCircle, TrendingUp, TrendingDown, Users, Target, AlertTriangle } from 'lucide-react';
import { InfoPopover } from '@/components/info-popover';
+import { GLOSSARY_HREF } from '@/lib/glossary-constants';
interface ReadinessData {
summary: {
@@ -187,7 +189,18 @@ export function ReadinessAssessmentChart({ data, isLoading, error }: ReadinessAs
Student readiness categorization
- AI-powered assessment analyzing student preparation, engagement, and success indicators. High readiness indicates students are well-positioned for success.
+
+ AI-powered assessment analyzing student preparation, engagement, and success indicators. High readiness
+ indicates students are well-positioned for success.
+
diff --git a/codebenders-dashboard/content/metric-glossary.md b/codebenders-dashboard/content/metric-glossary.md
index 2c733ec..c9ad94b 100644
--- a/codebenders-dashboard/content/metric-glossary.md
+++ b/codebenders-dashboard/content/metric-glossary.md
@@ -1,6 +1,6 @@
# Metric glossary
-Single source of truth for dashboard KPI definitions. Each section is keyed by its URL anchor (e.g. `/glossary#overall-retention-rate`). Cross-walks are indicative — institutions should confirm against their PDP documentation, IPEDS submission manuals, and state reporting rules.
+Single source of truth for dashboard KPIs and chart views. Each section is keyed by its URL anchor (e.g. `/glossary#overall-retention-rate`). Cross-walks are indicative — institutions should confirm against their PDP documentation, IPEDS submission manuals, and state reporting rules.
---
@@ -49,3 +49,39 @@ Single source of truth for dashboard KPI definitions. Each section is keyed by i
**IPEDS:** Conceptually related to success rates and progression, but IPEDS collects many distinct measures (e.g., completions by award) — do not assume identity without a written cross-walk.
**State compliance:** Often parallels “success rate” or “credit completion ratio” in performance funding models; verify denominator rules match your state formula.
+
+---
+
+## risk-alert-distribution
+
+**Plain English:** Pie chart of students grouped by **composite risk alert** band (LOW, MODERATE, HIGH, URGENT) used for triage — not the same as the retention-probability-only funnel chart.
+
+**PDP / analysis-ready:** Counts come from `at_risk_alert` on `student_level_with_predictions` after dashboard filters. The composite rule combines retention probability, GPA bands, course completion, and credit progress (see in-chart tooltip and methodology).
+
+**IPEDS:** No direct IPEDS collection; analogous to internal early-alert or “at risk” population counts if your institution defines them similarly.
+
+**State compliance:** Operational metric; if reported externally, align labels and thresholds with your state’s definitions and suppress small cells where required.
+
+---
+
+## retention-risk-funnel
+
+**Plain English:** Horizontal bar chart of students by **model retention risk category** (Critical / High / Moderate / Low) from predicted retention probability alone.
+
+**PDP / analysis-ready:** Buckets are derived from `retention_probability` (XGBoost) using fixed cut points on `student_level_with_predictions`.
+
+**IPEDS:** Not an IPEDS measure; related conceptually to retention outcome reporting but this view is **predictive**, not audited cohort outcomes.
+
+**State compliance:** Use for advising and planning; do not substitute for official retention rates in external reporting without documentation.
+
+---
+
+## readiness-assessment
+
+**Plain English:** PDP-aligned **readiness index** — composite score and High / Medium / Low bands summarizing academic, engagement, and ML-risk components for the filtered cohort.
+
+**PDP / analysis-ready:** Scores and levels are computed server-side (see `/api/dashboard/readiness` and methodology) from fields on `student_level_with_predictions` and related logic.
+
+**IPEDS:** No IPEDS analog; closest institutional parallels are internal “student success” or “momentum” indices if your IR office publishes them.
+
+**State compliance:** Treat as an internal diagnostic; confirm any export or public use against institutional policy and small-N rules.
diff --git a/codebenders-dashboard/lib/__tests__/metric-glossary-coverage.test.ts b/codebenders-dashboard/lib/__tests__/metric-glossary-coverage.test.ts
index debf689..15dcb36 100644
--- a/codebenders-dashboard/lib/__tests__/metric-glossary-coverage.test.ts
+++ b/codebenders-dashboard/lib/__tests__/metric-glossary-coverage.test.ts
@@ -1,24 +1,21 @@
import { describe, expect, it } from "vitest"
-import {
- DASHBOARD_KPI_GLOSSARY_SLUGS,
- GLOSSARY_TOPIC_SECTIONS,
-} from "@/lib/glossary-constants"
+import { GLOSSARY_TOPIC_SECTIONS, METRIC_GLOSSARY_INDEX_SLUGS } from "@/lib/glossary-constants"
import { parseGlossaryEntries, readMetricGlossaryMarkdown } from "@/lib/metric-glossary"
-describe("metric glossary coverage (#105)", () => {
- it("includes every dashboard KPI slug in metric-glossary.md", () => {
+describe("metric glossary coverage (#105 / #124)", () => {
+ it("includes every indexed slug in metric-glossary.md", () => {
const md = readMetricGlossaryMarkdown()
const entries = parseGlossaryEntries(md)
- for (const slug of DASHBOARD_KPI_GLOSSARY_SLUGS) {
+ for (const slug of METRIC_GLOSSARY_INDEX_SLUGS) {
expect(entries[slug], `missing ## ${slug} in content/metric-glossary.md`).toBeTruthy()
expect(entries[slug]!.length).toBeGreaterThan(20)
}
})
- it("topic sections list each KPI slug exactly once", () => {
+ it("topic sections list each indexed slug exactly once", () => {
const listed = GLOSSARY_TOPIC_SECTIONS.flatMap((t) => [...t.slugOrder])
- expect(listed.length).toBe(DASHBOARD_KPI_GLOSSARY_SLUGS.length)
- for (const slug of DASHBOARD_KPI_GLOSSARY_SLUGS) {
+ expect(listed.length).toBe(METRIC_GLOSSARY_INDEX_SLUGS.length)
+ for (const slug of METRIC_GLOSSARY_INDEX_SLUGS) {
const n = listed.filter((s) => s === slug).length
expect(n, `slug ${slug} should appear once in GLOSSARY_TOPIC_SECTIONS`).toBe(1)
}
diff --git a/codebenders-dashboard/lib/glossary-constants.ts b/codebenders-dashboard/lib/glossary-constants.ts
index 2a86003..b61f757 100644
--- a/codebenders-dashboard/lib/glossary-constants.ts
+++ b/codebenders-dashboard/lib/glossary-constants.ts
@@ -3,8 +3,8 @@
export const GLOSSARY_HREF = "/glossary" as const
/**
- * Source of truth for topic groupings and KPI slug order on the glossary page.
- * `DASHBOARD_KPI_GLOSSARY_SLUGS` is derived from this list; every `##` section in
+ * Source of truth for topic groupings on the glossary page.
+ * `METRIC_GLOSSARY_INDEX_SLUGS` is derived from this list; every `##` section in
* `content/metric-glossary.md` must stay in sync (see
* `lib/__tests__/metric-glossary-coverage.test.ts`).
*/
@@ -23,18 +23,33 @@ const GLOSSARY_TOPIC_SECTIONS_RAW = [
label: "Completion & course success",
slugOrder: ["avg-course-completion"] as const,
},
+ {
+ id: "charts",
+ label: "Charts & composite views",
+ slugOrder: [
+ "risk-alert-distribution",
+ "retention-risk-funnel",
+ "readiness-assessment",
+ ] as const,
+ },
] as const
-export type DashboardKpiGlossarySlug =
+export type MetricGlossarySlug =
(typeof GLOSSARY_TOPIC_SECTIONS_RAW)[number]["slugOrder"][number]
-export const DASHBOARD_KPI_GLOSSARY_SLUGS: readonly DashboardKpiGlossarySlug[] =
+/** @deprecated Use METRIC_GLOSSARY_INDEX_SLUGS */
+export type DashboardKpiGlossarySlug = MetricGlossarySlug
+
+export const METRIC_GLOSSARY_INDEX_SLUGS: readonly MetricGlossarySlug[] =
GLOSSARY_TOPIC_SECTIONS_RAW.flatMap((topic) => [...topic.slugOrder])
+/** @deprecated Use METRIC_GLOSSARY_INDEX_SLUGS */
+export const DASHBOARD_KPI_GLOSSARY_SLUGS = METRIC_GLOSSARY_INDEX_SLUGS
+
export const GLOSSARY_TOPIC_SECTIONS: {
id: string
label: string
- slugOrder: readonly DashboardKpiGlossarySlug[]
+ slugOrder: readonly MetricGlossarySlug[]
}[] = GLOSSARY_TOPIC_SECTIONS_RAW.map((topic) => ({
id: topic.id,
label: topic.label,
From 4ef84048dd212ec1026f7b07ba70cb7e6e0b9839 Mon Sep 17 00:00:00 2001
From: William Hill
Date: Sun, 3 May 2026 12:57:42 -0400
Subject: [PATCH 2/2] refactor(dashboard): dedupe metric glossary deep links
(#124)
- Add metricGlossaryEntryHref and rename topic section source constant
- Introduce GlossaryMetricEntryLink for shared KPI/chart glossary CTAs
- Simplify glossary coverage test with ordered slug equality
- Drop unused TrendingDown import in readiness chart
Co-authored-by: Cursor
---
codebenders-dashboard/app/page.tsx | 38 ++++---------------
.../components/glossary-metric-entry-link.tsx | 24 ++++++++++++
.../components/readiness-assessment-chart.tsx | 14 ++-----
.../metric-glossary-coverage.test.ts | 10 ++---
.../lib/glossary-constants.ts | 22 ++++++-----
5 files changed, 50 insertions(+), 58 deletions(-)
create mode 100644 codebenders-dashboard/components/glossary-metric-entry-link.tsx
diff --git a/codebenders-dashboard/app/page.tsx b/codebenders-dashboard/app/page.tsx
index 0074d9e..a0a2b2f 100644
--- a/codebenders-dashboard/app/page.tsx
+++ b/codebenders-dashboard/app/page.tsx
@@ -16,7 +16,7 @@ import {
} from "@/components/ui/select"
import { TrendingUp, Users, AlertTriangle, BookOpen, Search, Table2, X } from "lucide-react"
import Link from "next/link"
-import { GLOSSARY_HREF } from "@/lib/glossary-constants"
+import { GlossaryMetricEntryLink } from "@/components/glossary-metric-entry-link"
interface KPIData {
overallRetentionRate: string
@@ -276,11 +276,7 @@ export default function DashboardPage() {
What it shows: Percentage of students retained year-to-year based on historical data.
Data source: Retention field from student cohort records (0=Not Retained, 1=Retained).
Use for: Baseline institutional performance metric.
Note: These are different from Risk Alerts above. This chart shows pure retention probability, while Risk Alerts combine retention with GPA and completion metrics.