{"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-1d9300741be146ee", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/data-streams/data-streams-client.tsx:858", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/data-streams/data-streams-client.tsx:858"}, "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-80b5021a3df0c34d", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/tiers/tiers-client.tsx:813", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/tiers/tiers-client.tsx:813"}, "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-a4cec00108ced8ef", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/topology/topology-client.tsx:948", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/topology/topology-client.tsx:948"}, "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-f5081ae366923c61", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/evidence-packs/evidence-packs-client.tsx:518", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/evidence-packs/evidence-packs-client.tsx:518"}, "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-b195540597cc54ac", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/dashboards/dashboards-client.tsx:595", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/dashboards/dashboards-client.tsx:595"}, "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-e242db6a4b85f1c7", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/settings/clusters/clusters-client.tsx:766", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/settings/clusters/clusters-client.tsx:766"}, "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-4bff9e466c9553c7", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/overview/overview-client.tsx:1019", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/overview/overview-client.tsx:1019"}, "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-fe251452e8be150e", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/app-shell.tsx:129", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/app-shell.tsx:129"}, "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-fec706eac874618d", "name": "Very large file: apps/web/src/app/data-streams/data-streams-client.tsx (1576 lines)", "shortDescription": {"text": "Very large file: apps/web/src/app/data-streams/data-streams-client.tsx (1576 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-f28bbf4a09ec2800", "name": "Very large file: apps/web/src/app/overview/overview-client.tsx (1911 lines)", "shortDescription": {"text": "Very large file: apps/web/src/app/overview/overview-client.tsx (1911 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": "15 tests / 67 src (ratio 0.22)."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e4163774a587facf", "name": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/app/settings/clusters/clusters-client.tsx:347", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/app/settings/clusters/clusters-client.tsx:347"}, "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-1b5a76780c3df9aa", "name": "1 env vars used in code but missing from .env.example", "shortDescription": {"text": "1 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `FLEXICLAW_CREDENTIAL_KEY`. Add them (with a placeholder/comment) to .env.example so onboarding doesn't break."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "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:\npackages/core/flexiclaw_core/dashboards.py:latest_snapshot, packages/core/flexiclaw_core/evidence.py:latest_snapshot, apps/api/flexiclaw_api/routers/clusters.py:get_latest_snapshot\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-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:\napps/api/flexiclaw_api/schemas.py:credential_payload, apps/api/flexiclaw_api/schemas.py:credential_payload\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}}]}}, "automationDetails": {"id": "repobility/24778"}, "properties": {"repository": "byviz/flexiclaw-platform", "repoUrl": "https://github.com/byviz/flexiclaw-platform", "branch": "main"}, "results": [{"ruleId": "scanner-1d9300741be146ee", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/data-streams/data-streams-client.tsx:858"}, "properties": {"repobilityId": "714ae2d73a25b976", "scanner": "scanner-primary", "fingerprint": "1d9300741be146ee", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-80b5021a3df0c34d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/tiers/tiers-client.tsx:813"}, "properties": {"repobilityId": "9e219f1863673530", "scanner": "scanner-primary", "fingerprint": "80b5021a3df0c34d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a4cec00108ced8ef", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/topology/topology-client.tsx:948"}, "properties": {"repobilityId": "4e51c2d91e09531d", "scanner": "scanner-primary", "fingerprint": "a4cec00108ced8ef", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f5081ae366923c61", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/evidence-packs/evidence-packs-client.tsx:518"}, "properties": {"repobilityId": "3a7c045748e64de0", "scanner": "scanner-primary", "fingerprint": "f5081ae366923c61", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b195540597cc54ac", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/dashboards/dashboards-client.tsx:595"}, "properties": {"repobilityId": "bde7a2f5401a3d41", "scanner": "scanner-primary", "fingerprint": "b195540597cc54ac", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-e242db6a4b85f1c7", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/settings/clusters/clusters-client.tsx:766"}, "properties": {"repobilityId": "f327e7369f010e58", "scanner": "scanner-primary", "fingerprint": "e242db6a4b85f1c7", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4bff9e466c9553c7", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/app/overview/overview-client.tsx:1019"}, "properties": {"repobilityId": "ae6b6afa31c7b6d0", "scanner": "scanner-primary", "fingerprint": "4bff9e466c9553c7", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-fe251452e8be150e", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/app-shell.tsx:129"}, "properties": {"repobilityId": "2e0ddd2abf2e4915", "scanner": "scanner-primary", "fingerprint": "fe251452e8be150e", "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-fec706eac874618d", "level": "note", "message": {"text": "Very large file: apps/web/src/app/data-streams/data-streams-client.tsx (1576 lines)"}, "properties": {"repobilityId": "e2c3914d8c28af96", "scanner": "scanner-primary", "fingerprint": "fec706eac874618d", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-f28bbf4a09ec2800", "level": "note", "message": {"text": "Very large file: apps/web/src/app/overview/overview-client.tsx (1911 lines)"}, "properties": {"repobilityId": "e5ca39f06aa74e16", "scanner": "scanner-primary", "fingerprint": "f28bbf4a09ec2800", "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-e4163774a587facf", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/app/settings/clusters/clusters-client.tsx:347"}, "properties": {"repobilityId": "85f467e1a821e67a", "scanner": "scanner-primary", "fingerprint": "e4163774a587facf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-1b5a76780c3df9aa", "level": "none", "message": {"text": "1 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "d04379b337b44a15", "scanner": "scanner-primary", "fingerprint": "1b5a76780c3df9aa", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-be46ea126aa5d8dc", "level": "note", "message": {"text": "Near-duplicate function bodies in 3 places"}, "properties": {"repobilityId": "15b195e3814cd001", "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": "efdbfb65a049b1b2", "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": "6cd0d9be09827268", "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": "81a8036104d1c8ff", "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": "2838aaea503a615d", "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": "42c1ba3a6765665c", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}]}]}