service logic for facts, chunks, candidates, and current-approved-vs-target comparison

This commit is contained in:
2026-04-26 15:43:03 +02:00
parent 35274baac1
commit ea5da4a8e0
7 changed files with 600 additions and 0 deletions

View File

@@ -16,7 +16,9 @@ from repo_registry.web_api.schemas import (
AbilityCreate,
AbilitySummaryResponse,
AbilityUpdate,
AnalysisRunChangeApproval,
AnalysisRunCreate,
AnalysisRunDiffResponse,
AnalysisRunResponse,
CandidateAbilityMerge,
CandidateCapabilityMerge,
@@ -239,6 +241,29 @@ def get_analysis_run(
raise HTTPException(status_code=404, detail=str(exc)) from exc
@app.get(
"/repos/{repository_id}/analysis-runs/{base_analysis_run_id}/diff/{target_analysis_run_id}",
tags=["review"],
response_model=AnalysisRunDiffResponse,
)
def diff_analysis_runs(
repository_id: int,
base_analysis_run_id: int,
target_analysis_run_id: int,
service: RegistryService = Depends(get_service),
) -> dict[str, object]:
try:
return asdict(
service.diff_analysis_runs(
repository_id,
base_analysis_run_id,
target_analysis_run_id,
)
)
except NotFoundError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@app.get(
"/repos/{repository_id}/review-decisions",
tags=["review"],
@@ -375,6 +400,29 @@ def approve_candidate_graph(
raise HTTPException(status_code=404, detail=str(exc)) from exc
@app.post(
"/repos/{repository_id}/analysis-runs/{analysis_run_id}/changes/approve",
tags=["review"],
response_model=RepositoryAbilityMapResponse,
)
def approve_analysis_run_changes(
repository_id: int,
analysis_run_id: int,
payload: AnalysisRunChangeApproval,
service: RegistryService = Depends(get_service),
) -> dict[str, object]:
try:
return asdict(
service.approve_analysis_run_changes(
repository_id,
analysis_run_id,
notes=payload.notes,
)
)
except NotFoundError as exc:
raise HTTPException(status_code=404, detail=str(exc)) from exc
@app.post(
"/repos/{repository_id}/analysis-runs/{analysis_run_id}"
"/candidate-abilities/{candidate_ability_id}/reject",

View File

@@ -206,6 +206,16 @@ class CandidateGraphApproval(BaseModel):
}
class AnalysisRunChangeApproval(BaseModel):
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [{"notes": "Accept target run changes after review."}]
}
}
class CandidateRejection(BaseModel):
notes: str = ""
@@ -506,6 +516,31 @@ class CandidateGraphResponse(BaseModel):
}
class AnalysisRunDiffItemResponse(BaseModel):
change_type: str
item_type: str
key: str
base: dict[str, Any] | None = None
target: dict[str, Any] | None = None
class AnalysisRunDiffSectionResponse(BaseModel):
added: list[AnalysisRunDiffItemResponse]
removed: list[AnalysisRunDiffItemResponse]
changed: list[AnalysisRunDiffItemResponse]
weakened: list[AnalysisRunDiffItemResponse]
class AnalysisRunDiffResponse(BaseModel):
repository: RepositoryResponse
base_run: AnalysisRunResponse
target_run: AnalysisRunResponse
facts: AnalysisRunDiffSectionResponse
chunks: AnalysisRunDiffSectionResponse
candidates: AnalysisRunDiffSectionResponse
approved_entries: AnalysisRunDiffSectionResponse
class EvidenceResponse(BaseModel):
id: int
type: str