From 060a938b9629b134b9110db4d1cbc99577ee5674 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Wed, 24 Jun 2026 06:47:07 -0400 Subject: fix(flashcard): name the Anki deck from #+TITLE, not the filename flashcard-to-anki.py's default_deck_name returned the input basename, so a deck built through flashcard-sync (which passes no --deck) was named after the file slug (refutation-drill) instead of the curated #+TITLE the phone deck should read (Refutations). flashcard-review.org already documented the #+TITLE behavior, and the script never matched it. default_deck_name now scans for a #+TITLE line (case-insensitive, trimmed) and falls back to the basename when there's none. Five new tests cover title-drives-name, trimming, case-insensitivity, and the two basename fallbacks. The two old tests that asserted basename-always are replaced. The pre-staged script and test (validated 2026-06-21) applied cleanly red-to-green; their redundant copies are removed and the rationale doc kept. Migration: deck IDs derive from the name, so decks previously built without --deck land as new decks on the next import. Old basename-named decks keep their history and can be deleted by hand. Claude-Session: https://claude.ai/code/session_017PtX1nt1rtYVATuzmzBS4f --- .ai/scripts/tests/test_flashcard_to_anki.py | 31 +++++++++++++++++++++++------ 1 file changed, 25 insertions(+), 6 deletions(-) (limited to '.ai/scripts/tests') diff --git a/.ai/scripts/tests/test_flashcard_to_anki.py b/.ai/scripts/tests/test_flashcard_to_anki.py index 058b0cd..87008a8 100644 --- a/.ai/scripts/tests/test_flashcard_to_anki.py +++ b/.ai/scripts/tests/test_flashcard_to_anki.py @@ -34,14 +34,33 @@ def test_default_output_path_targets_phone_anki_dir(drill): assert result == Path.home() / "sync" / "phone" / "anki" / "health-drill.apkg" -def test_default_deck_name_is_raw_basename(drill): - """Deck name is the input basename with case preserved; #+TITLE is ignored.""" - assert drill.default_deck_name(Path("/x/deepsat.org")) == "deepsat" +def test_default_deck_name_uses_org_title(drill): + """The #+TITLE drives the Anki deck name, not the filename slug.""" + org = "#+TITLE: Refutations\n* Section\n** Q? :drill:\na\n" + assert drill.default_deck_name(Path("/x/refutation-drill.org"), org) == "Refutations" -def test_default_deck_name_keeps_hyphens(drill): - """A hyphenated basename is kept verbatim rather than title-cased.""" - assert drill.default_deck_name(Path("/x/health-drill.org")) == "health-drill" +def test_default_deck_name_title_is_trimmed(drill): + """Surrounding whitespace on the #+TITLE value is stripped.""" + org = "#+TITLE: DeepSat Flashcards \n" + assert drill.default_deck_name(Path("/x/deepsat.org"), org) == "DeepSat Flashcards" + + +def test_default_deck_name_title_match_is_case_insensitive(drill): + """A lowercase #+title: keyword is still recognized.""" + org = "#+title: Health Flashcards\n" + assert drill.default_deck_name(Path("/x/health-drill.org"), org) == "Health Flashcards" + + +def test_default_deck_name_falls_back_to_basename_without_title(drill): + """No #+TITLE line falls back to the input basename, case preserved.""" + org = "* Section\n** Q? :drill:\na\n" + assert drill.default_deck_name(Path("/x/deepsat.org"), org) == "deepsat" + + +def test_default_deck_name_blank_title_falls_back_to_basename(drill): + """An empty #+TITLE value is ignored in favour of the basename.""" + assert drill.default_deck_name(Path("/x/health-drill.org"), "#+TITLE: \n") == "health-drill" # --- section_to_tag (pure) --- -- cgit v1.2.3