generated from coulomb/repo-seed
Milestone 3: candidate graph generation
This commit is contained in:
194
src/repo_registry/candidate_graph/generator.py
Normal file
194
src/repo_registry/candidate_graph/generator.py
Normal file
@@ -0,0 +1,194 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
|
||||
from repo_registry.core.models import ObservedFact, Repository, SourceReference
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CandidateEvidenceDraft:
|
||||
type: str
|
||||
reference: str
|
||||
strength: str
|
||||
source_refs: list[SourceReference]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CandidateFeatureDraft:
|
||||
name: str
|
||||
type: str
|
||||
location: str
|
||||
confidence: float
|
||||
source_refs: list[SourceReference]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CandidateCapabilityDraft:
|
||||
name: str
|
||||
description: str
|
||||
inputs: list[str]
|
||||
outputs: list[str]
|
||||
confidence: float
|
||||
source_refs: list[SourceReference]
|
||||
features: list[CandidateFeatureDraft] = field(default_factory=list)
|
||||
evidence: list[CandidateEvidenceDraft] = field(default_factory=list)
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CandidateAbilityDraft:
|
||||
name: str
|
||||
description: str
|
||||
confidence: float
|
||||
source_refs: list[SourceReference]
|
||||
capabilities: list[CandidateCapabilityDraft] = field(default_factory=list)
|
||||
|
||||
|
||||
class CandidateGraphGenerator:
|
||||
"""Build conservative review candidates from observed facts."""
|
||||
|
||||
def generate(
|
||||
self,
|
||||
repository: Repository,
|
||||
facts: list[ObservedFact],
|
||||
) -> list[CandidateAbilityDraft]:
|
||||
if not facts:
|
||||
return []
|
||||
|
||||
docs = self._facts(facts, "documentation")
|
||||
tests = self._facts(facts, "test")
|
||||
examples = self._facts(facts, "example")
|
||||
interfaces = self._facts(facts, "interface")
|
||||
manifests = self._facts(facts, "manifest")
|
||||
frameworks = self._facts(facts, "framework")
|
||||
languages = self._facts(facts, "language")
|
||||
|
||||
ability_sources = docs or manifests or languages
|
||||
ability = CandidateAbilityDraft(
|
||||
name=f"Review {repository.name} Repository Usefulness",
|
||||
description=(
|
||||
"Candidate usefulness summary generated from observed repository "
|
||||
"documentation, manifests, languages, and interfaces. This is a "
|
||||
"review seed, not an asserted domain ability."
|
||||
),
|
||||
confidence=0.55 if docs else 0.35,
|
||||
source_refs=self._source_refs(ability_sources),
|
||||
capabilities=[],
|
||||
)
|
||||
|
||||
capabilities: list[CandidateCapabilityDraft] = []
|
||||
if interfaces:
|
||||
capabilities.append(self._interface_capability(interfaces, tests, examples, docs))
|
||||
if manifests or frameworks or languages:
|
||||
capabilities.append(
|
||||
CandidateCapabilityDraft(
|
||||
name="Describe Repository Structure",
|
||||
description=(
|
||||
"Summarize detected languages, package manifests, and framework "
|
||||
"hints as structural context for review."
|
||||
),
|
||||
inputs=[],
|
||||
outputs=["repository structure summary"],
|
||||
confidence=0.6,
|
||||
source_refs=self._source_refs(manifests + frameworks + languages),
|
||||
evidence=self._evidence(tests, examples, docs),
|
||||
)
|
||||
)
|
||||
|
||||
return [
|
||||
CandidateAbilityDraft(
|
||||
name=ability.name,
|
||||
description=ability.description,
|
||||
confidence=ability.confidence,
|
||||
source_refs=ability.source_refs,
|
||||
capabilities=capabilities,
|
||||
)
|
||||
]
|
||||
|
||||
def _interface_capability(
|
||||
self,
|
||||
interfaces: list[ObservedFact],
|
||||
tests: list[ObservedFact],
|
||||
examples: list[ObservedFact],
|
||||
docs: list[ObservedFact],
|
||||
) -> CandidateCapabilityDraft:
|
||||
features = [
|
||||
CandidateFeatureDraft(
|
||||
name=fact.value or fact.name,
|
||||
type=self._feature_type(fact),
|
||||
location=fact.path,
|
||||
confidence=0.65 if fact.value else 0.45,
|
||||
source_refs=self._source_refs([fact]),
|
||||
)
|
||||
for fact in interfaces
|
||||
]
|
||||
return CandidateCapabilityDraft(
|
||||
name="Expose Repository Interface",
|
||||
description=(
|
||||
"Expose one or more likely user-facing API or CLI entry points. "
|
||||
"Review is required to name the concrete domain behavior."
|
||||
),
|
||||
inputs=[],
|
||||
outputs=["callable interface"],
|
||||
confidence=0.65,
|
||||
source_refs=self._source_refs(interfaces),
|
||||
features=features,
|
||||
evidence=self._evidence(tests, examples, docs),
|
||||
)
|
||||
|
||||
def _evidence(
|
||||
self,
|
||||
tests: list[ObservedFact],
|
||||
examples: list[ObservedFact],
|
||||
docs: list[ObservedFact],
|
||||
) -> list[CandidateEvidenceDraft]:
|
||||
evidence: list[CandidateEvidenceDraft] = []
|
||||
for fact in tests:
|
||||
evidence.append(
|
||||
CandidateEvidenceDraft(
|
||||
type="test",
|
||||
reference=fact.path,
|
||||
strength="strong",
|
||||
source_refs=self._source_refs([fact]),
|
||||
)
|
||||
)
|
||||
for fact in examples:
|
||||
evidence.append(
|
||||
CandidateEvidenceDraft(
|
||||
type="example",
|
||||
reference=fact.path,
|
||||
strength="strong",
|
||||
source_refs=self._source_refs([fact]),
|
||||
)
|
||||
)
|
||||
for fact in docs:
|
||||
evidence.append(
|
||||
CandidateEvidenceDraft(
|
||||
type="documentation",
|
||||
reference=fact.path,
|
||||
strength="medium",
|
||||
source_refs=self._source_refs([fact]),
|
||||
)
|
||||
)
|
||||
return evidence
|
||||
|
||||
def _feature_type(self, fact: ObservedFact) -> str:
|
||||
lower = f"{fact.name} {fact.path} {fact.value}".lower()
|
||||
if "cli" in lower or "command" in lower:
|
||||
return "CLI"
|
||||
if "api" in lower or "route" in lower or "@app." in lower or "@router." in lower:
|
||||
return "API"
|
||||
return "interface"
|
||||
|
||||
def _facts(self, facts: list[ObservedFact], kind: str) -> list[ObservedFact]:
|
||||
return [fact for fact in facts if fact.kind == kind]
|
||||
|
||||
def _source_refs(self, facts: list[ObservedFact]) -> list[SourceReference]:
|
||||
return [
|
||||
SourceReference(
|
||||
fact_id=fact.id,
|
||||
path=fact.path,
|
||||
kind=fact.kind,
|
||||
name=fact.name,
|
||||
)
|
||||
for fact in facts
|
||||
]
|
||||
Reference in New Issue
Block a user