{"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-1f2d9dfff55abba5", "name": "Stray `console.log` in TS/JS \u2014 backend/src/index.ts:56", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 backend/src/index.ts:56"}, "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-2998eb0b2ff6d6b6", "name": "Stray `console.log` in TS/JS \u2014 backend/src/db/service.ts:16", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 backend/src/db/service.ts:16"}, "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-ec36eea82753e548", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/page.tsx:58", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/page.tsx:58"}, "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-79c15b0f9ed2fb4a", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/ui.tsx:321", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/ui.tsx:321"}, "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-32d1e33de550df4a", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/PlayTab.tsx:194", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/PlayTab.tsx:194"}, "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-bf0b2b00191e1517", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/PlayersTab.tsx:112", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/PlayersTab.tsx:112"}, "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-2d591653a90064d9", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/StatsTab.tsx:119", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/StatsTab.tsx:119"}, "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-842557c764067fcc", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/HistoryTab.tsx:100", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/HistoryTab.tsx:100"}, "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-ea295ad128502313", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/modes/CaseMode.tsx:126", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/modes/CaseMode.tsx:126"}, "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-0ec99080ac25a7ae", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/modes/DraftMode.tsx:135", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/modes/DraftMode.tsx:135"}, "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-5ff7d4e240e6199d", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/modes/common.tsx:156", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/modes/common.tsx:156"}, "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-6372cebde0220094", "name": "No auth library detected", "shortDescription": {"text": "No auth library detected"}, "fullDescription": {"text": "The scanner did not find any standard auth library (JWT, OAuth, NextAuth, Auth0, etc.). The repo has auth/admin/session surface indicators, so auth may live in custom code, in a separate service, or be missing."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-0a5ab549038c1cc1", "name": "GitHub Action is tag-pinned rather than SHA-pinned", "shortDescription": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "fullDescription": {"text": "tauri-apps/tauri-action@v0 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-4da77c8b475b9ec3", "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-28c4a04bd807da0c", "name": "GitHub Action is tag-pinned rather than SHA-pinned", "shortDescription": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "fullDescription": {"text": "actions/deploy-pages@v4 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-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-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "0 test file(s) for 37 source file(s) (ratio 0.00). Consider adding integration or unit tests for critical paths."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-141b30a41e03817b", "name": "No license file detected", "shortDescription": {"text": "No license file detected"}, "fullDescription": {"text": "No LICENSE/COPYING/NOTICE file was found. Generated repositories often omit licensing, which blocks reuse and automated intake."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3a092b5c39e242a1", "name": "Node manifest has dependencies but no lockfile: backend/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: backend/package.json"}, "fullDescription": {"text": "`package.json` declares dependencies, but no same-directory npm/pnpm/yarn/bun lockfile was found. Generated projects without lockfiles are less reproducible and harder to secure-scan precisely."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2d0c7b7ab8f8aacf", "name": "Critical user flow still appears backed by mock or placeholder data", "shortDescription": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "fullDescription": {"text": "A payment/auth/admin/order/billing-style flow contains mock, fake, TODO, dummy, or placeholder markers in runtime source. In the Fable corpus this is a high-leverage completeness smell: the app can look finished while the money, identity, or tenant flow is still scaffolded."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-11825279136b53a3", "name": "CI is configured but no tests are detected", "shortDescription": {"text": "CI is configured but no tests are detected"}, "fullDescription": {"text": "A CI pipeline exists, but the scan found no test files to gate. Opus labeled this generated-code pattern as config theater: release machinery exists, but it has little behavioral signal."}, "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, tests, lockfile. 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": "medium", "confidence": 1.0}}, {"id": "scanner-c05c4efb4e408239", "name": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/lib/ddragon.ts:32", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/lib/ddragon.ts:32"}, "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-5baa8971ebe192a1", "name": "Unused endpoint: GET /", "shortDescription": {"text": "Unused endpoint: GET /"}, "fullDescription": {"text": "`backend/api/index.ts` declares `GET /` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a3c7eaacc44a0d8e", "name": "Unused endpoint: POST /random", "shortDescription": {"text": "Unused endpoint: POST /random"}, "fullDescription": {"text": "`backend/src/routes/games.ts` declares `POST /random` 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-557f558e0855ff9d", "name": "Unused endpoint: POST /captain", "shortDescription": {"text": "Unused endpoint: POST /captain"}, "fullDescription": {"text": "`backend/src/routes/games.ts` declares `POST /captain` 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-cc45d32de360740d", "name": "Unused endpoint: POST /wheel", "shortDescription": {"text": "Unused endpoint: POST /wheel"}, "fullDescription": {"text": "`backend/src/routes/games.ts` declares `POST /wheel` 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-ca5756175765b49d", "name": "Unused endpoint: GET /:id", "shortDescription": {"text": "Unused endpoint: GET /:id"}, "fullDescription": {"text": "`backend/src/routes/games.ts` declares `GET /: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-3b30f4c0994a30b4", "name": "Unused endpoint: DELETE /", "shortDescription": {"text": "Unused endpoint: DELETE /"}, "fullDescription": {"text": "`backend/src/routes/games.ts` declares `DELETE /` 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-7a009b1a56794f45", "name": "Unused endpoint: POST /", "shortDescription": {"text": "Unused endpoint: POST /"}, "fullDescription": {"text": "`backend/src/routes/matches.ts` declares `POST /` 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-03aaa75ed73a0881", "name": "Unused endpoint: PATCH /:id/complete", "shortDescription": {"text": "Unused endpoint: PATCH /:id/complete"}, "fullDescription": {"text": "`backend/src/routes/matches.ts` declares `PATCH /:id/complete` 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-7c30c711d68dc5f9", "name": "Unused endpoint: GET /statistics", "shortDescription": {"text": "Unused endpoint: GET /statistics"}, "fullDescription": {"text": "`backend/src/routes/matches.ts` declares `GET /statistics` 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-fe8e0f1921dea745", "name": "Unused endpoint: GET /statistics/overview", "shortDescription": {"text": "Unused endpoint: GET /statistics/overview"}, "fullDescription": {"text": "`backend/src/routes/matches.ts` declares `GET /statistics/overview` 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-5fbc954f63526821", "name": "Unused endpoint: PATCH /:id", "shortDescription": {"text": "Unused endpoint: PATCH /:id"}, "fullDescription": {"text": "`backend/src/routes/matches.ts` declares `PATCH /: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-7a61c112b611f4bb", "name": "Unused endpoint: DELETE /:id", "shortDescription": {"text": "Unused endpoint: DELETE /:id"}, "fullDescription": {"text": "`backend/src/routes/matches.ts` declares `DELETE /: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-6b5926bb4ca569fd", "name": "Unused endpoint: GET /export/:playerId", "shortDescription": {"text": "Unused endpoint: GET /export/:playerId"}, "fullDescription": {"text": "`backend/src/routes/matches.ts` declares `GET /export/:playerId` 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-5d0613dcd0fda5a0", "name": "Unused endpoint: POST /:gameId/complete", "shortDescription": {"text": "Unused endpoint: POST /:gameId/complete"}, "fullDescription": {"text": "`backend/src/routes/match-history.ts` declares `POST /:gameId/complete` 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-c4e68c24f8e6c5f9", "name": "Unused endpoint: GET /stats/players", "shortDescription": {"text": "Unused endpoint: GET /stats/players"}, "fullDescription": {"text": "`backend/src/routes/match-history.ts` declares `GET /stats/players` 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-5032e3144ad00d34", "name": "Unused endpoint: GET /stats/overview", "shortDescription": {"text": "Unused endpoint: GET /stats/overview"}, "fullDescription": {"text": "`backend/src/routes/match-history.ts` declares `GET /stats/overview` 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-9edfffc2c99514bc", "name": "Unused endpoint: GET /inactive", "shortDescription": {"text": "Unused endpoint: GET /inactive"}, "fullDescription": {"text": "`backend/src/routes/players.ts` declares `GET /inactive` 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-90631dcf4fb49f54", "name": "Unused endpoint: POST /bulk", "shortDescription": {"text": "Unused endpoint: POST /bulk"}, "fullDescription": {"text": "`backend/src/routes/players.ts` declares `POST /bulk` 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-8d5b2b188d08ca82", "name": "Unused endpoint: PUT /:id", "shortDescription": {"text": "Unused endpoint: PUT /:id"}, "fullDescription": {"text": "`backend/src/routes/players.ts` declares `PUT /: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-0ca7f3140223f687", "name": "Unused endpoint: PATCH /:id/reactivate", "shortDescription": {"text": "Unused endpoint: PATCH /:id/reactivate"}, "fullDescription": {"text": "`backend/src/routes/players.ts` declares `PATCH /:id/reactivate` 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/24178"}, "properties": {"repository": "andreidavid03/League-Custom-Game-Helper", "repoUrl": "https://github.com/andreidavid03/League-Custom-Game-Helper", "branch": "main"}, "results": [{"ruleId": "scanner-1f2d9dfff55abba5", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 backend/src/index.ts:56"}, "properties": {"repobilityId": "db2171a39601fa41", "scanner": "scanner-primary", "fingerprint": "1f2d9dfff55abba5", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-2998eb0b2ff6d6b6", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 backend/src/db/service.ts:16"}, "properties": {"repobilityId": "2275ad3194c85ddc", "scanner": "scanner-primary", "fingerprint": "2998eb0b2ff6d6b6", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-ec36eea82753e548", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/page.tsx:58"}, "properties": {"repobilityId": "646669d428c89604", "scanner": "scanner-primary", "fingerprint": "ec36eea82753e548", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-79c15b0f9ed2fb4a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/ui.tsx:321"}, "properties": {"repobilityId": "38d079c0add1126a", "scanner": "scanner-primary", "fingerprint": "79c15b0f9ed2fb4a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-32d1e33de550df4a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/PlayTab.tsx:194"}, "properties": {"repobilityId": "f95e86dd7398ab9c", "scanner": "scanner-primary", "fingerprint": "32d1e33de550df4a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-bf0b2b00191e1517", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/PlayersTab.tsx:112"}, "properties": {"repobilityId": "458257db05b8a6bf", "scanner": "scanner-primary", "fingerprint": "bf0b2b00191e1517", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-2d591653a90064d9", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/StatsTab.tsx:119"}, "properties": {"repobilityId": "b89b3d97098299a8", "scanner": "scanner-primary", "fingerprint": "2d591653a90064d9", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-842557c764067fcc", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/tabs/HistoryTab.tsx:100"}, "properties": {"repobilityId": "2a9f29407c50db47", "scanner": "scanner-primary", "fingerprint": "842557c764067fcc", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-ea295ad128502313", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/modes/CaseMode.tsx:126"}, "properties": {"repobilityId": "639e78192fa7da16", "scanner": "scanner-primary", "fingerprint": "ea295ad128502313", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-0ec99080ac25a7ae", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/modes/DraftMode.tsx:135"}, "properties": {"repobilityId": "87da7602d6342d06", "scanner": "scanner-primary", "fingerprint": "0ec99080ac25a7ae", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-5ff7d4e240e6199d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/components/modes/common.tsx:156"}, "properties": {"repobilityId": "3871ad0f06d7d9a3", "scanner": "scanner-primary", "fingerprint": "5ff7d4e240e6199d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-6372cebde0220094", "level": "warning", "message": {"text": "No auth library detected"}, "properties": {"repobilityId": "a5b6035a5bbf8054", "scanner": "scanner-primary", "fingerprint": "6372cebde0220094", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["coverage", "auth"]}}, {"ruleId": "scanner-0a5ab549038c1cc1", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "21d72c513ba52208", "scanner": "scanner-primary", "fingerprint": "0a5ab549038c1cc1", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/desktop.yml"}, "region": {"startLine": 43}}}]}, {"ruleId": "scanner-4da77c8b475b9ec3", "level": "warning", "message": {"text": "GitHub Actions workflow grants broad write permissions"}, "properties": {"repobilityId": "e1da11cf4c7b100d", "scanner": "scanner-primary", "fingerprint": "4da77c8b475b9ec3", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "least-privilege"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/desktop.yml"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-28c4a04bd807da0c", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "419d1ec7943efec2", "scanner": "scanner-primary", "fingerprint": "28c4a04bd807da0c", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy.yml"}, "region": {"startLine": 51}}}]}, {"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-6893a6c8b0861585", "level": "warning", "message": {"text": "Very low test-to-source ratio"}, "properties": {"repobilityId": "54a7de3f06314bf0", "scanner": "scanner-primary", "fingerprint": "6893a6c8b0861585", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["tests", "coverage"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "9d6fa9f8ac3cd70e", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-3a092b5c39e242a1", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: backend/package.json"}, "properties": {"repobilityId": "fc853e57ce7048c4", "scanner": "scanner-primary", "fingerprint": "3a092b5c39e242a1", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "backend/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-2d0c7b7ab8f8aacf", "level": "warning", "message": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "properties": {"repobilityId": "7c3ba07dba911d22", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-11825279136b53a3", "level": "warning", "message": {"text": "CI is configured but no tests are detected"}, "properties": {"repobilityId": "1f60d86cae7726b5", "scanner": "scanner-primary", "fingerprint": "11825279136b53a3", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["tests", "ci", "config-theater", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-b9088664ace7f748", "level": "warning", "message": {"text": "Composite production-readiness gap"}, "properties": {"repobilityId": "b402f7016059d4cd", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-c05c4efb4e408239", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/lib/ddragon.ts:32"}, "properties": {"repobilityId": "88f482ae2fe22331", "scanner": "scanner-primary", "fingerprint": "c05c4efb4e408239", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-5baa8971ebe192a1", "level": "note", "message": {"text": "Unused endpoint: GET /"}, "properties": {"repobilityId": "42c1b3d10318ddef", "scanner": "scanner-primary", "fingerprint": "5baa8971ebe192a1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a3c7eaacc44a0d8e", "level": "note", "message": {"text": "Unused endpoint: POST /random"}, "properties": {"repobilityId": "5cf6c1d34f445e4b", "scanner": "scanner-primary", "fingerprint": "a3c7eaacc44a0d8e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-557f558e0855ff9d", "level": "note", "message": {"text": "Unused endpoint: POST /captain"}, "properties": {"repobilityId": "8907b2bc0b7ede00", "scanner": "scanner-primary", "fingerprint": "557f558e0855ff9d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-cc45d32de360740d", "level": "note", "message": {"text": "Unused endpoint: POST /wheel"}, "properties": {"repobilityId": "7948390068249e8b", "scanner": "scanner-primary", "fingerprint": "cc45d32de360740d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ca5756175765b49d", "level": "note", "message": {"text": "Unused endpoint: GET /:id"}, "properties": {"repobilityId": "e4afaf91e5d71999", "scanner": "scanner-primary", "fingerprint": "ca5756175765b49d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-3b30f4c0994a30b4", "level": "note", "message": {"text": "Unused endpoint: DELETE /"}, "properties": {"repobilityId": "731616d305885c1f", "scanner": "scanner-primary", "fingerprint": "3b30f4c0994a30b4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7a009b1a56794f45", "level": "note", "message": {"text": "Unused endpoint: POST /"}, "properties": {"repobilityId": "113db91bc5f2cda9", "scanner": "scanner-primary", "fingerprint": "7a009b1a56794f45", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-03aaa75ed73a0881", "level": "note", "message": {"text": "Unused endpoint: PATCH /:id/complete"}, "properties": {"repobilityId": "8ff5ae8c3b9a92fb", "scanner": "scanner-primary", "fingerprint": "03aaa75ed73a0881", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7c30c711d68dc5f9", "level": "note", "message": {"text": "Unused endpoint: GET /statistics"}, "properties": {"repobilityId": "a3b007fae231c6ec", "scanner": "scanner-primary", "fingerprint": "7c30c711d68dc5f9", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-fe8e0f1921dea745", "level": "note", "message": {"text": "Unused endpoint: GET /statistics/overview"}, "properties": {"repobilityId": "976fa9201589b50d", "scanner": "scanner-primary", "fingerprint": "fe8e0f1921dea745", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5fbc954f63526821", "level": "note", "message": {"text": "Unused endpoint: PATCH /:id"}, "properties": {"repobilityId": "b1ab8fc8502a149a", "scanner": "scanner-primary", "fingerprint": "5fbc954f63526821", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7a61c112b611f4bb", "level": "note", "message": {"text": "Unused endpoint: DELETE /:id"}, "properties": {"repobilityId": "e2337b32a2e69225", "scanner": "scanner-primary", "fingerprint": "7a61c112b611f4bb", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-6b5926bb4ca569fd", "level": "note", "message": {"text": "Unused endpoint: GET /export/:playerId"}, "properties": {"repobilityId": "6c0a1ab828b9a5f2", "scanner": "scanner-primary", "fingerprint": "6b5926bb4ca569fd", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5d0613dcd0fda5a0", "level": "note", "message": {"text": "Unused endpoint: POST /:gameId/complete"}, "properties": {"repobilityId": "5d72039fe9df7249", "scanner": "scanner-primary", "fingerprint": "5d0613dcd0fda5a0", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-c4e68c24f8e6c5f9", "level": "note", "message": {"text": "Unused endpoint: GET /stats/players"}, "properties": {"repobilityId": "b48254700b919f0c", "scanner": "scanner-primary", "fingerprint": "c4e68c24f8e6c5f9", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5032e3144ad00d34", "level": "note", "message": {"text": "Unused endpoint: GET /stats/overview"}, "properties": {"repobilityId": "8d812058f6a7217f", "scanner": "scanner-primary", "fingerprint": "5032e3144ad00d34", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9edfffc2c99514bc", "level": "note", "message": {"text": "Unused endpoint: GET /inactive"}, "properties": {"repobilityId": "215e2f5c3f2f867a", "scanner": "scanner-primary", "fingerprint": "9edfffc2c99514bc", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-90631dcf4fb49f54", "level": "note", "message": {"text": "Unused endpoint: POST /bulk"}, "properties": {"repobilityId": "9971372fa22b604a", "scanner": "scanner-primary", "fingerprint": "90631dcf4fb49f54", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8d5b2b188d08ca82", "level": "note", "message": {"text": "Unused endpoint: PUT /:id"}, "properties": {"repobilityId": "e33d483cc90d9d50", "scanner": "scanner-primary", "fingerprint": "8d5b2b188d08ca82", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-0ca7f3140223f687", "level": "note", "message": {"text": "Unused endpoint: PATCH /:id/reactivate"}, "properties": {"repobilityId": "99a55d32bc62457a", "scanner": "scanner-primary", "fingerprint": "0ca7f3140223f687", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}