Files
stack/tests/llm/test_vocab.py
kert 7693e97d36 feat(llm): closed theme vocabulary for comment tagging — themes.yaml v1, llm.vocab loader, stack llm vocab, P35 design spec (refs #574)
docs/superpowers/specs/2026-09-22-llm-tagging-design.md lays out P35:
a versioned hand-curated vocabulary, embedding shortlist + per-theme
yes/no judgement with an evidence chunk on the largest live host,
resumable docket-scoped runs with state in bib extra_json, write-back
that replaces only llm: tags, and a golden-set gate before fan-out.

Slice 1: src/llm/vocab/themes.yaml — 53 themes (conversion factor,
practice expense, telehealth, care management, behavioral health, Part
B drugs, MSSP, QPP, …), each with a label, one-sentence definition,
letter-language synonyms and the FR section stems it was seeded from
(dev/scripts/llm_vocab_candidates.py mines heading paragraphs from the
CY2018+ rules' fr_anchors). llm.vocab.load() validates unique
kebab-case slugs, non-empty definitions, integer version ≥ 1 and that
retired slugs are not still active; Theme.card is the text embedded
per theme; split_tags() separates llm: tags from hand tags for the
write-back. stack llm vocab [--path] [--slug].
2026-09-22 16:48:51 -04:00

115 lines
3.6 KiB
Python

"""llm.vocab — the closed theme vocabulary (#574)."""
from __future__ import annotations
import pytest
from llm.vocab import Theme, Vocab, VocabError, is_llm_tag, load, parse, split_tags
GOOD = """
version: 3
themes:
- slug: telehealth
label: Telehealth
definition: Medicare telehealth services.
synonyms: [telehealth, audio-only]
sections: [Medicare Telehealth Services]
- slug: care-management
definition: Monthly care management codes.
retired: [old-theme]
"""
class TestParse:
def test_reads_themes_and_version(self):
v = parse(GOOD, source="t")
assert isinstance(v, Vocab) and v.version == 3 and len(v) == 2
assert v.slugs == ("telehealth", "care-management")
t = v.get("telehealth")
assert isinstance(t, Theme) and t.synonyms == ("telehealth", "audio-only")
assert (
v.get("care-management").label == "care-management"
) # label defaults to slug
assert v.retired == ("old-theme",) and "telehealth" in v and "nope" not in v
def test_cards_and_tags(self):
v = parse(GOOD)
assert (
v.cards["telehealth"]
== "Telehealth. Medicare telehealth services. Also: telehealth, audio-only."
)
assert (
v.cards["care-management"]
== "care-management. Monthly care management codes."
)
assert (
v.tag("telehealth") == "llm:telehealth"
and v.get("telehealth").tag == "llm:telehealth"
)
@pytest.mark.parametrize(
"text, msg",
[
(
"version: 1\nthemes:\n - slug: Bad Slug\n definition: x\n",
"kebab-case",
),
(
"version: 1\nthemes:\n - slug: a\n definition: ''\n",
"definition is empty",
),
(
"version: 1\nthemes:\n - slug: a\n definition: x\n - slug: a\n definition: y\n",
"duplicate slug",
),
(
"version: 0\nthemes:\n - slug: a\n definition: x\n",
"version must be >= 1",
),
("version: x\nthemes: []\n", "version must be an integer"),
("version: 1\nthemes: []\n", "no themes"),
("- a\n- b\n", "expected a mapping"),
(
"version: 1\nthemes:\n - slug: a\n definition: x\nretired: [a]\n",
"retired slugs still active",
),
],
)
def test_rejects_bad_files(self, text, msg):
with pytest.raises(VocabError, match=msg):
parse(text, source="t")
class TestPackagedVocab:
def test_loads_and_is_sane(self):
v = load()
assert v.version >= 1 and 40 <= len(v) <= 150
assert all(t.definition.endswith(".") for t in v.themes)
assert all(len(t.synonyms) >= 1 for t in v.themes)
for must in (
"telehealth",
"care-management",
"conversion-factor",
"practice-expense",
"palliative-care",
"skin-substitutes",
):
assert must in v
def test_load_from_path(self, tmp_path):
p = tmp_path / "v.yaml"
p.write_text(GOOD)
assert load(p).source == str(p)
class TestTagHelpers:
def test_split(self):
ours, rest = split_tags(
["llm:telehealth", "topic:palliative", "llm:care-management", "docket:x"]
)
assert ours == ["llm:telehealth", "llm:care-management"] and rest == [
"topic:palliative",
"docket:x",
]
assert is_llm_tag("llm:x") and not is_llm_tag("llmx:y")