Pydantic models out of app.py into the new schemas.py

This commit is contained in:
2026-04-26 09:24:45 +02:00
parent d786589dd1
commit c31b062a6b
2 changed files with 533 additions and 495 deletions

View File

@@ -2,16 +2,49 @@ from __future__ import annotations
from dataclasses import asdict
from pathlib import Path
from typing import Any
from fastapi import Depends, FastAPI, HTTPException, Query
from pydantic import BaseModel, Field
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
from repo_registry.core.service import RegistryService
from repo_registry.llm_extraction import LLMCandidateExtractor, create_llm_connect_adapter
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.storage.sqlite import NotFoundError, RegistryStore
from repo_registry.web_api.schemas import (
AbilityCreate,
AbilitySummaryResponse,
AbilityUpdate,
AnalysisRunCreate,
AnalysisRunResponse,
CandidateAbilityMerge,
CandidateCapabilityMerge,
CandidateCapabilityRelink,
CandidateEdit,
CandidateEvidenceMerge,
CandidateFeatureMerge,
CandidateGraphApproval,
CandidateGraphResponse,
CandidateLeafRelink,
CandidateRejection,
CapabilityCreate,
CapabilitySummaryResponse,
CapabilityUpdate,
ContentChunkResponse,
EvidenceCreate,
EvidenceUpdate,
FeatureCreate,
FeatureUpdate,
IdResponse,
ObservedFactResponse,
RepositoryAbilityMapResponse,
RepositoryCreate,
RepositoryResponse,
RepositoryUpdate,
ReviewDecisionResponse,
ScanSummaryResponse,
SearchResultResponse,
)
class Settings(BaseSettings):
@@ -46,499 +79,6 @@ def get_service(settings: Settings = Depends(get_settings)) -> RegistryService:
)
class RepositoryCreate(BaseModel):
url: str
name: str | None = None
description: str | None = None
branch: str = "main"
model_config = {
"json_schema_extra": {
"examples": [
{
"url": "https://github.com/example/repository.git",
"name": "Example Repository",
"description": "Optional human-readable repository summary.",
"branch": "main",
}
]
}
}
class RepositoryUpdate(BaseModel):
name: str | None = None
description: str | None = None
branch: str | None = None
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Renamed Repository",
"description": "Updated curator-facing summary.",
"branch": "main",
}
]
}
}
class AbilityCreate(BaseModel):
name: str
description: str = ""
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Business Email Routing",
"description": "Route inbound messages to the right team.",
"confidence": 0.92,
}
]
}
}
class AbilityUpdate(BaseModel):
name: str | None = None
description: str | None = None
confidence: float | None = Field(default=None, ge=0.0, le=1.0)
class CapabilityCreate(BaseModel):
ability_id: int
name: str
description: str = ""
inputs: list[str] = Field(default_factory=list)
outputs: list[str] = Field(default_factory=list)
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
model_config = {
"json_schema_extra": {
"examples": [
{
"ability_id": 1,
"name": "Classify Incoming Email",
"description": "Classify messages by intent.",
"inputs": ["subject", "body"],
"outputs": ["intent", "confidence"],
"confidence": 0.88,
}
]
}
}
class CapabilityUpdate(BaseModel):
name: str | None = None
description: str | None = None
inputs: list[str] | None = None
outputs: list[str] | None = None
confidence: float | None = Field(default=None, ge=0.0, le=1.0)
class FeatureCreate(BaseModel):
capability_id: int
name: str
type: str
location: str = ""
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
model_config = {
"json_schema_extra": {
"examples": [
{
"capability_id": 1,
"name": "POST /api/classify-email",
"type": "REST endpoint",
"location": "src/routes/classify_email.py",
"confidence": 0.84,
}
]
}
}
class FeatureUpdate(BaseModel):
name: str | None = None
type: str | None = None
location: str | None = None
confidence: float | None = Field(default=None, ge=0.0, le=1.0)
class EvidenceCreate(BaseModel):
capability_id: int
type: str
reference: str
strength: str = "medium"
model_config = {
"json_schema_extra": {
"examples": [
{
"capability_id": 1,
"type": "unit_test",
"reference": "tests/test_email_classification.py",
"strength": "strong",
}
]
}
}
class EvidenceUpdate(BaseModel):
type: str | None = None
reference: str | None = None
strength: str | None = None
class AnalysisRunCreate(BaseModel):
source_path: str | None = None
model_config = {
"json_schema_extra": {
"examples": [
{},
{"source_path": "/path/to/local/repository"},
]
}
}
class CandidateGraphApproval(BaseModel):
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [{"notes": "Approved after curator review."}]
}
}
class CandidateRejection(BaseModel):
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [{"notes": "Rejected because the claim is too generic."}]
}
}
class CandidateEdit(BaseModel):
name: str
description: str = ""
confidence: float = Field(default=0.5, ge=0.0, le=1.0)
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Service Health Monitoring",
"description": "Expose health state for operational checks.",
"confidence": 0.9,
"notes": "Renamed from generated review seed.",
}
]
}
}
class CandidateCapabilityRelink(BaseModel):
target_ability_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{"target_ability_id": 2, "notes": "Move under operational ability."}
]
}
}
class CandidateLeafRelink(BaseModel):
target_capability_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{
"target_capability_id": 3,
"notes": "Evidence supports a different capability.",
}
]
}
}
class CandidateAbilityMerge(BaseModel):
target_ability_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{"target_ability_id": 2, "notes": "Duplicate ability wording."}
]
}
}
class CandidateCapabilityMerge(BaseModel):
target_capability_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{"target_capability_id": 3, "notes": "Duplicate capability."}
]
}
}
class CandidateFeatureMerge(BaseModel):
target_feature_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [{"target_feature_id": 4, "notes": "Duplicate route."}]
}
}
class CandidateEvidenceMerge(BaseModel):
target_evidence_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [{"target_evidence_id": 5, "notes": "Duplicate evidence."}]
}
}
class RepositoryResponse(BaseModel):
id: int
name: str
url: str
description: str | None
branch: str
status: str
class RepositorySnapshotResponse(BaseModel):
id: int
repository_id: int
commit_hash: str
branch: str
source_path: str
file_count: int
class AnalysisRunResponse(BaseModel):
id: int
repository_id: int
snapshot_id: int | None
status: str
started_at: str
completed_at: str | None
error_message: str | None
scanner_version: str
class ReviewDecisionResponse(BaseModel):
id: int
repository_id: int
analysis_run_id: int | None
action: str
notes: str
created_at: str
class ObservedFactResponse(BaseModel):
id: int
repository_id: int
analysis_run_id: int
snapshot_id: int | None
kind: str
path: str
name: str
value: str
metadata: dict[str, Any]
class ContentChunkResponse(BaseModel):
id: int
repository_id: int
analysis_run_id: int
snapshot_id: int | None
path: str
kind: str
start_line: int
end_line: int
text: str
class ScanSummaryResponse(BaseModel):
analysis_run: AnalysisRunResponse
snapshot: RepositorySnapshotResponse | None
facts: list[ObservedFactResponse]
class SourceReferenceResponse(BaseModel):
fact_id: int | None
path: str
kind: str
name: str
line: int | None = None
class CandidateEvidenceResponse(BaseModel):
id: int
type: str
reference: str
strength: str
status: str
source_refs: list[SourceReferenceResponse]
class CandidateFeatureResponse(BaseModel):
id: int
name: str
type: str
location: str
confidence: float
status: str
source_refs: list[SourceReferenceResponse]
confidence_label: str
class CandidateCapabilityResponse(BaseModel):
id: int
name: str
description: str
inputs: list[str]
outputs: list[str]
confidence: float
status: str
source_refs: list[SourceReferenceResponse]
confidence_label: str
features: list[CandidateFeatureResponse]
evidence: list[CandidateEvidenceResponse]
class CandidateAbilityResponse(BaseModel):
id: int
name: str
description: str
confidence: float
status: str
source_refs: list[SourceReferenceResponse]
confidence_label: str
capabilities: list[CandidateCapabilityResponse]
class CandidateGraphResponse(BaseModel):
repository: RepositoryResponse
analysis_run: AnalysisRunResponse
abilities: list[CandidateAbilityResponse]
class EvidenceResponse(BaseModel):
id: int
type: str
reference: str
strength: str
source_refs: list[SourceReferenceResponse]
class FeatureResponse(BaseModel):
id: int
name: str
type: str
location: str
confidence: float
confidence_label: str
source_refs: list[SourceReferenceResponse]
class CapabilityResponse(BaseModel):
id: int
name: str
description: str
inputs: list[str]
outputs: list[str]
confidence: float
confidence_label: str
features: list[FeatureResponse]
evidence: list[EvidenceResponse]
class AbilityResponse(BaseModel):
id: int
name: str
description: str
confidence: float
confidence_label: str
capabilities: list[CapabilityResponse]
class RepositoryAbilityMapResponse(BaseModel):
repository: RepositoryResponse
abilities: list[AbilityResponse]
class IdResponse(BaseModel):
id: int
class SearchResultResponse(BaseModel):
repository_id: int
repository_name: str
match_type: str
match_name: str
confidence: float
confidence_label: str
match_description: str
matched_field: str
ability_id: int | None = None
ability_name: str | None = None
capability_id: int | None = None
capability_name: str | None = None
evidence_level: str | None = None
source_reference: str | None = None
class AbilitySummaryResponse(BaseModel):
id: int
repository_id: int
repository_name: str
name: str
description: str
confidence: float
confidence_label: str
class CapabilitySummaryResponse(BaseModel):
id: int
repository_id: int
repository_name: str
ability_id: int
ability_name: str
name: str
description: str
confidence: float
confidence_label: str
API_DESCRIPTION = (
"Register repositories, analyze their observable implementation facts, "
"curate reviewable ability graphs, and search approved repository abilities."

View File

@@ -0,0 +1,498 @@
from __future__ import annotations
from typing import Any
from pydantic import BaseModel, Field
class RepositoryCreate(BaseModel):
url: str
name: str | None = None
description: str | None = None
branch: str = "main"
model_config = {
"json_schema_extra": {
"examples": [
{
"url": "https://github.com/example/repository.git",
"name": "Example Repository",
"description": "Optional human-readable repository summary.",
"branch": "main",
}
]
}
}
class RepositoryUpdate(BaseModel):
name: str | None = None
description: str | None = None
branch: str | None = None
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Renamed Repository",
"description": "Updated curator-facing summary.",
"branch": "main",
}
]
}
}
class AbilityCreate(BaseModel):
name: str
description: str = ""
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Business Email Routing",
"description": "Route inbound messages to the right team.",
"confidence": 0.92,
}
]
}
}
class AbilityUpdate(BaseModel):
name: str | None = None
description: str | None = None
confidence: float | None = Field(default=None, ge=0.0, le=1.0)
class CapabilityCreate(BaseModel):
ability_id: int
name: str
description: str = ""
inputs: list[str] = Field(default_factory=list)
outputs: list[str] = Field(default_factory=list)
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
model_config = {
"json_schema_extra": {
"examples": [
{
"ability_id": 1,
"name": "Classify Incoming Email",
"description": "Classify messages by intent.",
"inputs": ["subject", "body"],
"outputs": ["intent", "confidence"],
"confidence": 0.88,
}
]
}
}
class CapabilityUpdate(BaseModel):
name: str | None = None
description: str | None = None
inputs: list[str] | None = None
outputs: list[str] | None = None
confidence: float | None = Field(default=None, ge=0.0, le=1.0)
class FeatureCreate(BaseModel):
capability_id: int
name: str
type: str
location: str = ""
confidence: float = Field(default=1.0, ge=0.0, le=1.0)
model_config = {
"json_schema_extra": {
"examples": [
{
"capability_id": 1,
"name": "POST /api/classify-email",
"type": "REST endpoint",
"location": "src/routes/classify_email.py",
"confidence": 0.84,
}
]
}
}
class FeatureUpdate(BaseModel):
name: str | None = None
type: str | None = None
location: str | None = None
confidence: float | None = Field(default=None, ge=0.0, le=1.0)
class EvidenceCreate(BaseModel):
capability_id: int
type: str
reference: str
strength: str = "medium"
model_config = {
"json_schema_extra": {
"examples": [
{
"capability_id": 1,
"type": "unit_test",
"reference": "tests/test_email_classification.py",
"strength": "strong",
}
]
}
}
class EvidenceUpdate(BaseModel):
type: str | None = None
reference: str | None = None
strength: str | None = None
class AnalysisRunCreate(BaseModel):
source_path: str | None = None
model_config = {
"json_schema_extra": {
"examples": [
{},
{"source_path": "/path/to/local/repository"},
]
}
}
class CandidateGraphApproval(BaseModel):
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [{"notes": "Approved after curator review."}]
}
}
class CandidateRejection(BaseModel):
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [{"notes": "Rejected because the claim is too generic."}]
}
}
class CandidateEdit(BaseModel):
name: str
description: str = ""
confidence: float = Field(default=0.5, ge=0.0, le=1.0)
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{
"name": "Service Health Monitoring",
"description": "Expose health state for operational checks.",
"confidence": 0.9,
"notes": "Renamed from generated review seed.",
}
]
}
}
class CandidateCapabilityRelink(BaseModel):
target_ability_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{"target_ability_id": 2, "notes": "Move under operational ability."}
]
}
}
class CandidateLeafRelink(BaseModel):
target_capability_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{
"target_capability_id": 3,
"notes": "Evidence supports a different capability.",
}
]
}
}
class CandidateAbilityMerge(BaseModel):
target_ability_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{"target_ability_id": 2, "notes": "Duplicate ability wording."}
]
}
}
class CandidateCapabilityMerge(BaseModel):
target_capability_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [
{"target_capability_id": 3, "notes": "Duplicate capability."}
]
}
}
class CandidateFeatureMerge(BaseModel):
target_feature_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [{"target_feature_id": 4, "notes": "Duplicate route."}]
}
}
class CandidateEvidenceMerge(BaseModel):
target_evidence_id: int
notes: str = ""
model_config = {
"json_schema_extra": {
"examples": [{"target_evidence_id": 5, "notes": "Duplicate evidence."}]
}
}
class RepositoryResponse(BaseModel):
id: int
name: str
url: str
description: str | None
branch: str
status: str
class RepositorySnapshotResponse(BaseModel):
id: int
repository_id: int
commit_hash: str
branch: str
source_path: str
file_count: int
class AnalysisRunResponse(BaseModel):
id: int
repository_id: int
snapshot_id: int | None
status: str
started_at: str
completed_at: str | None
error_message: str | None
scanner_version: str
class ReviewDecisionResponse(BaseModel):
id: int
repository_id: int
analysis_run_id: int | None
action: str
notes: str
created_at: str
class ObservedFactResponse(BaseModel):
id: int
repository_id: int
analysis_run_id: int
snapshot_id: int | None
kind: str
path: str
name: str
value: str
metadata: dict[str, Any]
class ContentChunkResponse(BaseModel):
id: int
repository_id: int
analysis_run_id: int
snapshot_id: int | None
path: str
kind: str
start_line: int
end_line: int
text: str
class ScanSummaryResponse(BaseModel):
analysis_run: AnalysisRunResponse
snapshot: RepositorySnapshotResponse | None
facts: list[ObservedFactResponse]
class SourceReferenceResponse(BaseModel):
fact_id: int | None
path: str
kind: str
name: str
line: int | None = None
class CandidateEvidenceResponse(BaseModel):
id: int
type: str
reference: str
strength: str
status: str
source_refs: list[SourceReferenceResponse]
class CandidateFeatureResponse(BaseModel):
id: int
name: str
type: str
location: str
confidence: float
status: str
source_refs: list[SourceReferenceResponse]
confidence_label: str
class CandidateCapabilityResponse(BaseModel):
id: int
name: str
description: str
inputs: list[str]
outputs: list[str]
confidence: float
status: str
source_refs: list[SourceReferenceResponse]
confidence_label: str
features: list[CandidateFeatureResponse]
evidence: list[CandidateEvidenceResponse]
class CandidateAbilityResponse(BaseModel):
id: int
name: str
description: str
confidence: float
status: str
source_refs: list[SourceReferenceResponse]
confidence_label: str
capabilities: list[CandidateCapabilityResponse]
class CandidateGraphResponse(BaseModel):
repository: RepositoryResponse
analysis_run: AnalysisRunResponse
abilities: list[CandidateAbilityResponse]
class EvidenceResponse(BaseModel):
id: int
type: str
reference: str
strength: str
source_refs: list[SourceReferenceResponse]
class FeatureResponse(BaseModel):
id: int
name: str
type: str
location: str
confidence: float
confidence_label: str
source_refs: list[SourceReferenceResponse]
class CapabilityResponse(BaseModel):
id: int
name: str
description: str
inputs: list[str]
outputs: list[str]
confidence: float
confidence_label: str
features: list[FeatureResponse]
evidence: list[EvidenceResponse]
class AbilityResponse(BaseModel):
id: int
name: str
description: str
confidence: float
confidence_label: str
capabilities: list[CapabilityResponse]
class RepositoryAbilityMapResponse(BaseModel):
repository: RepositoryResponse
abilities: list[AbilityResponse]
class IdResponse(BaseModel):
id: int
class SearchResultResponse(BaseModel):
repository_id: int
repository_name: str
match_type: str
match_name: str
confidence: float
confidence_label: str
match_description: str
matched_field: str
ability_id: int | None = None
ability_name: str | None = None
capability_id: int | None = None
capability_name: str | None = None
evidence_level: str | None = None
source_reference: str | None = None
class AbilitySummaryResponse(BaseModel):
id: int
repository_id: int
repository_name: str
name: str
description: str
confidence: float
confidence_label: str
class CapabilitySummaryResponse(BaseModel):
id: int
repository_id: int
repository_name: str
ability_id: int
ability_name: str
name: str
description: str
confidence: float
confidence_label: str