import json from pathlib import Path from fastapi.testclient import TestClient from repo_scoping.web_api.app import Settings, app, get_settings def override_settings(tmp_path): def _override(): return Settings( database_path=str(tmp_path / "scope-context.sqlite3"), checkout_root=str(tmp_path / "checkouts"), state_hub_base_url="", ) return _override def test_scope_context_endpoint_returns_activity_core_contract(tmp_path): scoped_source = tmp_path / "scoped-repo" scoped_source.mkdir() (scoped_source / "SCOPE.md").write_text( "# SCOPE\n\n" "> Generated context note.\n\n" "---\n\n" "## One-liner\n\n" "Maps repositories into concise operating context.\n\n" "## Notes\n\n" "Further details stay out of the summary.\n", encoding="utf-8", ) plain_source = tmp_path / "plain-repo" plain_source.mkdir() app.dependency_overrides[get_settings] = override_settings(tmp_path) client = TestClient(app) try: scoped = client.post( "/repos", json={ "name": "Scoped Repo", "url": str(scoped_source), "description": "Registry fallback for scoped repo.", }, ).json() ability_id = client.post( f"/repos/{scoped['id']}/abilities", json={ "name": "Context Publishing", "description": "Expose repository context to callers.", }, ).json()["id"] client.post( f"/repos/{scoped['id']}/capabilities", json={ "ability_id": ability_id, "name": "Generate SCOPE.md", "description": "Render repository scope from approved entries.", }, ) client.post( "/repos", json={ "name": "Plain Repo", "url": str(plain_source), "description": "Plain repository metadata summary.", }, ) client.post( "/repos", json={ "name": "Remote Repo", "url": "https://example.test/remote-repo.git", "description": "Remote repository metadata summary.", }, ) scoped_context = client.get("/repos/scoped-repo/scope/context") assert scoped_context.status_code == 200 assert scoped_context.json() == { "repo_slug": "scoped-repo", "capabilities": ["Generate SCOPE.md"], "tags": ["ability", "capability"], "scope_md_exists": True, "scope_summary": "Maps repositories into concise operating context.", } plain_context = client.get("/repos/plain-repo/scope/context") assert plain_context.status_code == 200 assert plain_context.json() == { "repo_slug": "plain-repo", "capabilities": [], "tags": [], "scope_md_exists": False, "scope_summary": "Plain repository metadata summary.", } remote_context = client.get("/repos/remote-repo/scope/context") assert remote_context.status_code == 200 assert remote_context.json() == { "repo_slug": "remote-repo", "capabilities": [], "tags": [], "scope_md_exists": False, "scope_summary": "Remote repository metadata summary.", } missing_context = client.get("/repos/missing-repo/scope/context") assert missing_context.status_code == 404 assert missing_context.json()["detail"] markdown_scope = client.get("/repos/scoped-repo/scope") assert markdown_scope.status_code == 200 assert markdown_scope.headers["content-type"].startswith("text/markdown") assert "# SCOPE" in markdown_scope.text finally: app.dependency_overrides.clear() def test_scope_context_schema_artifact_matches_contract_shape(): schema = json.loads( ( Path(__file__).parents[1] / "docs" / "schemas" / "repo-scope-context-response.json" ).read_text(encoding="utf-8") ) assert schema["additionalProperties"] is False assert schema["required"] == [ "repo_slug", "capabilities", "tags", "scope_md_exists", "scope_summary", ] assert schema["properties"]["scope_md_exists"]["type"] == "boolean" assert schema["properties"]["scope_summary"]["type"] == ["string", "null"] def test_scope_context_openapi_contract_is_exposed(tmp_path): app.dependency_overrides[get_settings] = override_settings(tmp_path) client = TestClient(app) try: schema = client.get("/openapi.json").json() finally: app.dependency_overrides.clear() operation = schema["paths"]["/repos/{repo_slug}/scope/context"]["get"] assert operation["tags"] == ["scope"] response_schema = operation["responses"]["200"]["content"]["application/json"][ "schema" ] assert response_schema["$ref"].endswith("/RepositoryScopeContextResponse") assert ( "RepositoryScopeContextResponse" in schema["components"]["schemas"] )