Milestone 5 of 8

Score and rank with complete contribution traces

Add exact query-count and document-count products, record zero and positive contributions, apply fixed tie rules, and return no zero-score filler results.

Now turn query matches into a score that can be checked one row at a time. The formula is supplied for this project so that ranking does not hide a design choice.

Goal

Calculate complete per-term contributions, rank positive-score documents with three deterministic tie rules, and retain enough rows to reproduce every result score.

Scoring rule

For each distinct query term and each document, use:

term_contribution = query_term_count * document_term_count
score = sum(term_contribution)

Record one contribution row for every distinct query term, including a zero row when that term is missing from the document. Also record the number of distinct query terms with a positive document match.

Ranking rule

Consider only documents with a positive score. Sort them by:

  1. decreasing score;
  2. decreasing matched distinct query-term count; and
  3. increasing document_id for an exact remaining tie.

Return at most top_k results and record the number of positive-score candidates before truncation. Never fill a short result list with zero-score documents.

Deliverables

Implement scoring and ranking in src/rank.py. Save output/score_contributions.csv and output/ranked_results.jsonl. Each result must carry its query ID, document ID, score, matched-term count, rank, and candidate count. The score must equal the sum of its contribution rows.

Checks

Hand-calculate a repeated-term query, a query with one missing term, and a query whose documents tie on score. Exercise all three tie stages. Check top_k below, equal to, and above the candidate count. Check empty and ignored-only queries, no positive candidates, and a document with a zero contribution row.

Deliberately omit or alter one contribution and make the verifier report the disagreement. Run ranking twice and compare complete rows. Confirm that contribution generation does not mutate postings or query analysis.

Workspace

Keep formula, contribution traces, candidate counting, and sorting in src/rank.py. Excerpt selection belongs to the next milestone.

Hints

HintA zero row is evidence
A missing term contributes zero, but its row proves that the term was considered. Do not silently omit it.
HintSort after calculating
Calculate all candidate fields first, then apply the three sort keys. This makes a tie explainable.

Review

Choose one returned result and rebuild its score from the CSV rows. Which rule decides its position if two documents have the same score and matched-term count? What would adding zero-score fillers falsely suggest?

How to check your work

Checks compare contributions, scores, candidate counts, and rank order with the fixtures. This is a supplied integer rule that rewards repeated exact terms; it is not probability, semantic similarity, or a universal relevance measure.

LLM PrimerScore and rank with complete contribution traceshttps://llmprimer.com/python/projects/build-a-document-search-index/score-and-rank-with-complete-contribution-traces© 2026 LLM Primer