generated from coulomb/repo-seed
Build dependency graph and dependency aware propagation of changes
This commit is contained in:
@@ -3,6 +3,7 @@ import logging
|
||||
import subprocess
|
||||
|
||||
from repo_registry.core.logging import LOGGER_NAME
|
||||
from repo_registry.core.models import SourceReference
|
||||
from repo_registry.core.service import RegistryService
|
||||
from repo_registry.llm_extraction import (
|
||||
ExtractedAbility,
|
||||
@@ -140,6 +141,128 @@ def test_manual_registry_builds_ability_map(tmp_path):
|
||||
assert updated_map.scope.description == "Email routing repository scope."
|
||||
|
||||
|
||||
def test_dependency_impact_propagates_changed_fact_to_scope(tmp_path):
|
||||
service = make_service(tmp_path)
|
||||
source = write_python_cli_repo(tmp_path)
|
||||
repository = service.register_repository(
|
||||
name="PyCLI",
|
||||
url=str(source),
|
||||
description="CLI command repository.",
|
||||
)
|
||||
base_summary = service.analyze_repository(
|
||||
repository.id,
|
||||
source_path=str(source),
|
||||
use_llm_assistance=False,
|
||||
)
|
||||
click_fact = next(
|
||||
fact
|
||||
for fact in base_summary.facts
|
||||
if fact.kind == "framework"
|
||||
and fact.path == "requirements.txt"
|
||||
and fact.name == "Click"
|
||||
)
|
||||
source_ref = SourceReference(
|
||||
fact_id=click_fact.id,
|
||||
path=click_fact.path,
|
||||
kind=click_fact.kind,
|
||||
name=click_fact.name,
|
||||
)
|
||||
ability_id = service.add_ability(
|
||||
repository.id,
|
||||
name="Command Line Operations",
|
||||
description="Expose command line workflows.",
|
||||
)
|
||||
capability_id = service.add_capability(
|
||||
repository.id,
|
||||
ability_id,
|
||||
name="Click Command Execution",
|
||||
description="Run commands through Click.",
|
||||
)
|
||||
feature_id = service.store.create_feature(
|
||||
repository.id,
|
||||
capability_id,
|
||||
name="Click decorator",
|
||||
type="interface",
|
||||
location="cli.py",
|
||||
confidence=0.9,
|
||||
source_refs=[source_ref],
|
||||
)
|
||||
evidence_id = service.store.create_evidence(
|
||||
repository.id,
|
||||
capability_id,
|
||||
type="dependency",
|
||||
reference="Click dependency",
|
||||
strength="strong",
|
||||
source_refs=[source_ref],
|
||||
)
|
||||
|
||||
(source / "requirements.txt").write_text("typer\npytest\n", encoding="utf-8")
|
||||
target_summary = service.analyze_repository(
|
||||
repository.id,
|
||||
source_path=str(source),
|
||||
use_llm_assistance=False,
|
||||
)
|
||||
|
||||
impact = service.analyze_dependency_impact(
|
||||
repository.id,
|
||||
base_summary.analysis_run.id,
|
||||
target_summary.analysis_run.id,
|
||||
)
|
||||
|
||||
impacted_keys = {item.item_key for item in impact.impacts}
|
||||
assert f"feature:{feature_id}" in impacted_keys
|
||||
assert f"evidence:{evidence_id}" in impacted_keys
|
||||
assert f"capability:{capability_id}" in impacted_keys
|
||||
assert f"ability:{ability_id}" in impacted_keys
|
||||
assert f"scope:{service.store.get_ability_map(repository.id).scope.id}" in impacted_keys
|
||||
assert impact.scope_impacted is True
|
||||
assert impact.max_depth == 4
|
||||
assert any(
|
||||
"removed fact fact:framework:requirements.txt:Click" in reason
|
||||
for item in impact.impacts
|
||||
for reason in item.reasons
|
||||
)
|
||||
assert all(item.freshness_state == "stale" for item in impact.impacts)
|
||||
|
||||
|
||||
def test_dependency_graph_flags_same_layer_edges(tmp_path):
|
||||
service = make_service(tmp_path)
|
||||
repository = service.register_repository(
|
||||
name="Same Layer",
|
||||
url="https://example.com/same-layer.git",
|
||||
description="Tests same-layer dependency normalization signals.",
|
||||
)
|
||||
ability_id = service.add_ability(repository.id, name="Operations")
|
||||
first_capability_id = service.add_capability(
|
||||
repository.id,
|
||||
ability_id,
|
||||
name="Source Capability",
|
||||
)
|
||||
second_capability_id = service.add_capability(
|
||||
repository.id,
|
||||
ability_id,
|
||||
name="Target Capability",
|
||||
)
|
||||
service.store.create_evidence(
|
||||
repository.id,
|
||||
second_capability_id,
|
||||
type="relationship",
|
||||
reference="Target depends on source capability",
|
||||
strength="medium",
|
||||
target_kind="capability",
|
||||
target_id=second_capability_id,
|
||||
reference_kind="capability",
|
||||
reference_id=first_capability_id,
|
||||
)
|
||||
|
||||
graph = service.build_dependency_graph(repository.id)
|
||||
|
||||
same_layer_edges = [edge for edge in graph.edges if edge.same_layer]
|
||||
assert len(same_layer_edges) == 1
|
||||
assert same_layer_edges[0].source_key == f"capability:{first_capability_id}"
|
||||
assert same_layer_edges[0].target_key == f"capability:{second_capability_id}"
|
||||
|
||||
|
||||
def test_manual_registry_updates_and_deletes_approved_entries(tmp_path):
|
||||
service = make_service(tmp_path)
|
||||
repository = service.register_repository(
|
||||
|
||||
Reference in New Issue
Block a user