{"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-5faa19b6c99d17f1", "name": "Possibly dead Python function: rate_limit_assistant", "shortDescription": {"text": "Possibly dead Python function: rate_limit_assistant"}, "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-f3067be91193a700", "name": "Possibly dead Python function: rate_limit_predictions", "shortDescription": {"text": "Possibly dead Python function: rate_limit_predictions"}, "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-98db33927b63aa5f", "name": "Possibly dead Python function: rate_limit_public", "shortDescription": {"text": "Possibly dead Python function: rate_limit_public"}, "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-08b50d50d5af0da7", "name": "Possibly dead Python function: require_pro", "shortDescription": {"text": "Possibly dead Python function: require_pro"}, "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-174cec2978aa0005", "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-ba03ac89ab9b22e3", "name": "Possibly dead Python function: push_alert_to_user", "shortDescription": {"text": "Possibly dead Python function: push_alert_to_user"}, "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-ed5f555715ab8b4a", "name": "Possibly dead Python function: work", "shortDescription": {"text": "Possibly dead Python function: work"}, "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-01beba283de1c64d", "name": "Possibly dead Python function: retry_async", "shortDescription": {"text": "Possibly dead Python function: retry_async"}, "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-b9ec3d41a6163ee7", "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-68506be352d39d46", "name": "Possibly dead Python function: save_temps_passage", "shortDescription": {"text": "Possibly dead Python function: save_temps_passage"}, "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-b4ee751e48e20e93", "name": "Possibly dead Python function: should_retrain", "shortDescription": {"text": "Possibly dead Python function: should_retrain"}, "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-da6f507c005a04b3", "name": "Possibly dead Python function: compute_features_for_participation", "shortDescription": {"text": "Possibly dead Python function: compute_features_for_participation"}, "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-d3b6dd8ceb03fafd", "name": "Possibly dead Python function: latest_edge_monitor", "shortDescription": {"text": "Possibly dead Python function: latest_edge_monitor"}, "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-587c20a6de361d3c", "name": "Possibly dead Python function: cout_combo", "shortDescription": {"text": "Possibly dead Python function: cout_combo"}, "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-f149ddca01ecd60b", "name": "Possibly dead Python function: p_tierce_ordre", "shortDescription": {"text": "Possibly dead Python function: p_tierce_ordre"}, "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-81357793be611e3d", "name": "Possibly dead Python function: optimize_multi_race_portfolio", "shortDescription": {"text": "Possibly dead Python function: optimize_multi_race_portfolio"}, "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-478ceb6d2e3453ac", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/layout/Navbar.tsx:90", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/layout/Navbar.tsx:90"}, "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-a11a79880aaf27a3", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/page.tsx:202", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/page.tsx:202"}, "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-4939e8bd9e17f5b6", "name": "Stray `console.log` in TS/JS \u2014 frontend/src/app/layout.tsx:95", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 frontend/src/app/layout.tsx:95"}, "fullDescription": {"text": "Replace with the toast helper, an error boundary, or remove. `console.warn` / `console.error` are acceptable.\n\nWhy: Hygiene \u2014 easy to leak debug output.\nRule id: fq.console-leak"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8b84df45e27b72e6", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/admin/page.tsx:298", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/admin/page.tsx:298"}, "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-b2b671dc2d1898ad", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/admin/algorithme/page.tsx:398", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/admin/algorithme/page.tsx:398"}, "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-87fb26f8ac8705c8", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/recherche/page.tsx:115", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/recherche/page.tsx:115"}, "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-de4bb957d81a1c0f", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/chevaux/[id]/page.tsx:474", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/chevaux/[id]/page.tsx:474"}, "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-a070d5c394c25b69", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/dashboard/page.tsx:230", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/dashboard/page.tsx:230"}, "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-1bdf0fc1d898e7ed", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/value-bets/page.tsx:117", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/value-bets/page.tsx:117"}, "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-8e40479f71aad31d", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/track-record/page.tsx:142", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/track-record/page.tsx:142"}, "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-e7e117dc1e9c5f4a", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/statistiques/page.tsx:122", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/statistiques/page.tsx:122"}, "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-b9ac3bb8664efd67", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/courses/[id]/page.tsx:914", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/courses/[id]/page.tsx:914"}, "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-8a6445873c5e188d", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/jockeys/[id]/page.tsx:293", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/jockeys/[id]/page.tsx:293"}, "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-f0e76350242b1488", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/programme/page.tsx:444", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/programme/page.tsx:444"}, "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-5997060157770591", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/profil/page.tsx:230", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/profil/page.tsx:230"}, "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-f15f11283ea861b2", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/bankroll/page.tsx:515", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/bankroll/page.tsx:515"}, "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-faa134129e5545ff", "name": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-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-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-714c31ca9f474ae6", "name": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-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-e48802eb33362e96", "name": "Insecure pattern 'local_storage_auth_token' in frontend/src/lib/api.ts:41", "shortDescription": {"text": "Insecure pattern 'local_storage_auth_token' in frontend/src/lib/api.ts:41"}, "fullDescription": {"text": "Found a known-risky pattern (local_storage_auth_token). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-ae6fb0091580ae52", "name": "Insecure pattern 'local_storage_auth_token' in frontend/src/lib/auth.ts:27", "shortDescription": {"text": "Insecure pattern 'local_storage_auth_token' in frontend/src/lib/auth.ts:27"}, "fullDescription": {"text": "Found a known-risky pattern (local_storage_auth_token). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "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": "docker/login-action@v3 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": "medium", "confidence": 1.0}}, {"id": "scanner-ad6701f0a8405e22", "name": "GitHub Actions workflow grants broad write permissions", "shortDescription": {"text": "GitHub Actions workflow grants broad write permissions"}, "fullDescription": {"text": "CI tokens with write permissions increase blast radius when an action, dependency, or PR workflow is compromised. Prefer job-level least-privilege permissions."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-27924aa79fa4a517", "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@v5 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-5cbdea4030768ad0", "name": "Very large file: frontend/src/app/(main)/courses/[id]/page.tsx (2759 lines)", "shortDescription": {"text": "Very large file: frontend/src/app/(main)/courses/[id]/page.tsx (2759 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-74b60fe486e13149", "name": "Very large file: backend/api/routes/admin.py (1374 lines)", "shortDescription": {"text": "Very large file: backend/api/routes/admin.py (1374 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-9d695a757c189164", "name": "Very large file: backend/api/routes/courses.py (2238 lines)", "shortDescription": {"text": "Very large file: backend/api/routes/courses.py (2238 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-79f8c21cda77f9e6", "name": "Very large file: backend/ml/features.py (2329 lines)", "shortDescription": {"text": "Very large file: backend/ml/features.py (2329 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-ba75480253a6d9f7", "name": "Very large file: backend/ml/pipeline.py (1748 lines)", "shortDescription": {"text": "Very large file: backend/ml/pipeline.py (1748 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-bed8d5e5e5e8cad3", "name": "Very large file: backend/services/mise_calculator.py (1087 lines)", "shortDescription": {"text": "Very large file: backend/services/mise_calculator.py (1087 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-8a1d0f7a4d0f0807", "name": "Very large file: backend/db/models.py (1011 lines)", "shortDescription": {"text": "Very large file: backend/db/models.py (1011 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-ea3b5e389d8c9c0f", "name": "Low test-to-source ratio", "shortDescription": {"text": "Low test-to-source ratio"}, "fullDescription": {"text": "33 tests / 179 src (ratio 0.18)."}, "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-faccb9061e9b52a0", "name": "No README detected", "shortDescription": {"text": "No README detected"}, "fullDescription": {"text": "No README file was found. Generated repos without README context are hard to operate, validate, or safely hand off."}, "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 180 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 37 placeholder/mock markers across 18 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-b9088664ace7f748", "name": "Composite production-readiness gap", "shortDescription": {"text": "Composite production-readiness gap"}, "fullDescription": {"text": "Multiple low-cost hardening controls are missing together: license, operator-readme. 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, operator-readme. 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-55af9265afe00516", "name": "Agent authority lacks a verifier contract: frontend/.claude/launch.json", "shortDescription": {"text": "Agent authority lacks a verifier contract: frontend/.claude/launch.json"}, "fullDescription": {"text": "This agent instruction grants code or shell authority but does not state the verification gate that decides promotion. The recurring safe pattern is: LLM proposes; deterministic tests/build/security checks verify; only verified code promotes."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-e5f6be9269c9be43", "name": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/components/layout/Navbar.tsx:48", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/components/layout/Navbar.tsx:48"}, "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-e9f3f3e75aebd089", "name": "Legacy-named symbol `triangulation_cotes_v2` in backend/tests/test_ml_units.py:7", "shortDescription": {"text": "Legacy-named symbol `triangulation_cotes_v2` in backend/tests/test_ml_units.py:7"}, "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-0a0af506478c5242", "name": "Commented-code block (6 lines) in backend/api/model_metrics.py:97", "shortDescription": {"text": "Commented-code block (6 lines) in backend/api/model_metrics.py:97"}, "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-261bbbd36a7ec4b7", "name": "Commented-code block (5 lines) in backend/api/profil_backtest.py:153", "shortDescription": {"text": "Commented-code block (5 lines) in backend/api/profil_backtest.py:153"}, "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-dee3bdcda7e0ae47", "name": "Legacy-named symbol `export_csv_legacy` in backend/api/routes/bankroll.py:355", "shortDescription": {"text": "Legacy-named symbol `export_csv_legacy` in backend/api/routes/bankroll.py:355"}, "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-31429b025a23559c", "name": "Commented-code block (5 lines) in backend/api/routes/courses.py:33", "shortDescription": {"text": "Commented-code block (5 lines) in backend/api/routes/courses.py:33"}, "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-b5c58c1845b5ac1e", "name": "Commented-code block (6 lines) in backend/api/routes/stats.py:858", "shortDescription": {"text": "Commented-code block (6 lines) in backend/api/routes/stats.py:858"}, "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-2b1ae899cf2a7b3c", "name": "Blocking `urllib.request.urlopen(...)` inside `async def validate` \u2014 backend/scripts/validate_pmu_integrity.py:43", "shortDescription": {"text": "Blocking `urllib.request.urlopen(...)` inside `async def validate` \u2014 backend/scripts/validate_pmu_integrity.py:43"}, "fullDescription": {"text": "Sync I/O inside an async function blocks the event loop. While `urllib.request.urlopen(...)` is running, *all* other coroutines on this loop are paused \u2014 silent throughput collapse under concurrency. Use the async equivalent (`httpx.AsyncClient`, `asyncio.sleep`, `aiofiles`) or wrap with `await asyncio.to_thread(...)`."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "high", "confidence": 1.0}}, {"id": "scanner-ae67417ddd537019", "name": "Commented-code block (5 lines) in backend/scraper/orchestrator.py:122", "shortDescription": {"text": "Commented-code block (5 lines) in backend/scraper/orchestrator.py:122"}, "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-dc53b053c152b81e", "name": "Commented-code block (5 lines) in backend/scraper/sources/pmu.py:172", "shortDescription": {"text": "Commented-code block (5 lines) in backend/scraper/sources/pmu.py:172"}, "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-5f4e1d335dbbaa79", "name": "Legacy-named symbol `triangulation_cotes_v2` in backend/ml/valuebets.py:112", "shortDescription": {"text": "Legacy-named symbol `triangulation_cotes_v2` in backend/ml/valuebets.py:112"}, "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-db4af332955173b5", "name": "Commented-code block (12 lines) in backend/ml/valuebets.py:43", "shortDescription": {"text": "Commented-code block (12 lines) in backend/ml/valuebets.py:43"}, "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-8ac96c8fe3002722", "name": "Legacy-named symbol `mean_old` in backend/ml/drift_detector.py:185", "shortDescription": {"text": "Legacy-named symbol `mean_old` in backend/ml/drift_detector.py:185"}, "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-4c1dc1e5f748ace1", "name": "Commented-code block (5 lines) in backend/ml/models.py:106", "shortDescription": {"text": "Commented-code block (5 lines) in backend/ml/models.py:106"}, "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-adcd6ee8c0a21c05", "name": "Commented-code block (6 lines) in backend/ml/cote_calibration.py:49", "shortDescription": {"text": "Commented-code block (6 lines) in backend/ml/cote_calibration.py:49"}, "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-f97f85b20680d301", "name": "Commented-code block (9 lines) in backend/ml/adaptive_learning.py:128", "shortDescription": {"text": "Commented-code block (9 lines) in backend/ml/adaptive_learning.py:128"}, "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-3811bf94da091680", "name": "Commented-code block (5 lines) in backend/ml/combo_bets.py:329", "shortDescription": {"text": "Commented-code block (5 lines) in backend/ml/combo_bets.py:329"}, "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-a4766050efaf03ce", "name": "Legacy-named symbol `p_copy` in backend/ml/portfolio.py:596", "shortDescription": {"text": "Legacy-named symbol `p_copy` in backend/ml/portfolio.py:596"}, "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-1364c929b495b210", "name": "Commented-code block (5 lines) in backend/ml/algo_flags.py:87", "shortDescription": {"text": "Commented-code block (5 lines) in backend/ml/algo_flags.py:87"}, "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-d81c66430fdadfd8", "name": "Commented-code block (7 lines) in backend/ml/pipeline.py:214", "shortDescription": {"text": "Commented-code block (7 lines) in backend/ml/pipeline.py:214"}, "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-84d53416a1830b4a", "name": "Commented-code block (7 lines) in backend/ml/meta_learner.py:262", "shortDescription": {"text": "Commented-code block (7 lines) in backend/ml/meta_learner.py:262"}, "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-0e4d3f6457b29e1d", "name": "Commented-code block (6 lines) in backend/services/bet_settlement.py:27", "shortDescription": {"text": "Commented-code block (6 lines) in backend/services/bet_settlement.py:27"}, "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-82cb04f8073d2cbb", "name": "Commented-code block (12 lines) in backend/services/mise_calculator.py:198", "shortDescription": {"text": "Commented-code block (12 lines) in backend/services/mise_calculator.py:198"}, "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-022e6399d1ef2beb", "name": "12 env vars used in code but missing from .env.example", "shortDescription": {"text": "12 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `BETFAIR_APPKEY`, `BETFAIR_COUNTRIES`, `BETFAIR_PASS`, `BETFAIR_USER`, `BLACKTURF_ALLOW_SEED`, `BLACKTURF_INGEST_TOKEN`, `BLACKTURF_INGEST_URL`, `NEXT_PUBLIC_API_URL` + 4 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/api/routes/bankroll.py:export_bankroll_csv, backend/api/routes/bankroll.py:export_bankroll_pdf\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/api/routes/admin.py:change_user_plan, backend/api/routes/admin.py:update_user, backend/api/routes/admin.py:adjust_bankroll\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-c6680af428106701", "name": "FastAPI POST `refresh` without auth dependency \u2014 backend/api/routes/auth.py:204", "shortDescription": {"text": "FastAPI POST `refresh` without auth dependency \u2014 backend/api/routes/auth.py:204"}, "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-d48d519aa5b4047c", "name": "FastAPI POST `google_oauth` without auth dependency \u2014 backend/api/routes/auth.py:221", "shortDescription": {"text": "FastAPI POST `google_oauth` without auth dependency \u2014 backend/api/routes/auth.py:221"}, "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-c7ac23fba125c2c8", "name": "FastAPI POST `forgot_password` without auth dependency \u2014 backend/api/routes/auth.py:379", "shortDescription": {"text": "FastAPI POST `forgot_password` without auth dependency \u2014 backend/api/routes/auth.py:379"}, "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-cb5d09b01c3be1d8", "name": "FastAPI POST `reset_password` without auth dependency \u2014 backend/api/routes/auth.py:421", "shortDescription": {"text": "FastAPI POST `reset_password` without auth dependency \u2014 backend/api/routes/auth.py:421"}, "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-4972baec155021be", "name": "FastAPI POST `telegram_webhook` without auth dependency \u2014 backend/api/routes/telegram.py:18", "shortDescription": {"text": "FastAPI POST `telegram_webhook` without auth dependency \u2014 backend/api/routes/telegram.py:18"}, "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-6be7da00628ea00e", "name": "FastAPI POST `stripe_webhook` without auth dependency \u2014 backend/api/routes/stripe_routes.py:116", "shortDescription": {"text": "FastAPI POST `stripe_webhook` without auth dependency \u2014 backend/api/routes/stripe_routes.py:116"}, "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-8a1f0de1fece0b89", "name": "FastAPI POST `ingest_betfair` without auth dependency \u2014 backend/api/routes/admin.py:1290", "shortDescription": {"text": "FastAPI POST `ingest_betfair` without auth dependency \u2014 backend/api/routes/admin.py:1290"}, "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-a436691337284d03", "name": "Unused endpoint: GET /api/v1/health", "shortDescription": {"text": "Unused endpoint: GET /api/v1/health"}, "fullDescription": {"text": "`backend/api/main.py` declares `GET /api/v1/health` 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-741a3a809c6417b0", "name": "Unused endpoint: GET /api/v1/notifications/count-unread", "shortDescription": {"text": "Unused endpoint: GET /api/v1/notifications/count-unread"}, "fullDescription": {"text": "`backend/api/routes/notifications.py` declares `GET /api/v1/notifications/count-unread` 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-39acc2e8471d20d3", "name": "Unused endpoint: GET /api/v1/notifications/", "shortDescription": {"text": "Unused endpoint: GET /api/v1/notifications/"}, "fullDescription": {"text": "`backend/api/routes/notifications.py` declares `GET /api/v1/notifications/` 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-33df10ac9815d35a", "name": "Unused endpoint: PUT /api/v1/notifications/{alerte_id}/lue", "shortDescription": {"text": "Unused endpoint: PUT /api/v1/notifications/{alerte_id}/lue"}, "fullDescription": {"text": "`backend/api/routes/notifications.py` declares `PUT /api/v1/notifications/{alerte_id}/lue` 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-24e15a5787c3af34", "name": "Unused endpoint: DELETE /api/v1/notifications/all", "shortDescription": {"text": "Unused endpoint: DELETE /api/v1/notifications/all"}, "fullDescription": {"text": "`backend/api/routes/notifications.py` declares `DELETE /api/v1/notifications/all` 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-94096e55ccb413ce", "name": "Unused endpoint: GET /api/v1/notifications/prefs", "shortDescription": {"text": "Unused endpoint: GET /api/v1/notifications/prefs"}, "fullDescription": {"text": "`backend/api/routes/notifications.py` declares `GET /api/v1/notifications/prefs` 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-b97217af0428e6b2", "name": "Unused endpoint: PUT /api/v1/notifications/prefs", "shortDescription": {"text": "Unused endpoint: PUT /api/v1/notifications/prefs"}, "fullDescription": {"text": "`backend/api/routes/notifications.py` declares `PUT /api/v1/notifications/prefs` 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-07e10c77f3915647", "name": "Unused endpoint: GET /api/v1/bankroll/entries", "shortDescription": {"text": "Unused endpoint: GET /api/v1/bankroll/entries"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `GET /api/v1/bankroll/entries` 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-d87d856049a3b196", "name": "Unused endpoint: POST /api/v1/bankroll/entries", "shortDescription": {"text": "Unused endpoint: POST /api/v1/bankroll/entries"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `POST /api/v1/bankroll/entries` 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-a9ec86a86b751b0b", "name": "Unused endpoint: PATCH /api/v1/bankroll/entries/{entry_id}", "shortDescription": {"text": "Unused endpoint: PATCH /api/v1/bankroll/entries/{entry_id}"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `PATCH /api/v1/bankroll/entries/{entry_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-911724af7930f065", "name": "Unused endpoint: DELETE /api/v1/bankroll/entries/{entry_id}", "shortDescription": {"text": "Unused endpoint: DELETE /api/v1/bankroll/entries/{entry_id}"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `DELETE /api/v1/bankroll/entries/{entry_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-a84965ef4f801176", "name": "Unused endpoint: GET /api/v1/bankroll/stats", "shortDescription": {"text": "Unused endpoint: GET /api/v1/bankroll/stats"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `GET /api/v1/bankroll/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-993eb8904258a125", "name": "Unused endpoint: GET /api/v1/bankroll/export", "shortDescription": {"text": "Unused endpoint: GET /api/v1/bankroll/export"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `GET /api/v1/bankroll/export` 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-0161d07875ed841f", "name": "Unused endpoint: GET /api/v1/bankroll/export/csv", "shortDescription": {"text": "Unused endpoint: GET /api/v1/bankroll/export/csv"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `GET /api/v1/bankroll/export/csv` 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-f34235cbcca70ad3", "name": "Unused endpoint: GET /api/v1/bankroll/export/pdf", "shortDescription": {"text": "Unused endpoint: GET /api/v1/bankroll/export/pdf"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `GET /api/v1/bankroll/export/pdf` 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-2c8f64207be0c928", "name": "Unused endpoint: GET /api/v1/bankroll/portefeuilles", "shortDescription": {"text": "Unused endpoint: GET /api/v1/bankroll/portefeuilles"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `GET /api/v1/bankroll/portefeuilles` 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-fba8ebcf4adf6705", "name": "Unused endpoint: POST /api/v1/bankroll/portefeuilles", "shortDescription": {"text": "Unused endpoint: POST /api/v1/bankroll/portefeuilles"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `POST /api/v1/bankroll/portefeuilles` 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-9117c77480e10bc7", "name": "Unused endpoint: PUT /api/v1/bankroll/portefeuilles/{bankroll_id}", "shortDescription": {"text": "Unused endpoint: PUT /api/v1/bankroll/portefeuilles/{bankroll_id}"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `PUT /api/v1/bankroll/portefeuilles/{bankroll_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-cf21f8388c40e751", "name": "Unused endpoint: DELETE /api/v1/bankroll/portefeuilles/{bankroll_id}", "shortDescription": {"text": "Unused endpoint: DELETE /api/v1/bankroll/portefeuilles/{bankroll_id}"}, "fullDescription": {"text": "`backend/api/routes/bankroll.py` declares `DELETE /api/v1/bankroll/portefeuilles/{bankroll_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-5f258b679ceb30eb", "name": "Unused endpoint: POST /api/v1/assistant/chat", "shortDescription": {"text": "Unused endpoint: POST /api/v1/assistant/chat"}, "fullDescription": {"text": "`backend/api/routes/assistant.py` declares `POST /api/v1/assistant/chat` 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-fd00117fc2812427", "name": "Unused endpoint: GET /api/v1/assistant/suggestions", "shortDescription": {"text": "Unused endpoint: GET /api/v1/assistant/suggestions"}, "fullDescription": {"text": "`backend/api/routes/assistant.py` declares `GET /api/v1/assistant/suggestions` 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-92076c2733fc7c54", "name": "Unused endpoint: POST /api/v1/auth/register", "shortDescription": {"text": "Unused endpoint: POST /api/v1/auth/register"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `POST /api/v1/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}}, {"id": "scanner-72530ed44ad5a45a", "name": "Unused endpoint: POST /api/v1/auth/login", "shortDescription": {"text": "Unused endpoint: POST /api/v1/auth/login"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `POST /api/v1/auth/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-5be7411e2f955aa7", "name": "Unused endpoint: POST /api/v1/auth/refresh", "shortDescription": {"text": "Unused endpoint: POST /api/v1/auth/refresh"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `POST /api/v1/auth/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-d697b8b6d16c521a", "name": "Unused endpoint: POST /api/v1/auth/google", "shortDescription": {"text": "Unused endpoint: POST /api/v1/auth/google"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `POST /api/v1/auth/google` 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-f28d5598f27ace34", "name": "Unused endpoint: GET /api/v1/auth/me", "shortDescription": {"text": "Unused endpoint: GET /api/v1/auth/me"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `GET /api/v1/auth/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-bbac82a8ea1450d7", "name": "Unused endpoint: PATCH /api/v1/auth/me", "shortDescription": {"text": "Unused endpoint: PATCH /api/v1/auth/me"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `PATCH /api/v1/auth/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-d712faa28bfd34fc", "name": "Unused endpoint: POST /api/v1/auth/resend-verification", "shortDescription": {"text": "Unused endpoint: POST /api/v1/auth/resend-verification"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `POST /api/v1/auth/resend-verification` 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-cd85d2abab3309ca", "name": "Unused endpoint: GET /api/v1/auth/verify-email", "shortDescription": {"text": "Unused endpoint: GET /api/v1/auth/verify-email"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `GET /api/v1/auth/verify-email` 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-5684ca2c4f33eed7", "name": "Unused endpoint: POST /api/v1/auth/forgot-password", "shortDescription": {"text": "Unused endpoint: POST /api/v1/auth/forgot-password"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `POST /api/v1/auth/forgot-password` 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-0f03ca5262a56374", "name": "Unused endpoint: POST /api/v1/auth/reset-password", "shortDescription": {"text": "Unused endpoint: POST /api/v1/auth/reset-password"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `POST /api/v1/auth/reset-password` 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-8829b53061ce58a5", "name": "Unused endpoint: PUT /api/v1/auth/push-subscription", "shortDescription": {"text": "Unused endpoint: PUT /api/v1/auth/push-subscription"}, "fullDescription": {"text": "`backend/api/routes/auth.py` declares `PUT /api/v1/auth/push-subscription` 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-3e6588cd40ddbe8c", "name": "Unused endpoint: GET /api/v1/courses/{course_id}/predictions", "shortDescription": {"text": "Unused endpoint: GET /api/v1/courses/{course_id}/predictions"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `GET /api/v1/courses/{course_id}/predictions` 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-c5e463fde9d32ad2", "name": "Unused endpoint: POST /api/v1/courses/{course_id}/predict", "shortDescription": {"text": "Unused endpoint: POST /api/v1/courses/{course_id}/predict"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `POST /api/v1/courses/{course_id}/predict` 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-4f83c0840343eacf", "name": "Unused endpoint: GET /api/v1/value-bets", "shortDescription": {"text": "Unused endpoint: GET /api/v1/value-bets"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `GET /api/v1/value-bets` 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-36bb261b77efdcf3", "name": "Unused endpoint: GET /api/v1/pari-du-jour-profils", "shortDescription": {"text": "Unused endpoint: GET /api/v1/pari-du-jour-profils"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `GET /api/v1/pari-du-jour-profils` 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-c1dfd1b558f56d57", "name": "Unused endpoint: GET /api/v1/pari-du-jour", "shortDescription": {"text": "Unused endpoint: GET /api/v1/pari-du-jour"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `GET /api/v1/pari-du-jour` 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-4c898df4c4e9b250", "name": "Unused endpoint: GET /api/v1/value-bets/historique", "shortDescription": {"text": "Unused endpoint: GET /api/v1/value-bets/historique"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `GET /api/v1/value-bets/historique` 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-dd0342dd3dd90f03", "name": "Unused endpoint: GET /api/v1/courses/{course_id}/analyse", "shortDescription": {"text": "Unused endpoint: GET /api/v1/courses/{course_id}/analyse"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `GET /api/v1/courses/{course_id}/analyse` 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-e1e5db105157c379", "name": "Unused endpoint: GET /api/v1/courses/{course_id}/dutch", "shortDescription": {"text": "Unused endpoint: GET /api/v1/courses/{course_id}/dutch"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `GET /api/v1/courses/{course_id}/dutch` 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-11f0ee5044f41fdf", "name": "Unused endpoint: GET /api/v1/courses/{course_id}/feature-importance", "shortDescription": {"text": "Unused endpoint: GET /api/v1/courses/{course_id}/feature-importance"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `GET /api/v1/courses/{course_id}/feature-importance` 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-9df3890be7ea45a9", "name": "Unused endpoint: GET /api/v1/model/version", "shortDescription": {"text": "Unused endpoint: GET /api/v1/model/version"}, "fullDescription": {"text": "`backend/api/routes/predictions.py` declares `GET /api/v1/model/version` 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-987e97d879e20f6e", "name": "Unused endpoint: POST /api/v1/telegram/webhook", "shortDescription": {"text": "Unused endpoint: POST /api/v1/telegram/webhook"}, "fullDescription": {"text": "`backend/api/routes/telegram.py` declares `POST /api/v1/telegram/webhook` 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-6ec44f910ea70dc4", "name": "Unused endpoint: POST /api/v1/telegram/setup-webhook", "shortDescription": {"text": "Unused endpoint: POST /api/v1/telegram/setup-webhook"}, "fullDescription": {"text": "`backend/api/routes/telegram.py` declares `POST /api/v1/telegram/setup-webhook` 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-e8d6c6c69cf237af", "name": "Unused endpoint: POST /api/v1/stripe/checkout", "shortDescription": {"text": "Unused endpoint: POST /api/v1/stripe/checkout"}, "fullDescription": {"text": "`backend/api/routes/stripe_routes.py` declares `POST /api/v1/stripe/checkout` 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-0026b7e45cb8b0e9", "name": "Unused endpoint: POST /api/v1/stripe/portal", "shortDescription": {"text": "Unused endpoint: POST /api/v1/stripe/portal"}, "fullDescription": {"text": "`backend/api/routes/stripe_routes.py` declares `POST /api/v1/stripe/portal` 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-c59819f14bc18216", "name": "Unused endpoint: POST /api/v1/stripe/webhook", "shortDescription": {"text": "Unused endpoint: POST /api/v1/stripe/webhook"}, "fullDescription": {"text": "`backend/api/routes/stripe_routes.py` declares `POST /api/v1/stripe/webhook` 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-06dab826707e3f82", "name": "Unused endpoint: GET /admin/api/dashboard", "shortDescription": {"text": "Unused endpoint: GET /admin/api/dashboard"}, "fullDescription": {"text": "`backend/api/routes/admin.py` declares `GET /admin/api/dashboard` 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-0c40c92a29df9af8", "name": "Unused endpoint: GET /admin/api/users", "shortDescription": {"text": "Unused endpoint: GET /admin/api/users"}, "fullDescription": {"text": "`backend/api/routes/admin.py` declares `GET /admin/api/users` 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-95b11f5eb8a15433", "name": "Unused endpoint: GET /admin/api/users/{user_id}", "shortDescription": {"text": "Unused endpoint: GET /admin/api/users/{user_id}"}, "fullDescription": {"text": "`backend/api/routes/admin.py` declares `GET /admin/api/users/{user_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}}]}}, "automationDetails": {"id": "repobility/21207"}, "properties": {"repository": "thomasbeaumonttb24-del/blackturf", "repoUrl": "https://github.com/thomasbeaumonttb24-del/blackturf", "branch": "main"}, "results": [{"ruleId": "scanner-5faa19b6c99d17f1", "level": "note", "message": {"text": "Possibly dead Python function: rate_limit_assistant"}, "properties": {"repobilityId": "f31b9c036f65c0e7", "scanner": "scanner-primary", "fingerprint": "5faa19b6c99d17f1", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/middleware/rate_limit.py:59"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-f3067be91193a700", "level": "note", "message": {"text": "Possibly dead Python function: rate_limit_predictions"}, "properties": {"repobilityId": "2a235b6d85353c01", "scanner": "scanner-primary", "fingerprint": "f3067be91193a700", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/middleware/rate_limit.py:68"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-98db33927b63aa5f", "level": "note", "message": {"text": "Possibly dead Python function: rate_limit_public"}, "properties": {"repobilityId": "211ecda68f4afab7", "scanner": "scanner-primary", "fingerprint": "98db33927b63aa5f", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/middleware/rate_limit.py:76"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-08b50d50d5af0da7", "level": "note", "message": {"text": "Possibly dead Python function: require_pro"}, "properties": {"repobilityId": "b59aa1b27b7897e8", "scanner": "scanner-primary", "fingerprint": "08b50d50d5af0da7", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/auth.py:129"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-174cec2978aa0005", "level": "note", "message": {"text": "Possibly dead Python function: require_admin"}, "properties": {"repobilityId": "3c06db2e25566bf7", "scanner": "scanner-primary", "fingerprint": "174cec2978aa0005", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/auth.py:135"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-ba03ac89ab9b22e3", "level": "note", "message": {"text": "Possibly dead Python function: push_alert_to_user"}, "properties": {"repobilityId": "d5cb8be393ce31de", "scanner": "scanner-primary", "fingerprint": "ba03ac89ab9b22e3", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/ws.py:393"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-ed5f555715ab8b4a", "level": "note", "message": {"text": "Possibly dead Python function: work"}, "properties": {"repobilityId": "c5b0e9acf413d08f", "scanner": "scanner-primary", "fingerprint": "ed5f555715ab8b4a", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/scripts/audit_schema_drift.py:19"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-01beba283de1c64d", "level": "note", "message": {"text": "Possibly dead Python function: retry_async"}, "properties": {"repobilityId": "88ea1cc98a5db9ea", "scanner": "scanner-primary", "fingerprint": "01beba283de1c64d", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/scraper/base.py:21"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-b9ec3d41a6163ee7", "level": "note", "message": {"text": "Possibly dead Python function: decorator"}, "properties": {"repobilityId": "ffbcbc9bc189af1c", "scanner": "scanner-primary", "fingerprint": "b9ec3d41a6163ee7", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/scraper/base.py:26"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-68506be352d39d46", "level": "note", "message": {"text": "Possibly dead Python function: save_temps_passage"}, "properties": {"repobilityId": "a18ae05a2302594a", "scanner": "scanner-primary", "fingerprint": "68506be352d39d46", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/scraper/db_writer.py:703"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-b4ee751e48e20e93", "level": "note", "message": {"text": "Possibly dead Python function: should_retrain"}, "properties": {"repobilityId": "80a13f86182628f3", "scanner": "scanner-primary", "fingerprint": "b4ee751e48e20e93", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/ml/post_race_analyzer.py:614"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-da6f507c005a04b3", "level": "note", "message": {"text": "Possibly dead Python function: compute_features_for_participation"}, "properties": {"repobilityId": "a2594156d46b8f57", "scanner": "scanner-primary", "fingerprint": "da6f507c005a04b3", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/ml/features.py:272"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-d3b6dd8ceb03fafd", "level": "note", "message": {"text": "Possibly dead Python function: latest_edge_monitor"}, "properties": {"repobilityId": "dcb0ecb27938ff3f", "scanner": "scanner-primary", "fingerprint": "d3b6dd8ceb03fafd", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/ml/edge_monitor.py:109"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-587c20a6de361d3c", "level": "note", "message": {"text": "Possibly dead Python function: cout_combo"}, "properties": {"repobilityId": "0dbed3d75a5f240b", "scanner": "scanner-primary", "fingerprint": "587c20a6de361d3c", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/ml/recommendations.py:75"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-f149ddca01ecd60b", "level": "note", "message": {"text": "Possibly dead Python function: p_tierce_ordre"}, "properties": {"repobilityId": "c4a95cd71af4b078", "scanner": "scanner-primary", "fingerprint": "f149ddca01ecd60b", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/ml/combo_bets.py:122"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-81357793be611e3d", "level": "note", "message": {"text": "Possibly dead Python function: optimize_multi_race_portfolio"}, "properties": {"repobilityId": "25e2c73e13f9e38b", "scanner": "scanner-primary", "fingerprint": "81357793be611e3d", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/ml/portfolio.py:890"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-478ceb6d2e3453ac", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/layout/Navbar.tsx:90"}, "properties": {"repobilityId": "160dc9625fa2292f", "scanner": "scanner-primary", "fingerprint": "478ceb6d2e3453ac", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a11a79880aaf27a3", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/page.tsx:202"}, "properties": {"repobilityId": "646669d428c89604", "scanner": "scanner-primary", "fingerprint": "a11a79880aaf27a3", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4939e8bd9e17f5b6", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 frontend/src/app/layout.tsx:95"}, "properties": {"repobilityId": "5229a767d0f4516f", "scanner": "scanner-primary", "fingerprint": "4939e8bd9e17f5b6", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-8b84df45e27b72e6", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/admin/page.tsx:298"}, "properties": {"repobilityId": "07861c13e1626063", "scanner": "scanner-primary", "fingerprint": "8b84df45e27b72e6", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b2b671dc2d1898ad", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/admin/algorithme/page.tsx:398"}, "properties": {"repobilityId": "e9ddd88833da8e5a", "scanner": "scanner-primary", "fingerprint": "b2b671dc2d1898ad", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-87fb26f8ac8705c8", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/recherche/page.tsx:115"}, "properties": {"repobilityId": "d63e9227c5be4413", "scanner": "scanner-primary", "fingerprint": "87fb26f8ac8705c8", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-de4bb957d81a1c0f", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/chevaux/[id]/page.tsx:474"}, "properties": {"repobilityId": "bfe7cd1b9b9b3266", "scanner": "scanner-primary", "fingerprint": "de4bb957d81a1c0f", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a070d5c394c25b69", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/dashboard/page.tsx:230"}, "properties": {"repobilityId": "e702472a029419ef", "scanner": "scanner-primary", "fingerprint": "a070d5c394c25b69", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1bdf0fc1d898e7ed", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/value-bets/page.tsx:117"}, "properties": {"repobilityId": "e4f885478ae7e30b", "scanner": "scanner-primary", "fingerprint": "1bdf0fc1d898e7ed", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-8e40479f71aad31d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/track-record/page.tsx:142"}, "properties": {"repobilityId": "19a0098162f24f7e", "scanner": "scanner-primary", "fingerprint": "8e40479f71aad31d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-e7e117dc1e9c5f4a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/statistiques/page.tsx:122"}, "properties": {"repobilityId": "0b0647b4e1ab49f1", "scanner": "scanner-primary", "fingerprint": "e7e117dc1e9c5f4a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b9ac3bb8664efd67", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/courses/[id]/page.tsx:914"}, "properties": {"repobilityId": "44e9a1e067c4ed7b", "scanner": "scanner-primary", "fingerprint": "b9ac3bb8664efd67", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-8a6445873c5e188d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/jockeys/[id]/page.tsx:293"}, "properties": {"repobilityId": "3e4c85618720ed0a", "scanner": "scanner-primary", "fingerprint": "8a6445873c5e188d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f0e76350242b1488", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/programme/page.tsx:444"}, "properties": {"repobilityId": "24b8c43f4c73edbf", "scanner": "scanner-primary", "fingerprint": "f0e76350242b1488", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-5997060157770591", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/profil/page.tsx:230"}, "properties": {"repobilityId": "b517900d5640d8a1", "scanner": "scanner-primary", "fingerprint": "5997060157770591", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f15f11283ea861b2", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/(main)/bankroll/page.tsx:515"}, "properties": {"repobilityId": "2e51ac7ebb5e70a3", "scanner": "scanner-primary", "fingerprint": "f15f11283ea861b2", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-faa134129e5545ff", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine"}, "properties": {"repobilityId": "3e90d440e1f9ece1", "scanner": "scanner-primary", "fingerprint": "faa134129e5545ff", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-faa134129e5545ff", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine"}, "properties": {"repobilityId": "2c78bf130bb0be38", "scanner": "scanner-primary", "fingerprint": "faa134129e5545ff", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/Dockerfile"}, "region": {"startLine": 5}}}]}, {"ruleId": "scanner-faa134129e5545ff", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine"}, "properties": {"repobilityId": "c23a2c6a5b1a38a9", "scanner": "scanner-primary", "fingerprint": "faa134129e5545ff", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/Dockerfile"}, "region": {"startLine": 17}}}]}, {"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-714c31ca9f474ae6", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim"}, "properties": {"repobilityId": "f614a1e41f331b37", "scanner": "scanner-primary", "fingerprint": "714c31ca9f474ae6", "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-e48802eb33362e96", "level": "warning", "message": {"text": "Insecure pattern 'local_storage_auth_token' in frontend/src/lib/api.ts:41"}, "properties": {"repobilityId": "90843d9d5330409d", "scanner": "scanner-primary", "fingerprint": "e48802eb33362e96", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "local_storage_auth_token"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/src/lib/api.ts"}, "region": {"startLine": 41}}}]}, {"ruleId": "scanner-ae6fb0091580ae52", "level": "warning", "message": {"text": "Insecure pattern 'local_storage_auth_token' in frontend/src/lib/auth.ts:27"}, "properties": {"repobilityId": "fa82456966cc4f76", "scanner": "scanner-primary", "fingerprint": "ae6fb0091580ae52", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "local_storage_auth_token"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/src/lib/auth.ts"}, "region": {"startLine": 27}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "5206950cf3c3cb8f", "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": 32}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "cdd488c07b90bf4b", "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": 39}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "161a25eab2e68ed3", "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": 44}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "a996444fe9d8260b", "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-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "161a25eab2e68ed3", "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": 64}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "a996444fe9d8260b", "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": 72}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "85be6b43ccc2bf69", "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": 95}}}]}, {"ruleId": "scanner-ad6701f0a8405e22", "level": "warning", "message": {"text": "GitHub Actions workflow grants broad write permissions"}, "properties": {"repobilityId": "8384c23520d55657", "scanner": "scanner-primary", "fingerprint": "ad6701f0a8405e22", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "least-privilege"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "04f57d208548fcef", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 22}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "04f57d208548fcef", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 50}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "989a74409a402368", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 79}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "989a74409a402368", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 104}}}]}, {"ruleId": "scanner-5cbdea4030768ad0", "level": "note", "message": {"text": "Very large file: frontend/src/app/(main)/courses/[id]/page.tsx (2759 lines)"}, "properties": {"repobilityId": "e1b0146394b58a31", "scanner": "scanner-primary", "fingerprint": "5cbdea4030768ad0", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-74b60fe486e13149", "level": "note", "message": {"text": "Very large file: backend/api/routes/admin.py (1374 lines)"}, "properties": {"repobilityId": "4b6c77abb260413a", "scanner": "scanner-primary", "fingerprint": "74b60fe486e13149", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-9d695a757c189164", "level": "note", "message": {"text": "Very large file: backend/api/routes/courses.py (2238 lines)"}, "properties": {"repobilityId": "070a934c6e57a734", "scanner": "scanner-primary", "fingerprint": "9d695a757c189164", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-79f8c21cda77f9e6", "level": "note", "message": {"text": "Very large file: backend/ml/features.py (2329 lines)"}, "properties": {"repobilityId": "259294c5b1224d04", "scanner": "scanner-primary", "fingerprint": "79f8c21cda77f9e6", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-ba75480253a6d9f7", "level": "note", "message": {"text": "Very large file: backend/ml/pipeline.py (1748 lines)"}, "properties": {"repobilityId": "9033cd1068f04d8c", "scanner": "scanner-primary", "fingerprint": "ba75480253a6d9f7", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-bed8d5e5e5e8cad3", "level": "note", "message": {"text": "Very large file: backend/services/mise_calculator.py (1087 lines)"}, "properties": {"repobilityId": "bec0f2534c3b8cb7", "scanner": "scanner-primary", "fingerprint": "bed8d5e5e5e8cad3", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-8a1d0f7a4d0f0807", "level": "note", "message": {"text": "Very large file: backend/db/models.py (1011 lines)"}, "properties": {"repobilityId": "6547745dc7d64cc5", "scanner": "scanner-primary", "fingerprint": "8a1d0f7a4d0f0807", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-ea3b5e389d8c9c0f", "level": "note", "message": {"text": "Low test-to-source ratio"}, "properties": {"repobilityId": "ef7b2552cc00a375", "scanner": "scanner-primary", "fingerprint": "ea3b5e389d8c9c0f", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["tests"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "a11a34d8691db2d2", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-faccb9061e9b52a0", "level": "note", "message": {"text": "No README detected"}, "properties": {"repobilityId": "7a84022b616ba9af", "scanner": "scanner-primary", "fingerprint": "faccb9061e9b52a0", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["docs", "readme", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-3ab5d313dda8e5f9", "level": "note", "message": {"text": "Debug logging residue appears in source files"}, "properties": {"repobilityId": "4f4130b63c869109", "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": "ff002547d646040b", "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": "a00588dfa76bd6b0", "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": "410c278eafed2ea2", "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": "6e4873cdf520ad58", "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": "34b2479dcbe93b15", "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": "b6a6754f70f8b248", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-55af9265afe00516", "level": "warning", "message": {"text": "Agent authority lacks a verifier contract: frontend/.claude/launch.json"}, "properties": {"repobilityId": "8600e124eea34aeb", "scanner": "scanner-primary", "fingerprint": "55af9265afe00516", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["agent-instructions", "verification", "claude_instruction"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/.claude/launch.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-e5f6be9269c9be43", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/components/layout/Navbar.tsx:48"}, "properties": {"repobilityId": "8f87ecd7aae195d9", "scanner": "scanner-primary", "fingerprint": "e5f6be9269c9be43", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-e9f3f3e75aebd089", "level": "note", "message": {"text": "Legacy-named symbol `triangulation_cotes_v2` in backend/tests/test_ml_units.py:7"}, "properties": {"repobilityId": "0fa27fa63adb9e28", "scanner": "scanner-primary", "fingerprint": "e9f3f3e75aebd089", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-0a0af506478c5242", "level": "none", "message": {"text": "Commented-code block (6 lines) in backend/api/model_metrics.py:97"}, "properties": {"repobilityId": "a6e7ba7a60488c74", "scanner": "scanner-primary", "fingerprint": "0a0af506478c5242", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-261bbbd36a7ec4b7", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/api/profil_backtest.py:153"}, "properties": {"repobilityId": "62afad908301d4a7", "scanner": "scanner-primary", "fingerprint": "261bbbd36a7ec4b7", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-dee3bdcda7e0ae47", "level": "note", "message": {"text": "Legacy-named symbol `export_csv_legacy` in backend/api/routes/bankroll.py:355"}, "properties": {"repobilityId": "8526295d1864912e", "scanner": "scanner-primary", "fingerprint": "dee3bdcda7e0ae47", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-31429b025a23559c", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/api/routes/courses.py:33"}, "properties": {"repobilityId": "ca527af2fac47545", "scanner": "scanner-primary", "fingerprint": "31429b025a23559c", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-b5c58c1845b5ac1e", "level": "none", "message": {"text": "Commented-code block (6 lines) in backend/api/routes/stats.py:858"}, "properties": {"repobilityId": "8142a52306a5519d", "scanner": "scanner-primary", "fingerprint": "b5c58c1845b5ac1e", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-2b1ae899cf2a7b3c", "level": "error", "message": {"text": "Blocking `urllib.request.urlopen(...)` inside `async def validate` \u2014 backend/scripts/validate_pmu_integrity.py:43"}, "properties": {"repobilityId": "52cb07b74e264e44", "scanner": "scanner-primary", "fingerprint": "2b1ae899cf2a7b3c", "layer": "quality", "severity": "high", "confidence": 1.0, "tags": ["integrity", "sync-io-in-async", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/scripts/validate_pmu_integrity.py"}, "region": {"startLine": 43}}}]}, {"ruleId": "scanner-ae67417ddd537019", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/scraper/orchestrator.py:122"}, "properties": {"repobilityId": "ab065e287ce0a7de", "scanner": "scanner-primary", "fingerprint": "ae67417ddd537019", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-dc53b053c152b81e", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/scraper/sources/pmu.py:172"}, "properties": {"repobilityId": "1c2e82712e400bf6", "scanner": "scanner-primary", "fingerprint": "dc53b053c152b81e", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-5f4e1d335dbbaa79", "level": "note", "message": {"text": "Legacy-named symbol `triangulation_cotes_v2` in backend/ml/valuebets.py:112"}, "properties": {"repobilityId": "8b704207465c806a", "scanner": "scanner-primary", "fingerprint": "5f4e1d335dbbaa79", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-db4af332955173b5", "level": "none", "message": {"text": "Commented-code block (12 lines) in backend/ml/valuebets.py:43"}, "properties": {"repobilityId": "453735a854db5d61", "scanner": "scanner-primary", "fingerprint": "db4af332955173b5", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-8ac96c8fe3002722", "level": "note", "message": {"text": "Legacy-named symbol `mean_old` in backend/ml/drift_detector.py:185"}, "properties": {"repobilityId": "fd47c156051246a3", "scanner": "scanner-primary", "fingerprint": "8ac96c8fe3002722", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-4c1dc1e5f748ace1", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/ml/models.py:106"}, "properties": {"repobilityId": "761948d19c3dc501", "scanner": "scanner-primary", "fingerprint": "4c1dc1e5f748ace1", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-adcd6ee8c0a21c05", "level": "none", "message": {"text": "Commented-code block (6 lines) in backend/ml/cote_calibration.py:49"}, "properties": {"repobilityId": "0d810156e2bac1e5", "scanner": "scanner-primary", "fingerprint": "adcd6ee8c0a21c05", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-f97f85b20680d301", "level": "none", "message": {"text": "Commented-code block (9 lines) in backend/ml/adaptive_learning.py:128"}, "properties": {"repobilityId": "d3846ade95520321", "scanner": "scanner-primary", "fingerprint": "f97f85b20680d301", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-3811bf94da091680", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/ml/combo_bets.py:329"}, "properties": {"repobilityId": "f0322b5c60adc56d", "scanner": "scanner-primary", "fingerprint": "3811bf94da091680", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-a4766050efaf03ce", "level": "note", "message": {"text": "Legacy-named symbol `p_copy` in backend/ml/portfolio.py:596"}, "properties": {"repobilityId": "d767cf3d087ed804", "scanner": "scanner-primary", "fingerprint": "a4766050efaf03ce", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-1364c929b495b210", "level": "none", "message": {"text": "Commented-code block (5 lines) in backend/ml/algo_flags.py:87"}, "properties": {"repobilityId": "803a75fff8432333", "scanner": "scanner-primary", "fingerprint": "1364c929b495b210", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-d81c66430fdadfd8", "level": "none", "message": {"text": "Commented-code block (7 lines) in backend/ml/pipeline.py:214"}, "properties": {"repobilityId": "638ff03075269590", "scanner": "scanner-primary", "fingerprint": "d81c66430fdadfd8", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-84d53416a1830b4a", "level": "none", "message": {"text": "Commented-code block (7 lines) in backend/ml/meta_learner.py:262"}, "properties": {"repobilityId": "f8de5d7a293e6264", "scanner": "scanner-primary", "fingerprint": "84d53416a1830b4a", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-0e4d3f6457b29e1d", "level": "none", "message": {"text": "Commented-code block (6 lines) in backend/services/bet_settlement.py:27"}, "properties": {"repobilityId": "2fb05f670659f9c1", "scanner": "scanner-primary", "fingerprint": "0e4d3f6457b29e1d", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-82cb04f8073d2cbb", "level": "none", "message": {"text": "Commented-code block (12 lines) in backend/services/mise_calculator.py:198"}, "properties": {"repobilityId": "6fd56fbb522b847f", "scanner": "scanner-primary", "fingerprint": "82cb04f8073d2cbb", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-022e6399d1ef2beb", "level": "note", "message": {"text": "12 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "7bf4178327da75a2", "scanner": "scanner-primary", "fingerprint": "022e6399d1ef2beb", "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": "c11bd1a04fd422d4", "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": "0679384eff84c7be", "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": "ae1b452fcf2aec19", "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": "0e063f12394e3e50", "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": "702a9a183990b508", "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": "615d0be64cf7b08a", "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": "dd9cda5c76c59544", "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": "d3f2e615b9702894", "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": "96935d5c41805c81", "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": "d06fff8625d58b43", "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": "a160d94271b9c308", "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": "e2e3ff20a6d9fdad", "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": "a37f2781aea240b4", "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": "f208f83c049e165b", "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": "1995df8e7f01fd55", "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": "38fa3f49b1430e3c", "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": "012090f28bfd524a", "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": "bd0566d9c3a12b60", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-c6680af428106701", "level": "error", "message": {"text": "FastAPI POST `refresh` without auth dependency \u2014 backend/api/routes/auth.py:204"}, "properties": {"repobilityId": "bed49b9ecbab41c6", "scanner": "scanner-primary", "fingerprint": "c6680af428106701", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/auth.py"}, "region": {"startLine": 204}}}]}, {"ruleId": "scanner-d48d519aa5b4047c", "level": "error", "message": {"text": "FastAPI POST `google_oauth` without auth dependency \u2014 backend/api/routes/auth.py:221"}, "properties": {"repobilityId": "ab77a23ea958778a", "scanner": "scanner-primary", "fingerprint": "d48d519aa5b4047c", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/auth.py"}, "region": {"startLine": 221}}}]}, {"ruleId": "scanner-c7ac23fba125c2c8", "level": "error", "message": {"text": "FastAPI POST `forgot_password` without auth dependency \u2014 backend/api/routes/auth.py:379"}, "properties": {"repobilityId": "2eb93ef1f5f4efd4", "scanner": "scanner-primary", "fingerprint": "c7ac23fba125c2c8", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/auth.py"}, "region": {"startLine": 379}}}]}, {"ruleId": "scanner-cb5d09b01c3be1d8", "level": "error", "message": {"text": "FastAPI POST `reset_password` without auth dependency \u2014 backend/api/routes/auth.py:421"}, "properties": {"repobilityId": "f2197f430cd5e694", "scanner": "scanner-primary", "fingerprint": "cb5d09b01c3be1d8", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/auth.py"}, "region": {"startLine": 421}}}]}, {"ruleId": "scanner-4972baec155021be", "level": "error", "message": {"text": "FastAPI POST `telegram_webhook` without auth dependency \u2014 backend/api/routes/telegram.py:18"}, "properties": {"repobilityId": "1e76890f48e2c6f6", "scanner": "scanner-primary", "fingerprint": "4972baec155021be", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/telegram.py"}, "region": {"startLine": 18}}}]}, {"ruleId": "scanner-6be7da00628ea00e", "level": "error", "message": {"text": "FastAPI POST `stripe_webhook` without auth dependency \u2014 backend/api/routes/stripe_routes.py:116"}, "properties": {"repobilityId": "17785b9adfaad691", "scanner": "scanner-primary", "fingerprint": "6be7da00628ea00e", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/stripe_routes.py"}, "region": {"startLine": 116}}}]}, {"ruleId": "scanner-8a1f0de1fece0b89", "level": "error", "message": {"text": "FastAPI POST `ingest_betfair` without auth dependency \u2014 backend/api/routes/admin.py:1290"}, "properties": {"repobilityId": "93f44992bbe30461", "scanner": "scanner-primary", "fingerprint": "8a1f0de1fece0b89", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.fastapi.unauth_mutation"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/api/routes/admin.py"}, "region": {"startLine": 1290}}}]}, {"ruleId": "scanner-a436691337284d03", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/health"}, "properties": {"repobilityId": "c3644657a25237a4", "scanner": "scanner-primary", "fingerprint": "a436691337284d03", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-741a3a809c6417b0", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/notifications/count-unread"}, "properties": {"repobilityId": "a53aef22323e6eda", "scanner": "scanner-primary", "fingerprint": "741a3a809c6417b0", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-39acc2e8471d20d3", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/notifications/"}, "properties": {"repobilityId": "665e1950e3d90332", "scanner": "scanner-primary", "fingerprint": "39acc2e8471d20d3", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-33df10ac9815d35a", "level": "note", "message": {"text": "Unused endpoint: PUT /api/v1/notifications/{alerte_id}/lue"}, "properties": {"repobilityId": "a9671dc3acec1c3d", "scanner": "scanner-primary", "fingerprint": "33df10ac9815d35a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-24e15a5787c3af34", "level": "note", "message": {"text": "Unused endpoint: DELETE /api/v1/notifications/all"}, "properties": {"repobilityId": "b3076d6706a4e8ae", "scanner": "scanner-primary", "fingerprint": "24e15a5787c3af34", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-94096e55ccb413ce", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/notifications/prefs"}, "properties": {"repobilityId": "b62e9c6dd71fdefb", "scanner": "scanner-primary", "fingerprint": "94096e55ccb413ce", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-b97217af0428e6b2", "level": "note", "message": {"text": "Unused endpoint: PUT /api/v1/notifications/prefs"}, "properties": {"repobilityId": "f0c37e3d1a53fcc1", "scanner": "scanner-primary", "fingerprint": "b97217af0428e6b2", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-07e10c77f3915647", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/bankroll/entries"}, "properties": {"repobilityId": "1f0c84737c60e14d", "scanner": "scanner-primary", "fingerprint": "07e10c77f3915647", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d87d856049a3b196", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/bankroll/entries"}, "properties": {"repobilityId": "1a21041c1b192439", "scanner": "scanner-primary", "fingerprint": "d87d856049a3b196", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a9ec86a86b751b0b", "level": "note", "message": {"text": "Unused endpoint: PATCH /api/v1/bankroll/entries/{entry_id}"}, "properties": {"repobilityId": "68b6049ab4035f24", "scanner": "scanner-primary", "fingerprint": "a9ec86a86b751b0b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-911724af7930f065", "level": "note", "message": {"text": "Unused endpoint: DELETE /api/v1/bankroll/entries/{entry_id}"}, "properties": {"repobilityId": "72aab549e16e8f8b", "scanner": "scanner-primary", "fingerprint": "911724af7930f065", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a84965ef4f801176", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/bankroll/stats"}, "properties": {"repobilityId": "b6f0205e7536f1df", "scanner": "scanner-primary", "fingerprint": "a84965ef4f801176", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-993eb8904258a125", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/bankroll/export"}, "properties": {"repobilityId": "e8eaa1b2149dcac0", "scanner": "scanner-primary", "fingerprint": "993eb8904258a125", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-0161d07875ed841f", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/bankroll/export/csv"}, "properties": {"repobilityId": "c7cde70161f27df8", "scanner": "scanner-primary", "fingerprint": "0161d07875ed841f", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f34235cbcca70ad3", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/bankroll/export/pdf"}, "properties": {"repobilityId": "78a5dead80797fc9", "scanner": "scanner-primary", "fingerprint": "f34235cbcca70ad3", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2c8f64207be0c928", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/bankroll/portefeuilles"}, "properties": {"repobilityId": "1678193bbbc4adad", "scanner": "scanner-primary", "fingerprint": "2c8f64207be0c928", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-fba8ebcf4adf6705", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/bankroll/portefeuilles"}, "properties": {"repobilityId": "1acb03f25df75e95", "scanner": "scanner-primary", "fingerprint": "fba8ebcf4adf6705", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9117c77480e10bc7", "level": "note", "message": {"text": "Unused endpoint: PUT /api/v1/bankroll/portefeuilles/{bankroll_id}"}, "properties": {"repobilityId": "cfebde3f41e210df", "scanner": "scanner-primary", "fingerprint": "9117c77480e10bc7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-cf21f8388c40e751", "level": "note", "message": {"text": "Unused endpoint: DELETE /api/v1/bankroll/portefeuilles/{bankroll_id}"}, "properties": {"repobilityId": "0ffd17efec595bd6", "scanner": "scanner-primary", "fingerprint": "cf21f8388c40e751", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5f258b679ceb30eb", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/assistant/chat"}, "properties": {"repobilityId": "dafc223243434878", "scanner": "scanner-primary", "fingerprint": "5f258b679ceb30eb", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-fd00117fc2812427", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/assistant/suggestions"}, "properties": {"repobilityId": "9a04f42d57155c6f", "scanner": "scanner-primary", "fingerprint": "fd00117fc2812427", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-92076c2733fc7c54", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/auth/register"}, "properties": {"repobilityId": "212834c72c86b0aa", "scanner": "scanner-primary", "fingerprint": "92076c2733fc7c54", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-72530ed44ad5a45a", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/auth/login"}, "properties": {"repobilityId": "48db0e79494e2568", "scanner": "scanner-primary", "fingerprint": "72530ed44ad5a45a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5be7411e2f955aa7", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/auth/refresh"}, "properties": {"repobilityId": "d702e459464d6e58", "scanner": "scanner-primary", "fingerprint": "5be7411e2f955aa7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d697b8b6d16c521a", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/auth/google"}, "properties": {"repobilityId": "e9d4a05275b2fd60", "scanner": "scanner-primary", "fingerprint": "d697b8b6d16c521a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f28d5598f27ace34", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/auth/me"}, "properties": {"repobilityId": "a1b3ef97fe02f397", "scanner": "scanner-primary", "fingerprint": "f28d5598f27ace34", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-bbac82a8ea1450d7", "level": "note", "message": {"text": "Unused endpoint: PATCH /api/v1/auth/me"}, "properties": {"repobilityId": "611a4b80aa0b0005", "scanner": "scanner-primary", "fingerprint": "bbac82a8ea1450d7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d712faa28bfd34fc", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/auth/resend-verification"}, "properties": {"repobilityId": "aa16cf63fa1190d5", "scanner": "scanner-primary", "fingerprint": "d712faa28bfd34fc", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-cd85d2abab3309ca", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/auth/verify-email"}, "properties": {"repobilityId": "6e14afff9139b544", "scanner": "scanner-primary", "fingerprint": "cd85d2abab3309ca", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5684ca2c4f33eed7", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/auth/forgot-password"}, "properties": {"repobilityId": "fc2761ccf5768180", "scanner": "scanner-primary", "fingerprint": "5684ca2c4f33eed7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-0f03ca5262a56374", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/auth/reset-password"}, "properties": {"repobilityId": "9d17cf167c1e5b42", "scanner": "scanner-primary", "fingerprint": "0f03ca5262a56374", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8829b53061ce58a5", "level": "note", "message": {"text": "Unused endpoint: PUT /api/v1/auth/push-subscription"}, "properties": {"repobilityId": "4bdf27a7e2a3a94f", "scanner": "scanner-primary", "fingerprint": "8829b53061ce58a5", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-3e6588cd40ddbe8c", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/courses/{course_id}/predictions"}, "properties": {"repobilityId": "4933fe084bf6585d", "scanner": "scanner-primary", "fingerprint": "3e6588cd40ddbe8c", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-c5e463fde9d32ad2", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/courses/{course_id}/predict"}, "properties": {"repobilityId": "f6f4beee1c64169e", "scanner": "scanner-primary", "fingerprint": "c5e463fde9d32ad2", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4f83c0840343eacf", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/value-bets"}, "properties": {"repobilityId": "ac58c675aeced2e1", "scanner": "scanner-primary", "fingerprint": "4f83c0840343eacf", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-36bb261b77efdcf3", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/pari-du-jour-profils"}, "properties": {"repobilityId": "1b7113a01b440502", "scanner": "scanner-primary", "fingerprint": "36bb261b77efdcf3", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-c1dfd1b558f56d57", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/pari-du-jour"}, "properties": {"repobilityId": "c3e97f16e2d27b83", "scanner": "scanner-primary", "fingerprint": "c1dfd1b558f56d57", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4c898df4c4e9b250", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/value-bets/historique"}, "properties": {"repobilityId": "5f32d3a3aedcef24", "scanner": "scanner-primary", "fingerprint": "4c898df4c4e9b250", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-dd0342dd3dd90f03", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/courses/{course_id}/analyse"}, "properties": {"repobilityId": "4611aa5e856b7140", "scanner": "scanner-primary", "fingerprint": "dd0342dd3dd90f03", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e1e5db105157c379", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/courses/{course_id}/dutch"}, "properties": {"repobilityId": "6a809543e62dda8a", "scanner": "scanner-primary", "fingerprint": "e1e5db105157c379", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-11f0ee5044f41fdf", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/courses/{course_id}/feature-importance"}, "properties": {"repobilityId": "743c47b02960face", "scanner": "scanner-primary", "fingerprint": "11f0ee5044f41fdf", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9df3890be7ea45a9", "level": "note", "message": {"text": "Unused endpoint: GET /api/v1/model/version"}, "properties": {"repobilityId": "d7f7b24496ce412e", "scanner": "scanner-primary", "fingerprint": "9df3890be7ea45a9", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-987e97d879e20f6e", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/telegram/webhook"}, "properties": {"repobilityId": "d3b228aeac5f1250", "scanner": "scanner-primary", "fingerprint": "987e97d879e20f6e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-6ec44f910ea70dc4", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/telegram/setup-webhook"}, "properties": {"repobilityId": "905cdb0ff88c77c4", "scanner": "scanner-primary", "fingerprint": "6ec44f910ea70dc4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e8d6c6c69cf237af", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/stripe/checkout"}, "properties": {"repobilityId": "f9b91b195978d14b", "scanner": "scanner-primary", "fingerprint": "e8d6c6c69cf237af", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-0026b7e45cb8b0e9", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/stripe/portal"}, "properties": {"repobilityId": "5c29dc473cc08e22", "scanner": "scanner-primary", "fingerprint": "0026b7e45cb8b0e9", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-c59819f14bc18216", "level": "note", "message": {"text": "Unused endpoint: POST /api/v1/stripe/webhook"}, "properties": {"repobilityId": "e63877f17fdded1c", "scanner": "scanner-primary", "fingerprint": "c59819f14bc18216", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-06dab826707e3f82", "level": "note", "message": {"text": "Unused endpoint: GET /admin/api/dashboard"}, "properties": {"repobilityId": "bb0fd4d97790d8fc", "scanner": "scanner-primary", "fingerprint": "06dab826707e3f82", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-0c40c92a29df9af8", "level": "note", "message": {"text": "Unused endpoint: GET /admin/api/users"}, "properties": {"repobilityId": "54df1a39045b12a2", "scanner": "scanner-primary", "fingerprint": "0c40c92a29df9af8", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-95b11f5eb8a15433", "level": "note", "message": {"text": "Unused endpoint: GET /admin/api/users/{user_id}"}, "properties": {"repobilityId": "7fb8601b100fd935", "scanner": "scanner-primary", "fingerprint": "95b11f5eb8a15433", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}