Candidate support/evidence acceptance

This commit is contained in:
2026-04-29 17:52:42 +02:00
parent 0bb0c61f75
commit 466fd86d6d
6 changed files with 200 additions and 0 deletions

View File

@@ -379,6 +379,13 @@ class RegistryService:
type=evidence.type,
reference=evidence.reference,
strength=evidence.strength,
target_kind=evidence.target_kind,
target_id=self._approved_evidence_target_id(
evidence,
approved_capability_id,
),
reference_kind=evidence.reference_kind,
reference_id=evidence.reference_id,
source_refs=evidence.source_refs,
)
@@ -520,6 +527,58 @@ class RegistryService:
)
return self.store.get_ability_map(repository_id)
def accept_candidate_evidence(
self,
repository_id: int,
analysis_run_id: int,
candidate_evidence_id: int,
*,
notes: str = "",
) -> RepositoryAbilityMap:
graph = self.store.get_candidate_graph(repository_id, analysis_run_id)
parent_ability, parent_capability, evidence = (
self._candidate_evidence_with_parent(graph, candidate_evidence_id)
)
if evidence.status != "candidate":
raise ValueError(
f"candidate evidence {candidate_evidence_id} is not pending"
)
approved_ability_id = self._ensure_approved_ability(repository_id, parent_ability)
approved_capability_id = self._ensure_approved_capability(
repository_id,
approved_ability_id,
parent_ability.name,
parent_capability,
)
self.store.create_evidence(
repository_id,
approved_capability_id,
type=evidence.type,
reference=evidence.reference,
strength=evidence.strength,
target_kind=evidence.target_kind,
target_id=self._approved_evidence_target_id(
evidence,
approved_capability_id,
),
reference_kind=evidence.reference_kind,
reference_id=evidence.reference_id,
source_refs=evidence.source_refs,
)
self.store.mark_candidate_evidence_status(
repository_id,
analysis_run_id,
candidate_evidence_id,
"approved",
)
self._record_candidate_acceptance(
repository_id,
analysis_run_id,
"accept_candidate_evidence",
notes or f"Accepted candidate support: {evidence.reference}",
)
return self.store.get_ability_map(repository_id)
def diff_analysis_runs(
self,
repository_id: int,
@@ -618,6 +677,13 @@ class RegistryService:
type=evidence.type,
reference=evidence.reference,
strength=evidence.strength,
target_kind=evidence.target_kind,
target_id=self._approved_evidence_target_id(
evidence,
approved_capability_id,
),
reference_kind=evidence.reference_kind,
reference_id=evidence.reference_id,
source_refs=evidence.source_refs,
)
return approved_capability_id
@@ -673,6 +739,15 @@ class RegistryService:
return ability, capability
raise ValueError(f"candidate capability {candidate_capability_id} was not found")
def _approved_evidence_target_id(
self,
evidence: CandidateEvidence,
approved_capability_id: int,
) -> int | None:
if evidence.target_kind == "capability":
return approved_capability_id
return evidence.target_id
def _candidate_feature_with_parent(
self,
graph: CandidateGraph,
@@ -685,6 +760,18 @@ class RegistryService:
return ability, capability, feature
raise ValueError(f"candidate feature {candidate_feature_id} was not found")
def _candidate_evidence_with_parent(
self,
graph: CandidateGraph,
candidate_evidence_id: int,
) -> tuple[CandidateAbility, CandidateCapability, CandidateEvidence]:
for ability in graph.abilities:
for capability in ability.capabilities:
for evidence in capability.evidence:
if evidence.id == candidate_evidence_id:
return ability, capability, evidence
raise ValueError(f"candidate evidence {candidate_evidence_id} was not found")
def _record_candidate_acceptance(
self,
repository_id: int,