Finalize repo-scoping runtime rename

This commit is contained in:
tegwick 2026-05-15 21:16:34 +02:00
parent 084159e51c
commit 28fad1b248
62 changed files with 445 additions and 305 deletions

View file

@ -2,7 +2,7 @@
## Repo Identity
**Purpose:** Repository Ability Registry — turns Git repositories into reviewable,
**Purpose:** Repository Scoping — turns Git repositories into reviewable,
source-linked maps of `Ability → Capability → Feature → Evidence`. Deterministic
scanners establish observed facts; LLM-assisted extractors propose interpreted
claims; humans or trusted agents approve registry truth.
@ -154,7 +154,7 @@ Task description.
pip install -e ".[dev]"
# Run dev server
uvicorn src.repo_registry.app:app --reload
uvicorn repo_scoping.web_api.app:app --reload
# Run tests
pytest tests/

View file

@ -9,7 +9,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
pip install -e ".[dev]"
# Run dev server (port 8001)
uvicorn repo_registry.web_api.app:app --reload --port 8001
uvicorn repo_scoping.web_api.app:app --reload --port 8001
# Run tests
pytest
@ -20,8 +20,6 @@ pytest tests/test_web_api.py # single file
curl http://127.0.0.1:8001/health
```
Note: `AGENTS.md` shows `src.repo_registry.app:app` but the correct module path is `repo_registry.web_api.app:app` (as installed via `src/`).
## Architecture
The service maps Git repositories to reviewable scope maps using a fixed hierarchy:
@ -38,7 +36,7 @@ Scope → Ability → Capability → Feature → Evidence → ObservedFact
4. `DeterministicScanner` produces `ObservedFact` objects (files, languages, manifests, APIs, etc.)
5. `ContentExtractor` chunks files into searchable segments
6. `CandidateGraphGenerator` builds a draft ability→capability→feature→evidence tree from facts
7. Optionally, `LLMCandidateExtractor` proposes additional candidates (requires `REPO_REGISTRY_LLM_ENABLED=true`)
7. Optionally, `LLMCandidateExtractor` proposes additional candidates (requires `REPO_SCOPING_LLM_ENABLED=true`)
8. Candidates are stored; humans or agents review them via `POST .../candidate-graph/approve`
9. Approved characteristics feed `ScopeGenerator` to produce `SCOPE.md`
@ -46,17 +44,17 @@ Scope → Ability → Capability → Feature → Evidence → ObservedFact
| Component | Path |
|-----------|------|
| FastAPI routes + DI | `src/repo_registry/web_api/app.py` |
| Orchestration | `src/repo_registry/core/service.py` |
| Frozen dataclasses | `src/repo_registry/core/models.py` |
| Deterministic scanner | `src/repo_registry/repo_scanning/scanner.py` |
| Candidate graph builder | `src/repo_registry/candidate_graph/generator.py` |
| SQLite store | `src/repo_registry/storage/sqlite.py` |
| FastAPI routes + DI | `src/repo_scoping/web_api/app.py` |
| Orchestration | `src/repo_scoping/core/service.py` |
| Frozen dataclasses | `src/repo_scoping/core/models.py` |
| Deterministic scanner | `src/repo_scoping/repo_scanning/scanner.py` |
| Candidate graph builder | `src/repo_scoping/candidate_graph/generator.py` |
| SQLite store | `src/repo_scoping/storage/sqlite.py` |
| Schema migration | `migrations/0001_initial.sql` |
**Storage:** SQLite at `var/repo-registry.sqlite3` (auto-created). Schema migrations run at startup. Dynamic columns are added to support evidence relationships, classification, and expectation gaps.
**Storage:** SQLite at `var/repo-scoping.sqlite3` (auto-created). Schema migrations run at startup. Dynamic columns are added to support evidence relationships, classification, and expectation gaps.
**LLM extraction** is optional and disabled by default. Enable with `REPO_REGISTRY_LLM_ENABLED=true` plus `REPO_REGISTRY_LLM_PROVIDER` and `REPO_REGISTRY_LLM_MODEL`. The `llm-connect` sibling package provides the adapter abstraction.
**LLM extraction** is optional and disabled by default. Enable with `REPO_SCOPING_LLM_ENABLED=true` plus `REPO_SCOPING_LLM_PROVIDER` and `REPO_SCOPING_LLM_MODEL`. The `llm-connect` sibling package provides the adapter abstraction.
**Semantic search** uses `HashingEmbeddingProvider` by default — deterministic, no external service required.
@ -64,12 +62,12 @@ Scope → Ability → Capability → Feature → Evidence → ObservedFact
| Variable | Default | Purpose |
|----------|---------|---------|
| `REPO_REGISTRY_DATABASE_PATH` | `var/repo-registry.sqlite3` | SQLite file |
| `REPO_REGISTRY_CHECKOUT_ROOT` | `var/checkouts` | Git clone cache |
| `REPO_REGISTRY_LLM_ENABLED` | `true` | Enable LLM extraction |
| `REPO_REGISTRY_LLM_PROVIDER` | — | e.g. `gemini`, `anthropic` |
| `REPO_REGISTRY_LLM_MODEL` | — | e.g. `gemini-2.5-flash` |
| `REPO_REGISTRY_STATE_HUB_BASE_URL` | `http://127.0.0.1:8000` | State Hub for coordination |
| `REPO_SCOPING_DATABASE_PATH` | `var/repo-scoping.sqlite3` | SQLite file |
| `REPO_SCOPING_CHECKOUT_ROOT` | `var/checkouts` | Git clone cache |
| `REPO_SCOPING_LLM_ENABLED` | `true` | Enable LLM extraction |
| `REPO_SCOPING_LLM_PROVIDER` | — | e.g. `gemini`, `anthropic` |
| `REPO_SCOPING_LLM_MODEL` | — | e.g. `gemini-2.5-flash` |
| `REPO_SCOPING_STATE_HUB_BASE_URL` | `http://127.0.0.1:8000` | State Hub for coordination |
## State Hub & Workplans

View file

@ -136,11 +136,11 @@ characteristics support those claims.
## Getting Oriented
- Start with: `README.md`, `AGENTS.md`, and this `SCOPE.md`.
- Key files / directories: `src/repo_registry/web_api/app.py`,
`src/repo_registry/core/service.py`, `src/repo_registry/scope/`,
`src/repo_registry/candidate_graph/`, `src/repo_registry/repo_scanning/`,
- Key files / directories: `src/repo_scoping/web_api/app.py`,
`src/repo_scoping/core/service.py`, `src/repo_scoping/scope/`,
`src/repo_scoping/candidate_graph/`, `src/repo_scoping/repo_scanning/`,
`docs/scope-md-spec.md`, and `workplans/`.
- Entry points: `uvicorn repo_registry.web_api.app:app --reload`, the `/ui`
- Entry points: `uvicorn repo_scoping.web_api.app:app --reload`, the `/ui`
routes, and the `/repos/{repo_slug}/scope*` API endpoints.
---
@ -171,5 +171,5 @@ keywords: [scope, scope-md, update, diff, staleness]
- The product and managed repository identity are Repository Scoping /
`repo-scoping`.
- The Python package name `repo_registry`, `REPO_REGISTRY_` environment prefix,
and default SQLite filename remain compatibility details.
- The Python package name `repo_scoping`, `REPO_SCOPING_` environment prefix,
and default SQLite filename are the current runtime names.

View file

@ -16,7 +16,7 @@ start: ## Start the API server in the background on port 8002
@if [ -f $(PIDFILE) ] && kill -0 $$(cat $(PIDFILE)) 2>/dev/null; then \
echo "Already running (PID $$(cat $(PIDFILE)))"; \
else \
setsid sh -c 'echo $$$$ > $(PIDFILE); exec $(UVICORN) repo_registry.web_api.app:app --host 127.0.0.1 --port $(PORT)' \
setsid sh -c 'echo $$$$ > $(PIDFILE); exec $(UVICORN) repo_scoping.web_api.app:app --host 127.0.0.1 --port $(PORT)' \
>> $(LOGFILE) 2>&1 & \
PID=""; \
for i in $$(seq 1 50); do \

View file

@ -27,10 +27,12 @@ pytest
Run the API:
```bash
uvicorn repo_registry.web_api.app:app --reload
uvicorn repo_scoping.web_api.app:app --reload
```
The API creates a local SQLite database at `var/repo-registry.sqlite3` by default. The database path, `REPO_REGISTRY_` environment prefix, and `repo_registry` Python package name remain compatibility details after the product rename to Repository Scoping.
The API creates a local SQLite database at `var/repo-scoping.sqlite3` by
default. Runtime configuration uses the `REPO_SCOPING_` environment prefix, and
the Python package is `repo_scoping`.
## First API Loop
@ -40,7 +42,10 @@ curl -X POST http://127.0.0.1:8000/repos \
-d '{"url":"https://example.com/mail-router.git"}'
```
The registry imports name and description from `pyproject.toml`, `package.json`, or README where possible. Then add abilities, capabilities, features, and evidence under that repository and inspect:
The registry uses the submitted repository path or URL as the default name, then
imports description and fallback metadata from `pyproject.toml`, `package.json`,
or README where possible. Then add abilities, capabilities, features, and
evidence under that repository and inspect:
```bash
curl http://127.0.0.1:8000/repos/1/ability-map
@ -135,17 +140,17 @@ draft.
The FastAPI settings object also accepts `llm_provider` and `llm_model`. By
default `llm_provider` is unset, so analysis is fully offline and deterministic.
Environment variables use the `REPO_REGISTRY_` prefix:
Environment variables use the `REPO_SCOPING_` prefix:
```bash
REPO_REGISTRY_LLM_PROVIDER=gemini
REPO_REGISTRY_LLM_MODEL=gemini-2.5-flash
REPO_SCOPING_LLM_PROVIDER=gemini
REPO_SCOPING_LLM_MODEL=gemini-2.5-flash
```
LLM assistance can also be disabled even when a provider is configured:
```bash
REPO_REGISTRY_LLM_ENABLED=false
REPO_SCOPING_LLM_ENABLED=false
```
Individual analysis requests may opt out with `{"use_llm_assistance": false}`.

View file

@ -136,11 +136,11 @@ characteristics support those claims.
## Getting Oriented
- Start with: `README.md`, `AGENTS.md`, and this `SCOPE.md`.
- Key files / directories: `src/repo_registry/web_api/app.py`,
`src/repo_registry/core/service.py`, `src/repo_registry/scope/`,
`src/repo_registry/candidate_graph/`, `src/repo_registry/repo_scanning/`,
- Key files / directories: `src/repo_scoping/web_api/app.py`,
`src/repo_scoping/core/service.py`, `src/repo_scoping/scope/`,
`src/repo_scoping/candidate_graph/`, `src/repo_scoping/repo_scanning/`,
`docs/scope-md-spec.md`, and `workplans/`.
- Entry points: `uvicorn repo_registry.web_api.app:app --reload`, the `/ui`
- Entry points: `uvicorn repo_scoping.web_api.app:app --reload`, the `/ui`
routes, and the `/repos/{repo_slug}/scope*` API endpoints.
---
@ -171,5 +171,5 @@ keywords: [scope, scope-md, update, diff, staleness]
- The product and managed repository identity are Repository Scoping /
`repo-scoping`.
- The Python package name `repo_registry`, `REPO_REGISTRY_` environment prefix,
and default SQLite filename remain compatibility details.
- The Python package name `repo_scoping`, `REPO_SCOPING_` environment prefix,
and default SQLite filename are the current runtime names.

View file

@ -5,18 +5,18 @@ Repository Scoping service.
## Configuration
Configuration is read from environment variables with the `REPO_REGISTRY_`
prefix. That prefix is retained as an implementation compatibility detail after
the product rename from Repository Ability Registry to Repository Scoping.
Configuration is read from environment variables with the `REPO_SCOPING_`
prefix. The same naming is used by the import package and default local
database path so service identity stays aligned with Repository Scoping.
| Variable | Default | Purpose |
| --- | --- | --- |
| `REPO_REGISTRY_DATABASE_PATH` | `var/repo-registry.sqlite3` | SQLite database file used by the default store. |
| `REPO_REGISTRY_CHECKOUT_ROOT` | `var/checkouts` | Local checkout cache used during repository ingestion. |
| `REPO_REGISTRY_LLM_PROVIDER` | unset | Optional LLM provider name for candidate extraction. |
| `REPO_REGISTRY_LLM_MODEL` | unset | Optional model name passed to the configured LLM provider. |
| `REPO_REGISTRY_EMBEDDING_PROVIDER` | unset | Set to `hashing` to enable deterministic local hybrid search scoring. |
| `REPO_REGISTRY_LOG_LEVEL` | `INFO` | Log level for the `repo_registry.operations` structured event logger. |
| `REPO_SCOPING_DATABASE_PATH` | `var/repo-scoping.sqlite3` | SQLite database file used by the default store. |
| `REPO_SCOPING_CHECKOUT_ROOT` | `var/checkouts` | Local checkout cache used during repository ingestion. |
| `REPO_SCOPING_LLM_PROVIDER` | unset | Optional LLM provider name for candidate extraction. |
| `REPO_SCOPING_LLM_MODEL` | unset | Optional model name passed to the configured LLM provider. |
| `REPO_SCOPING_EMBEDDING_PROVIDER` | unset | Set to `hashing` to enable deterministic local hybrid search scoring. |
| `REPO_SCOPING_LOG_LEVEL` | `INFO` | Log level for the `repo_scoping.operations` structured event logger. |
## Health Checks
@ -27,7 +27,7 @@ be checked locally:
{
"status": "ok",
"database": {
"path": "var/repo-registry.sqlite3",
"path": "var/repo-scoping.sqlite3",
"reachable": true,
"error": null
},
@ -44,13 +44,13 @@ ingestion path.
## Structured Logs
Operational events are emitted through the `repo_registry.operations` logger as
Operational events are emitted through the `repo_scoping.operations` logger as
single-line JSON messages. Current events include repository registration,
analysis start/completion/failure, LLM extraction usage/failure, and review
decisions.
Configure the Python or ASGI server logging stack to route this logger to the
same sink as application logs. `REPO_REGISTRY_LOG_LEVEL` controls the logger
same sink as application logs. `REPO_SCOPING_LOG_LEVEL` controls the logger
level used by API-created service instances.
## SQLite Backup And Restore
@ -60,18 +60,18 @@ continue while the backup is created:
```bash
mkdir -p backups
sqlite3 var/repo-registry.sqlite3 ".backup 'backups/repo-registry-$(date +%F).sqlite3'"
sqlite3 var/repo-scoping.sqlite3 ".backup 'backups/repo-scoping-$(date +%F).sqlite3'"
```
For the most conservative backup window, stop writes first, run the backup, then
resume the service. Verify a backup with:
```bash
sqlite3 backups/repo-registry-YYYY-MM-DD.sqlite3 "PRAGMA integrity_check;"
sqlite3 backups/repo-scoping-YYYY-MM-DD.sqlite3 "PRAGMA integrity_check;"
```
To restore, stop the service, move the current database aside, copy the backup to
`REPO_REGISTRY_DATABASE_PATH`, start the service, and verify `GET /health`.
`REPO_SCOPING_DATABASE_PATH`, start the service, and verify `GET /health`.
## PostgreSQL Migration Notes

View file

@ -586,7 +586,7 @@
},
"contamination_sources": [
{
"path": "src/repo_registry/repo_scanning/scanner.py",
"path": "src/repo_scoping/repo_scanning/scanner.py",
"reason": "Scanner rule vocabulary was treated as repo-owned capability evidence."
}
]

View file

@ -29,16 +29,16 @@
"name": "Create and update repository records",
"primary_class": "api",
"source_paths": [
"src/repo_registry/core/service.py",
"src/repo_registry/web_api/app.py",
"src/repo_registry/web_ui/views.py"
"src/repo_scoping/core/service.py",
"src/repo_scoping/web_api/app.py",
"src/repo_scoping/web_ui/views.py"
]
},
{
"name": "Resolve local or remote Git checkouts",
"primary_class": "backend",
"source_paths": [
"src/repo_registry/repo_ingestion/git.py",
"src/repo_scoping/repo_ingestion/git.py",
"tests/test_git_ingestion.py"
]
},
@ -46,7 +46,7 @@
"name": "Import repository metadata",
"primary_class": "backend",
"source_paths": [
"src/repo_registry/repo_ingestion/metadata.py",
"src/repo_scoping/repo_ingestion/metadata.py",
"tests/test_repository_metadata.py"
]
}
@ -61,7 +61,7 @@
"name": "Detect source languages, manifests, docs, tests, config, and interfaces",
"primary_class": "backend",
"source_paths": [
"src/repo_registry/repo_scanning/scanner.py",
"src/repo_scoping/repo_scanning/scanner.py",
"tests/test_repository_scanner.py"
]
},
@ -69,7 +69,7 @@
"name": "Classify source roles for facts",
"primary_class": "backend",
"source_paths": [
"src/repo_registry/repo_scanning/scanner.py",
"src/repo_scoping/repo_scanning/scanner.py",
"docs/characteristic-evidence-model.md"
]
},
@ -77,7 +77,7 @@
"name": "Preserve analysis snapshots and fact records",
"primary_class": "storage",
"source_paths": [
"src/repo_registry/storage/sqlite.py",
"src/repo_scoping/storage/sqlite.py",
"migrations/0001_initial.sql"
]
}
@ -92,7 +92,7 @@
"name": "Create source-linked content chunks from observed facts",
"primary_class": "backend",
"source_paths": [
"src/repo_registry/content_indexing/extractor.py",
"src/repo_scoping/content_indexing/extractor.py",
"tests/test_content_indexing.py"
]
},
@ -100,8 +100,8 @@
"name": "Carry source-role metadata into downstream generation",
"primary_class": "backend",
"source_paths": [
"src/repo_registry/content_indexing/extractor.py",
"src/repo_registry/llm_extraction/extractor.py"
"src/repo_scoping/content_indexing/extractor.py",
"src/repo_scoping/llm_extraction/extractor.py"
]
}
]
@ -115,8 +115,8 @@
"name": "Build candidate abilities, capabilities, features, and evidence",
"primary_class": "backend",
"source_paths": [
"src/repo_registry/candidate_graph/generator.py",
"src/repo_registry/candidate_graph/normalization.py",
"src/repo_scoping/candidate_graph/generator.py",
"src/repo_scoping/candidate_graph/normalization.py",
"tests/test_candidate_graph.py"
]
},
@ -124,8 +124,8 @@
"name": "Optionally map structured LLM extraction into candidates",
"primary_class": "integration",
"source_paths": [
"src/repo_registry/llm_extraction/extractor.py",
"src/repo_registry/llm_extraction/mapper.py",
"src/repo_scoping/llm_extraction/extractor.py",
"src/repo_scoping/llm_extraction/mapper.py",
"tests/test_llm_extraction.py"
]
}
@ -140,9 +140,9 @@
"name": "Edit, reject, merge, and relink candidate graph entries",
"primary_class": "api",
"source_paths": [
"src/repo_registry/core/service.py",
"src/repo_registry/web_api/app.py",
"src/repo_registry/web_ui/views.py",
"src/repo_scoping/core/service.py",
"src/repo_scoping/web_api/app.py",
"src/repo_scoping/web_ui/views.py",
"tests/test_registry_service.py"
]
},
@ -150,16 +150,16 @@
"name": "Publish approved characteristic maps after review",
"primary_class": "storage",
"source_paths": [
"src/repo_registry/core/service.py",
"src/repo_registry/storage/sqlite.py"
"src/repo_scoping/core/service.py",
"src/repo_scoping/storage/sqlite.py"
]
},
{
"name": "Record review decisions and expectation gaps",
"primary_class": "audit",
"source_paths": [
"src/repo_registry/core/service.py",
"src/repo_registry/web_api/schemas.py"
"src/repo_scoping/core/service.py",
"src/repo_scoping/web_api/schemas.py"
]
}
]
@ -173,8 +173,8 @@
"name": "Search approved abilities, capabilities, features, and evidence",
"primary_class": "api",
"source_paths": [
"src/repo_registry/core/service.py",
"src/repo_registry/semantic/embeddings.py",
"src/repo_scoping/core/service.py",
"src/repo_scoping/semantic/embeddings.py",
"tests/test_registry_service.py"
]
},
@ -182,15 +182,15 @@
"name": "Compare repositories and identify capability gaps",
"primary_class": "api",
"source_paths": [
"src/repo_registry/core/service.py",
"src/repo_registry/web_api/app.py"
"src/repo_scoping/core/service.py",
"src/repo_scoping/web_api/app.py"
]
},
{
"name": "Export repository profiles",
"primary_class": "api",
"source_paths": [
"src/repo_registry/web_api/app.py",
"src/repo_scoping/web_api/app.py",
"docs/api-contract.md"
]
}
@ -205,7 +205,7 @@
"name": "Render SCOPE.md from approved characteristics",
"primary_class": "backend",
"source_paths": [
"src/repo_registry/scope/generator.py",
"src/repo_scoping/scope/generator.py",
"tests/test_scope_generator.py",
"docs/scope-md-spec.md"
]
@ -214,9 +214,9 @@
"name": "Diff, validate, and write scope files",
"primary_class": "api",
"source_paths": [
"src/repo_registry/scope/validator.py",
"src/repo_registry/web_api/app.py",
"src/repo_registry/web_ui/views.py"
"src/repo_scoping/scope/validator.py",
"src/repo_scoping/web_api/app.py",
"src/repo_scoping/web_ui/views.py"
]
}
]
@ -230,7 +230,7 @@
"name": "Model dependencies between facts, evidence, features, capabilities, abilities, and scope",
"primary_class": "backend",
"source_paths": [
"src/repo_registry/core/service.py",
"src/repo_scoping/core/service.py",
"docs/dependency-aware-scope-propagation.md",
"docs/dependency-visualization-exploration.md"
]
@ -239,7 +239,7 @@
"name": "Render dependency graph views and profiles",
"primary_class": "ui",
"source_paths": [
"src/repo_registry/web_ui/views.py",
"src/repo_scoping/web_ui/views.py",
"tests/test_web_api.py"
]
}
@ -254,7 +254,7 @@
"name": "Return compact JSON scope context by repository slug",
"primary_class": "api",
"source_paths": [
"src/repo_registry/web_api/app.py",
"src/repo_scoping/web_api/app.py",
"docs/schemas/repo-scope-context-response.json",
"tests/test_scope_context_api.py"
]

View file

@ -11,7 +11,7 @@ development. It produces deterministic token-bucket vectors without any network
dependency. Configure it with:
```bash
REPO_REGISTRY_EMBEDDING_PROVIDER=hashing
REPO_SCOPING_EMBEDDING_PROVIDER=hashing
```
When enabled, search combines:

View file

@ -10,10 +10,10 @@ repository is for and how that claim is supported.
- Repository Scoping is the product and UI name.
- `repo-scoping` is the managed repository slug, Git remote identity, and State
Hub repository identity.
- `repo_registry`, `REPO_REGISTRY_`, and `var/repo-registry.sqlite3` are retained
compatibility names in code and local configuration.
- Repository Ability Registry and `repo-registry` are historical names from
before the scope-oriented rename.
- `repo_scoping`, `REPO_SCOPING_`, and `var/repo-scoping.sqlite3` are the
current package, environment-prefix, and default SQLite names.
- Earlier registry-oriented names are historical only and should not be used in
runtime configuration, package imports, or new documentation.
## Characteristic Model

View file

@ -3,7 +3,7 @@ requires = ["setuptools>=68"]
build-backend = "setuptools.build_meta"
[project]
name = "repo-registry"
name = "repo-scoping"
version = "0.1.0"
description = "Repository Scoping"
readme = "README.md"
@ -22,7 +22,7 @@ dev = [
]
[project.scripts]
repo-scoping = "repo_registry.cli:main"
repo-scoping = "repo_scoping.cli:main"
[tool.setuptools.packages.find]
where = ["src"]

View file

@ -1,18 +1,18 @@
from repo_registry.acceptance.agentic import (
from repo_scoping.acceptance.agentic import (
AgenticReviewer,
AgenticReviewDecision,
AgenticReviewRequest,
validate_agentic_review_decision,
validate_agentic_review_decisions,
)
from repo_registry.acceptance.criteria import (
from repo_scoping.acceptance.criteria import (
active_quality_criteria_version,
criteria_registry_dict,
criteria_registry_json,
criteria_registry_markdown,
load_quality_criteria,
)
from repo_registry.acceptance.gates import (
from repo_scoping.acceptance.gates import (
blocking_quality_gate_outcomes,
evaluate_candidate_capability_quality,
evaluate_candidate_graph_quality,

View file

@ -4,8 +4,8 @@ from dataclasses import dataclass
from typing import Any
from typing import Protocol
from repo_registry.acceptance.gates import QualityGateOutcome
from repo_registry.core.models import CandidateGraph, Repository
from repo_scoping.acceptance.gates import QualityGateOutcome
from repo_scoping.core.models import CandidateGraph, Repository
AGENTIC_REVIEW_ACTIONS = {
"approve",

View file

@ -2,12 +2,12 @@ from __future__ import annotations
from dataclasses import asdict, dataclass
from repo_registry.acceptance.criteria import (
from repo_scoping.acceptance.criteria import (
QualityCriteriaRegistry,
QualityCriterion,
load_quality_criteria,
)
from repo_registry.core.models import (
from repo_scoping.core.models import (
CandidateCapability,
CandidateFeature,
CandidateGraph,

View file

@ -3,7 +3,7 @@ from __future__ import annotations
import re
from dataclasses import dataclass, field, replace
from repo_registry.core.models import ContentChunk, ObservedFact, Repository, SourceReference
from repo_scoping.core.models import ContentChunk, ObservedFact, Repository, SourceReference
@dataclass(frozen=True)
@ -59,18 +59,18 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
(
"Create and update repository records",
"api",
["src/repo_registry/core/service.py", "src/repo_registry/web_api/app.py"],
["src/repo_scoping/core/service.py", "src/repo_scoping/web_api/app.py"],
),
(
"Resolve local or remote Git checkouts",
"backend",
["src/repo_registry/repo_ingestion/git.py", "tests/test_git_ingestion.py"],
["src/repo_scoping/repo_ingestion/git.py", "tests/test_git_ingestion.py"],
),
(
"Import repository metadata",
"backend",
[
"src/repo_registry/repo_ingestion/metadata.py",
"src/repo_scoping/repo_ingestion/metadata.py",
"tests/test_repository_metadata.py",
],
),
@ -84,17 +84,17 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
(
"Detect source languages, manifests, docs, tests, config, and interfaces",
"backend",
["src/repo_registry/repo_scanning/scanner.py", "tests/test_repository_scanner.py"],
["src/repo_scoping/repo_scanning/scanner.py", "tests/test_repository_scanner.py"],
),
(
"Classify source roles for facts",
"backend",
["src/repo_registry/repo_scanning/scanner.py", "docs/characteristic-evidence-model.md"],
["src/repo_scoping/repo_scanning/scanner.py", "docs/characteristic-evidence-model.md"],
),
(
"Preserve analysis snapshots and fact records",
"storage",
["src/repo_registry/storage/sqlite.py", "migrations/0001_initial.sql"],
["src/repo_scoping/storage/sqlite.py", "migrations/0001_initial.sql"],
),
],
},
@ -106,14 +106,14 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
(
"Create source-linked content chunks from observed facts",
"backend",
["src/repo_registry/content_indexing/extractor.py", "tests/test_content_indexing.py"],
["src/repo_scoping/content_indexing/extractor.py", "tests/test_content_indexing.py"],
),
(
"Carry source-role metadata into downstream generation",
"backend",
[
"src/repo_registry/content_indexing/extractor.py",
"src/repo_registry/llm_extraction/extractor.py",
"src/repo_scoping/content_indexing/extractor.py",
"src/repo_scoping/llm_extraction/extractor.py",
],
),
],
@ -127,8 +127,8 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
"Build candidate abilities, capabilities, features, and evidence",
"backend",
[
"src/repo_registry/candidate_graph/generator.py",
"src/repo_registry/candidate_graph/normalization.py",
"src/repo_scoping/candidate_graph/generator.py",
"src/repo_scoping/candidate_graph/normalization.py",
"tests/test_candidate_graph.py",
],
),
@ -136,8 +136,8 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
"Optionally map structured LLM extraction into candidates",
"integration",
[
"src/repo_registry/llm_extraction/extractor.py",
"src/repo_registry/llm_extraction/mapper.py",
"src/repo_scoping/llm_extraction/extractor.py",
"src/repo_scoping/llm_extraction/mapper.py",
"tests/test_llm_extraction.py",
],
),
@ -152,20 +152,20 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
"Edit, reject, merge, and relink candidate graph entries",
"api",
[
"src/repo_registry/core/service.py",
"src/repo_registry/web_api/app.py",
"src/repo_scoping/core/service.py",
"src/repo_scoping/web_api/app.py",
"tests/test_registry_service.py",
],
),
(
"Publish approved characteristic maps after review",
"storage",
["src/repo_registry/core/service.py", "src/repo_registry/storage/sqlite.py"],
["src/repo_scoping/core/service.py", "src/repo_scoping/storage/sqlite.py"],
),
(
"Record review decisions and expectation gaps",
"audit",
["src/repo_registry/core/service.py", "src/repo_registry/web_api/schemas.py"],
["src/repo_scoping/core/service.py", "src/repo_scoping/web_api/schemas.py"],
),
],
},
@ -177,17 +177,17 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
(
"Search approved abilities, capabilities, features, and evidence",
"api",
["src/repo_registry/core/service.py", "tests/test_registry_service.py"],
["src/repo_scoping/core/service.py", "tests/test_registry_service.py"],
),
(
"Compare repositories and identify capability gaps",
"api",
["src/repo_registry/core/service.py", "src/repo_registry/web_api/app.py"],
["src/repo_scoping/core/service.py", "src/repo_scoping/web_api/app.py"],
),
(
"Export repository profiles",
"api",
["src/repo_registry/web_api/app.py", "docs/api-contract.md"],
["src/repo_scoping/web_api/app.py", "docs/api-contract.md"],
),
],
},
@ -200,7 +200,7 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
"Render SCOPE.md from approved characteristics",
"backend",
[
"src/repo_registry/scope/generator.py",
"src/repo_scoping/scope/generator.py",
"tests/test_scope_generator.py",
"docs/scope-md-spec.md",
],
@ -209,8 +209,8 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
"Diff, validate, and write scope files",
"api",
[
"src/repo_registry/scope/validator.py",
"src/repo_registry/web_api/app.py",
"src/repo_scoping/scope/validator.py",
"src/repo_scoping/web_api/app.py",
],
),
],
@ -224,7 +224,7 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
"Model dependencies between facts, evidence, features, capabilities, abilities, and scope",
"backend",
[
"src/repo_registry/core/service.py",
"src/repo_scoping/core/service.py",
"docs/dependency-aware-scope-propagation.md",
"docs/dependency-visualization-exploration.md",
],
@ -232,7 +232,7 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
(
"Render dependency graph views and profiles",
"ui",
["src/repo_registry/web_ui/views.py", "tests/test_web_api.py"],
["src/repo_scoping/web_ui/views.py", "tests/test_web_api.py"],
),
],
},
@ -245,7 +245,7 @@ REPO_SCOPING_NATIVE_CAPABILITY_SEEDS = [
"Return compact JSON scope context by repository slug",
"api",
[
"src/repo_registry/web_api/app.py",
"src/repo_scoping/web_api/app.py",
"docs/schemas/repo-scope-context-response.json",
"tests/test_scope_context_api.py",
],
@ -661,7 +661,7 @@ class CandidateGraphGenerator:
identity = f"{repository.name} {repository.url} {repository.description or ''}".lower()
if "repo-scoping" in identity or "repository scoping" in identity:
return True
return any(fact.path.startswith("src/repo_registry/") for fact in facts)
return any(fact.path.startswith("src/repo_scoping/") for fact in facts)
def _facts_for_paths(
self,

View file

@ -3,13 +3,13 @@ from __future__ import annotations
import re
from dataclasses import replace
from repo_registry.candidate_graph.generator import (
from repo_scoping.candidate_graph.generator import (
CandidateAbilityDraft,
CandidateCapabilityDraft,
CandidateEvidenceDraft,
CandidateFeatureDraft,
)
from repo_registry.core.models import SourceReference
from repo_scoping.core.models import SourceReference
STOP_WORDS = {

View file

@ -6,24 +6,24 @@ from dataclasses import asdict
from pathlib import Path
from typing import Sequence
from repo_registry.acceptance import (
from repo_scoping.acceptance import (
criteria_registry_json,
criteria_registry_markdown,
load_quality_criteria,
)
from repo_registry.core.models import CharacteristicRebuildResult, Repository
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.self_scoping.assessment import artifact_json, export_assessment_artifact
from repo_registry.self_scoping.comparison import (
from repo_scoping.core.models import CharacteristicRebuildResult, Repository
from repo_scoping.core.service import RegistryService
from repo_scoping.llm_extraction import LLMCandidateExtractor, create_llm_connect_adapter
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.self_scoping.assessment import artifact_json, export_assessment_artifact
from repo_scoping.self_scoping.comparison import (
compare_assessment_to_golden,
comparison_json,
comparison_markdown,
load_json,
)
from repo_registry.storage.sqlite import NotFoundError, RegistryStore
from repo_registry.web_api.app import Settings
from repo_scoping.storage.sqlite import NotFoundError, RegistryStore
from repo_scoping.web_api.app import Settings
def build_parser() -> argparse.ArgumentParser:
@ -56,8 +56,8 @@ def build_parser() -> argparse.ArgumentParser:
action="store_true",
help="Confirm a destructive all-repository rebuild.",
)
rebuild.add_argument("--database-path", help="Override REPO_REGISTRY_DATABASE_PATH.")
rebuild.add_argument("--checkout-root", help="Override REPO_REGISTRY_CHECKOUT_ROOT.")
rebuild.add_argument("--database-path", help="Override REPO_SCOPING_DATABASE_PATH.")
rebuild.add_argument("--checkout-root", help="Override REPO_SCOPING_CHECKOUT_ROOT.")
export = subparsers.add_parser(
"export-assessment",
help="Export a completed analysis run as a self-scoping assessment artifact.",
@ -87,8 +87,8 @@ def build_parser() -> argparse.ArgumentParser:
)
export.add_argument("--reviewer", default="codex", help="Reviewer name recorded in the artifact.")
export.add_argument("--summary", help="Assessment summary override.")
export.add_argument("--database-path", help="Override REPO_REGISTRY_DATABASE_PATH.")
export.add_argument("--checkout-root", help="Override REPO_REGISTRY_CHECKOUT_ROOT.")
export.add_argument("--database-path", help="Override REPO_SCOPING_DATABASE_PATH.")
export.add_argument("--checkout-root", help="Override REPO_SCOPING_CHECKOUT_ROOT.")
compare = subparsers.add_parser(
"compare-assessment",
help="Compare a self-scoping assessment artifact against a golden profile.",
@ -155,8 +155,8 @@ def build_parser() -> argparse.ArgumentParser:
action="store_true",
help="Return exit code 1 only when comparison status is regression.",
)
self_assess.add_argument("--database-path", help="Override REPO_REGISTRY_DATABASE_PATH.")
self_assess.add_argument("--checkout-root", help="Override REPO_REGISTRY_CHECKOUT_ROOT.")
self_assess.add_argument("--database-path", help="Override REPO_SCOPING_DATABASE_PATH.")
self_assess.add_argument("--checkout-root", help="Override REPO_SCOPING_CHECKOUT_ROOT.")
self_assess.set_defaults(no_llm=True)
criteria = subparsers.add_parser(
"list-quality-criteria",
@ -177,8 +177,8 @@ def build_parser() -> argparse.ArgumentParser:
"list-legacy-auto-approvals",
help="List historical trusted deterministic auto-approval records.",
)
legacy.add_argument("--database-path", help="Override REPO_REGISTRY_DATABASE_PATH.")
legacy.add_argument("--checkout-root", help="Override REPO_REGISTRY_CHECKOUT_ROOT.")
legacy.add_argument("--database-path", help="Override REPO_SCOPING_DATABASE_PATH.")
legacy.add_argument("--checkout-root", help="Override REPO_SCOPING_CHECKOUT_ROOT.")
legacy.add_argument("--output", help="Write inventory output to this path instead of stdout.")
legacy.add_argument(
"--format",

View file

@ -1,3 +1,3 @@
from repo_registry.content_indexing.extractor import ContentChunkCandidate, ContentExtractor
from repo_scoping.content_indexing.extractor import ContentChunkCandidate, ContentExtractor
__all__ = ["ContentChunkCandidate", "ContentExtractor"]

View file

@ -3,7 +3,7 @@ from __future__ import annotations
from dataclasses import dataclass, field
from pathlib import Path
from repo_registry.core.models import ObservedFact
from repo_scoping.core.models import ObservedFact
INDEXED_FACT_KINDS = {

View file

@ -5,7 +5,7 @@ import logging
from typing import Any
LOGGER_NAME = "repo_registry.operations"
LOGGER_NAME = "repo_scoping.operations"
def log_operation(event: str, **fields: Any) -> None:

View file

@ -4,7 +4,7 @@ from collections.abc import Sequence
from dataclasses import asdict, replace
from typing import Any
from repo_registry.acceptance import (
from repo_scoping.acceptance import (
AgenticReviewDecision,
AgenticReviewer,
AgenticReviewRequest,
@ -14,7 +14,7 @@ from repo_registry.acceptance import (
evaluate_candidate_graph_quality,
validate_agentic_review_decisions,
)
from repo_registry.core.models import (
from repo_scoping.core.models import (
AbilitySummary,
AnalysisRunDiff,
AnalysisRunDiffItem,
@ -43,17 +43,17 @@ from repo_registry.core.models import (
TrustedAutoApprovalMigrationRecord,
enrich_review_decision,
)
from repo_registry.candidate_graph.generator import CandidateGraphGenerator
from repo_registry.candidate_graph.normalization import normalize_candidate_drafts
from repo_registry.content_indexing.extractor import ContentExtractor
from repo_registry.core.logging import log_operation
from repo_registry.llm_extraction.extractor import LLMCandidateExtractor
from repo_registry.llm_extraction.mapper import LLMExtractionMapper
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.repo_ingestion.metadata import RepositoryMetadataExtractor
from repo_registry.repo_scanning.scanner import DeterministicScanner
from repo_registry.semantic import EmbeddingProvider, cosine_similarity
from repo_registry.storage.sqlite import NotFoundError, RegistryStore
from repo_scoping.candidate_graph.generator import CandidateGraphGenerator
from repo_scoping.candidate_graph.normalization import normalize_candidate_drafts
from repo_scoping.content_indexing.extractor import ContentExtractor
from repo_scoping.core.logging import log_operation
from repo_scoping.llm_extraction.extractor import LLMCandidateExtractor
from repo_scoping.llm_extraction.mapper import LLMExtractionMapper
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.repo_ingestion.metadata import RepositoryMetadataExtractor
from repo_scoping.repo_scanning.scanner import DeterministicScanner
from repo_scoping.semantic import EmbeddingProvider, cosine_similarity
from repo_scoping.storage.sqlite import NotFoundError, RegistryStore
class RegistryService:

View file

@ -1,4 +1,4 @@
from repo_registry.llm_extraction.extractor import (
from repo_scoping.llm_extraction.extractor import (
ExtractedAbility,
ExtractedCapability,
ExtractedEvidence,
@ -7,7 +7,7 @@ from repo_registry.llm_extraction.extractor import (
LLMExtractionError,
create_llm_connect_adapter,
)
from repo_registry.llm_extraction.mapper import LLMExtractionMapper
from repo_scoping.llm_extraction.mapper import LLMExtractionMapper
__all__ = [
"ExtractedAbility",

View file

@ -4,7 +4,7 @@ import json
from dataclasses import dataclass, field
from typing import Any, Protocol
from repo_registry.core.models import ContentChunk, Repository
from repo_scoping.core.models import ContentChunk, Repository
class LLMExtractionError(ValueError):

View file

@ -1,13 +1,13 @@
from __future__ import annotations
from repo_registry.candidate_graph.generator import (
from repo_scoping.candidate_graph.generator import (
CandidateAbilityDraft,
CandidateCapabilityDraft,
CandidateEvidenceDraft,
CandidateFeatureDraft,
)
from repo_registry.core.models import ContentChunk, ObservedFact, SourceReference
from repo_registry.llm_extraction.extractor import ExtractedAbility
from repo_scoping.core.models import ContentChunk, ObservedFact, SourceReference
from repo_scoping.llm_extraction.extractor import ExtractedAbility
class LLMExtractionMapper:

View file

@ -19,10 +19,16 @@ class RepositoryMetadataExtractor:
pyproject = self._from_pyproject(root)
package = self._from_package_json(root)
readme = self._from_readme(root)
fallback_name = self._name_from_url_or_path(url)
source_name = self._source_name(url) or self._source_name(str(root))
return RepositoryMetadata(
name=pyproject.name or package.name or readme.name or fallback_name,
name=(
source_name
or pyproject.name
or package.name
or readme.name
or "repository"
),
description=(
pyproject.description
or package.description
@ -77,10 +83,13 @@ class RepositoryMetadataExtractor:
return RepositoryMetadata(name=title, description=None)
return RepositoryMetadata(name="", description=None)
def _name_from_url_or_path(self, value: str) -> str:
def _source_name(self, value: str) -> str:
parsed = urlparse(value)
path = parsed.path if parsed.scheme else value
name = Path(path.rstrip("/")).name or "repository"
name = Path(path.rstrip("/")).name
if name.endswith(".git"):
name = name[:-4]
return name or "repository"
normalized = name.strip()
if normalized.lower() in {"", ".", "repo", "repository", "source", "checkout"}:
return ""
return normalized

View file

@ -1,4 +1,4 @@
from repo_registry.scope.generator import ScopeGenerator
from repo_registry.scope.validator import ScopeValidator
from repo_scoping.scope.generator import ScopeGenerator
from repo_scoping.scope.validator import ScopeValidator
__all__ = ["ScopeGenerator", "ScopeValidator"]

View file

@ -3,8 +3,8 @@ from __future__ import annotations
import re
from dataclasses import asdict
from repo_registry.core.service import RegistryService
from repo_registry.storage.sqlite import NotFoundError
from repo_scoping.core.service import RegistryService
from repo_scoping.storage.sqlite import NotFoundError
SCOPE_SECTIONS = [

View file

@ -4,7 +4,7 @@ import re
from dataclasses import dataclass
from pathlib import Path
from repo_registry.scope.generator import SCOPE_SECTIONS, ScopeGenerator
from repo_scoping.scope.generator import SCOPE_SECTIONS, ScopeGenerator
@dataclass(frozen=True)

View file

@ -1,6 +1,6 @@
from repo_registry.self_scoping.assessment import export_assessment_artifact
from repo_registry.self_scoping.comparison import compare_assessment_to_golden
from repo_registry.self_scoping.review_store import (
from repo_scoping.self_scoping.assessment import export_assessment_artifact
from repo_scoping.self_scoping.comparison import compare_assessment_to_golden
from repo_scoping.self_scoping.review_store import (
record_assessment_outcome,
record_assessment_pair_outcome,
)

View file

@ -9,12 +9,12 @@ from importlib import metadata
from pathlib import Path
from typing import Any
from repo_registry.acceptance import (
from repo_scoping.acceptance import (
active_quality_criteria_version,
evaluate_candidate_graph_quality,
quality_gate_outcome_dicts,
)
from repo_registry.core.models import (
from repo_scoping.core.models import (
Ability,
CandidateAbility,
CandidateCapability,
@ -26,7 +26,7 @@ from repo_registry.core.models import (
ReviewDecision,
SourceReference,
)
from repo_registry.core.service import RegistryService
from repo_scoping.core.service import RegistryService
SCHEMA_VERSION = "self-scoping-assessment/v1"
@ -151,7 +151,7 @@ def _engine_identity(scanner_version: str, engine_root: Path) -> dict[str, Any]:
def _package_version() -> str:
try:
return metadata.version("repo-registry")
return metadata.version("repo-scoping")
except metadata.PackageNotFoundError:
return "unknown"

View file

@ -9,7 +9,7 @@ from typing import Any
from uuid import uuid4
SELF_SCOPING_ROOT_ENV = "REPO_REGISTRY_SELF_SCOPING_ROOT"
SELF_SCOPING_ROOT_ENV = "REPO_SCOPING_SELF_SCOPING_ROOT"
OUTCOME_SCHEMA_VERSION = "self-scoping-review-outcome/v1"
ALLOWED_OUTCOMES = {
"prefer_golden",

View file

@ -1,4 +1,4 @@
from repo_registry.semantic.embeddings import (
from repo_scoping.semantic.embeddings import (
EmbeddingProvider,
HashingEmbeddingProvider,
cosine_similarity,

View file

@ -4,7 +4,7 @@ import json
import sqlite3
from pathlib import Path
from repo_registry.core.models import (
from repo_scoping.core.models import (
Ability,
AbilitySummary,
AnalysisRun,
@ -30,10 +30,10 @@ from repo_registry.core.models import (
SourceReference,
confidence_label,
)
from repo_registry.core.logging import log_operation
from repo_registry.content_indexing.extractor import ContentChunkCandidate
from repo_registry.candidate_graph.generator import CandidateAbilityDraft
from repo_registry.repo_scanning.scanner import FactCandidate, ScanResult
from repo_scoping.core.logging import log_operation
from repo_scoping.content_indexing.extractor import ContentChunkCandidate
from repo_scoping.candidate_graph.generator import CandidateAbilityDraft
from repo_scoping.repo_scanning.scanner import FactCandidate, ScanResult
class NotFoundError(ValueError):

View file

@ -12,19 +12,19 @@ from fastapi.responses import PlainTextResponse
from pydantic import Field
from pydantic_settings import BaseSettings, SettingsConfigDict
from repo_registry.acceptance import (
from repo_scoping.acceptance import (
criteria_registry_dict,
evaluate_candidate_graph_quality,
load_quality_criteria,
quality_gate_outcome_dicts,
)
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.semantic import HashingEmbeddingProvider
from repo_registry.scope import ScopeGenerator, ScopeValidator
from repo_registry.storage.sqlite import NotFoundError, RegistryStore
from repo_registry.web_api.schemas import (
from repo_scoping.core.service import RegistryService
from repo_scoping.llm_extraction import LLMCandidateExtractor, create_llm_connect_adapter
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.semantic import HashingEmbeddingProvider
from repo_scoping.scope import ScopeGenerator, ScopeValidator
from repo_scoping.storage.sqlite import NotFoundError, RegistryStore
from repo_scoping.web_api.schemas import (
AbilityCreate,
AbilitySummaryResponse,
AbilityUpdate,
@ -86,9 +86,9 @@ def slugify(value: str) -> str:
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="REPO_REGISTRY_")
model_config = SettingsConfigDict(env_prefix="REPO_SCOPING_")
database_path: str = Field(default="var/repo-registry.sqlite3")
database_path: str = Field(default="var/repo-scoping.sqlite3")
checkout_root: str = Field(default="var/checkouts")
llm_enabled: bool = Field(default=True)
llm_provider: str | None = Field(default=None)
@ -103,7 +103,7 @@ def get_settings() -> Settings:
def get_service(settings: Settings = Depends(get_settings)) -> RegistryService:
logging.getLogger("repo_registry.operations").setLevel(
logging.getLogger("repo_scoping.operations").setLevel(
getattr(logging, settings.log_level.upper(), logging.INFO)
)
database_path = Path(settings.database_path)
@ -165,7 +165,7 @@ app = FastAPI(
)
from repo_registry.web_ui.views import router as ui_router
from repo_scoping.web_ui.views import router as ui_router
app.include_router(ui_router)

View file

@ -9,13 +9,13 @@ from urllib.parse import quote_plus, urlparse
from fastapi import APIRouter, Depends, Form, HTTPException, Query
from fastapi.responses import HTMLResponse, PlainTextResponse, RedirectResponse
from repo_registry.acceptance import (
from repo_scoping.acceptance import (
evaluate_candidate_graph_quality,
quality_gate_outcome_dicts,
)
from repo_registry.core.service import RegistryService
from repo_registry.self_scoping.comparison import compare_assessment_to_golden
from repo_registry.self_scoping.review_store import (
from repo_scoping.core.service import RegistryService
from repo_scoping.self_scoping.comparison import compare_assessment_to_golden
from repo_scoping.self_scoping.review_store import (
ALLOWED_OUTCOMES,
list_assessment_artifacts,
list_golden_profiles,
@ -24,8 +24,8 @@ from repo_registry.self_scoping.review_store import (
record_assessment_outcome,
record_assessment_pair_outcome,
)
from repo_registry.storage.sqlite import NotFoundError
from repo_registry.web_api.app import get_service
from repo_scoping.storage.sqlite import NotFoundError
from repo_scoping.web_api.app import get_service
router = APIRouter(include_in_schema=False)

View file

@ -1,7 +1,7 @@
from repo_registry.acceptance import AgenticReviewDecision
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.storage.sqlite import RegistryStore
from repo_scoping.acceptance import AgenticReviewDecision
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.storage.sqlite import RegistryStore
class BoundaryApprovingReviewer:

View file

@ -1,12 +1,12 @@
import pytest
from repo_registry.acceptance import (
from repo_scoping.acceptance import (
AgenticReviewDecision,
validate_agentic_review_decision,
)
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.storage.sqlite import RegistryStore
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.storage.sqlite import RegistryStore
class RecordingAgenticReviewer:

View file

@ -1,5 +1,5 @@
from repo_registry.candidate_graph.generator import CandidateGraphGenerator
from repo_registry.core.models import ContentChunk, ObservedFact, Repository
from repo_scoping.candidate_graph.generator import CandidateGraphGenerator
from repo_scoping.core.models import ContentChunk, ObservedFact, Repository
def fact(id, kind, name, path="", value="", metadata=None):
@ -533,7 +533,7 @@ def test_candidate_generator_does_not_promote_owned_provider_vocabulary_to_capab
3,
"llm_provider",
"OpenRouter",
"src/repo_registry/repo_scanning/scanner.py",
"src/repo_scoping/repo_scanning/scanner.py",
"openrouter",
{"source_role": "implementation_source", "utility_relationship": "owned"},
),
@ -541,7 +541,7 @@ def test_candidate_generator_does_not_promote_owned_provider_vocabulary_to_capab
4,
"provider_registry",
"LLM provider registry",
"src/repo_registry/repo_scanning/scanner.py",
"src/repo_scoping/repo_scanning/scanner.py",
metadata={
"source_role": "implementation_source",
"utility_relationship": "owned",
@ -551,7 +551,7 @@ def test_candidate_generator_does_not_promote_owned_provider_vocabulary_to_capab
5,
"credential_config",
"OpenRouter API key",
"src/repo_registry/repo_scanning/scanner.py",
"src/repo_scoping/repo_scanning/scanner.py",
"OPENROUTER_API_KEY",
{"source_role": "implementation_source", "utility_relationship": "configure"},
),
@ -619,7 +619,7 @@ def test_candidate_generator_recovers_repo_scoping_native_candidate_families():
17,
"interface",
"python route decorator",
"src/repo_registry/web_api/app.py",
"src/repo_scoping/web_api/app.py",
'@app.post("/repos")',
),
]

View file

@ -1,10 +1,10 @@
from repo_registry.candidate_graph.generator import (
from repo_scoping.candidate_graph.generator import (
CandidateAbilityDraft,
CandidateCapabilityDraft,
CandidateFeatureDraft,
)
from repo_registry.candidate_graph.normalization import normalize_candidate_drafts
from repo_registry.core.models import SourceReference
from repo_scoping.candidate_graph.normalization import normalize_candidate_drafts
from repo_scoping.core.models import SourceReference
def ref(fact_id, path):

View file

@ -2,10 +2,10 @@ import json
import pytest
from repo_registry.cli import main
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.storage.sqlite import RegistryStore
from repo_scoping.cli import main
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.storage.sqlite import RegistryStore
def make_service(tmp_path):

View file

@ -1,5 +1,5 @@
from repo_registry.content_indexing.extractor import ContentExtractor
from repo_registry.core.models import ObservedFact
from repo_scoping.content_indexing.extractor import ContentExtractor
from repo_scoping.core.models import ObservedFact
def fact(id, kind, name, path="", line=None, source_role=""):

View file

@ -1,6 +1,6 @@
import subprocess
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_scoping.repo_ingestion.git import GitIngestionService
def run(command, cwd):

View file

@ -1,6 +1,6 @@
from datetime import date
from repo_registry.intent.bootstrap import bootstrap_intent_from_scope, scope_to_intent_text
from repo_scoping.intent.bootstrap import bootstrap_intent_from_scope, scope_to_intent_text
def test_scope_to_intent_text_replaces_scope_heading_and_marks_bootstrap():

View file

@ -1,7 +1,7 @@
import pytest
from repo_registry.core.models import ContentChunk, Repository
from repo_registry.llm_extraction import (
from repo_scoping.core.models import ContentChunk, Repository
from repo_scoping.llm_extraction import (
LLMCandidateExtractor,
LLMExtractionError,
create_llm_connect_adapter,

View file

@ -1,5 +1,5 @@
from repo_registry.core.models import ContentChunk, ObservedFact
from repo_registry.llm_extraction import (
from repo_scoping.core.models import ContentChunk, ObservedFact
from repo_scoping.llm_extraction import (
ExtractedAbility,
ExtractedCapability,
ExtractedEvidence,

View file

@ -1,4 +1,4 @@
from repo_registry.acceptance import (
from repo_scoping.acceptance import (
active_quality_criteria_version,
criteria_registry_markdown,
load_quality_criteria,

View file

@ -1,10 +1,10 @@
from repo_registry.acceptance import (
from repo_scoping.acceptance import (
blocking_quality_gate_outcomes,
evaluate_candidate_capability_quality,
evaluate_candidate_graph_quality,
quality_gate_outcome_dicts,
)
from repo_registry.core.models import (
from repo_scoping.core.models import (
AnalysisRun,
CandidateAbility,
CandidateCapability,
@ -13,9 +13,9 @@ from repo_registry.core.models import (
Repository,
SourceReference,
)
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.storage.sqlite import RegistryStore
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.storage.sqlite import RegistryStore
def source_ref(path="src/app.py", kind="source"):

View file

@ -2,17 +2,17 @@ import json
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 (
from repo_scoping.core.logging import LOGGER_NAME
from repo_scoping.core.models import SourceReference
from repo_scoping.core.service import RegistryService
from repo_scoping.llm_extraction import (
ExtractedAbility,
ExtractedCapability,
ExtractedFeature,
)
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.semantic import HashingEmbeddingProvider
from repo_registry.storage.sqlite import NotFoundError, RegistryStore
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.semantic import HashingEmbeddingProvider
from repo_scoping.storage.sqlite import NotFoundError, RegistryStore
from tests.fixtures import (
write_dependency_only_repo,
write_empty_repo,

View file

@ -1,7 +1,21 @@
from repo_registry.repo_ingestion.metadata import RepositoryMetadataExtractor
from repo_scoping.repo_ingestion.metadata import RepositoryMetadataExtractor
def test_metadata_prefers_pyproject(tmp_path):
def test_metadata_prefers_source_identity_over_pyproject(tmp_path):
repo = tmp_path / "repo-scoping"
repo.mkdir()
(repo / "pyproject.toml").write_text(
'[project]\nname = "repo-registry"\ndescription = "Repository Scoping."\n',
encoding="utf-8",
)
metadata = RepositoryMetadataExtractor().extract(repo, str(repo))
assert metadata.name == "repo-scoping"
assert metadata.description == "Repository Scoping."
def test_metadata_uses_pyproject_when_source_name_is_generic(tmp_path):
repo = tmp_path / "repo"
repo.mkdir()
(repo / "pyproject.toml").write_text(
@ -15,7 +29,7 @@ def test_metadata_prefers_pyproject(tmp_path):
assert metadata.description == "Extract invoice data."
def test_metadata_uses_package_json(tmp_path):
def test_metadata_uses_package_json_when_source_name_is_generic(tmp_path):
repo = tmp_path / "repo"
repo.mkdir()
(repo / "package.json").write_text(
@ -29,8 +43,8 @@ def test_metadata_uses_package_json(tmp_path):
assert metadata.description == "Browse repository abilities."
def test_metadata_falls_back_to_readme_title(tmp_path):
repo = tmp_path / "repo-name"
def test_metadata_uses_readme_title_when_source_name_is_generic(tmp_path):
repo = tmp_path / "repository"
repo.mkdir()
(repo / "README.md").write_text(
"# Useful Registry\n\nExtra details follow.\n",
@ -41,3 +55,19 @@ def test_metadata_falls_back_to_readme_title(tmp_path):
assert metadata.name == "Useful Registry"
assert metadata.description == "Extra details follow."
def test_metadata_strips_git_suffix_from_url_identity(tmp_path):
repo = tmp_path / "checkout"
repo.mkdir()
(repo / "pyproject.toml").write_text(
'[project]\nname = "old-package-name"\n',
encoding="utf-8",
)
metadata = RepositoryMetadataExtractor().extract(
repo,
"https://example.test/acme/repo-scoping.git",
)
assert metadata.name == "repo-scoping"

View file

@ -1,4 +1,4 @@
from repo_registry.repo_scanning.scanner import DeterministicScanner
from repo_scoping.repo_scanning.scanner import DeterministicScanner
from tests.fixtures import (
write_javascript_typescript_package_repo,
write_misleading_docs_repo,

View file

@ -1,9 +1,9 @@
import json
from pathlib import Path
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.storage.sqlite import RegistryStore
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.storage.sqlite import RegistryStore
def test_llm_connect_provider_expectations_are_detected_without_llm(tmp_path):

View file

@ -3,7 +3,7 @@ from pathlib import Path
from fastapi.testclient import TestClient
from repo_registry.web_api.app import Settings, app, get_settings
from repo_scoping.web_api.app import Settings, app, get_settings
def override_settings(tmp_path):

View file

@ -1,8 +1,8 @@
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.scope.generator import SCOPE_SECTIONS, ScopeGenerator
from repo_registry.scope.validator import ScopeValidator
from repo_registry.storage.sqlite import RegistryStore
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.scope.generator import SCOPE_SECTIONS, ScopeGenerator
from repo_scoping.scope.validator import ScopeValidator
from repo_scoping.storage.sqlite import RegistryStore
def make_service(tmp_path):
@ -15,7 +15,7 @@ def test_scope_generator_renders_canonical_sections_and_capability_blocks(tmp_pa
service = make_service(tmp_path)
repository = service.register_repository(
name="Repo Registry",
url="https://example.test/coulomb/repo-registry.git",
url="https://example.test/coulomb/repo-scoping.git",
description="Generates repository scope files from approved characteristics.",
)
service.update_scope(
@ -46,10 +46,10 @@ def test_scope_generator_renders_canonical_sections_and_capability_blocks(tmp_pa
type="business-usecase",
primary_class="business-usecase",
attributes=["scope", "preview"],
location="src/repo_registry/scope/generator.py",
location="src/repo_scoping/scope/generator.py",
)
content = ScopeGenerator(service).generate("repo-registry")
content = ScopeGenerator(service).generate("repo-scoping")
assert content.startswith("# SCOPE\n")
for section in SCOPE_SECTIONS:
@ -57,7 +57,7 @@ def test_scope_generator_renders_canonical_sections_and_capability_blocks(tmp_pa
assert "Generates and validates SCOPE.md files" in content
assert "Maintain Repository Scope" in content
assert "Preview generated SCOPE.md" in content
assert "src/repo_registry/scope/generator.py" in content
assert "src/repo_scoping/scope/generator.py" in content
assert "```capability" in content
assert "type: api" in content
assert "title: Generate SCOPE.md" in content

View file

@ -1,7 +1,7 @@
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.self_scoping.assessment import export_assessment_artifact
from repo_registry.storage.sqlite import RegistryStore
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.self_scoping.assessment import export_assessment_artifact
from repo_scoping.storage.sqlite import RegistryStore
def make_service(tmp_path):

View file

@ -1,6 +1,6 @@
from pathlib import Path
from repo_registry.self_scoping.comparison import (
from repo_scoping.self_scoping.comparison import (
compare_assessment_to_golden,
comparison_markdown,
load_json,

View file

@ -2,7 +2,7 @@ import json
import pytest
from repo_registry.self_scoping.review_store import (
from repo_scoping.self_scoping.review_store import (
list_assessment_artifacts,
list_golden_profiles,
load_json_artifact,

View file

@ -2,7 +2,7 @@ import json
from fastapi.testclient import TestClient
from repo_registry.web_api.app import app
from repo_scoping.web_api.app import app
def write_json(path, payload):
@ -47,7 +47,7 @@ def seed_review_artifacts(root):
{
"name": "HTTP API surface",
"type": "API",
"location": "src/repo_registry/web_api/app.py",
"location": "src/repo_scoping/web_api/app.py",
}
],
}
@ -76,7 +76,7 @@ def seed_review_artifacts(root):
{
"name": "HTTP API surface",
"type": "API",
"location": "src/repo_registry/web_api/app.py",
"location": "src/repo_scoping/web_api/app.py",
}
],
}
@ -92,7 +92,7 @@ def seed_review_artifacts(root):
def test_self_scoping_ui_compares_and_records_outcome(tmp_path, monkeypatch):
root = tmp_path / "self-scoping"
seed_review_artifacts(root)
monkeypatch.setenv("REPO_REGISTRY_SELF_SCOPING_ROOT", str(root))
monkeypatch.setenv("REPO_SCOPING_SELF_SCOPING_ROOT", str(root))
client = TestClient(app)
index = client.get("/ui/self-scoping")
@ -126,7 +126,7 @@ def test_self_scoping_ui_compares_and_records_outcome(tmp_path, monkeypatch):
def test_self_scoping_ui_compares_two_assessment_runs(tmp_path, monkeypatch):
root = tmp_path / "self-scoping"
seed_review_artifacts(root)
monkeypatch.setenv("REPO_REGISTRY_SELF_SCOPING_ROOT", str(root))
monkeypatch.setenv("REPO_SCOPING_SELF_SCOPING_ROOT", str(root))
client = TestClient(app)
review = client.get(

View file

@ -1,8 +1,8 @@
import sqlite3
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.storage.sqlite import RegistryStore
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.storage.sqlite import RegistryStore
def make_service(tmp_path):

View file

@ -1,6 +1,6 @@
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.storage.sqlite import RegistryStore
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.storage.sqlite import RegistryStore
def make_service(tmp_path):

View file

@ -3,11 +3,11 @@ import sqlite3
from fastapi.testclient import TestClient
from repo_registry.core.service import RegistryService
from repo_registry.repo_ingestion.git import GitIngestionService
from repo_registry.storage.sqlite import RegistryStore
from repo_registry.web_api import app as app_module
from repo_registry.web_api.app import Settings, app, get_service, get_settings
from repo_scoping.core.service import RegistryService
from repo_scoping.repo_ingestion.git import GitIngestionService
from repo_scoping.storage.sqlite import RegistryStore
from repo_scoping.web_api import app as app_module
from repo_scoping.web_api.app import Settings, app, get_service, get_settings
def add_candidate_capability(database_path, repository_id, analysis_run_id, name):
@ -1063,12 +1063,12 @@ def test_api_service_settings_can_enable_hashing_embedding_provider(tmp_path):
def test_settings_can_load_from_environment(monkeypatch):
monkeypatch.setenv("REPO_REGISTRY_DATABASE_PATH", "var/env.sqlite3")
monkeypatch.setenv("REPO_REGISTRY_CHECKOUT_ROOT", "var/env-checkouts")
monkeypatch.setenv("REPO_REGISTRY_LLM_PROVIDER", "mock")
monkeypatch.setenv("REPO_REGISTRY_LLM_MODEL", "demo-model")
monkeypatch.setenv("REPO_REGISTRY_EMBEDDING_PROVIDER", "hashing")
monkeypatch.setenv("REPO_REGISTRY_LOG_LEVEL", "DEBUG")
monkeypatch.setenv("REPO_SCOPING_DATABASE_PATH", "var/env.sqlite3")
monkeypatch.setenv("REPO_SCOPING_CHECKOUT_ROOT", "var/env-checkouts")
monkeypatch.setenv("REPO_SCOPING_LLM_PROVIDER", "mock")
monkeypatch.setenv("REPO_SCOPING_LLM_MODEL", "demo-model")
monkeypatch.setenv("REPO_SCOPING_EMBEDDING_PROVIDER", "hashing")
monkeypatch.setenv("REPO_SCOPING_LOG_LEVEL", "DEBUG")
settings = Settings()
@ -2696,7 +2696,7 @@ def test_ui_manual_registry_entry_loop(tmp_path):
delete_repository_response = client.post(
f"{repository_path}/delete",
data={"confirm_name": "Manual Repo"},
data={"confirm_name": "manual-repo"},
follow_redirects=False,
)
assert delete_repository_response.status_code == 303

View file

@ -0,0 +1,98 @@
---
id: RREG-WP-0017
type: workplan
title: "Finalize Repo-Scoping Rename"
domain: capabilities
repo: repo-scoping
status: done
owner: codex
topic_slug: foerster-capabilities
created: "2026-05-15"
updated: "2026-05-15"
state_hub_workstream_id: "dbeae3c5-74fc-46c0-be61-1bd8d81e65df"
---
# Finalize Repo-Scoping Rename
The repo has already moved from the old `repo-registry` product name to
repo-scoping, but the implementation still exposes several legacy names. That
leaked into self-registration: metadata extraction preferred package metadata,
so a checkout could still be registered as `repo-registry` even when the
repository path and current project identity are `repo-scoping`.
Because this repository has not entered production use, there is no need to keep
old names as compatibility aliases. This workplan removes the legacy runtime
names and makes repo identity follow the repository source first.
## T01: Prefer Repository Source Identity
```task
id: RREG-WP-0017-T01
status: done
priority: high
state_hub_task_id: "2e0dbb87-e095-4e46-a37e-b54860b1f14d"
```
Repository registration should derive the default repository name from the
submitted checkout path or URL before falling back to package metadata.
Acceptance criteria:
- A local checkout under `repo-scoping` registers as `repo-scoping` by default.
- Package names still provide a fallback when the source path has no meaningful
repository identity.
- Regression coverage protects the priority order.
Implementation note 2026-05-15: metadata extraction now uses a non-generic
checkout path or URL slug before package and README names. This prevents a
source checkout named `repo-scoping` from being registered as an old package
name, while still allowing package metadata to fill generic temporary checkout
names such as `repo` or `checkout`.
## T02: Remove Legacy Runtime Names
```task
id: RREG-WP-0017-T02
status: done
priority: high
state_hub_task_id: "d7fefaa5-1dc0-4817-a13c-2bada32a86c7"
```
Rename the package, environment variables, default database path, commands,
documentation, and non-historical implementation references from
`repo-registry` / `repo_registry` / `REPO_REGISTRY` to
`repo-scoping` / `repo_scoping` / `REPO_SCOPING`.
Acceptance criteria:
- The import package is `repo_scoping`.
- Runtime configuration uses `REPO_SCOPING_*` environment variables.
- The default local database is `var/repo-scoping.sqlite3`.
- No compatibility shim remains for the old pre-production name.
Implementation note 2026-05-15: renamed the source package to `repo_scoping`,
updated imports, CLI entry points, settings, self-scoping release metadata,
candidate source seeds, and docs. The local editable install now exposes the
`repo-scoping` distribution and the `repo-scoping` console script imports
`repo_scoping.cli`.
## T03: Validate And Capture The Rename
```task
id: RREG-WP-0017-T03
status: done
priority: medium
state_hub_task_id: "70b29772-67ac-4074-988a-4caf2411b7b1"
```
Update tests, docs, and self-scoping fixtures affected by the rename, then run
the relevant regression suite.
Acceptance criteria:
- The full test suite passes.
- The State Hub sync accepts the workplan and task status.
- Remaining historical `repo-registry` references are limited to completed
historical records or old assessment artifacts.
Implementation note 2026-05-15: full regression suite passed with 190 tests.
The only remaining tracked old-name reference outside historical assessment and
workplan records is a deliberate metadata regression fixture proving that the
new source-identity priority overrides an old package name.