{"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-a27bca98eb9887e0", "name": "Possibly dead Python function: upgrade", "shortDescription": {"text": "Possibly dead Python function: upgrade"}, "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-822b619fb82c402d", "name": "Possibly dead Python function: downgrade", "shortDescription": {"text": "Possibly dead Python function: downgrade"}, "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-e029de4f75910dfe", "name": "Possibly dead Python function: upgrade", "shortDescription": {"text": "Possibly dead Python function: upgrade"}, "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-12da3034afd64f6e", "name": "Possibly dead Python function: downgrade", "shortDescription": {"text": "Possibly dead Python function: downgrade"}, "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-8cb76141afc710a1", "name": "Possibly dead Python function: upgrade", "shortDescription": {"text": "Possibly dead Python function: upgrade"}, "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-c72b87d306d0e27d", "name": "Possibly dead Python function: downgrade", "shortDescription": {"text": "Possibly dead Python function: downgrade"}, "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-b4f5977998324431", "name": "Possibly dead Python function: parse_all_raw_files", "shortDescription": {"text": "Possibly dead Python function: parse_all_raw_files"}, "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-7158ffa1e9badba8", "name": "Possibly dead Python function: objective", "shortDescription": {"text": "Possibly dead Python function: objective"}, "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-2f5be84c0e5a70fb", "name": "TODO/FIXME marker in shipping code \u2014 frontend/src/firebase.ts:5", "shortDescription": {"text": "TODO/FIXME marker in shipping code \u2014 frontend/src/firebase.ts:5"}, "fullDescription": {"text": "Track in /reviews or /issues, not as a code comment that rots.\n\nWhy: Drift control \u2014 shouldn't be the same as Quality TODO scanner.\nRule id: fq.todo-marker"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-d63da3583b14afc0", "name": "Dockerfile runs as root: Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: 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-e066691601852931", "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-2c482023445423a4", "name": "Runtime dotenv file present in repo: frontend/.env.production", "shortDescription": {"text": "Runtime dotenv file present in repo: frontend/.env.production"}, "fullDescription": {"text": "`frontend/.env.production` looks like a runtime dotenv file. It contains secret-looking assignments for REACT_APP_SENTRY_DSN. Move real values to a secret manager and keep only `.env.example` style templates in source control."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "critical", "confidence": 1.0}}, {"id": "scanner-6372cebde0220094", "name": "No auth library detected", "shortDescription": {"text": "No auth library detected"}, "fullDescription": {"text": "The scanner did not find any standard auth library (JWT, OAuth, NextAuth, Auth0, etc.). The repo has auth/admin/session surface indicators, so auth may live in custom code, in a separate service, or be missing."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-4601e3ad3bb28677", "name": "No CI/CD pipelines detected", "shortDescription": {"text": "No CI/CD pipelines detected"}, "fullDescription": {"text": "No GitHub Actions, GitLab CI, or CircleCI configs found. Without CI you can't gate deploys on tests/lints."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a13efd5ec31c2c09", "name": "Very large file: backend/football/routes.py (1326 lines)", "shortDescription": {"text": "Very large file: backend/football/routes.py (1326 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-5fd9c8fc63095645", "name": "Very large file: backend/football/tests/test_routes.py (2089 lines)", "shortDescription": {"text": "Very large file: backend/football/tests/test_routes.py (2089 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "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 51 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-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-b9088664ace7f748", "name": "Composite production-readiness gap", "shortDescription": {"text": "Composite production-readiness gap"}, "fullDescription": {"text": "Multiple low-cost hardening controls are missing together: license, ci. Opus verification showed these co-occurring gaps are a better readiness signal than reading each flag in isolation."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "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, ci. 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-2f76bf4a84f41ba7", "name": "Commented-code block (5 lines) in frontend/src/football/types/prediction.ts:1", "shortDescription": {"text": "Commented-code block (5 lines) in frontend/src/football/types/prediction.ts:1"}, "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-524da66860efa8bb", "name": "Legacy-named symbol `dixon_coles_v1` in frontend/src/football/__fixtures__/sampleResponse.ts:94", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in frontend/src/football/__fixtures__/sampleResponse.ts:94"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-c0c2050696aba029", "name": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/football/hooks/useLivePolling.test.ts:184", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/football/hooks/useLivePolling.test.ts:184"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-9c8b2566364e3a0c", "name": "Commented-code block (6 lines) in frontend/src/football/hooks/useMatchPrediction.ts:102", "shortDescription": {"text": "Commented-code block (6 lines) in frontend/src/football/hooks/useMatchPrediction.ts:102"}, "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-ff53a32d6c9daea8", "name": "Commented-code block (6 lines) in frontend/src/football/hooks/useFixtures.ts:8", "shortDescription": {"text": "Commented-code block (6 lines) in frontend/src/football/hooks/useFixtures.ts:8"}, "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-6b251293546cf58a", "name": "Network/subprocess call without timeout or try/except \u2014 backend/live_data_provider.py:54", "shortDescription": {"text": "Network/subprocess call without timeout or try/except \u2014 backend/live_data_provider.py:54"}, "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-778e6ab6aee4f424", "name": "Commented-code block (5 lines) in backend/shared/settings.py:59", "shortDescription": {"text": "Commented-code block (5 lines) in backend/shared/settings.py:59"}, "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-b4ab6a395d810e18", "name": "Legacy-named symbol `derive_live_v1` in backend/football/routes.py:57", "shortDescription": {"text": "Legacy-named symbol `derive_live_v1` in backend/football/routes.py:57"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6a7f86e48d775ea3", "name": "Commented-code block (6 lines) in backend/football/routes.py:815", "shortDescription": {"text": "Commented-code block (6 lines) in backend/football/routes.py:815"}, "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-8d81fe824c5267e6", "name": "Commented-code block (5 lines) in backend/football/data_provider.py:402", "shortDescription": {"text": "Commented-code block (5 lines) in backend/football/data_provider.py:402"}, "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-be0f5255d8d577c9", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/persistence.py:276", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/persistence.py:276"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-df4462f49555a706", "name": "Commented-code block (5 lines) in backend/football/live_stats.py:199", "shortDescription": {"text": "Commented-code block (5 lines) in backend/football/live_stats.py:199"}, "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-d1dffcd469f35548", "name": "Legacy-named symbol `derive_live_v1` in backend/football/predictions/derivations.py:287", "shortDescription": {"text": "Legacy-named symbol `derive_live_v1` in backend/football/predictions/derivations.py:287"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d21ec1eb459d2f8c", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/predictions/engine.py:41", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/predictions/engine.py:41"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-06b5162f623d8d21", "name": "Legacy-named symbol `derive_live_v1` in backend/football/predictions/tests/test_predictions.py:21", "shortDescription": {"text": "Legacy-named symbol `derive_live_v1` in backend/football/predictions/tests/test_predictions.py:21"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-bd2ddd7f7a262b63", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/tests/test_routes.py:111", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/tests/test_routes.py:111"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1c631ff96945a231", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/tests/test_prewarm.py:93", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/tests/test_prewarm.py:93"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-cdcf1d55f999ef6e", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/tests/test_persistence.py:103", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/tests/test_persistence.py:103"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8069c6b48c8c8a7e", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/scripts/tests/test_compute_accuracy.py:46", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/scripts/tests/test_compute_accuracy.py:46"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-77e322f5a1681e8e", "name": "Legacy-named symbol `live_note_v1` in backend/football/agent/tests/test_live_narration.py:85", "shortDescription": {"text": "Legacy-named symbol `live_note_v1` in backend/football/agent/tests/test_live_narration.py:85"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4178c8c5e0ba4a71", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_prefetch.py:38", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_prefetch.py:38"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6178841131c3447c", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_single_shot.py:46", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_single_shot.py:46"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-335afdf1af1c27e9", "name": "Commented-code block (7 lines) in backend/football/agent/tests/test_cost_profile.py:314", "shortDescription": {"text": "Commented-code block (7 lines) in backend/football/agent/tests/test_cost_profile.py:314"}, "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-f7fc7fcbe7940e45", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_upset.py:59", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_upset.py:59"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6aac8440637b74f9", "name": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_reasoning.py:57", "shortDescription": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_reasoning.py:57"}, "fullDescription": {"text": "Names with suffixes like `_old`, `_v1`, `_deprecated` usually indicate replaced-but-not-removed code (typical AI-coder leftover). Confirm and delete, or rename if it's the active version."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-65df07ab4020db79", "name": "18 env vars used in code but missing from .env.example", "shortDescription": {"text": "18 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `ANTHROPIC_API_KEY`, `CACHE_NAMESPACE`, `CACHE_VERSION`, `CRICBUZZ_SCORECARD_ENDPOINT`, `CRICKETDATA_API_KEY`, `ENV`, `NODE_ENV`, `REACT_APP_API_URL` + 10 more. 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:\nbackend/prediction_engine_api.py:pre_match_predictions, backend/prediction_engine_api.py:live_predictions\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-be46ea126aa5d8dc", "name": "Near-duplicate function bodies in 3 places", "shortDescription": {"text": "Near-duplicate function bodies in 3 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\nbackend/live_data_provider.py:get_todays_matches_for_series, backend/live_data_provider.py:get_todays_match, backend/live_data_provider.py:get_todays_matches\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-49c98f7cedd9c977", "name": "Near-duplicate function bodies in 4 places", "shortDescription": {"text": "Near-duplicate function bodies in 4 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\nbackend/main.py:predict_winner, backend/main.py:predict_score_range, backend/main.py:predict_wickets_range, backend/main.py:predict_powerplay_range\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-c87fc0bcd4205389", "name": "Frontend route `/cricket/ipl` has no Link/navigate to it \u2014 frontend/src/App.tsx", "shortDescription": {"text": "Frontend route `/cricket/ipl` 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-7c725b4bd6912e8f", "name": "Frontend route `/cricket/t20-world-cup` has no Link/navigate to it \u2014 frontend/src/App.tsx", "shortDescription": {"text": "Frontend route `/cricket/t20-world-cup` 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-1eb1e060fcc1c7aa", "name": "Frontend route `live` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/WorldCup2026Layout.test.tsx", "shortDescription": {"text": "Frontend route `live` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/WorldCup2026Layout.test.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-ff3da518ea806f70", "name": "Frontend route `track-record` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/WorldCup2026Layout.test", "shortDescription": {"text": "Frontend route `track-record` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/WorldCup2026Layout.test.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-aa791f313976037e", "name": "Frontend route `standings` has no Link/navigate to it \u2014 frontend/src/App.tsx", "shortDescription": {"text": "Frontend route `standings` 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-e5ef1e006efc4fc7", "name": "Frontend route `knockouts` has no Link/navigate to it \u2014 frontend/src/App.tsx", "shortDescription": {"text": "Frontend route `knockouts` 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-2d268f47cbdb1950", "name": "Frontend route `/football/match/:fixtureId` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/MatchPage", "shortDescription": {"text": "Frontend route `/football/match/:fixtureId` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/MatchPage.test.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-18dba25c093b42ba", "name": "Frontend route `/test` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/SchedulePage.test.tsx", "shortDescription": {"text": "Frontend route `/test` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/SchedulePage.test.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-b08a030e81bdf55f", "name": "FastAPI POST `update_match_context_endpoint` without auth dependency \u2014 backend/main.py:170", "shortDescription": {"text": "FastAPI POST `update_match_context_endpoint` without auth dependency \u2014 backend/main.py:170"}, "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-4f6cb6479d43bd22", "name": "FastAPI POST `update_t20wc_match_context` without auth dependency \u2014 backend/main.py:194", "shortDescription": {"text": "FastAPI POST `update_t20wc_match_context` without auth dependency \u2014 backend/main.py:194"}, "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-8e0e04a1df0449e4", "name": "Unused endpoint: POST /update-match-context", "shortDescription": {"text": "Unused endpoint: POST /update-match-context"}, "fullDescription": {"text": "`backend/main.py` declares `POST /update-match-context` 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-1c3f8a5f2ed4bf7c", "name": "Unused endpoint: POST /t20wc/update-match-context", "shortDescription": {"text": "Unused endpoint: POST /t20wc/update-match-context"}, "fullDescription": {"text": "`backend/main.py` declares `POST /t20wc/update-match-context` 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-b8ecc43cb29112a1", "name": "Unused endpoint: GET /matches", "shortDescription": {"text": "Unused endpoint: GET /matches"}, "fullDescription": {"text": "`backend/main.py` declares `GET /matches` 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-f71ec32783394200", "name": "Unused endpoint: GET /t20wc/matches", "shortDescription": {"text": "Unused endpoint: GET /t20wc/matches"}, "fullDescription": {"text": "`backend/main.py` declares `GET /t20wc/matches` 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-916a90de49d0057e", "name": "Unused endpoint: GET /predict/pre-match", "shortDescription": {"text": "Unused endpoint: GET /predict/pre-match"}, "fullDescription": {"text": "`backend/main.py` declares `GET /predict/pre-match` 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-d9cb47288b13079c", "name": "Unused endpoint: GET /predict/live", "shortDescription": {"text": "Unused endpoint: GET /predict/live"}, "fullDescription": {"text": "`backend/main.py` declares `GET /predict/live` 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-bb2ec537b9029aef", "name": "Unused endpoint: GET /predict/winner", "shortDescription": {"text": "Unused endpoint: GET /predict/winner"}, "fullDescription": {"text": "`backend/main.py` declares `GET /predict/winner` 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-38faf25ce98a7383", "name": "Unused endpoint: GET /predict/score", "shortDescription": {"text": "Unused endpoint: GET /predict/score"}, "fullDescription": {"text": "`backend/main.py` declares `GET /predict/score` 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-164632ebb565b3d6", "name": "Unused endpoint: GET /predict/wickets", "shortDescription": {"text": "Unused endpoint: GET /predict/wickets"}, "fullDescription": {"text": "`backend/main.py` declares `GET /predict/wickets` 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-f0fc9cf0a1f895a4", "name": "Unused endpoint: GET /predict/powerplay", "shortDescription": {"text": "Unused endpoint: GET /predict/powerplay"}, "fullDescription": {"text": "`backend/main.py` declares `GET /predict/powerplay` 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-afd8c5d7d4e32d91", "name": "Unused endpoint: GET /t20wc/predict/winner", "shortDescription": {"text": "Unused endpoint: GET /t20wc/predict/winner"}, "fullDescription": {"text": "`backend/main.py` declares `GET /t20wc/predict/winner` 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-34223c73f6979b06", "name": "Unused endpoint: GET /t20wc/predict/score", "shortDescription": {"text": "Unused endpoint: GET /t20wc/predict/score"}, "fullDescription": {"text": "`backend/main.py` declares `GET /t20wc/predict/score` 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-5a0c78933a11fd30", "name": "Unused endpoint: GET /t20wc/predict/wickets", "shortDescription": {"text": "Unused endpoint: GET /t20wc/predict/wickets"}, "fullDescription": {"text": "`backend/main.py` declares `GET /t20wc/predict/wickets` 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-22f4259b77dede15", "name": "Unused endpoint: GET /t20wc/predict/powerplay", "shortDescription": {"text": "Unused endpoint: GET /t20wc/predict/powerplay"}, "fullDescription": {"text": "`backend/main.py` declares `GET /t20wc/predict/powerplay` 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-d4f30be717232cf4", "name": "Unused endpoint: GET /t20wc/predict/live", "shortDescription": {"text": "Unused endpoint: GET /t20wc/predict/live"}, "fullDescription": {"text": "`backend/main.py` declares `GET /t20wc/predict/live` 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/main.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-c1b72039c6338063", "name": "Unused endpoint: GET /fixtures", "shortDescription": {"text": "Unused endpoint: GET /fixtures"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /fixtures` 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-b2ac6334175384b3", "name": "Unused endpoint: GET /fixtures/rounds", "shortDescription": {"text": "Unused endpoint: GET /fixtures/rounds"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /fixtures/rounds` 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-94f46778dbacd267", "name": "Unused endpoint: GET /fixtures/{fixture_id}", "shortDescription": {"text": "Unused endpoint: GET /fixtures/{fixture_id}"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /fixtures/{fixture_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-6fc0caa269292c44", "name": "Unused endpoint: GET /coverage", "shortDescription": {"text": "Unused endpoint: GET /coverage"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /coverage` 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-fa5ca8f5ddd49bd7", "name": "Unused endpoint: GET /standings", "shortDescription": {"text": "Unused endpoint: GET /standings"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /standings` 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-5b87f452fc16ed41", "name": "Unused endpoint: GET /head-to-head", "shortDescription": {"text": "Unused endpoint: GET /head-to-head"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /head-to-head` 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-078960b9f507bc18", "name": "Unused endpoint: GET /upsets", "shortDescription": {"text": "Unused endpoint: GET /upsets"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /upsets` 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-d30c5f99d4960b4a", "name": "Unused endpoint: GET /predict/pre-match/{fixture_id}", "shortDescription": {"text": "Unused endpoint: GET /predict/pre-match/{fixture_id}"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /predict/pre-match/{fixture_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-673abf4c36b45a04", "name": "Unused endpoint: GET /predict/live/{fixture_id}", "shortDescription": {"text": "Unused endpoint: GET /predict/live/{fixture_id}"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /predict/live/{fixture_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-22043c4d6ebd13bd", "name": "Unused endpoint: GET /predict/reasoning/{fixture_id}", "shortDescription": {"text": "Unused endpoint: GET /predict/reasoning/{fixture_id}"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /predict/reasoning/{fixture_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-b97c7994467ea7f6", "name": "Unused endpoint: GET /predictions/history/{fixture_id}", "shortDescription": {"text": "Unused endpoint: GET /predictions/history/{fixture_id}"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /predictions/history/{fixture_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-a20634ec0c061386", "name": "Unused endpoint: GET /accuracy", "shortDescription": {"text": "Unused endpoint: GET /accuracy"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /accuracy` 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-3842558ecfad92dc", "name": "Unused endpoint: GET /accuracy/matches", "shortDescription": {"text": "Unused endpoint: GET /accuracy/matches"}, "fullDescription": {"text": "`backend/football/routes.py` declares `GET /accuracy/matches` 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-498e5eeecf0ec443", "name": "Unused endpoint: POST /admin/prewarm/upcoming", "shortDescription": {"text": "Unused endpoint: POST /admin/prewarm/upcoming"}, "fullDescription": {"text": "`backend/football/routes.py` declares `POST /admin/prewarm/upcoming` 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/20257"}, "properties": {"repository": "stata1991/sportspredictor", "repoUrl": "https://github.com/stata1991/sportspredictor", "branch": "main"}, "results": [{"ruleId": "scanner-a27bca98eb9887e0", "level": "note", "message": {"text": "Possibly dead Python function: upgrade"}, "properties": {"repobilityId": "cf0b8e5e6e2f8bc4", "scanner": "scanner-primary", "fingerprint": "a27bca98eb9887e0", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/shared/alembic/versions/0001_create_football_schema.py:21"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-822b619fb82c402d", "level": "note", "message": {"text": "Possibly dead Python function: downgrade"}, "properties": {"repobilityId": "c03debbf11efa0c5", "scanner": "scanner-primary", "fingerprint": "822b619fb82c402d", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/shared/alembic/versions/0001_create_football_schema.py:108"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-e029de4f75910dfe", "level": "note", "message": {"text": "Possibly dead Python function: upgrade"}, "properties": {"repobilityId": "cf0b8e5e6e2f8bc4", "scanner": "scanner-primary", "fingerprint": "e029de4f75910dfe", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/shared/alembic/versions/0002_nullable_ht_outcome_columns.py:23"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-12da3034afd64f6e", "level": "note", "message": {"text": "Possibly dead Python function: downgrade"}, "properties": {"repobilityId": "c03debbf11efa0c5", "scanner": "scanner-primary", "fingerprint": "12da3034afd64f6e", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/shared/alembic/versions/0002_nullable_ht_outcome_columns.py:40"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-8cb76141afc710a1", "level": "note", "message": {"text": "Possibly dead Python function: upgrade"}, "properties": {"repobilityId": "cf0b8e5e6e2f8bc4", "scanner": "scanner-primary", "fingerprint": "8cb76141afc710a1", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/shared/alembic/versions/0003_add_round_to_outcomes.py:25"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-c72b87d306d0e27d", "level": "note", "message": {"text": "Possibly dead Python function: downgrade"}, "properties": {"repobilityId": "c03debbf11efa0c5", "scanner": "scanner-primary", "fingerprint": "c72b87d306d0e27d", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/shared/alembic/versions/0003_add_round_to_outcomes.py:33"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-b4f5977998324431", "level": "note", "message": {"text": "Possibly dead Python function: parse_all_raw_files"}, "properties": {"repobilityId": "91261b2c0f0cf4e6", "scanner": "scanner-primary", "fingerprint": "b4f5977998324431", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/football/historical/parser.py:124"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-7158ffa1e9badba8", "level": "note", "message": {"text": "Possibly dead Python function: objective"}, "properties": {"repobilityId": "b2ca8f96950eb149", "scanner": "scanner-primary", "fingerprint": "7158ffa1e9badba8", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/football/models/dixon_coles.py:486"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-2f5be84c0e5a70fb", "level": "none", "message": {"text": "TODO/FIXME marker in shipping code \u2014 frontend/src/firebase.ts:5"}, "properties": {"repobilityId": "d5eb7963ce88387f", "scanner": "scanner-primary", "fingerprint": "2f5be84c0e5a70fb", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.todo-marker"]}}, {"ruleId": "scanner-d63da3583b14afc0", "level": "warning", "message": {"text": "Dockerfile runs as root: Dockerfile"}, "properties": {"repobilityId": "a2ed1bd120e507db", "scanner": "scanner-primary", "fingerprint": "d63da3583b14afc0", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-e066691601852931", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.11-slim"}, "properties": {"repobilityId": "f391052c9bfd7e8b", "scanner": "scanner-primary", "fingerprint": "e066691601852931", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "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-2c482023445423a4", "level": "error", "message": {"text": "Runtime dotenv file present in repo: frontend/.env.production"}, "properties": {"repobilityId": "f727d22a89e309c5", "scanner": "scanner-primary", "fingerprint": "2c482023445423a4", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets", "config", "env-file", "runtime-env", "env_file_with_secret"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/.env.production"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-6372cebde0220094", "level": "warning", "message": {"text": "No auth library detected"}, "properties": {"repobilityId": "a5b6035a5bbf8054", "scanner": "scanner-primary", "fingerprint": "6372cebde0220094", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["coverage", "auth"]}}, {"ruleId": "scanner-4601e3ad3bb28677", "level": "warning", "message": {"text": "No CI/CD pipelines detected"}, "properties": {"repobilityId": "c3ee439bce2bc51e", "scanner": "scanner-primary", "fingerprint": "4601e3ad3bb28677", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["coverage"]}}, {"ruleId": "scanner-a13efd5ec31c2c09", "level": "note", "message": {"text": "Very large file: backend/football/routes.py (1326 lines)"}, "properties": {"repobilityId": "f93179bbbf3af09b", "scanner": "scanner-primary", "fingerprint": "a13efd5ec31c2c09", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-5fd9c8fc63095645", "level": "note", "message": {"text": "Very large file: backend/football/tests/test_routes.py (2089 lines)"}, "properties": {"repobilityId": "1be5122b156b8bda", "scanner": "scanner-primary", "fingerprint": "5fd9c8fc63095645", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "e06a3d42a7b86709", "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": "ea0afeef3dbbd3e6", "scanner": "scanner-primary", "fingerprint": "3ab5d313dda8e5f9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["debug", "cleanup", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-2d0c7b7ab8f8aacf", "level": "warning", "message": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "properties": {"repobilityId": "3bf0a828cd61ab32", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-b9088664ace7f748", "level": "note", "message": {"text": "Composite production-readiness gap"}, "properties": {"repobilityId": "6b28444331dd820b", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-749d4bc1bd66df5f", "level": "warning", "message": {"text": "Agent instructions exist but release-hardening basics are missing"}, "properties": {"repobilityId": "91b0da3a33e671ca", "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": "41c935a96474a5c8", "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": "3d4860aec6e94eb4", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-2f76bf4a84f41ba7", "level": "none", "message": {"text": "Commented-code block (5 lines) in frontend/src/football/types/prediction.ts:1"}, "properties": {"repobilityId": "279a86b4075968e3", "scanner": "scanner-primary", "fingerprint": "2f76bf4a84f41ba7", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-524da66860efa8bb", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in frontend/src/football/__fixtures__/sampleResponse.ts:94"}, "properties": {"repobilityId": "308a5ced2e581fff", "scanner": "scanner-primary", "fingerprint": "524da66860efa8bb", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-c0c2050696aba029", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/football/hooks/useLivePolling.test.ts:184"}, "properties": {"repobilityId": "0a194fe60990996d", "scanner": "scanner-primary", "fingerprint": "c0c2050696aba029", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-9c8b2566364e3a0c", "level": "none", "message": {"text": "Commented-code block (6 lines) in frontend/src/football/hooks/useMatchPrediction.ts:102"}, "properties": {"repobilityId": "03131b2963b21b7c", "scanner": "scanner-primary", "fingerprint": "9c8b2566364e3a0c", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-ff53a32d6c9daea8", "level": "none", "message": {"text": "Commented-code block (6 lines) in frontend/src/football/hooks/useFixtures.ts:8"}, "properties": {"repobilityId": "15311f0256937c8b", "scanner": "scanner-primary", "fingerprint": "ff53a32d6c9daea8", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-6b251293546cf58a", "level": "warning", "message": {"text": "Network/subprocess call without timeout or try/except \u2014 backend/live_data_provider.py:54"}, "properties": {"repobilityId": "a83b6217972d6fa1", "scanner": "scanner-primary", "fingerprint": "6b251293546cf58a", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-778e6ab6aee4f424", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/shared/settings.py:59"}, "properties": {"repobilityId": "5324c8d70b9ca63a", "scanner": "scanner-primary", "fingerprint": "778e6ab6aee4f424", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-b4ab6a395d810e18", "level": "note", "message": {"text": "Legacy-named symbol `derive_live_v1` in backend/football/routes.py:57"}, "properties": {"repobilityId": "1052a4dff57c1ca6", "scanner": "scanner-primary", "fingerprint": "b4ab6a395d810e18", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-6a7f86e48d775ea3", "level": "none", "message": {"text": "Commented-code block (6 lines) in backend/football/routes.py:815"}, "properties": {"repobilityId": "d1e1da63de953006", "scanner": "scanner-primary", "fingerprint": "6a7f86e48d775ea3", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-8d81fe824c5267e6", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/football/data_provider.py:402"}, "properties": {"repobilityId": "5b72c3eff743c775", "scanner": "scanner-primary", "fingerprint": "8d81fe824c5267e6", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-be0f5255d8d577c9", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/persistence.py:276"}, "properties": {"repobilityId": "2c1a82c4c7e91a03", "scanner": "scanner-primary", "fingerprint": "be0f5255d8d577c9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-df4462f49555a706", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/football/live_stats.py:199"}, "properties": {"repobilityId": "50eec34dac7c94ab", "scanner": "scanner-primary", "fingerprint": "df4462f49555a706", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-d1dffcd469f35548", "level": "note", "message": {"text": "Legacy-named symbol `derive_live_v1` in backend/football/predictions/derivations.py:287"}, "properties": {"repobilityId": "3dc88ded952441a5", "scanner": "scanner-primary", "fingerprint": "d1dffcd469f35548", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-d21ec1eb459d2f8c", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/predictions/engine.py:41"}, "properties": {"repobilityId": "cc0f216c2319334a", "scanner": "scanner-primary", "fingerprint": "d21ec1eb459d2f8c", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-06b5162f623d8d21", "level": "note", "message": {"text": "Legacy-named symbol `derive_live_v1` in backend/football/predictions/tests/test_predictions.py:21"}, "properties": {"repobilityId": "b6098511dabaaa75", "scanner": "scanner-primary", "fingerprint": "06b5162f623d8d21", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-bd2ddd7f7a262b63", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/tests/test_routes.py:111"}, "properties": {"repobilityId": "a435085abaf3b08e", "scanner": "scanner-primary", "fingerprint": "bd2ddd7f7a262b63", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-1c631ff96945a231", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/tests/test_prewarm.py:93"}, "properties": {"repobilityId": "3e0129e151e7de39", "scanner": "scanner-primary", "fingerprint": "1c631ff96945a231", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-cdcf1d55f999ef6e", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/tests/test_persistence.py:103"}, "properties": {"repobilityId": "a0ca73c7db3b59a8", "scanner": "scanner-primary", "fingerprint": "cdcf1d55f999ef6e", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-8069c6b48c8c8a7e", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/scripts/tests/test_compute_accuracy.py:46"}, "properties": {"repobilityId": "dfaaaf792cb72867", "scanner": "scanner-primary", "fingerprint": "8069c6b48c8c8a7e", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-77e322f5a1681e8e", "level": "note", "message": {"text": "Legacy-named symbol `live_note_v1` in backend/football/agent/tests/test_live_narration.py:85"}, "properties": {"repobilityId": "33f1963d42259477", "scanner": "scanner-primary", "fingerprint": "77e322f5a1681e8e", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-4178c8c5e0ba4a71", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_prefetch.py:38"}, "properties": {"repobilityId": "f1733ba34cbbc21a", "scanner": "scanner-primary", "fingerprint": "4178c8c5e0ba4a71", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-6178841131c3447c", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_single_shot.py:46"}, "properties": {"repobilityId": "522dda29a78359c1", "scanner": "scanner-primary", "fingerprint": "6178841131c3447c", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-335afdf1af1c27e9", "level": "none", "message": {"text": "Commented-code block (7 lines) in backend/football/agent/tests/test_cost_profile.py:314"}, "properties": {"repobilityId": "32bc61bf6ea63119", "scanner": "scanner-primary", "fingerprint": "335afdf1af1c27e9", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-f7fc7fcbe7940e45", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_upset.py:59"}, "properties": {"repobilityId": "8224080d4d3c2bed", "scanner": "scanner-primary", "fingerprint": "f7fc7fcbe7940e45", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-6aac8440637b74f9", "level": "note", "message": {"text": "Legacy-named symbol `dixon_coles_v1` in backend/football/agent/tests/test_reasoning.py:57"}, "properties": {"repobilityId": "4fb2e6077d2ce0fd", "scanner": "scanner-primary", "fingerprint": "6aac8440637b74f9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-65df07ab4020db79", "level": "note", "message": {"text": "18 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "5e334d56f52c02e1", "scanner": "scanner-primary", "fingerprint": "65df07ab4020db79", "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": "26f64993771513f2", "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": "d8929ccb111f4d58", "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": "153192b43d33e55b", "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": "fb455adb8f8d87f2", "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": "fdde26d07ac851ed", "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": "8fb4bcb2b657babf", "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": "7d04d2862773fe8e", "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": "6f662f9b635c9bc5", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-be46ea126aa5d8dc", "level": "note", "message": {"text": "Near-duplicate function bodies in 3 places"}, "properties": {"repobilityId": "10b1dc1f937241fd", "scanner": "scanner-primary", "fingerprint": "be46ea126aa5d8dc", "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": "030a1e1e3aa33231", "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": "d12e58d7f726e4ad", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-49c98f7cedd9c977", "level": "note", "message": {"text": "Near-duplicate function bodies in 4 places"}, "properties": {"repobilityId": "91db393492496bd1", "scanner": "scanner-primary", "fingerprint": "49c98f7cedd9c977", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-49c98f7cedd9c977", "level": "note", "message": {"text": "Near-duplicate function bodies in 4 places"}, "properties": {"repobilityId": "e31ff568232ae629", "scanner": "scanner-primary", "fingerprint": "49c98f7cedd9c977", "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": "690cbf406bf1e44f", "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": "42bc4578a6a2ac5d", "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": "336147c464d825d4", "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": "f30c91f5fb7bad5b", "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": "b4cd0aa02ff8cde1", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-c87fc0bcd4205389", "level": "warning", "message": {"text": "Frontend route `/cricket/ipl` has no Link/navigate to it \u2014 frontend/src/App.tsx"}, "properties": {"repobilityId": "2c9b77df2a231b5c", "scanner": "scanner-primary", "fingerprint": "c87fc0bcd4205389", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-7c725b4bd6912e8f", "level": "warning", "message": {"text": "Frontend route `/cricket/t20-world-cup` has no Link/navigate to it \u2014 frontend/src/App.tsx"}, "properties": {"repobilityId": "eb8a8d5ec1e4cc82", "scanner": "scanner-primary", "fingerprint": "7c725b4bd6912e8f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-1eb1e060fcc1c7aa", "level": "warning", "message": {"text": "Frontend route `live` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/WorldCup2026Layout.test.tsx"}, "properties": {"repobilityId": "71df785acab02804", "scanner": "scanner-primary", "fingerprint": "1eb1e060fcc1c7aa", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-ff3da518ea806f70", "level": "warning", "message": {"text": "Frontend route `track-record` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/WorldCup2026Layout.test.tsx"}, "properties": {"repobilityId": "3668dc682f161d80", "scanner": "scanner-primary", "fingerprint": "ff3da518ea806f70", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-aa791f313976037e", "level": "warning", "message": {"text": "Frontend route `standings` has no Link/navigate to it \u2014 frontend/src/App.tsx"}, "properties": {"repobilityId": "6b824cf577c13212", "scanner": "scanner-primary", "fingerprint": "aa791f313976037e", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-e5ef1e006efc4fc7", "level": "warning", "message": {"text": "Frontend route `knockouts` has no Link/navigate to it \u2014 frontend/src/App.tsx"}, "properties": {"repobilityId": "094f007db538676e", "scanner": "scanner-primary", "fingerprint": "e5ef1e006efc4fc7", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-2d268f47cbdb1950", "level": "warning", "message": {"text": "Frontend route `/football/match/:fixtureId` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/MatchPage.test.tsx"}, "properties": {"repobilityId": "40f22bcb31befc98", "scanner": "scanner-primary", "fingerprint": "2d268f47cbdb1950", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-18dba25c093b42ba", "level": "warning", "message": {"text": "Frontend route `/test` has no Link/navigate to it \u2014 frontend/src/pages/football/__tests__/SchedulePage.test.tsx"}, "properties": {"repobilityId": "6d42c91dd61a7fc4", "scanner": "scanner-primary", "fingerprint": "18dba25c093b42ba", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-b08a030e81bdf55f", "level": "error", "message": {"text": "FastAPI POST `update_match_context_endpoint` without auth dependency \u2014 backend/main.py:170"}, "properties": {"repobilityId": "662722ca284ff064", "scanner": "scanner-primary", "fingerprint": "b08a030e81bdf55f", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/main.py"}, "region": {"startLine": 170}}}]}, {"ruleId": "scanner-4f6cb6479d43bd22", "level": "error", "message": {"text": "FastAPI POST `update_t20wc_match_context` without auth dependency \u2014 backend/main.py:194"}, "properties": {"repobilityId": "5570ccdd93c5d9c9", "scanner": "scanner-primary", "fingerprint": "4f6cb6479d43bd22", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/main.py"}, "region": {"startLine": 194}}}]}, {"ruleId": "scanner-8e0e04a1df0449e4", "level": "note", "message": {"text": "Unused endpoint: POST /update-match-context"}, "properties": {"repobilityId": "e705a27db1cb081c", "scanner": "scanner-primary", "fingerprint": "8e0e04a1df0449e4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-1c3f8a5f2ed4bf7c", "level": "note", "message": {"text": "Unused endpoint: POST /t20wc/update-match-context"}, "properties": {"repobilityId": "ed6a2a1afce568ff", "scanner": "scanner-primary", "fingerprint": "1c3f8a5f2ed4bf7c", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-b8ecc43cb29112a1", "level": "note", "message": {"text": "Unused endpoint: GET /matches"}, "properties": {"repobilityId": "084feef3dcd547f9", "scanner": "scanner-primary", "fingerprint": "b8ecc43cb29112a1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f71ec32783394200", "level": "note", "message": {"text": "Unused endpoint: GET /t20wc/matches"}, "properties": {"repobilityId": "11ce0035fc05c907", "scanner": "scanner-primary", "fingerprint": "f71ec32783394200", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-916a90de49d0057e", "level": "note", "message": {"text": "Unused endpoint: GET /predict/pre-match"}, "properties": {"repobilityId": "8a1bd2f2b9fd6255", "scanner": "scanner-primary", "fingerprint": "916a90de49d0057e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d9cb47288b13079c", "level": "note", "message": {"text": "Unused endpoint: GET /predict/live"}, "properties": {"repobilityId": "38113d0ad1f5b941", "scanner": "scanner-primary", "fingerprint": "d9cb47288b13079c", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-bb2ec537b9029aef", "level": "note", "message": {"text": "Unused endpoint: GET /predict/winner"}, "properties": {"repobilityId": "da18ab36b828b758", "scanner": "scanner-primary", "fingerprint": "bb2ec537b9029aef", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-38faf25ce98a7383", "level": "note", "message": {"text": "Unused endpoint: GET /predict/score"}, "properties": {"repobilityId": "5dfbcc8877072eff", "scanner": "scanner-primary", "fingerprint": "38faf25ce98a7383", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-164632ebb565b3d6", "level": "note", "message": {"text": "Unused endpoint: GET /predict/wickets"}, "properties": {"repobilityId": "d7214622fa9d7437", "scanner": "scanner-primary", "fingerprint": "164632ebb565b3d6", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f0fc9cf0a1f895a4", "level": "note", "message": {"text": "Unused endpoint: GET /predict/powerplay"}, "properties": {"repobilityId": "9ede491d35e64b39", "scanner": "scanner-primary", "fingerprint": "f0fc9cf0a1f895a4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-afd8c5d7d4e32d91", "level": "note", "message": {"text": "Unused endpoint: GET /t20wc/predict/winner"}, "properties": {"repobilityId": "329d58c24e658348", "scanner": "scanner-primary", "fingerprint": "afd8c5d7d4e32d91", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-34223c73f6979b06", "level": "note", "message": {"text": "Unused endpoint: GET /t20wc/predict/score"}, "properties": {"repobilityId": "f60dd59505077683", "scanner": "scanner-primary", "fingerprint": "34223c73f6979b06", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5a0c78933a11fd30", "level": "note", "message": {"text": "Unused endpoint: GET /t20wc/predict/wickets"}, "properties": {"repobilityId": "730a61ec52d0d4f7", "scanner": "scanner-primary", "fingerprint": "5a0c78933a11fd30", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-22f4259b77dede15", "level": "note", "message": {"text": "Unused endpoint: GET /t20wc/predict/powerplay"}, "properties": {"repobilityId": "71a28fda4f81bcfe", "scanner": "scanner-primary", "fingerprint": "22f4259b77dede15", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d4f30be717232cf4", "level": "note", "message": {"text": "Unused endpoint: GET /t20wc/predict/live"}, "properties": {"repobilityId": "f099173fd2baf9be", "scanner": "scanner-primary", "fingerprint": "d4f30be717232cf4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5baa8971ebe192a1", "level": "note", "message": {"text": "Unused endpoint: GET /"}, "properties": {"repobilityId": "9266ee3970fba636", "scanner": "scanner-primary", "fingerprint": "5baa8971ebe192a1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-c1b72039c6338063", "level": "note", "message": {"text": "Unused endpoint: GET /fixtures"}, "properties": {"repobilityId": "453bad20a5ab78b6", "scanner": "scanner-primary", "fingerprint": "c1b72039c6338063", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-b2ac6334175384b3", "level": "note", "message": {"text": "Unused endpoint: GET /fixtures/rounds"}, "properties": {"repobilityId": "b464a346ed20fa20", "scanner": "scanner-primary", "fingerprint": "b2ac6334175384b3", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-94f46778dbacd267", "level": "note", "message": {"text": "Unused endpoint: GET /fixtures/{fixture_id}"}, "properties": {"repobilityId": "15160e544955d7fc", "scanner": "scanner-primary", "fingerprint": "94f46778dbacd267", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-6fc0caa269292c44", "level": "note", "message": {"text": "Unused endpoint: GET /coverage"}, "properties": {"repobilityId": "5bf059d05551d1b5", "scanner": "scanner-primary", "fingerprint": "6fc0caa269292c44", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-fa5ca8f5ddd49bd7", "level": "note", "message": {"text": "Unused endpoint: GET /standings"}, "properties": {"repobilityId": "95b7959265011402", "scanner": "scanner-primary", "fingerprint": "fa5ca8f5ddd49bd7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5b87f452fc16ed41", "level": "note", "message": {"text": "Unused endpoint: GET /head-to-head"}, "properties": {"repobilityId": "eec7bba06737e03c", "scanner": "scanner-primary", "fingerprint": "5b87f452fc16ed41", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-078960b9f507bc18", "level": "note", "message": {"text": "Unused endpoint: GET /upsets"}, "properties": {"repobilityId": "c4b686325bdc8f74", "scanner": "scanner-primary", "fingerprint": "078960b9f507bc18", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d30c5f99d4960b4a", "level": "note", "message": {"text": "Unused endpoint: GET /predict/pre-match/{fixture_id}"}, "properties": {"repobilityId": "3f01c1572625540f", "scanner": "scanner-primary", "fingerprint": "d30c5f99d4960b4a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-673abf4c36b45a04", "level": "note", "message": {"text": "Unused endpoint: GET /predict/live/{fixture_id}"}, "properties": {"repobilityId": "7c74db0554d5e2ff", "scanner": "scanner-primary", "fingerprint": "673abf4c36b45a04", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-22043c4d6ebd13bd", "level": "note", "message": {"text": "Unused endpoint: GET /predict/reasoning/{fixture_id}"}, "properties": {"repobilityId": "d8709e08318d5ff2", "scanner": "scanner-primary", "fingerprint": "22043c4d6ebd13bd", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-b97c7994467ea7f6", "level": "note", "message": {"text": "Unused endpoint: GET /predictions/history/{fixture_id}"}, "properties": {"repobilityId": "0c2fc133e03c3ef7", "scanner": "scanner-primary", "fingerprint": "b97c7994467ea7f6", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a20634ec0c061386", "level": "note", "message": {"text": "Unused endpoint: GET /accuracy"}, "properties": {"repobilityId": "45bb7405f873d64a", "scanner": "scanner-primary", "fingerprint": "a20634ec0c061386", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-3842558ecfad92dc", "level": "note", "message": {"text": "Unused endpoint: GET /accuracy/matches"}, "properties": {"repobilityId": "eb33da19d4b1263d", "scanner": "scanner-primary", "fingerprint": "3842558ecfad92dc", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-498e5eeecf0ec443", "level": "note", "message": {"text": "Unused endpoint: POST /admin/prewarm/upcoming"}, "properties": {"repobilityId": "732cab9db39c8dc9", "scanner": "scanner-primary", "fingerprint": "498e5eeecf0ec443", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}