Files
50e7b0a8a4 feat(kb): automatic KB builder, ingestion & validation tooling (#35) (#139)
* 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>
2026-07-13 18:10:17 +02:00

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