A ranked ID is not yet a useful result card. Join it back to the snapshot to recover the title and a preview, while preserving the ordering and full score produced by ranking. The join also checks an important invariant: a result must still refer to a known document. A stale ID is an error, not a reason to invent an empty result.
This course uses a deliberately simple preview: collapse whitespace and keep a bounded prefix of the body. It is not a passage finder or highlighter. Keeping that limitation explicit makes it possible to test the presenter independently from the search model.
Normalize whitespace before applying the width budget. If text exceeds the budget, reserve one code point for a single ellipsis. A width of one can therefore produce just … for a nonempty truncated string. Empty text remains empty. An exactly fitting string remains complete, with no added ellipsis.
text = ' '.join(' beta\n gamma '.split())
width = 4
snippet = text if len(text) <= width else text[:width - 1] + '…'
print(text, repr(snippet), len(snippet))The budget counts Python string code points. It does not count UTF-8 bytes, terminal columns or user-perceived grapheme clusters. Those are different useful policies, but changing between them silently would break the exercise contract. The original text stays available in the corpus for a future passage-aware preview.
Return plain text. A note can contain , & or a URL without being trusted HTML. JSON serialization and HTML rendering are different boundaries: serializing a JSON string does not authorize inserting it through raw HTML. A renderer must apply its own context-appropriate escaping; this presenter should not double-escape stored data.
import html
preview = '<b>Tokyo</b>'
print(preview)
print(html.escape(preview))Test rank order, unknown IDs, repeated hits, whitespace, exact-width text and a one-character budget. Check that editing a returned result does not change the input record. Keep scores unrounded in the result data. You can format a score separately for display, but that formatting should not feed back into ranking or evaluation.