CI / quality (push) Canceled after 0s
Adds claim-bound online evidence records and citation verification scripts, node removal transport/adapter, retrieval benchmark and owner-review tooling, GraphCanvas/SourceDetail knowledge browser UI, and the ingest handoff helper. Bumps the agents/gewu pack to the online-verification branch.
112 lines
4.1 KiB
Python
112 lines
4.1 KiB
Python
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
|