Skip to content
How much to read

Knowledge base

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/13 showed Anatomy's Hand & Wrist under a Biochemistry breadcrumb) because getTopic was not scoped to its subject.
  • rankCutoff never read its database value: an unquoted AS maxYear alias folded to maxyear in Postgres, so the query result was silently undefined and 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.
  • mostRecentMonth took the max month across all years rather than the month belonging to mostRecentYear, 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.

This page was written by a model from my own repositories and checked by a second one against the same sources. I did not write it, and no version of it was approved by me before it went up. How that works, and where it can still be wrong.