fix(ci): run full pytest suite, repair 13 rotted tests
CI was running only test_plugin_contract.py and test_version_consistency.py (2 of 84 test files), masking 13 rotted tests across 4 clusters. The suite is fully offline-safe (1402 tests in ~7s without network), so the narrow scope wasn't gating integration flakiness; it was just stale. validate.yml now runs `uv run pytest` against the full suite. Engine fix: store.findings_from_report is rerank-first. ranked_candidates is the primary persistence path; hackernews/polymarket are unconditionally supplemented from items_by_source because they rank poorly but matter for watchlists. When ranked_candidates was empty (rerank failed or skipped), reddit, x, and every other source were silently dropped. The supplement loop now falls back to all sources only when ranked_candidates is empty; the normal path is unchanged. Test repairs: - test_store.py (6) + test_watchlist_commands.py (2): cascade from the engine fix - test_get_new_findings_filters_by_date (latent): local-time vs SQLite UTC flake — switched to datetime.now(timezone.utc) - TestPollDeviceAuth (3): mock_time.time side_effect lists too short after impl added a last_reminder call — padded timeout test, pinned others to return_value=0 (loops terminate via urlopen, not the clock) - test_bare_run_emits_web_promo: engine reads ~/.config/last30days/.env, so a contributor's saved EXA/PARALLEL key made grounding "available" and suppressed the web promo. Also missing X made the "x" promo preempt "web". Set LAST30DAYS_CONFIG_DIR="", subprocess cwd=tmpdir, XAI_API_KEY stub.
This commit is contained in:
@@ -673,27 +673,31 @@ def findings_from_report(
|
||||
limit: Optional[int] = None,
|
||||
) -> List[Dict[str, Any]]:
|
||||
"""Convert report into persisted findings.
|
||||
|
||||
|
||||
Uses ranked candidates (post-rerank) when available for quality scores and explanations.
|
||||
Supplements with raw items from items_by_source for HN/PM that didn't rank highly
|
||||
but are valuable for watchlist persistence.
|
||||
but are valuable for watchlist persistence. When ranked_candidates is empty
|
||||
(degraded path — rerank failed or was skipped), falls back to supplementing
|
||||
all sources from items_by_source so findings aren't silently dropped.
|
||||
"""
|
||||
findings = []
|
||||
seen_urls = set()
|
||||
|
||||
# Phase 1: Process ranked candidates (high-quality data with explanations and corroboration)
|
||||
|
||||
for candidate in report.ranked_candidates:
|
||||
finding = finding_from_candidate(candidate)
|
||||
findings.append(finding)
|
||||
findings.append(finding_from_candidate(candidate))
|
||||
seen_urls.add(candidate.url)
|
||||
|
||||
# Phase 2: Add HN/PM items not already captured in ranked candidates
|
||||
for source_name in ["hackernews", "polymarket"]:
|
||||
|
||||
supplement_sources = (
|
||||
list(report.items_by_source)
|
||||
if not report.ranked_candidates
|
||||
else ["hackernews", "polymarket"]
|
||||
)
|
||||
for source_name in supplement_sources:
|
||||
if source_name not in report.items_by_source:
|
||||
continue
|
||||
for item in report.items_by_source[source_name]:
|
||||
if item.url in seen_urls:
|
||||
continue # Already captured with rich data
|
||||
continue
|
||||
findings.append({
|
||||
"source": source_name,
|
||||
"source_url": item.url,
|
||||
@@ -705,8 +709,7 @@ def findings_from_report(
|
||||
"relevance_score": item.local_relevance or 0.5,
|
||||
})
|
||||
seen_urls.add(item.url)
|
||||
|
||||
# Apply global limit after collecting all findings (fix: was per-source, now global)
|
||||
|
||||
return findings[:limit] if limit is not None else findings
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user