{"version": "2.1.0", "$schema": "https://json.schemastore.org/sarif-2.1.0.json", "runs": [{"tool": {"driver": {"name": "Repobility", "informationUri": "https://repobility.com", "rules": [{"id": "scanner-e4881f745d267c4c", "name": "Possibly dead Python function: upsert_park_ride_history", "shortDescription": {"text": "Possibly dead Python function: upsert_park_ride_history"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-0d9d570856d17b09", "name": "Possibly dead Python function: upsert_park_ride", "shortDescription": {"text": "Possibly dead Python function: upsert_park_ride"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f072a8a0a2cf2999", "name": "Possibly dead Python function: extract_kdvalues", "shortDescription": {"text": "Possibly dead Python function: extract_kdvalues"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8338c00f9947ceec", "name": "Possibly dead Python function: is_statistik_url", "shortDescription": {"text": "Possibly dead Python function: is_statistik_url"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-c7ba331220b21129", "name": "Possibly dead Python function: require_admin", "shortDescription": {"text": "Possibly dead Python function: require_admin"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-0f24584433b3129d", "name": "Possibly dead Python function: decorator", "shortDescription": {"text": "Possibly dead Python function: decorator"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-226426d375bf4ffa", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/CatalogPanel.tsx:175", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/CatalogPanel.tsx:175"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-5ed20d8a25abe92d", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/DatasetList.tsx:66", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/DatasetList.tsx:66"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-00c1d1c6425f88dd", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/DatasetDetail.tsx:150", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/DatasetDetail.tsx:150"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-b1157fceae59ed3f", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/datasets/CategoryDatasets.tsx:25", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/datasets/CategoryDatasets.tsx:25"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-87d3bb2c18b85924", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/datasets/ColumnProfileCard.tsx:77", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/datasets/ColumnProfileCard.tsx:77"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-32eafd452310ad45", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/datasets/CategoryGrid.tsx:76", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/datasets/CategoryGrid.tsx:76"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-60427b03771411b6", "name": "Dockerfile runs as root: frontend/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: frontend/Dockerfile"}, "fullDescription": {"text": "No non-root USER set. Containers running as root expand the blast radius of any vulnerability inside the image."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a7f39cdd5fa21931", "name": "Docker base image is tag-pinned but not digest-pinned: node:22-alpine", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: node:22-alpine"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-b048d166901fd868", "name": "Docker base image is tag-pinned but not digest-pinned: nginx:alpine", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: nginx:alpine"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-97b19a51caa7cb6b", "name": "Dockerfile runs as root: etl/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: etl/Dockerfile"}, "fullDescription": {"text": "No non-root USER set. Containers running as root expand the blast radius of any vulnerability inside the image."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-7231ff23f3a85ff9", "name": "Docker base image is tag-pinned but not digest-pinned: python:3.11-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.11-slim"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1f66ad88286ca30a", "name": "Dockerfile runs as root: backend/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: backend/Dockerfile"}, "fullDescription": {"text": "No non-root USER set. Containers running as root expand the blast radius of any vulnerability inside the image."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-8cd20d539467d2c5", "name": "Docker base image is tag-pinned but not digest-pinned: python:3.11-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.11-slim"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-aa5acaa49eb8315b", "name": "Containers defined but no K8s/orchestration manifest found", "shortDescription": {"text": "Containers defined but no K8s/orchestration manifest found"}, "fullDescription": {"text": "Repo has Dockerfiles/compose but no Kubernetes/Nomad manifests. If the target deployment is K8s, the manifests may live in a separate ops repo."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-28c4a04bd807da0c", "name": "GitHub Action is tag-pinned rather than SHA-pinned", "shortDescription": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "fullDescription": {"text": "actions/setup-python@v6 can move without a code change in this repo. Pin third-party actions to a reviewed 40-character commit SHA."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "2 test file(s) for 83 source file(s) (ratio 0.02). Consider adding integration or unit tests for critical paths."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-141b30a41e03817b", "name": "No license file detected", "shortDescription": {"text": "No license file detected"}, "fullDescription": {"text": "No LICENSE/COPYING/NOTICE file was found. Generated repositories often omit licensing, which blocks reuse and automated intake."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3ab5d313dda8e5f9", "name": "Debug logging residue appears in source files", "shortDescription": {"text": "Debug logging residue appears in source files"}, "fullDescription": {"text": "Found 23 console/debugger/print-style debug statements in non-test source. This is a common fast-generation residue before production cleanup."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-72b2a6250083a784", "name": "Placeholder or mock-heavy implementation detected", "shortDescription": {"text": "Placeholder or mock-heavy implementation detected"}, "fullDescription": {"text": "Found 13 placeholder/mock markers across 9 source files. This often means the repo looks complete while core flows still use generated scaffolding or fake data."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2d0c7b7ab8f8aacf", "name": "Critical user flow still appears backed by mock or placeholder data", "shortDescription": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "fullDescription": {"text": "A payment/auth/admin/order/billing-style flow contains mock, fake, TODO, dummy, or placeholder markers in runtime source. In the Fable corpus this is a high-leverage completeness smell: the app can look finished while the money, identity, or tenant flow is still scaffolded."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-749d4bc1bd66df5f", "name": "Agent instructions exist but release-hardening basics are missing", "shortDescription": {"text": "Agent instructions exist but release-hardening basics are missing"}, "fullDescription": {"text": "AI-coder instruction files were found, but the repo is missing license. Treat this as a contract gap: the agent is guided, but the generated output is not yet guarded by the controls that make it repeatable."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-ea8f3013f588db25", "name": "Shallow git history limits provenance confidence", "shortDescription": {"text": "Shallow git history limits provenance confidence"}, "fullDescription": {"text": "The repository is a shallow clone. Origin/evolution analysis cannot distinguish fresh generation, imported legacy code, or long-lived human code with high confidence."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8424db9c75e04ba4", "name": "Very short observed git history", "shortDescription": {"text": "Very short observed git history"}, "fullDescription": {"text": "The repo has multiple source files but two or fewer visible commits. This is not a failure by itself, but it lowers confidence in evolution-based diagnosis."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-1d09a5242c8788a7", "name": "Network/subprocess call without timeout or try/except \u2014 openDataDatasets.py:12", "shortDescription": {"text": "Network/subprocess call without timeout or try/except \u2014 openDataDatasets.py:12"}, "fullDescription": {"text": "`requests.get(...)` here lacks both a `timeout=` arg and an enclosing try/except. This is exactly the class of bug that took down our git-clone earlier (HTTP/2 stream cancel surfaced as a fatal). Add a `timeout=` and wrap in try/except, or use a wrapper that retries."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-87507d701c579141", "name": "Network/subprocess call without timeout or try/except \u2014 etl/scripts/generate_election_definitions.py:125", "shortDescription": {"text": "Network/subprocess call without timeout or try/except \u2014 etl/scripts/generate_election_definitions.py:125"}, "fullDescription": {"text": "`subprocess.run(...)` here lacks both a `timeout=` arg and an enclosing try/except. This is exactly the class of bug that took down our git-clone earlier (HTTP/2 stream cancel surfaced as a fatal). Add a `timeout=` and wrap in try/except, or use a wrapper that retries."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-f45586d12787519c", "name": "Network/subprocess call without timeout or try/except \u2014 etl/scripts/generate_dataset_categories.py:71", "shortDescription": {"text": "Network/subprocess call without timeout or try/except \u2014 etl/scripts/generate_dataset_categories.py:71"}, "fullDescription": {"text": "`subprocess.run(...)` here lacks both a `timeout=` arg and an enclosing try/except. This is exactly the class of bug that took down our git-clone earlier (HTTP/2 stream cancel surfaced as a fatal). Add a `timeout=` and wrap in try/except, or use a wrapper that retries."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2bb32407d7647ca5", "name": "Network/subprocess call without timeout or try/except \u2014 etl/scripts/generate_indicator_catalog.py:42", "shortDescription": {"text": "Network/subprocess call without timeout or try/except \u2014 etl/scripts/generate_indicator_catalog.py:42"}, "fullDescription": {"text": "`subprocess.run(...)` here lacks both a `timeout=` arg and an enclosing try/except. This is exactly the class of bug that took down our git-clone earlier (HTTP/2 stream cancel surfaced as a fatal). Add a `timeout=` and wrap in try/except, or use a wrapper that retries."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-c742b1091f1d75e9", "name": "Commented-code block (7 lines) in etl/src/pipeline.py:209", "shortDescription": {"text": "Commented-code block (7 lines) in etl/src/pipeline.py:209"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-d419b62f73a52971", "name": "Commented-code block (5 lines) in etl/src/extractors/base.py:21", "shortDescription": {"text": "Commented-code block (5 lines) in etl/src/extractors/base.py:21"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-f4ac1f33127863c9", "name": "Commented-code block (5 lines) in backend/src/api/routers/datasets.py:132", "shortDescription": {"text": "Commented-code block (5 lines) in backend/src/api/routers/datasets.py:132"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-3e727b00bdd1a12e", "name": "Commented-code block (5 lines) in backend/src/api/routers/tiles_router.py:34", "shortDescription": {"text": "Commented-code block (5 lines) in backend/src/api/routers/tiles_router.py:34"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-b334d875f2339fa1", "name": "5 env vars used in code but missing from .env.example", "shortDescription": {"text": "5 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `ETL_CATEGORIES_PATH`, `ETL_ELECTIONS_PATH`, `ETL_FAMILIES_PATH`, `ETL_INDICATORS_PATH`, `ETL_LOGS_DIR`. Add them (with a placeholder/comment) to .env.example so onboarding doesn't break."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2c04133e54348533", "name": "Near-duplicate function bodies in 2 places", "shortDescription": {"text": "Near-duplicate function bodies in 2 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\netl/scripts/generate_dataset_categories.py:slugify, etl/scripts/generate_dataset_families.py:slugify\n\nThis is *the* AI-coder failure mode (4\u00d7 more duplication in vibe-coded repos \u2014 see https://jw.hn/ai-code-hygiene). Consolidate or document why they're separate."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-b34f11f2d32f5147", "name": "Frontend route `/*` has no Link/navigate to it \u2014 frontend/src/App.tsx", "shortDescription": {"text": "Frontend route `/*` has no Link/navigate to it \u2014 frontend/src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-360cacdd0870fe2b", "name": "Frontend route `/datasets/c/:categoryId` has no Link/navigate to it \u2014 frontend/src/pages/DashboardPage.tsx", "shortDescription": {"text": "Frontend route `/datasets/c/:categoryId` has no Link/navigate to it \u2014 frontend/src/pages/DashboardPage.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-148b520e49e84e41", "name": "Frontend route `/datasets/d/:slug` has no Link/navigate to it \u2014 frontend/src/pages/DashboardPage.tsx", "shortDescription": {"text": "Frontend route `/datasets/d/:slug` has no Link/navigate to it \u2014 frontend/src/pages/DashboardPage.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-310eb217a3c3b8e0", "name": "Frontend route `/datasets/:datasetId` has no Link/navigate to it \u2014 frontend/src/pages/DashboardPage.tsx", "shortDescription": {"text": "Frontend route `/datasets/:datasetId` has no Link/navigate to it \u2014 frontend/src/pages/DashboardPage.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-7c3fea619cbf5f81", "name": "FastAPI POST `refresh` without auth dependency \u2014 backend/src/api/routers/auth_router.py:75", "shortDescription": {"text": "FastAPI POST `refresh` without auth dependency \u2014 backend/src/api/routers/auth_router.py:75"}, "fullDescription": {"text": "`@router.post` decorator with no `Depends(get_current_user)` or auth-shaped dependency in its signature. Mutating endpoints should require authentication unless explicitly public."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-c5ef09589b954af4", "name": "Dangling fetch: POST /api/auth/login (frontend/src/store/authStore.ts:29)", "shortDescription": {"text": "Dangling fetch: POST /api/auth/login (frontend/src/store/authStore.ts:29)"}, "fullDescription": {"text": "`frontend/src/store/authStore.ts:29` calls `POST /api/auth/login` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/auth/login`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-5fd623de5e6a65de", "name": "Dangling fetch: GET /api/auth/me (frontend/src/store/authStore.ts:32)", "shortDescription": {"text": "Dangling fetch: GET /api/auth/me (frontend/src/store/authStore.ts:32)"}, "fullDescription": {"text": "`frontend/src/store/authStore.ts:32` calls `GET /api/auth/me` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/auth/me`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-3e8e496b77cbb027", "name": "Dangling fetch: POST /api/auth/refresh?refresh_token=${encodeURIComponent(rt)} (frontend/src/store/authStore.ts:53)", "shortDescription": {"text": "Dangling fetch: POST /api/auth/refresh?refresh_token=${encodeURIComponent(rt)} (frontend/src/store/authStore.ts:53)"}, "fullDescription": {"text": "`frontend/src/store/authStore.ts:53` calls `POST /api/auth/refresh?refresh_token=${encodeURIComponent(rt)}` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: axios\nNormalized path used for matching: `/auth/refresh`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-8c236625afb6a8cb", "name": "Unused endpoint: GET /ready", "shortDescription": {"text": "Unused endpoint: GET /ready"}, "fullDescription": {"text": "`backend/src/api/main.py` declares `GET /ready` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-5baa8971ebe192a1", "name": "Unused endpoint: GET /", "shortDescription": {"text": "Unused endpoint: GET /"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-34a0d470c601d97f", "name": "Unused endpoint: GET /catalog", "shortDescription": {"text": "Unused endpoint: GET /catalog"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /catalog` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9260174de75b32ba", "name": "Unused endpoint: GET /categories", "shortDescription": {"text": "Unused endpoint: GET /categories"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /categories` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9d7fbfb3c5f137cf", "name": "Unused endpoint: GET /categories/{category_id}", "shortDescription": {"text": "Unused endpoint: GET /categories/{category_id}"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /categories/{category_id}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-cd9713ea1e0a08e1", "name": "Unused endpoint: GET /by-slug/{slug}", "shortDescription": {"text": "Unused endpoint: GET /by-slug/{slug}"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /by-slug/{slug}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d7a741e2bbe14973", "name": "Unused endpoint: GET /{dataset_id}", "shortDescription": {"text": "Unused endpoint: GET /{dataset_id}"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /{dataset_id}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-cf1b72c5786be303", "name": "Unused endpoint: GET /{dataset_id}/rows", "shortDescription": {"text": "Unused endpoint: GET /{dataset_id}/rows"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /{dataset_id}/rows` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ed1f2b614f3c7acc", "name": "Unused endpoint: GET /{dataset_id}/stats", "shortDescription": {"text": "Unused endpoint: GET /{dataset_id}/stats"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /{dataset_id}/stats` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-962342cdbe4012e0", "name": "Unused endpoint: GET /{dataset_id}/profile", "shortDescription": {"text": "Unused endpoint: GET /{dataset_id}/profile"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /{dataset_id}/profile` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a961786cf3b86bf4", "name": "Unused endpoint: GET /{dataset_id}/profile/histogram", "shortDescription": {"text": "Unused endpoint: GET /{dataset_id}/profile/histogram"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /{dataset_id}/profile/histogram` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4cf11a0d740e340e", "name": "Unused endpoint: GET /{dataset_id}/history", "shortDescription": {"text": "Unused endpoint: GET /{dataset_id}/history"}, "fullDescription": {"text": "`backend/src/api/routers/datasets.py` declares `GET /{dataset_id}/history` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2c940bad5d5155b4", "name": "Unused endpoint: GET /timeseries", "shortDescription": {"text": "Unused endpoint: GET /timeseries"}, "fullDescription": {"text": "`backend/src/api/routers/stats_router.py` declares `GET /timeseries` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-80cd2cd5b749c8cc", "name": "Unused endpoint: GET /correlation", "shortDescription": {"text": "Unused endpoint: GET /correlation"}, "fullDescription": {"text": "`backend/src/api/routers/stats_router.py` declares `GET /correlation` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8d4ee48967b401b7", "name": "Unused endpoint: GET /choropleth", "shortDescription": {"text": "Unused endpoint: GET /choropleth"}, "fullDescription": {"text": "`backend/src/api/routers/stats_router.py` declares `GET /choropleth` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-69b8d1d7e29d848d", "name": "Unused endpoint: GET /{election_id}/summary", "shortDescription": {"text": "Unused endpoint: GET /{election_id}/summary"}, "fullDescription": {"text": "`backend/src/api/routers/elections_router.py` declares `GET /{election_id}/summary` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-59e29d3924ef4838", "name": "Unused endpoint: GET /{election_id}/results", "shortDescription": {"text": "Unused endpoint: GET /{election_id}/results"}, "fullDescription": {"text": "`backend/src/api/routers/elections_router.py` declares `GET /{election_id}/results` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3ab87317a90c5f7b", "name": "Unused endpoint: GET /{election_id}/choropleth", "shortDescription": {"text": "Unused endpoint: GET /{election_id}/choropleth"}, "fullDescription": {"text": "`backend/src/api/routers/elections_router.py` declares `GET /{election_id}/choropleth` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-618721b912bad1c2", "name": "Unused endpoint: POST /login", "shortDescription": {"text": "Unused endpoint: POST /login"}, "fullDescription": {"text": "`backend/src/api/routers/auth_router.py` declares `POST /login` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-7ce17d6b092a81ca", "name": "Unused endpoint: POST /refresh", "shortDescription": {"text": "Unused endpoint: POST /refresh"}, "fullDescription": {"text": "`backend/src/api/routers/auth_router.py` declares `POST /refresh` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-99fc36db98c134ce", "name": "Unused endpoint: POST /logout", "shortDescription": {"text": "Unused endpoint: POST /logout"}, "fullDescription": {"text": "`backend/src/api/routers/auth_router.py` declares `POST /logout` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-fd1dc91abf32142d", "name": "Unused endpoint: GET /me", "shortDescription": {"text": "Unused endpoint: GET /me"}, "fullDescription": {"text": "`backend/src/api/routers/auth_router.py` declares `GET /me` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-304b6f2b403d93f7", "name": "Unused endpoint: POST /register", "shortDescription": {"text": "Unused endpoint: POST /register"}, "fullDescription": {"text": "`backend/src/api/routers/auth_router.py` declares `POST /register` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4982dbfd71045a81", "name": "Unused endpoint: GET /topics", "shortDescription": {"text": "Unused endpoint: GET /topics"}, "fullDescription": {"text": "`backend/src/api/routers/indicators_router.py` declares `GET /topics` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8fc826700126d17f", "name": "Unused endpoint: GET /{indicator_id}/timeseries", "shortDescription": {"text": "Unused endpoint: GET /{indicator_id}/timeseries"}, "fullDescription": {"text": "`backend/src/api/routers/indicators_router.py` declares `GET /{indicator_id}/timeseries` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1d966dc8f33ec391", "name": "Unused endpoint: GET /feature-datasets", "shortDescription": {"text": "Unused endpoint: GET /feature-datasets"}, "fullDescription": {"text": "`backend/src/api/routers/map_router.py` declares `GET /feature-datasets` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-63a3c175ae001383", "name": "Unused endpoint: GET /park-ride", "shortDescription": {"text": "Unused endpoint: GET /park-ride"}, "fullDescription": {"text": "`backend/src/api/routers/map_router.py` declares `GET /park-ride` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4c46b7ef1858c697", "name": "Unused endpoint: GET /bicycle-counters", "shortDescription": {"text": "Unused endpoint: GET /bicycle-counters"}, "fullDescription": {"text": "`backend/src/api/routers/map_router.py` declares `GET /bicycle-counters` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a5c16de9385b8010", "name": "Unused endpoint: GET /restrictions", "shortDescription": {"text": "Unused endpoint: GET /restrictions"}, "fullDescription": {"text": "`backend/src/api/routers/map_router.py` declares `GET /restrictions` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6ba4f1151029e93a", "name": "Unused endpoint: GET /admin-boundaries", "shortDescription": {"text": "Unused endpoint: GET /admin-boundaries"}, "fullDescription": {"text": "`backend/src/api/routers/map_router.py` declares `GET /admin-boundaries` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-aaaadc469bb4a895", "name": "Unused endpoint: GET /tiles/{z}/{x}/{y}.pbf", "shortDescription": {"text": "Unused endpoint: GET /tiles/{z}/{x}/{y}.pbf"}, "fullDescription": {"text": "`backend/src/api/routers/tiles_router.py` declares `GET /tiles/{z}/{x}/{y}.pbf` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d0fa9ec843598ce4", "name": "Unused endpoint: GET /feature/{feature_id}", "shortDescription": {"text": "Unused endpoint: GET /feature/{feature_id}"}, "fullDescription": {"text": "`backend/src/api/routers/tiles_router.py` declares `GET /feature/{feature_id}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2ae65e2273f34b4e", "name": "Unused endpoint: GET /datasets/catalog", "shortDescription": {"text": "Unused endpoint: GET /datasets/catalog"}, "fullDescription": {"text": "`frontend/src/api/catalog.ts` declares `GET /datasets/catalog` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-7907b981d1c474b5", "name": "Unused endpoint: GET /map/feature-datasets", "shortDescription": {"text": "Unused endpoint: GET /map/feature-datasets"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /map/feature-datasets` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2e120c9b1a2319e0", "name": "Unused endpoint: GET /map/park-ride", "shortDescription": {"text": "Unused endpoint: GET /map/park-ride"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /map/park-ride` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-31f5eafb5bd3c7b8", "name": "Unused endpoint: GET /map/bicycle-counters", "shortDescription": {"text": "Unused endpoint: GET /map/bicycle-counters"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /map/bicycle-counters` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-96ded99f2d27fb22", "name": "Unused endpoint: GET /map/restrictions", "shortDescription": {"text": "Unused endpoint: GET /map/restrictions"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /map/restrictions` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-51b96fd97d682ade", "name": "Unused endpoint: GET /map/admin-boundaries", "shortDescription": {"text": "Unused endpoint: GET /map/admin-boundaries"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /map/admin-boundaries` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8c2d4e0fff184ef6", "name": "Unused endpoint: GET /stats/choropleth", "shortDescription": {"text": "Unused endpoint: GET /stats/choropleth"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /stats/choropleth` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-28e520cd43c3a8f2", "name": "Unused endpoint: GET /stats/correlation", "shortDescription": {"text": "Unused endpoint: GET /stats/correlation"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /stats/correlation` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2becdf7b6c95bf68", "name": "Unused endpoint: GET /stats/metrics", "shortDescription": {"text": "Unused endpoint: GET /stats/metrics"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /stats/metrics` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-5b6173f3f7bbf753", "name": "Unused endpoint: GET /datasets", "shortDescription": {"text": "Unused endpoint: GET /datasets"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /datasets` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-65ef25c6033de30b", "name": "Unused endpoint: GET /datasets/status", "shortDescription": {"text": "Unused endpoint: GET /datasets/status"}, "fullDescription": {"text": "`frontend/src/api/map.ts` declares `GET /datasets/status` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8292c0931391749a", "name": "Unused endpoint: POST /auth/register", "shortDescription": {"text": "Unused endpoint: POST /auth/register"}, "fullDescription": {"text": "`frontend/src/pages/SignupPage.tsx` declares `POST /auth/register` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/22953"}, "properties": {"repository": "xbyjoex/ComputationalSpatialHumanities", "repoUrl": "https://github.com/xbyjoex/ComputationalSpatialHumanities", "branch": "main"}, "results": [{"ruleId": "scanner-e4881f745d267c4c", "level": "note", "message": {"text": "Possibly dead Python function: upsert_park_ride_history"}, "properties": {"repobilityId": "85c7cf2bbf702133", "scanner": "scanner-primary", "fingerprint": "e4881f745d267c4c", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "etl/src/loaders/postgres.py:622"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-0d9d570856d17b09", "level": "note", "message": {"text": "Possibly dead Python function: upsert_park_ride"}, "properties": {"repobilityId": "0bcb92bfac25970f", "scanner": "scanner-primary", "fingerprint": "0d9d570856d17b09", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "etl/src/loaders/postgres.py:666"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-f072a8a0a2cf2999", "level": "note", "message": {"text": "Possibly dead Python function: extract_kdvalues"}, "properties": {"repobilityId": "5846ebd282ea68da", "scanner": "scanner-primary", "fingerprint": "f072a8a0a2cf2999", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "etl/src/extractors/json_extractor.py:33"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-8338c00f9947ceec", "level": "note", "message": {"text": "Possibly dead Python function: is_statistik_url"}, "properties": {"repobilityId": "e26c2434a2830639", "scanner": "scanner-primary", "fingerprint": "8338c00f9947ceec", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "etl/src/extractors/statistik_transform.py:35"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-c7ba331220b21129", "level": "note", "message": {"text": "Possibly dead Python function: require_admin"}, "properties": {"repobilityId": "3c06db2e25566bf7", "scanner": "scanner-primary", "fingerprint": "c7ba331220b21129", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/src/api/auth.py:88"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-0f24584433b3129d", "level": "note", "message": {"text": "Possibly dead Python function: decorator"}, "properties": {"repobilityId": "ffbcbc9bc189af1c", "scanner": "scanner-primary", "fingerprint": "0f24584433b3129d", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/src/api/cache.py:79"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-226426d375bf4ffa", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/CatalogPanel.tsx:175"}, "properties": {"repobilityId": "019d894a0f8387f6", "scanner": "scanner-primary", "fingerprint": "226426d375bf4ffa", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-5ed20d8a25abe92d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/DatasetList.tsx:66"}, "properties": {"repobilityId": "1150ebd5f3b2f2e1", "scanner": "scanner-primary", "fingerprint": "5ed20d8a25abe92d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-00c1d1c6425f88dd", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/DatasetDetail.tsx:150"}, "properties": {"repobilityId": "9a2569d41db1515e", "scanner": "scanner-primary", "fingerprint": "00c1d1c6425f88dd", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b1157fceae59ed3f", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/datasets/CategoryDatasets.tsx:25"}, "properties": {"repobilityId": "34ca8f6faf871254", "scanner": "scanner-primary", "fingerprint": "b1157fceae59ed3f", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-87d3bb2c18b85924", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/datasets/ColumnProfileCard.tsx:77"}, "properties": {"repobilityId": "e715e29ae629ac36", "scanner": "scanner-primary", "fingerprint": "87d3bb2c18b85924", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-32eafd452310ad45", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/datasets/CategoryGrid.tsx:76"}, "properties": {"repobilityId": "d30af6b9957d0d2c", "scanner": "scanner-primary", "fingerprint": "32eafd452310ad45", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-60427b03771411b6", "level": "warning", "message": {"text": "Dockerfile runs as root: frontend/Dockerfile"}, "properties": {"repobilityId": "735c01d8531dfd2c", "scanner": "scanner-primary", "fingerprint": "60427b03771411b6", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-a7f39cdd5fa21931", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:22-alpine"}, "properties": {"repobilityId": "6086a1867bf8e871", "scanner": "scanner-primary", "fingerprint": "a7f39cdd5fa21931", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-b048d166901fd868", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: nginx:alpine"}, "properties": {"repobilityId": "f6c34b2475254563", "scanner": "scanner-primary", "fingerprint": "b048d166901fd868", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/Dockerfile"}, "region": {"startLine": 7}}}]}, {"ruleId": "scanner-97b19a51caa7cb6b", "level": "warning", "message": {"text": "Dockerfile runs as root: etl/Dockerfile"}, "properties": {"repobilityId": "8c4f065636389717", "scanner": "scanner-primary", "fingerprint": "97b19a51caa7cb6b", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-7231ff23f3a85ff9", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.11-slim"}, "properties": {"repobilityId": "77091c431af477d9", "scanner": "scanner-primary", "fingerprint": "7231ff23f3a85ff9", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "etl/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-1f66ad88286ca30a", "level": "warning", "message": {"text": "Dockerfile runs as root: backend/Dockerfile"}, "properties": {"repobilityId": "7afd2b0e8a8c9eeb", "scanner": "scanner-primary", "fingerprint": "1f66ad88286ca30a", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-8cd20d539467d2c5", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.11-slim"}, "properties": {"repobilityId": "06b87ac9439092d6", "scanner": "scanner-primary", "fingerprint": "8cd20d539467d2c5", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-aa5acaa49eb8315b", "level": "note", "message": {"text": "Containers defined but no K8s/orchestration manifest found"}, "properties": {"repobilityId": "b230ea9b68736081", "scanner": "scanner-primary", "fingerprint": "aa5acaa49eb8315b", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["coverage", "deployment"]}}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "f2786f1086a78fa7", "scanner": "scanner-primary", "fingerprint": "28c4a04bd807da0c", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 17}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "c266bde81c839bdc", "scanner": "scanner-primary", "fingerprint": "28c4a04bd807da0c", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 28}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "284afe3f8d178493", "scanner": "scanner-primary", "fingerprint": "28c4a04bd807da0c", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 52}}}]}, {"ruleId": "scanner-6893a6c8b0861585", "level": "warning", "message": {"text": "Very low test-to-source ratio"}, "properties": {"repobilityId": "54a7de3f06314bf0", "scanner": "scanner-primary", "fingerprint": "6893a6c8b0861585", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["tests", "coverage"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "5ad208364b009f05", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-3ab5d313dda8e5f9", "level": "note", "message": {"text": "Debug logging residue appears in source files"}, "properties": {"repobilityId": "8f3461a8531f35c5", "scanner": "scanner-primary", "fingerprint": "3ab5d313dda8e5f9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["debug", "cleanup", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-72b2a6250083a784", "level": "warning", "message": {"text": "Placeholder or mock-heavy implementation detected"}, "properties": {"repobilityId": "edd9bd5bfc2017b9", "scanner": "scanner-primary", "fingerprint": "72b2a6250083a784", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "incomplete", "generated-repo-pattern"]}}, {"ruleId": "scanner-2d0c7b7ab8f8aacf", "level": "warning", "message": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "properties": {"repobilityId": "51b0eeb9c6b3f322", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-749d4bc1bd66df5f", "level": "warning", "message": {"text": "Agent instructions exist but release-hardening basics are missing"}, "properties": {"repobilityId": "86e0c305009a7c95", "scanner": "scanner-primary", "fingerprint": "749d4bc1bd66df5f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["agent-instructions", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-ea8f3013f588db25", "level": "note", "message": {"text": "Shallow git history limits provenance confidence"}, "properties": {"repobilityId": "6f1d57cd6a7cabb6", "scanner": "scanner-primary", "fingerprint": "ea8f3013f588db25", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-8424db9c75e04ba4", "level": "none", "message": {"text": "Very short observed git history"}, "properties": {"repobilityId": "d87bc6c577000cb8", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-1d09a5242c8788a7", "level": "warning", "message": {"text": "Network/subprocess call without timeout or try/except \u2014 openDataDatasets.py:12"}, "properties": {"repobilityId": "72da8251c0697677", "scanner": "scanner-primary", "fingerprint": "1d09a5242c8788a7", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-87507d701c579141", "level": "warning", "message": {"text": "Network/subprocess call without timeout or try/except \u2014 etl/scripts/generate_election_definitions.py:125"}, "properties": {"repobilityId": "a77f44a506cb5c56", "scanner": "scanner-primary", "fingerprint": "87507d701c579141", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-f45586d12787519c", "level": "warning", "message": {"text": "Network/subprocess call without timeout or try/except \u2014 etl/scripts/generate_dataset_categories.py:71"}, "properties": {"repobilityId": "decdab40037e90bc", "scanner": "scanner-primary", "fingerprint": "f45586d12787519c", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-2bb32407d7647ca5", "level": "warning", "message": {"text": "Network/subprocess call without timeout or try/except \u2014 etl/scripts/generate_indicator_catalog.py:42"}, "properties": {"repobilityId": "5d475e915c040fb8", "scanner": "scanner-primary", "fingerprint": "2bb32407d7647ca5", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-c742b1091f1d75e9", "level": "none", "message": {"text": "Commented-code block (7 lines) in etl/src/pipeline.py:209"}, "properties": {"repobilityId": "bd25b6c8520d6bd7", "scanner": "scanner-primary", "fingerprint": "c742b1091f1d75e9", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-d419b62f73a52971", "level": "none", "message": {"text": "Commented-code block (5 lines) in etl/src/extractors/base.py:21"}, "properties": {"repobilityId": "6e7c8a57f622cbc4", "scanner": "scanner-primary", "fingerprint": "d419b62f73a52971", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-f4ac1f33127863c9", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/src/api/routers/datasets.py:132"}, "properties": {"repobilityId": "771144b36a9a8ac9", "scanner": "scanner-primary", "fingerprint": "f4ac1f33127863c9", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-3e727b00bdd1a12e", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/src/api/routers/tiles_router.py:34"}, "properties": {"repobilityId": "a2d3974f66a349b1", "scanner": "scanner-primary", "fingerprint": "3e727b00bdd1a12e", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-b334d875f2339fa1", "level": "note", "message": {"text": "5 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "faa38682016f5d53", "scanner": "scanner-primary", "fingerprint": "b334d875f2339fa1", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "b6955a1b769e5d61", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "759099ad585d8de9", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "237e4c760de969b1", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "3657a042f614f9ef", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "1a98cc59064e72b0", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "436739c8aae3ae85", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-b34f11f2d32f5147", "level": "warning", "message": {"text": "Frontend route `/*` has no Link/navigate to it \u2014 frontend/src/App.tsx"}, "properties": {"repobilityId": "d835e5716182bd15", "scanner": "scanner-primary", "fingerprint": "b34f11f2d32f5147", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-360cacdd0870fe2b", "level": "warning", "message": {"text": "Frontend route `/datasets/c/:categoryId` has no Link/navigate to it \u2014 frontend/src/pages/DashboardPage.tsx"}, "properties": {"repobilityId": "8b20e4bf0a44d14a", "scanner": "scanner-primary", "fingerprint": "360cacdd0870fe2b", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-148b520e49e84e41", "level": "warning", "message": {"text": "Frontend route `/datasets/d/:slug` has no Link/navigate to it \u2014 frontend/src/pages/DashboardPage.tsx"}, "properties": {"repobilityId": "7d9c454d23de0da4", "scanner": "scanner-primary", "fingerprint": "148b520e49e84e41", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-310eb217a3c3b8e0", "level": "warning", "message": {"text": "Frontend route `/datasets/:datasetId` has no Link/navigate to it \u2014 frontend/src/pages/DashboardPage.tsx"}, "properties": {"repobilityId": "48412149d7245e62", "scanner": "scanner-primary", "fingerprint": "310eb217a3c3b8e0", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-7c3fea619cbf5f81", "level": "error", "message": {"text": "FastAPI POST `refresh` without auth dependency \u2014 backend/src/api/routers/auth_router.py:75"}, "properties": {"repobilityId": "30406e1485b03076", "scanner": "scanner-primary", "fingerprint": "7c3fea619cbf5f81", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/src/api/routers/auth_router.py"}, "region": {"startLine": 75}}}]}, {"ruleId": "scanner-c5ef09589b954af4", "level": "error", "message": {"text": "Dangling fetch: POST /api/auth/login (frontend/src/store/authStore.ts:29)"}, "properties": {"repobilityId": "eadac1e68f524c7b", "scanner": "scanner-primary", "fingerprint": "c5ef09589b954af4", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-5fd623de5e6a65de", "level": "error", "message": {"text": "Dangling fetch: GET /api/auth/me (frontend/src/store/authStore.ts:32)"}, "properties": {"repobilityId": "ffe3da1fb98f553b", "scanner": "scanner-primary", "fingerprint": "5fd623de5e6a65de", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-3e8e496b77cbb027", "level": "error", "message": {"text": "Dangling fetch: POST /api/auth/refresh?refresh_token=${encodeURIComponent(rt)} (frontend/src/store/authStore.ts:53)"}, "properties": {"repobilityId": "33d777e5af0a23bc", "scanner": "scanner-primary", "fingerprint": "3e8e496b77cbb027", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "axios"]}}, {"ruleId": "scanner-8c236625afb6a8cb", "level": "note", "message": {"text": "Unused endpoint: GET /ready"}, "properties": {"repobilityId": "219e1f8dd110bab9", "scanner": "scanner-primary", "fingerprint": "8c236625afb6a8cb", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5baa8971ebe192a1", "level": "note", "message": {"text": "Unused endpoint: GET /"}, "properties": {"repobilityId": "ea408ffa2725558a", "scanner": "scanner-primary", "fingerprint": "5baa8971ebe192a1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-34a0d470c601d97f", "level": "note", "message": {"text": "Unused endpoint: GET /catalog"}, "properties": {"repobilityId": "02b2d1416274ddf3", "scanner": "scanner-primary", "fingerprint": "34a0d470c601d97f", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9260174de75b32ba", "level": "note", "message": {"text": "Unused endpoint: GET /categories"}, "properties": {"repobilityId": "fcf665493b2faa3d", "scanner": "scanner-primary", "fingerprint": "9260174de75b32ba", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9d7fbfb3c5f137cf", "level": "note", "message": {"text": "Unused endpoint: GET /categories/{category_id}"}, "properties": {"repobilityId": "18d5243ef0de6d54", "scanner": "scanner-primary", "fingerprint": "9d7fbfb3c5f137cf", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-cd9713ea1e0a08e1", "level": "note", "message": {"text": "Unused endpoint: GET /by-slug/{slug}"}, "properties": {"repobilityId": "913d5c1cf954cb47", "scanner": "scanner-primary", "fingerprint": "cd9713ea1e0a08e1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d7a741e2bbe14973", "level": "note", "message": {"text": "Unused endpoint: GET /{dataset_id}"}, "properties": {"repobilityId": "c5563491dc20e82a", "scanner": "scanner-primary", "fingerprint": "d7a741e2bbe14973", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-cf1b72c5786be303", "level": "note", "message": {"text": "Unused endpoint: GET /{dataset_id}/rows"}, "properties": {"repobilityId": "5ab4c29fd64bb8d1", "scanner": "scanner-primary", "fingerprint": "cf1b72c5786be303", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ed1f2b614f3c7acc", "level": "note", "message": {"text": "Unused endpoint: GET /{dataset_id}/stats"}, "properties": {"repobilityId": "4b49987d247eaf98", "scanner": "scanner-primary", "fingerprint": "ed1f2b614f3c7acc", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-962342cdbe4012e0", "level": "note", "message": {"text": "Unused endpoint: GET /{dataset_id}/profile"}, "properties": {"repobilityId": "241de3eddfa612da", "scanner": "scanner-primary", "fingerprint": "962342cdbe4012e0", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a961786cf3b86bf4", "level": "note", "message": {"text": "Unused endpoint: GET /{dataset_id}/profile/histogram"}, "properties": {"repobilityId": "49046d2c6d73dc73", "scanner": "scanner-primary", "fingerprint": "a961786cf3b86bf4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4cf11a0d740e340e", "level": "note", "message": {"text": "Unused endpoint: GET /{dataset_id}/history"}, "properties": {"repobilityId": "903ce00c7430ebdd", "scanner": "scanner-primary", "fingerprint": "4cf11a0d740e340e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2c940bad5d5155b4", "level": "note", "message": {"text": "Unused endpoint: GET /timeseries"}, "properties": {"repobilityId": "41f910d59d8ab257", "scanner": "scanner-primary", "fingerprint": "2c940bad5d5155b4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-80cd2cd5b749c8cc", "level": "note", "message": {"text": "Unused endpoint: GET /correlation"}, "properties": {"repobilityId": "d5e1dbd5830472da", "scanner": "scanner-primary", "fingerprint": "80cd2cd5b749c8cc", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8d4ee48967b401b7", "level": "note", "message": {"text": "Unused endpoint: GET /choropleth"}, "properties": {"repobilityId": "08d81ea58d03156f", "scanner": "scanner-primary", "fingerprint": "8d4ee48967b401b7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-69b8d1d7e29d848d", "level": "note", "message": {"text": "Unused endpoint: GET /{election_id}/summary"}, "properties": {"repobilityId": "d5d404187ac308c8", "scanner": "scanner-primary", "fingerprint": "69b8d1d7e29d848d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-59e29d3924ef4838", "level": "note", "message": {"text": "Unused endpoint: GET /{election_id}/results"}, "properties": {"repobilityId": "2febe6ce0bddbdef", "scanner": "scanner-primary", "fingerprint": "59e29d3924ef4838", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-3ab87317a90c5f7b", "level": "note", "message": {"text": "Unused endpoint: GET /{election_id}/choropleth"}, "properties": {"repobilityId": "da9884305232dd77", "scanner": "scanner-primary", "fingerprint": "3ab87317a90c5f7b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-618721b912bad1c2", "level": "note", "message": {"text": "Unused endpoint: POST /login"}, "properties": {"repobilityId": "05ff525f18f2b8a2", "scanner": "scanner-primary", "fingerprint": "618721b912bad1c2", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7ce17d6b092a81ca", "level": "note", "message": {"text": "Unused endpoint: POST /refresh"}, "properties": {"repobilityId": "a7d883c51dc85ec1", "scanner": "scanner-primary", "fingerprint": "7ce17d6b092a81ca", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-99fc36db98c134ce", "level": "note", "message": {"text": "Unused endpoint: POST /logout"}, "properties": {"repobilityId": "d332bbf1347161d2", "scanner": "scanner-primary", "fingerprint": "99fc36db98c134ce", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-fd1dc91abf32142d", "level": "note", "message": {"text": "Unused endpoint: GET /me"}, "properties": {"repobilityId": "862a860d37244c98", "scanner": "scanner-primary", "fingerprint": "fd1dc91abf32142d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-304b6f2b403d93f7", "level": "note", "message": {"text": "Unused endpoint: POST /register"}, "properties": {"repobilityId": "b12fba5aa5dd34ed", "scanner": "scanner-primary", "fingerprint": "304b6f2b403d93f7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4982dbfd71045a81", "level": "note", "message": {"text": "Unused endpoint: GET /topics"}, "properties": {"repobilityId": "ea33347792539dff", "scanner": "scanner-primary", "fingerprint": "4982dbfd71045a81", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8fc826700126d17f", "level": "note", "message": {"text": "Unused endpoint: GET /{indicator_id}/timeseries"}, "properties": {"repobilityId": "e7438136d9903575", "scanner": "scanner-primary", "fingerprint": "8fc826700126d17f", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-1d966dc8f33ec391", "level": "note", "message": {"text": "Unused endpoint: GET /feature-datasets"}, "properties": {"repobilityId": "1b8b829b27d2a062", "scanner": "scanner-primary", "fingerprint": "1d966dc8f33ec391", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-63a3c175ae001383", "level": "note", "message": {"text": "Unused endpoint: GET /park-ride"}, "properties": {"repobilityId": "ca3647a04f354734", "scanner": "scanner-primary", "fingerprint": "63a3c175ae001383", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4c46b7ef1858c697", "level": "note", "message": {"text": "Unused endpoint: GET /bicycle-counters"}, "properties": {"repobilityId": "77b0510183e7c818", "scanner": "scanner-primary", "fingerprint": "4c46b7ef1858c697", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a5c16de9385b8010", "level": "note", "message": {"text": "Unused endpoint: GET /restrictions"}, "properties": {"repobilityId": "1e34754253bec5cd", "scanner": "scanner-primary", "fingerprint": "a5c16de9385b8010", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-6ba4f1151029e93a", "level": "note", "message": {"text": "Unused endpoint: GET /admin-boundaries"}, "properties": {"repobilityId": "91806c05052ed42d", "scanner": "scanner-primary", "fingerprint": "6ba4f1151029e93a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-aaaadc469bb4a895", "level": "note", "message": {"text": "Unused endpoint: GET /tiles/{z}/{x}/{y}.pbf"}, "properties": {"repobilityId": "72d70716d99729df", "scanner": "scanner-primary", "fingerprint": "aaaadc469bb4a895", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d0fa9ec843598ce4", "level": "note", "message": {"text": "Unused endpoint: GET /feature/{feature_id}"}, "properties": {"repobilityId": "70f443e140ef3fbb", "scanner": "scanner-primary", "fingerprint": "d0fa9ec843598ce4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2ae65e2273f34b4e", "level": "note", "message": {"text": "Unused endpoint: GET /datasets/catalog"}, "properties": {"repobilityId": "f6433ab9e4f365b2", "scanner": "scanner-primary", "fingerprint": "2ae65e2273f34b4e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7907b981d1c474b5", "level": "note", "message": {"text": "Unused endpoint: GET /map/feature-datasets"}, "properties": {"repobilityId": "f57eab986bc1175e", "scanner": "scanner-primary", "fingerprint": "7907b981d1c474b5", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2e120c9b1a2319e0", "level": "note", "message": {"text": "Unused endpoint: GET /map/park-ride"}, "properties": {"repobilityId": "22bf282f41f222d4", "scanner": "scanner-primary", "fingerprint": "2e120c9b1a2319e0", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-31f5eafb5bd3c7b8", "level": "note", "message": {"text": "Unused endpoint: GET /map/bicycle-counters"}, "properties": {"repobilityId": "061874f435eed458", "scanner": "scanner-primary", "fingerprint": "31f5eafb5bd3c7b8", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-96ded99f2d27fb22", "level": "note", "message": {"text": "Unused endpoint: GET /map/restrictions"}, "properties": {"repobilityId": "59476a5a03405123", "scanner": "scanner-primary", "fingerprint": "96ded99f2d27fb22", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-51b96fd97d682ade", "level": "note", "message": {"text": "Unused endpoint: GET /map/admin-boundaries"}, "properties": {"repobilityId": "334f377ac7c4c258", "scanner": "scanner-primary", "fingerprint": "51b96fd97d682ade", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8c2d4e0fff184ef6", "level": "note", "message": {"text": "Unused endpoint: GET /stats/choropleth"}, "properties": {"repobilityId": "b8ec977b7f1f9b0f", "scanner": "scanner-primary", "fingerprint": "8c2d4e0fff184ef6", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-28e520cd43c3a8f2", "level": "note", "message": {"text": "Unused endpoint: GET /stats/correlation"}, "properties": {"repobilityId": "c30ac622ccd45f5b", "scanner": "scanner-primary", "fingerprint": "28e520cd43c3a8f2", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2becdf7b6c95bf68", "level": "note", "message": {"text": "Unused endpoint: GET /stats/metrics"}, "properties": {"repobilityId": "66e1e54b17c342b0", "scanner": "scanner-primary", "fingerprint": "2becdf7b6c95bf68", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5b6173f3f7bbf753", "level": "note", "message": {"text": "Unused endpoint: GET /datasets"}, "properties": {"repobilityId": "3b991654a5f83eb0", "scanner": "scanner-primary", "fingerprint": "5b6173f3f7bbf753", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-65ef25c6033de30b", "level": "note", "message": {"text": "Unused endpoint: GET /datasets/status"}, "properties": {"repobilityId": "94880d781cf4b2b7", "scanner": "scanner-primary", "fingerprint": "65ef25c6033de30b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8292c0931391749a", "level": "note", "message": {"text": "Unused endpoint: POST /auth/register"}, "properties": {"repobilityId": "893ea4610defc20c", "scanner": "scanner-primary", "fingerprint": "8292c0931391749a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}