from scripts.review_benchmark_candidates import review from gewu.domain.validation import assertion_digest def _inputs(): extractions = { "extract-1": { "extraction_id": "extract-1", "source_revision_id": "source-1", "blocks": [{"block_id": "block-1", "page": 1, "normalized_text": "The sky is blue."}], } } item = { "source_stage": "review", "storage_state": "evaluated; needs-review", "evaluation": {"status": "needs-review", "eligible_for_auto_accept": False}, "proposal": { "proposal_id": "proposal-1", "revision": 1, "operations": [ { "node": { "claims": [ { "claim_id": "claim-1", "text": "The sky is blue.", "evidence": [ { "source_revision_id": "source-1", "extraction_id": "extract-1", "assertion_digest": assertion_digest("The sky is blue."), "quote": "The sky is blue.", "locator": { "block_id": "block-1", "start": 0, "end": 16, "page": 1, }, } ], } ] } } ], }, } return [item], extractions def test_valid_evidence_does_not_clear_protected_owner_review(): items, extractions = _inputs() result = review(items, extractions, input_sha256="b" * 64) assert result["summary"]["evidence_bindings_valid"] == 1 assert result["items"][0]["recommendation"] == "defer" assert result["summary"]["owner_decisions_written"] == 0 assert result["summary"]["canonical_records_written"] == 0 def test_invalid_quote_recommends_revision_without_mutating_input(): items, extractions = _inputs() items[0]["proposal"]["operations"][0]["node"]["claims"][0]["evidence"][0]["quote"] = ( "The sky is green." ) original = items[0]["proposal"]["operations"][0]["node"]["claims"][0]["evidence"][0]["quote"] result = review(items, extractions, input_sha256="c" * 64) assert result["items"][0]["recommendation"] == "revise-candidate" assert "QUOTE_SPAN_MISMATCH" in result["items"][0]["claims"][0]["issues"] assert ( items[0]["proposal"]["operations"][0]["node"]["claims"][0]["evidence"][0]["quote"] == original ) def test_missing_evidence_is_reported_for_each_claim(): items, extractions = _inputs() items[0]["proposal"]["operations"][0]["node"]["claims"][0]["evidence"] = [] result = review(items, extractions, input_sha256="d" * 64) assert result["items"][0]["claims"][0]["issues"] == ["CLAIM_EVIDENCE_REQUIRED"] assert result["items"][0]["recommendation"] == "revise-candidate" def test_assertion_digest_is_bound_to_the_exact_claim_text(): items, extractions = _inputs() evidence = items[0]["proposal"]["operations"][0]["node"]["claims"][0]["evidence"][0] evidence["assertion_digest"] = "0" * 64 result = review(items, extractions, input_sha256="e" * 64) assert "ASSERTION_DIGEST_MISMATCH" in result["items"][0]["claims"][0]["issues"] def test_supersession_edges_are_copied_to_advisory_ledger(): items, extractions = _inputs() edge = {"relation": "corrects", "source": "old-node", "target": "new-node"} items[0]["source_stage"] = "supersession" items[0]["proposal"]["operations"].append({"edge": edge}) result = review(items, extractions, input_sha256="e" * 64) row = result["items"][0] assert row["recommendation"] == "defer" assert row["supersession_edges"] == [edge] assert row["supersession_edges_preserved"] == 1