Expose review candidates in GroundRecall queries
This commit is contained in:
parent
fc33a5ad87
commit
d48ad29aa2
|
|
@ -41,6 +41,7 @@ def query_concept(store_dir: str | Path, concept_ref: str) -> dict[str, Any] | N
|
||||||
]
|
]
|
||||||
artifacts = {item.artifact_id: item for item in store.list_artifacts()}
|
artifacts = {item.artifact_id: item for item in store.list_artifacts()}
|
||||||
observations = {item.observation_id: item for item in store.list_observations()}
|
observations = {item.observation_id: item for item in store.list_observations()}
|
||||||
|
review_candidates = store.list_review_candidates()
|
||||||
|
|
||||||
supporting_observations = []
|
supporting_observations = []
|
||||||
for claim in claims:
|
for claim in claims:
|
||||||
|
|
@ -71,6 +72,12 @@ def query_concept(store_dir: str | Path, concept_ref: str) -> dict[str, Any] | N
|
||||||
for artifact in artifacts.values()
|
for artifact in artifacts.values()
|
||||||
if artifact.artifact_id in set(concept.source_artifact_ids)
|
if artifact.artifact_id in set(concept.source_artifact_ids)
|
||||||
]
|
]
|
||||||
|
related_review_candidates = [
|
||||||
|
item.model_dump()
|
||||||
|
for item in review_candidates
|
||||||
|
if item.candidate_id == concept.concept_id
|
||||||
|
or (item.candidate_type == "claim" and any(claim.claim_id == item.candidate_id for claim in claims))
|
||||||
|
]
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"query_type": "concept",
|
"query_type": "concept",
|
||||||
|
|
@ -80,6 +87,7 @@ def query_concept(store_dir: str | Path, concept_ref: str) -> dict[str, Any] | N
|
||||||
"related_concepts": related_concepts,
|
"related_concepts": related_concepts,
|
||||||
"supporting_observations": supporting_observations,
|
"supporting_observations": supporting_observations,
|
||||||
"source_artifacts": source_artifacts,
|
"source_artifacts": source_artifacts,
|
||||||
|
"review_candidates": related_review_candidates,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -156,6 +164,7 @@ def build_query_bundle_for_concept(store_dir: str | Path, concept_ref: str) -> d
|
||||||
"relevant_claims": claims,
|
"relevant_claims": claims,
|
||||||
"supporting_observations": payload["supporting_observations"],
|
"supporting_observations": payload["supporting_observations"],
|
||||||
"related_concepts": payload["related_concepts"],
|
"related_concepts": payload["related_concepts"],
|
||||||
|
"review_candidates": payload["review_candidates"],
|
||||||
"contradictions": contradictions,
|
"contradictions": contradictions,
|
||||||
"supersessions": supersessions,
|
"supersessions": supersessions,
|
||||||
"suggested_next_actions": [
|
"suggested_next_actions": [
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ from groundrecall.models import (
|
||||||
ObservationRecord,
|
ObservationRecord,
|
||||||
ProvenanceRecord,
|
ProvenanceRecord,
|
||||||
RelationRecord,
|
RelationRecord,
|
||||||
|
ReviewCandidateRecord,
|
||||||
)
|
)
|
||||||
from groundrecall.query import (
|
from groundrecall.query import (
|
||||||
build_query_bundle_for_concept,
|
build_query_bundle_for_concept,
|
||||||
|
|
@ -102,6 +103,30 @@ def _seed_store(store: GroundRecallStore) -> None:
|
||||||
current_status="promoted",
|
current_status="promoted",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
store.save_review_candidate(
|
||||||
|
ReviewCandidateRecord(
|
||||||
|
review_candidate_id="rq_concept_channel",
|
||||||
|
candidate_type="concept",
|
||||||
|
candidate_id="concept::channel-capacity",
|
||||||
|
triage_lane="conflict_resolution",
|
||||||
|
priority=12,
|
||||||
|
finding_codes=["bridge_concept"],
|
||||||
|
rationale="Channel Capacity | lane=conflict_resolution | priority=12 | graph=bridge_concept",
|
||||||
|
current_status="reviewed",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
store.save_review_candidate(
|
||||||
|
ReviewCandidateRecord(
|
||||||
|
review_candidate_id="rq_claim_channel",
|
||||||
|
candidate_type="claim",
|
||||||
|
candidate_id="clm_001",
|
||||||
|
triage_lane="knowledge_capture",
|
||||||
|
priority=20,
|
||||||
|
finding_codes=["claim_missing_concept"],
|
||||||
|
rationale="Channel capacity bounds reliable communication rate. | lane=knowledge_capture | priority=20",
|
||||||
|
current_status="reviewed",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_query_concept_returns_neighborhood_and_support(tmp_path: Path) -> None:
|
def test_query_concept_returns_neighborhood_and_support(tmp_path: Path) -> None:
|
||||||
|
|
@ -115,6 +140,9 @@ def test_query_concept_returns_neighborhood_and_support(tmp_path: Path) -> None:
|
||||||
assert len(payload["relations"]) == 1
|
assert len(payload["relations"]) == 1
|
||||||
assert any(item["concept_id"] == "concept::shannon-entropy" for item in payload["related_concepts"])
|
assert any(item["concept_id"] == "concept::shannon-entropy" for item in payload["related_concepts"])
|
||||||
assert payload["supporting_observations"][0]["origin_path"] == "wiki/channel-capacity.md"
|
assert payload["supporting_observations"][0]["origin_path"] == "wiki/channel-capacity.md"
|
||||||
|
assert len(payload["review_candidates"]) == 2
|
||||||
|
assert any(item["candidate_id"] == "concept::channel-capacity" for item in payload["review_candidates"])
|
||||||
|
assert any("graph=bridge_concept" in item["rationale"] for item in payload["review_candidates"])
|
||||||
|
|
||||||
|
|
||||||
def test_search_claims_matches_text_and_concept_titles(tmp_path: Path) -> None:
|
def test_search_claims_matches_text_and_concept_titles(tmp_path: Path) -> None:
|
||||||
|
|
@ -143,6 +171,7 @@ def test_build_query_bundle_for_concept_is_assistant_neutral(tmp_path: Path) ->
|
||||||
assert payload is not None
|
assert payload is not None
|
||||||
assert payload["bundle_kind"] == "groundrecall_query_bundle"
|
assert payload["bundle_kind"] == "groundrecall_query_bundle"
|
||||||
assert payload["concept"]["concept_id"] == "concept::channel-capacity"
|
assert payload["concept"]["concept_id"] == "concept::channel-capacity"
|
||||||
|
assert len(payload["review_candidates"]) == 2
|
||||||
assert isinstance(payload["suggested_next_actions"], list)
|
assert isinstance(payload["suggested_next_actions"], list)
|
||||||
forbidden = {"assistant", "codex", "claude", "prompt_text"}
|
forbidden = {"assistant", "codex", "claude", "prompt_text"}
|
||||||
assert set(payload).isdisjoint(forbidden)
|
assert set(payload).isdisjoint(forbidden)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue