Skip to main content

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

  1. Search by keyword: Find all notes where the keyword appears in the title OR the body (case-insensitive).

  2. Filter by tag: Optionally narrow results to notes that have a specific tag.

  3. Sort by relevance: Notes where the keyword appears in the title should come before notes where it only appears in the body.

  4. Return type: Return a list of matching notes, not strings or dicts.

  5. 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:

TestInputExpected
Keyword in titlekeyword="Python", notes with "Python Tips" titleMatches
Keyword in body onlykeyword="debugging", body contains "debugging tips"Matches
Case insensitivekeyword="python" vs title "Python Tips"Matches
Tag filterkeyword="", tag="research"Only notes with "research" tag
Keyword + tagkeyword="Python", tag="beginner"Notes matching both
No matcheskeyword="nonexistent"Empty list
Empty keywordkeyword=""All notes (or filtered by tag)
Empty notes listnotes=[]Empty list
Title matches before bodykeyword="Python", one note has it in title, another in bodyTitle-match note comes first

What Students Must Produce

  1. Stub file: smartnotes_search.py with the function stub
  2. Test file: test_smartnotes_search.py with 8+ tests
  3. Verification: uv run pyright passes on stub, uv run pytest fails (RED)
  4. AI prompt: "Implement search_notes to pass these tests. Do not modify the tests."
  5. Verification: uv run pytest -v all GREEN
  6. 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)