qa: warrant-lite — wire JSON variant of claim_lattice verifier

Initial Ticket H commit (38d95dd) only plumbed warrant into
verify_claim_lattice (pointer mode). The JSON variant
verify_claim_lattice_json was missed — and the CLI's
--answer-mode claim_lattice (the JSON path) was producing
EVIDENCE-LINKED on relation-question records without warrant
firing.

This adds the same warrant block to verify_claim_lattice_json:
question + warrant_check_enabled params, identical
WARRANT_MISSING violations, identical demote-to-HYBRID
semantics, same warrant_missing_claim_idxs field on the verdict.
Plumbs question= and warrant_check_enabled= through call sites
in runner.py and query.py for the JSON path.

Live verified: warrant correctly checks the FULL cited span
(not the spotlight excerpt). On the Homer-Simpson "boss is Mr.
Burns" case, the chunk text DOES contain "Mr. Burns" elsewhere
in the paragraph — warrant rightly passes. The misleading
spotlight excerpt that fox flagged is a separate render-layer
issue (failure to spotlight the load-bearing slice), not a
warrant failure.

Note: cache-hit path does not currently restore violations into
the result dict (providence_cache schema has no violations
column; run_dag_blob stores only hashes). On cache hits the
warrant_tail in CLI render won't surface even when warrant
fired at write-time. Follow-up needs a schema migration to
persist violations alongside the cached record.
This commit is contained in:
russell@unturf.com 2026-05-01 13:32:05 -04:00
parent 38d95dd21b
commit 182bb67996
No known key found for this signature in database
3 changed files with 43 additions and 0 deletions

View file

@ -1835,6 +1835,10 @@ def query(
max_claims_per_answer=int(policy.get(
"claim_lattice_max_claims_per_answer", 12
)),
question=question,
warrant_check_enabled=bool(policy.get(
"claim_lattice_warrant_check_enabled", True
)),
)
rendered = verdict["rendered_text"]
answer_text = rendered if rendered else raw_answer

View file

@ -652,6 +652,10 @@ def ask(
max_claims_per_answer=int(policy.get(
"claim_lattice_max_claims_per_answer", 12
)),
question=question,
warrant_check_enabled=bool(policy.get(
"claim_lattice_warrant_check_enabled", True
)),
)
rendered = verdict["rendered_text"]
answer_text = rendered if rendered else raw_answer

View file

@ -1467,6 +1467,8 @@ def verify_claim_lattice_json(
max_evidence_per_claim: int = DEFAULT_MAX_POINTERS_PER_CLAIM,
min_citation_coverage: float = DEFAULT_MIN_CITATION_COVERAGE,
max_claims_per_answer: int = DEFAULT_MAX_CLAIMS_PER_ANSWER,
question: str | None = None,
warrant_check_enabled: bool = True,
) -> dict:
"""Deterministic verifier for ``answer_mode="claim_lattice"`` (JSON).
@ -1710,6 +1712,38 @@ def verify_claim_lattice_json(
else:
audit_mode = "UNGROUNDED"
# Warrant-lite — same relation-question hard check as the pointer
# variant. See verify_claim_lattice for the rationale (Ticket H,
# 2026-05-01). Identical demote-to-HYBRID semantics; the JSON
# variant carries the same WARRANT_MISSING violations & the same
# warrant_missing_claim_idxs field on the verdict.
warrant_missing_claims: list[int] = []
if warrant_check_enabled and question and is_relation_question(question):
for cs in claim_statuses:
if cs.get("status") not in ("EVIDENCE_LINKED", "EVIDENCE_LINKED_PARTIAL"):
continue
cited_eids = cs.get("evidence_ids") or []
cited_spans = [
obj.span
for eid in cited_eids
for obj in [evidence_map_by_evidence_id_local(evidence_map, eid)]
if obj is not None
]
ok, missing = warrant_check(cs.get("text") or "", cited_spans)
if not ok:
warrant_missing_claims.append(cs.get("claim_idx"))
violations.append({
"kind": "WARRANT_MISSING",
"claim_idx": cs.get("claim_idx"),
"missing_anchors": missing,
"rationale": (
"claim names answer entity not present in any "
"cited span — pointer-linked but warrant missing"
),
})
if warrant_missing_claims and audit_mode == "STRICT":
audit_mode = "HYBRID"
# Same `verifier_method` as the pointer variant ("claim_lattice")
# so the providence_cache CHECK constraint accepts both. The mode
# is disambiguated downstream via `answer_mode` on the run-DAG &
@ -1725,4 +1759,5 @@ def verify_claim_lattice_json(
"rendered_text": rendered_text,
"evidence_id_pairs": evidence_id_pairs,
"json_fixups": json_fixups,
"warrant_missing_claim_idxs": warrant_missing_claims,
}