Repository navigation
Add grade distributions from the records request - #137
Merged
Merged
Conversation
Five academic years of per-section grade distributions, obtained under R.C. 149.43 because OSU publishes nothing like them, folded into one curve per instructor per course and drawn in the detail pane under the ratings. This is the one join in Finder that does not guess. RateMyProfessors has to be matched on a name, which is why two professors called Alan Reed get nothing; the records request asked for the instructor's OSU address, which content.osu.edu already publishes beside every section, so a curve keys on bucci.2 and lands on one person or on nobody. The pane leads with the mean and the share who got an A or A-, because the two disagree where it matters: half A and half E averages the same as entirely B. Withdrawals sit beside the curve rather than inside it, since nobody who withdrew has a grade to move a mean with. Every way a curve can be absent reads as absent rather than as a number. A course whose sections were all too small to publish, a pass-fail course and an instructor with no record are three different sentences, and gradesStatus keeps them apart. data/grades.json is not in the tree until the request is fulfilled. A 404 reads as unpublished and is never retried; a 500 stays retryable. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Five academic years of per-section grade distributions, obtained under R.C. 149.43 because OSU publishes nothing like them, folded into one curve per instructor per course and drawn in the detail pane under the ratings.
data/grades.jsonis not in this branch. The records request is still pending.loadGradesreads a 404 as "not published yet" — settled, never retried, distinct from the 500 that stays retryable — so the block does not render and nothing else on the page changes. Everything here is written and tested against fixtures, so the day the spreadsheet arrives the work is a column-name check, not a build.The join does not guess
Every other join in Finder does.
js/ratings.jsmatches RateMyProfessors on a first and last name and returns nothing when two people share one, because a wrong rating is worse than no rating — which is why both Alan Reeds get nothing.content.osu.edu/v2already publishes an instructor's address beside every section, and the records request asked for the same field. Verified against the live API while building:So a curve keys on
bucci.2and lands on one person or on nobody. Name matching survives as a fallback for rows that come back without an address, inheriting the same refusal to choose between two people with one name.What the pane shows
Leads with the mean and the share who got an A or A-, because the two disagree exactly where it matters: a section that is half A and half E averages the same as a section that is entirely B, and only one of them is a coin flip.
Withdrawals sit beside the curve rather than inside it. Nobody who withdrew has a grade, so they cannot move a mean, which means a course a third of the class drops posts a flattering one. The number that explains it belongs next to it.
Every way a curve can be absent reads as absent rather than as a number. A course whose sections were all too small to publish, a pass-fail course, and an instructor with no record are three different sentences;
gradesStatuskeeps them apart instead of printing one blank for all three.Two bugs the tests caught
The header normaliser collapsed
A-intoA. Field names have their punctuation stripped socatalog_nbrandCatalog Nbrare one spelling. Applied to grade columns that turnsA-intoa, which is also whatAturns into, so both resolved to whichever came first and every A-minus in five years would have been read out of the A column — silently, with no error and a completely normal-looking output. Grade headers now keep their sign, which is whymarkSlugexists next toslug.A negative count was reported as a pass-fail course. It has the right eleven columns, so a length-only check waved it through into a branch meaning "students finished on marks carrying no points". The validity rule now lives in one place that both the status and the mean read.
The import
scripts/fetch-grades.mjsfetches nothing; the records office sends a file once.The column names are not known in advance. Every field resolves through alias tables, and an unresolved one aborts printing the headers the file actually had, because the failure being avoided is silent — a file whose
B-column went unrecognised would write a curve missing every B-minus and look fine doing it. Same write gate as the other three snapshotters viascripts/guards.mjs: an instructor floor, a drop against the committed count, and an unreadable-row rate.Staff,TBAandUnassignedare dropped, since folding five years of unstaffed sections into one key would invent the most prolific instructor at the university.Verified
730 tests pass, 0 fail, up from 654 on
main. Rendered against the live OSU API in both themes with no console errors: 2.77 average GPA, 35% got A or A-, 860 graded, beside Bucci's 3.0 rating.Deliberately not included
No minimum-GPA filter and no grade sort. Both need real data to pick thresholds against; a cutoff tuned on fixtures is a guess.
One judgement call worth a second opinion: the rating spread runs red→green (1 to 5) and the grade curve runs green→red (A to E), stacked adjacent in the pane. Each is in its own scale's natural order and each carries a direction caption, so I left it alone.
Docs in
docs/osu-grades.md; README carries the new source, the layout line and a re-counted network audit (grades.js is a nineteenth module, so the page load is 30 requests).🤖 Generated with Claude Code