projects / easemysemester / features
Ranked topics view: topics ranked, questions listed
v2's ranked-topics screen ranks subjects' topics by frequency and shows real sittings, but deliberately never ranks or scores individual questions because the bank cannot support it.
feature · current · updated 2026-09-15 · EaseMySemester case study
See overview and the ranking engine this view renders.
What it does
A student picks a subject and sees its topics ranked by rankTopics, each showing how often it
was asked and the actual sittings it appeared in ("asked 20 times, in 11 of 23 sittings, 2015,
2016, 2017, 2020, 2021, 2022, 2023, 2024, 2025"), not a computed score. Opening a topic lists its
questions by occurrence count then recency, with the count shown only when greater than one, and
links to the existing answer screen.
Why questions are listed, never ranked
Of 809 questions across 23 sittings, 720 have been asked exactly once. A "top questions" list would be sorting 720 tied scores by database order and presenting it to a student as a prediction. Topics carry a real signal (Hand & Wrist has appeared in 20 of 23 papers); questions mostly do not, so the view ranks topics and only orders questions within them, marking the 89 that repeat without inventing a score for the rest. No probability is ever printed.
What review found and fixed
An architect review of the first version (6be4536, 86e77d4) found five defects, fixed in 4d80e8a:
- The headline number (raw occurrences) contradicted the actual sort order (weighted distinct sittings), inverting 13 of 50 adjacent rows. Fixed by leading with the field the order is built on and carrying occurrences as the secondary number.
- A topic could render under the wrong subject (
/subjects/2/topics/13showed Anatomy's Hand & Wrist under a Biochemistry breadcrumb) becausegetTopicwas not scoped to its subject. rankCutoffnever read its database value: an unquotedAS maxYearalias folded tomaxyearin Postgres, so the query result was silentlyundefinedand every call fell back to the wall clock, returning 2027 instead of the data-driven 2026.- The cutoff filter on displayed counts (
isBeforeCutoff) was unpinned by any test; deleting it left the existing suite green while every displayed count leaked post-cutoff occurrences. mostRecentMonthtook the max month across all years rather than the month belonging tomostRecentYear, a latent defect not yet observed live (every sampled occurrence month was null).
Each fix is pinned by a test that fails if the fix is reverted, including a new
ranked-view.db.test.ts covering the four SQL queries that had no db-lane coverage before.
Status
Shipped 2026-09-08, review findings fixed same day (4d80e8a). Both routes are in the single
PROTECTED_ROUTES list, enumerated by the existing route-protection test. The ranking weights
themselves were untouched by this work; see
topic ranking.