* feat(kb): automatic KB builder, ingestion & validation tooling (#35) Closes #118, #119, #120, #121, #122. - Ingest committed Danbooru alias/implication snapshots during generation: synonyms reach canonicals (long black stockings -> thighhighs), implications become expand relations. Curated-wins preserved. - Automatic candidate validator (structural rules reused from kb_validation + confidence heuristic, no approval gate; SC0022). - Duplicate/conflict detection tool (scripts/detect_kb_conflicts.py) + reusable detect_conflicts; clean reference KB reports zero. - KB coverage benchmark harness (scripts/coverage_benchmark.py) + JSON summary. - Single fully-automated, CI-runnable build pipeline (scripts/build_knowledge_base.py) that fails fast on rejections/conflicts and never prompts. Docs added. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * test(kb): use pytest.approx for confidence float assertions (SonarCloud reliability) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: kunail0804 <kunail0804@gmail.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
32 lines
1.3 KiB
Python
32 lines
1.3 KiB
Python
"""Smoke tests for the KB coverage benchmark harness (issue #121, epic #35)."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from scripts.coverage_benchmark import load_corpus, measure_coverage, run
|
|
from tests.regression.golden_scenes import load_reference_knowledge_base
|
|
|
|
|
|
def test_run_returns_expected_metric_keys() -> None:
|
|
summary = run()
|
|
assert set(summary) == {"total", "covered", "coverage_rate", "hit_rate", "per_category"}
|
|
assert set(summary["hit_rate"]) == {"exact", "head_noun", "fallback", "dropped"}
|
|
assert summary["total"] > 0
|
|
assert 0.0 <= summary["coverage_rate"] <= 1.0
|
|
|
|
|
|
def test_hit_rate_paths_sum_to_total() -> None:
|
|
kb = load_reference_knowledge_base()
|
|
summary = measure_coverage(kb, load_corpus())
|
|
assert sum(summary["hit_rate"].values()) == summary["total"]
|
|
assert summary["covered"] == summary["total"] - summary["hit_rate"]["dropped"]
|
|
|
|
|
|
def test_known_paths_are_classified() -> None:
|
|
kb = load_reference_knowledge_base()
|
|
# "long hair" resolves exactly; "white summer dress" via head-noun reduction;
|
|
# a nonsense phrase is dropped.
|
|
summary = measure_coverage(kb, ["long hair", "white summer dress", "zzz nonexistent thing"])
|
|
assert summary["hit_rate"]["exact"] >= 1
|
|
assert summary["hit_rate"]["head_noun"] >= 1
|
|
assert summary["hit_rate"]["dropped"] >= 1
|