pam ▸ docs/generated/ralph_loop_2026-03-16_semantic_review_candidate_gate.md
updated 2026-03-28

Ralph Loop 2026-03-16: Semantic Review Candidate Gate

Sub-problem

PRD 003 candidate review quality was still overstating live review quality by allowing no_semantic_sleeve_match rows into review_candidate when they only had a single blocker.

Change

  1. Updated research/candidate_review.py so semantically unmatched rows always remain research_candidate.
  2. Added a regression test covering the exact failure mode: a single-blocker unmatched row no longer appears in review_candidates.
  3. Documented the behavior in research/README.md.

Why it matters

The live review packet should only contain rows backed by at least one valid research sleeve. Without this guard, Ralph could treat sleeve-less rows as actionable review items, which weakens candidate review signal quality.

Validation

  1. pytest -q tests/test_candidate_review.py tests/test_continuous_loop.py - Result: 14 passed in 0.11s
  2. Live packet smoke check: - counts_by_state {'review_candidate': 1, 'research_candidate': 17} - review_tickers ['KXNEXTUKPM-30-NF'] - top_review_blockers [('sleeve_disabled:politics_midprice_reversal', 1)] - unmatched_semantic_sleeve_count 17

Outcome

Candidate review now excludes semantically unmatched rows from the review lane, which makes the remaining review packet more trustworthy without relaxing any deployment or replay gates.