You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
fix: NQL rate formatting and course_enrollments routing (#90)
- Add isRateColumn helper and formatCellValue to render 0–1 probabilities
as percentages in table cells, chart axes, tooltips, and KPI display
- Fix KPI suffix to only append % when value is actually in 0–1 range
- Add course_enrollments table to LLM prompt with schema, routing rules,
DFWI/pass rate SQL patterns, FERPA guardrails, and worked example
- Add SchemaEntry interface; remove as-any cast on courseColumns
- SQL patterns return 0–1 scale; display layer handles multiplication
- Column names with uppercase letters MUST be double-quoted in PostgreSQL SQL or the query will fail.
116
149
CORRECT: WHERE "Cohort" = 2023 AND "Cohort_Term" = 'Fall'
117
150
INCORRECT: WHERE cohort = 2023 AND cohort_term = 'Fall'
@@ -122,6 +155,16 @@ CRITICAL SCHEMA NOTES:
122
155
- Lowercase ML columns (retention_probability, at_risk_alert, etc.) do NOT need quoting.
123
156
- Use standard PostgreSQL syntax — no backtick quoting, no cross-database references
124
157
158
+
COMPUTING DFWI RATE from course_enrollments (returns 0–1, display layer multiplies by 100):
159
+
ROUND(COUNT(*) FILTER (WHERE grade IN ('D','F','W','I'))::numeric / NULLIF(COUNT(*), 0), 4) AS dfwi_rate
160
+
161
+
COMPUTING PASS RATE from course_enrollments (returns 0–1, display layer multiplies by 100):
162
+
ROUND(COUNT(*) FILTER (WHERE grade NOT IN ('D','F','W','I') AND grade IS NOT NULL AND grade != '')::numeric / NULLIF(COUNT(*), 0), 4) AS pass_rate
163
+
164
+
FERPA COMPLIANCE — NEVER include these in SELECT output:
165
+
Student_GUID, student_guid
166
+
Do not expose individual student identifiers in query results.
167
+
125
168
IMPORTANT QUERY INTERPRETATION RULES:
126
169
127
170
1. METRIC SELECTION:
@@ -151,7 +194,7 @@ IMPORTANT QUERY INTERPRETATION RULES:
151
194
- Age filters: use numeric comparisons directly (e.g., "Student_Age" >= 25)
152
195
153
196
4. VISUALIZATION:
154
-
- Comparing groups (age, gender, race) → "bar"
197
+
- Comparing groups (age, gender, race, courses) → "bar"
155
198
- Time series (cohort, term over time) → "line"
156
199
- Single number → "kpi"
157
200
- Percentages/shares → "pie"
@@ -166,7 +209,7 @@ Generate a query plan with:
166
209
- filters: any filters to apply [OPTIONAL]
167
210
- timeHint: human-readable time description [OPTIONAL]
168
211
- vizType: appropriate visualization [REQUIRED]
169
-
- sql: VALID executable PostgreSQL query against table "${schemaInfo.mainTable}" [REQUIRED]
212
+
- sql: VALID executable PostgreSQL query against the appropriate table (${schemaInfo.mainTable} or course_enrollments) [REQUIRED]
170
213
- queryString: empty string [OPTIONAL]
171
214
172
215
EXAMPLE for "segment students over 25 and under 25 in 2023 cohort":
@@ -176,6 +219,13 @@ EXAMPLE for "segment students over 25 and under 25 in 2023 cohort":
176
219
"queryString": ""
177
220
}
178
221
222
+
EXAMPLE for "top 5 courses with highest DFW rates":
223
+
{
224
+
"vizType": "bar",
225
+
"sql": "SELECT course_prefix || ' ' || course_number AS course, MAX(course_name) AS course_name, COUNT(*) AS enrollments, ROUND(COUNT(*) FILTER (WHERE grade IN ('D','F','W','I'))::numeric / NULLIF(COUNT(*), 0), 4) AS dfwi_rate FROM course_enrollments GROUP BY course_prefix, course_number HAVING COUNT(*) >= 10 ORDER BY dfwi_rate DESC LIMIT 5",
226
+
"queryString": ""
227
+
}
228
+
179
229
Make sure the SQL is valid PostgreSQL and addresses exactly what the user asked for!`,
0 commit comments