phase: 113_source_chip_quality
All gates green — no defects found; this pass was verification only. **Phase 113 final verification pass — report** - Verified (no code changes needed): `select_documents_tiered` cited/related tiering + `select_documents` wrapper, `TurnPlan.related_docs`, `ChatDoneEvent.related` (additive, old payloads parse), `appendRelated` UI row (`.related-doc`, never `.source-chip`), done-frame + restore-path wiring, two settings with validators, `.env.example` entries - `uv run pytest --cov=app --cov-report=term-missing` → 2422 passed, app/ coverage **99%** (>90% gate) - `uv run pytest tests/e2e/test_source_chip_quality.py -v --no-cov` (isolated) → 2 passed - Regression E2E `test_retrieval_quality.py` + `test_honest_deflection.py` + `test_chat_rag.py` + `test_sources_midstream_bug.py` → 17 passed - `uv run ruff check . && uv run pyright` → clean (0 errors); `bash .agents/validate.sh` → "validation OK" Completion criteria: 1. Single-doc question → exactly one `.source-chip` (E2E): ✅ passed 2. Weak 2nd doc only in de-emphasized related row, never `.source-chip` (unit + E2E): ✅ passed 3. Deflected turn → zero citation chips, weak hits in related row: ✅ passed 4. Full suite green, coverage >90%, isolated E2E green, lint/types clean: ✅ passed 5. `--no-gpg-sign` commit + phase dir move: left to harness per pass rules (task files already in `complete/`) No deviations. Next pending phase: `114_embed_question_length`.
This commit is contained in:
@@ -213,6 +213,75 @@ def test_agent_max_rounds_rejects_negative(monkeypatch: pytest.MonkeyPatch) -> N
|
||||
_settings()
|
||||
|
||||
|
||||
def test_source_usefulness_floor_default_and_env_override(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Phase 113 (LOCKED A2): the citation-slot bar — default 0.35 (the
|
||||
same bar as the A8 lexical support floor), env-tunable, ``0`` = the
|
||||
no-bar kill switch."""
|
||||
monkeypatch.delenv("BOR_SOURCE_USEFULNESS_FLOOR", raising=False)
|
||||
# The test process pins the mock-calibrated threshold (0.30, see
|
||||
# tests/conftest.py) — clear it so the PRODUCTION default pair
|
||||
# (0.62 / 0.35) is what the validator sees.
|
||||
monkeypatch.delenv("BOR_RELEVANCE_THRESHOLD", raising=False)
|
||||
assert _settings().source_usefulness_floor == 0.35
|
||||
monkeypatch.setenv("BOR_SOURCE_USEFULNESS_FLOOR", "0.5")
|
||||
assert _settings().source_usefulness_floor == 0.5
|
||||
monkeypatch.setenv("BOR_SOURCE_USEFULNESS_FLOOR", "0")
|
||||
assert _settings().source_usefulness_floor == 0.0
|
||||
|
||||
|
||||
def test_source_usefulness_floor_at_threshold_is_legal(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""The validator bound is inclusive (>=): a bar exactly at the
|
||||
relevance threshold is legal — the gate and the bar agree on every
|
||||
grounded document."""
|
||||
monkeypatch.delenv("BOR_SOURCE_USEFULNESS_FLOOR", raising=False)
|
||||
monkeypatch.delenv("BOR_RELEVANCE_THRESHOLD", raising=False)
|
||||
s = _settings(relevance_threshold=0.62, source_usefulness_floor=0.62)
|
||||
assert s.source_usefulness_floor == 0.62
|
||||
|
||||
|
||||
def test_source_usefulness_floor_rejects_above_threshold(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""A bar above the relevance threshold would demote to the related
|
||||
tier documents the gate itself calls grounded — a typo, so the
|
||||
validator fails loudly at startup (the lexical_support_floor guard)."""
|
||||
monkeypatch.delenv("BOR_SOURCE_USEFULNESS_FLOOR", raising=False)
|
||||
with pytest.raises(ValidationError, match="source_usefulness_floor"):
|
||||
_settings(relevance_threshold=0.62, source_usefulness_floor=0.70)
|
||||
|
||||
|
||||
def test_source_usefulness_floor_rejects_negative(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""A negative bar is a typo (the agent_max_rounds pattern)."""
|
||||
with pytest.raises(ValidationError, match="source_usefulness_floor"):
|
||||
_settings(source_usefulness_floor=-0.1)
|
||||
|
||||
|
||||
def test_related_max_docs_default_and_env_override(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""Phase 113 (LOCKED A4): the related-doc tier cap — default 2,
|
||||
``0`` = the no-related-docs kill switch."""
|
||||
monkeypatch.delenv("BOR_RELATED_MAX_DOCS", raising=False)
|
||||
assert _settings().related_max_docs == 2
|
||||
monkeypatch.setenv("BOR_RELATED_MAX_DOCS", "0")
|
||||
assert _settings().related_max_docs == 0
|
||||
|
||||
|
||||
def test_related_max_docs_rejects_negative(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
"""A negative cap is a typo (the agent_max_rounds pattern)."""
|
||||
monkeypatch.setenv("BOR_RELATED_MAX_DOCS", "-1")
|
||||
with pytest.raises(ValidationError, match="related_max_docs"):
|
||||
_settings()
|
||||
|
||||
|
||||
def test_read_max_chars_default_and_env_override(
|
||||
monkeypatch: pytest.MonkeyPatch,
|
||||
) -> None:
|
||||
|
||||
Reference in New Issue
Block a user