Scope as first class root charactaristic

This commit is contained in:
2026-04-29 16:25:24 +02:00
parent eb1513e463
commit 8d6a9f7050
10 changed files with 228 additions and 10 deletions

View File

@@ -25,6 +25,7 @@ from repo_registry.core.models import (
RepositorySnapshot,
ReviewDecision,
SearchResult,
Scope,
SourceReference,
confidence_label,
)
@@ -47,6 +48,7 @@ class RegistryStore:
with self.connect() as connection:
connection.executescript(migration_path.read_text(encoding="utf-8"))
self._ensure_content_chunks_table(connection)
self._ensure_repository_scopes_table(connection)
self._ensure_approved_source_ref_columns(connection)
self._ensure_evidence_relationship_columns(connection)
self._ensure_expectation_gaps_table(connection)
@@ -130,6 +132,23 @@ class RegistryStore:
"CREATE INDEX IF NOT EXISTS idx_content_chunks_run ON content_chunks(analysis_run_id)"
)
def _ensure_repository_scopes_table(self, connection: sqlite3.Connection) -> None:
connection.execute(
"""
CREATE TABLE IF NOT EXISTS repository_scopes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
repository_id INTEGER NOT NULL UNIQUE REFERENCES repositories(id) ON DELETE CASCADE,
name TEXT NOT NULL,
description TEXT NOT NULL DEFAULT '',
confidence REAL NOT NULL DEFAULT 1.0,
created_at TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP
)
"""
)
connection.execute(
"CREATE INDEX IF NOT EXISTS idx_scopes_repository ON repository_scopes(repository_id)"
)
def _ensure_expectation_gaps_table(self, connection: sqlite3.Connection) -> None:
connection.execute(
"""
@@ -170,6 +189,14 @@ class RegistryStore:
(name, url, description, branch),
)
repository_id = int(cursor.lastrowid)
connection.execute(
"""
INSERT INTO repository_scopes
(repository_id, name, description, confidence)
VALUES (?, ?, ?, 1.0)
""",
(repository_id, name, description or ""),
)
return self.get_repository(repository_id)
def update_repository(
@@ -1822,6 +1849,81 @@ class RegistryStore:
row_id=evidence_id,
)
def _ensure_scope(self, repository_id: int) -> Scope:
repository = self.get_repository(repository_id)
with self.connect() as connection:
row = connection.execute(
"""
SELECT id, name, description, confidence
FROM repository_scopes
WHERE repository_id = ?
""",
(repository_id,),
).fetchone()
if row is None:
cursor = connection.execute(
"""
INSERT INTO repository_scopes
(repository_id, name, description, confidence)
VALUES (?, ?, ?, 1.0)
""",
(repository_id, repository.name, repository.description or ""),
)
scope_id = int(cursor.lastrowid)
return Scope(
id=scope_id,
name=repository.name,
description=repository.description or "",
confidence=1.0,
confidence_label=confidence_label(1.0),
)
return self._scope_from_row(row)
def _get_scope(self, repository_id: int) -> Scope:
with self.connect() as connection:
row = connection.execute(
"""
SELECT id, name, description, confidence
FROM repository_scopes
WHERE repository_id = ?
""",
(repository_id,),
).fetchone()
if row is None:
return self._ensure_scope(repository_id)
return self._scope_from_row(row)
def _scope_from_row(self, row: sqlite3.Row) -> Scope:
return Scope(
id=row["id"],
name=row["name"],
description=row["description"],
confidence=row["confidence"],
confidence_label=confidence_label(row["confidence"]),
)
def update_scope(
self,
repository_id: int,
*,
name: str | None = None,
description: str | None = None,
confidence: float | None = None,
) -> Scope:
self._ensure_scope(repository_id)
self._update_approved_row(
table="repository_scopes",
label="scope",
repository_id=repository_id,
row_id=self._get_scope(repository_id).id,
values={
"name": name,
"description": description,
"confidence": confidence,
},
)
return self._get_scope(repository_id)
def replace_approved_from_candidate_graph(
self,
repository_id: int,
@@ -1922,6 +2024,7 @@ class RegistryStore:
def get_ability_map(self, repository_id: int) -> RepositoryAbilityMap:
repository = self.get_repository(repository_id)
scope = self._ensure_scope(repository_id)
with self.connect() as connection:
ability_rows = connection.execute(
"""
@@ -2018,7 +2121,7 @@ class RegistryStore:
)
for row in ability_rows
]
return RepositoryAbilityMap(repository=repository, abilities=abilities)
return RepositoryAbilityMap(repository=repository, scope=scope, abilities=abilities)
def search(
self,
@@ -2370,7 +2473,7 @@ class RegistryStore:
label: str,
repository_id: int,
row_id: int,
values: dict[str, str | float | None],
values: dict[str, str | float | int | None],
) -> None:
assignments: list[str] = []
params: list[str | float | int] = []