SmartNotes Search Feature Specification
This is the problem statement for the Chapter 57 Lesson 4 capstone. Students receive ONLY this spec. They drive the full TDG cycle independently: types, tests, prompt, verify, debug.
Problem Statement
SmartNotes needs a search feature. Users want to find notes by keyword and optionally filter by tag. The search should be case-insensitive and match against both the title and body of each note.
Requirements
-
Search by keyword: Find all notes where the keyword appears in the title OR the body (case-insensitive).
-
Filter by tag: Optionally narrow results to notes that have a specific tag.
-
Sort by relevance: Notes where the keyword appears in the title should come before notes where it only appears in the body.
-
Return type: Return a list of matching notes, not strings or dicts.
-
Edge cases:
- Empty keyword returns all notes (or all notes with the tag if filtered)
- No matches returns an empty list
- Empty notes list returns an empty list
Expected Function Signatures
Students should arrive at signatures similar to these (exact names may vary, but types should match):
from dataclasses import dataclass, field
@dataclass
class Note:
title: str
body: str
word_count: int
author: str = "Anonymous"
is_draft: bool = True
tags: list[str] = field(default_factory=list)
def search_notes(
notes: list[Note],
keyword: str,
tag: str | None = None,
) -> list[Note]:
"""Search notes by keyword with optional tag filter.
- Matches keyword against title and body (case-insensitive)
- If tag is provided, only returns notes that have that tag
- Title matches come before body-only matches
- Empty keyword returns all notes (filtered by tag if provided)
"""
...
Expected Test Cases
Students should write tests covering at least these scenarios:
| Test | Input | Expected |
|---|---|---|
| Keyword in title | keyword="Python", notes with "Python Tips" title | Matches |
| Keyword in body only | keyword="debugging", body contains "debugging tips" | Matches |
| Case insensitive | keyword="python" vs title "Python Tips" | Matches |
| Tag filter | keyword="", tag="research" | Only notes with "research" tag |
| Keyword + tag | keyword="Python", tag="beginner" | Notes matching both |
| No matches | keyword="nonexistent" | Empty list |
| Empty keyword | keyword="" | All notes (or filtered by tag) |
| Empty notes list | notes=[] | Empty list |
| Title matches before body | keyword="Python", one note has it in title, another in body | Title-match note comes first |
What Students Must Produce
- Stub file:
smartnotes_search.pywith the function stub - Test file:
test_smartnotes_search.pywith 8+ tests - Verification:
uv run pyrightpasses on stub,uv run pytestfails (RED) - AI prompt: "Implement search_notes to pass these tests. Do not modify the tests."
- Verification:
uv run pytest -vall GREEN - Review: Read the generated code using PRIMM. Predict behavior for an input not in tests.
Grading Criteria (Mastery Gate)
- All tests pass
- Student can explain the generated code without looking at it
- Student documented their cycle (what they specified, what failed, how they fixed it)