Files
Matt Van Horn 9c020b1393 feat(grounding): per-claim freshness verdicts (--verify-freshness) (#805)
* feat(grounding): per-claim freshness verdicts (--verify-freshness)

* fix: address self-review findings

* fix: address round-2 residual (surgical round)

* fix: prefer active markets in mixed-event verification, plan-only cookies for cached verification

* fix: verify event identity on slug-fallback refetch before assigning verdicts

* test: use a real outcome datum key in slug-identity test

* fix(freshness): carry values in stale detail and announce zero-claim passes

A stale verdict's machine-readable detail said only that the value
moved; the rendered table already showed was/now, so agent-JSON
consumers saw less than readers. Compose the detail as
"moved: <original> -> <current>", formatting each value the way the
claim text does (percent for Polymarket/StockTwits, thousands
separators for stars).

A verification pass that extracts zero claims used to complete
silently, which misled a live post-hoc run. _verify_report_set now
prints one stderr note when no verified report produced any verdict,
aggregated across main and entity reports so multi-report passes note
it once; the drill path routes through the same helper.

* fix(freshness): verify star facts attached by candidate enrichment

A GitHub-flavored run produced zero verdicts live: star enrichment
attaches metadata["github_stars"] to candidates after reranking, but
claim extraction read only item-level engagement, and those candidates'
primary items are typically non-GitHub sources.

Extraction now emits one repo-keyed star claim per enriched repo
(skipping repos already claimed at item level). These claims cannot
ride the item-source dispatch - they would land unsupported as
"reddit"/"x" claims - so verify_report routes the repo-slug shape
straight to the GitHub refetcher, bypassing the grounding-item lookup
and the per-source outcome gate (the datum came from enrichment, not
the github search source). refetch_datum accepts an owner/repo slug as
the datum key, and the snapshot cache keys these claims by repo so
multiple candidates citing one repo share one request.

* fix(freshness): review fixes - honest evidence, joinable export, rendered detail

Four review findings on the hardening pass:

- Unsupported verdicts no longer fabricate evidence: evidence_url and
  evidence_timestamp stay empty when no fresh evidence was obtained;
  provenance remains on source_url/source_timestamp.
- Agent export results now carry candidate_id so consumers can join
  freshness_verdicts to the result they annotate (schema_version 1.2,
  golden snapshot and docs updated).
- The rendered verdict table shows the verifier's detail - formatted
  movement on stale rows, the un-checkable reason on unsupported rows -
  instead of reconstructing raw values.
- Item-level star dedup is scoped per candidate: another candidate's
  item-level claim no longer suppresses an enriched candidate's own
  verdict and inline flag; both share one repo snapshot.

* fix(freshness): require event-id identity on Polymarket slug fallback

The slug-fallback refetch verified the response slug but accepted a
slug-matched event whose id differed from the cached item's event id,
so a re-created event reusing a slug could produce current/stale
verdicts from another market's prices. When the cached item carries a
real numeric event id, the fallback now requires the response id to
match it (synthetic PM<N> parse ids carry no identity and skip the
check); mismatches raise and degrade to an unsupported verdict.

* fix(freshness): fail closed when the slug fallback has no event identity

A cached item with neither metadata.event_id nor a real numeric item id
(the synthetic PM<N> parse fallback) let the slug fallback accept
whatever event currently owns the slug, so a recreated or loosely
matched event could still drive a current/stale verdict. With no
identity to verify against, the refetch now raises before any request
and the claim degrades to unsupported.

---------

Co-authored-by: Matt Van Horn <455140+mvanhorn@users.noreply.github.com>
2026-07-12 07:32:47 -07:00
..