Classify review-only claim proposals correctly (#186)
Some checks are pending
CI / lint-and-test (push) Waiting to run

This commit is contained in:
twentyOne2x 2026-07-18 01:14:58 +02:00 committed by GitHub
parent a6569214a3
commit 20e2f60b0e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 35 additions and 9 deletions

View file

@ -468,6 +468,22 @@ def _has_unnegated_action(query: str, actions: tuple[str, ...]) -> bool:
return False return False
def _has_unnegated_source_action(query: str) -> bool:
"""Detect source-intake verbs without treating a prohibition as intent."""
action_pattern = re.compile(
r"\b(?:send|hand|drop|upload|learn|absorb|ingest|extract|stage|add)(?:s|ed|ing)?\b|"
r"\bmake it part\b"
)
for segment in re.split(r"(?<=[.!?;])\s+|\n+", query.lower()):
if not action_pattern.search(segment):
continue
if "read-only" in segment or re.search(r"\b(?:do not|don't|dont|must not|without)\b", segment):
continue
return True
return False
def _has_unnegated_database_state_request(query: str) -> bool: def _has_unnegated_database_state_request(query: str) -> bool:
"""Detect an actual DB-state question instead of incidental lifecycle vocabulary.""" """Detect an actual DB-state question instead of incidental lifecycle vocabulary."""
@ -705,9 +721,16 @@ def operational_contracts(
candidate_claim_composition_question = bool( candidate_claim_composition_question = bool(
any( any(
term in lowered term in lowered
for term in ("candidate claim", "reviewable candidate", "candidate only", "revised exact claim body") for term in (
"candidate claim",
"reviewable candidate",
"candidate only",
"revised exact claim body",
"review-only proposal",
"review only proposal",
)
) )
and any(term in lowered for term in ("draft", "propose", "revise", "rewrite", "narrow", "return")) and any(term in lowered for term in ("draft", "propose", "revise", "rewrite", "narrow", "return", "turn"))
and not existing_claim_audit_question and not existing_claim_audit_question
) )
claim_evidence_challenge_question = bool( claim_evidence_challenge_question = bool(
@ -826,13 +849,7 @@ def operational_contracts(
) )
source_terms = ("document", "pdf", "tweet", "attachment", "ingest", "intake", "absorb", "extract") source_terms = ("document", "pdf", "tweet", "attachment", "ingest", "intake", "absorb", "extract")
broad_source_object = bool(re.search(r"\b(?:report|article|file|url|link)s?\b", normalized)) broad_source_object = bool(re.search(r"\b(?:report|article|file|url|link)s?\b", normalized))
broad_source_action = bool( broad_source_action = _has_unnegated_source_action(query)
re.search(
r"\b(?:send|hand|drop|upload|learn|absorb|ingest|extract|stage|add)(?:s|ed|ing)?\b|"
r"\bmake it part\b",
normalized,
)
)
source_intake_question = any(term in lowered for term in source_terms) or ( source_intake_question = any(term in lowered for term in source_terms) or (
broad_source_object and broad_source_action broad_source_object and broad_source_action
) )

View file

@ -1968,6 +1968,15 @@ def test_vps_bridge_direct_intents_reject_unrelated_and_resolve_overlaps() -> No
} }
assert reasoning_followup_ids & direct_ids == set() assert reasoning_followup_ids & direct_ids == set()
review_only_proposal_ids = {
item["id"]
for item in module.operational_contracts(
"Turn the surviving claim into a review-only proposal: exact body, confidence, falsifier, required "
"sources, and links to claims that support or contradict it. Do not stage or write anything."
)
}
assert review_only_proposal_ids == {"reply_budget"}
chat_memory_ids = { chat_memory_ids = {
item["id"] item["id"]
for item in module.operational_contracts( for item in module.operational_contracts(