{"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-3090f658001a2d98", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/App.tsx:662", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/App.tsx:662"}, "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-b4aadb6614e93626", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ForwardModal.tsx:116", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ForwardModal.tsx:116"}, "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-a6ee0c48a69a9d5d", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelSettingsModal.tsx:38", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelSettingsModal.tsx:38"}, "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-df8f6ba4e426446c", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/QuickSwitcher.tsx:162", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/QuickSwitcher.tsx:162"}, "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-73088057af3d9404", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ForumView.tsx:55", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ForumView.tsx:55"}, "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-8f92a6c05f25fc83", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/UserSettingsModal.tsx:86", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/UserSettingsModal.tsx:86"}, "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-413d3974d1b79356", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MediaView.tsx:36", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MediaView.tsx:36"}, "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-69ab4e2bc5348a11", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/UserProfileCard.tsx:219", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/UserProfileCard.tsx:219"}, "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-33905864012cb52a", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/StageView.tsx:122", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/StageView.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-ecbee4f0dfae1af5", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/AddFriendModal.tsx:263", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/AddFriendModal.tsx:263"}, "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-8deb903feae5f021", "name": "TODO/FIXME marker in shipping code \u2014 apps/web/src/components/AddFriendModal.tsx:99", "shortDescription": {"text": "TODO/FIXME marker in shipping code \u2014 apps/web/src/components/AddFriendModal.tsx:99"}, "fullDescription": {"text": "Track in /reviews or /issues, not as a code comment that rots.\n\nWhy: Drift control \u2014 shouldn't be the same as Quality TODO scanner.\nRule id: fq.todo-marker"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-e171f89726dc2680", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ScheduleMessageModal.tsx:122", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ScheduleMessageModal.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-443de6927374a02e", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/SearchModal.tsx:217", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/SearchModal.tsx:217"}, "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-61e31c06ac147a36", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/DMSidebar.tsx:160", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/DMSidebar.tsx:160"}, "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-2a5d7d0694326b8d", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/DiscoverPage.tsx:127", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/DiscoverPage.tsx:127"}, "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-a6cdf31b80df7fe1", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/OnboardingGate.tsx:114", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/OnboardingGate.tsx:114"}, "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-fac784b39112cf50", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/SavedMessagesModal.tsx:79", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/SavedMessagesModal.tsx:79"}, "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-36a8dfd27fc3613f", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MemberList.tsx:475", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MemberList.tsx:475"}, "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-871511608d9fac6d", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelList.tsx:238", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelList.tsx:238"}, "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-e571a3ec05a90c28", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MessageInput.tsx:461", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MessageInput.tsx:461"}, "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-81cd27ed442c84f3", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/VoiceStatusBar.tsx:82", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/VoiceStatusBar.tsx:82"}, "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-b4ccd0a943308388", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ServerSettingsModal.tsx:113", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ServerSettingsModal.tsx:113"}, "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-f7010dba6f6dd378", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/JoinGuildModal.tsx:94", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/JoinGuildModal.tsx:94"}, "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-da4ac5f6064c3ee3", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/DMUserPanel.tsx:280", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/DMUserPanel.tsx:280"}, "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-444e38950ea5bbdd", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/NewDMModal.tsx:164", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/NewDMModal.tsx:164"}, "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-03d2bd500e1be198", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelHeader.tsx:62", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelHeader.tsx:62"}, "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-40011492c74d8355", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MentionPicker.tsx:136", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MentionPicker.tsx:136"}, "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-644b9bc8c9ee6948", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelPermissionsModal.tsx:184", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelPermissionsModal.tsx:184"}, "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-5f7f9d6f982bc2f1", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MessageList.tsx:647", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MessageList.tsx:647"}, "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-8561d79c7e750e95", "name": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/FollowChannelModal.tsx:105", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/FollowChannelModal.tsx:105"}, "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-ae8f401ea3b16d98", "name": "Docker base image is tag-pinned but not digest-pinned: golang:1.22-alpine", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: golang:1.22-alpine"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e9a2abc56354d4d8", "name": "Docker base image is tag-pinned but not digest-pinned: alpine:3.19", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: alpine:3.19"}, "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-0cb3d9a9d0160cb2", "name": "Insecure pattern 'weak_hash' in apps/api/internal/auth/totp.go:67", "shortDescription": {"text": "Insecure pattern 'weak_hash' in apps/api/internal/auth/totp.go:67"}, "fullDescription": {"text": "Found a known-risky pattern (weak_hash). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-4ee81336338680de", "name": "Insecure pattern 'cors_wildcard' in apps/voice/src/presence_http.ts:16", "shortDescription": {"text": "Insecure pattern 'cors_wildcard' in apps/voice/src/presence_http.ts:16"}, "fullDescription": {"text": "Found a known-risky pattern (cors_wildcard). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "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/cache@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-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-dbacdf77955ed696", "name": "Very large file: apps/web/src/components/UserSettingsModal.tsx (1905 lines)", "shortDescription": {"text": "Very large file: apps/web/src/components/UserSettingsModal.tsx (1905 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-61112eb60d32f78d", "name": "Very large file: apps/web/src/components/ChannelList.tsx (1345 lines)", "shortDescription": {"text": "Very large file: apps/web/src/components/ChannelList.tsx (1345 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-aef2d60a22b34a0a", "name": "Very large file: apps/web/src/components/ServerSettingsModal.tsx (2515 lines)", "shortDescription": {"text": "Very large file: apps/web/src/components/ServerSettingsModal.tsx (2515 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-5537999221020194", "name": "Very large file: apps/web/src/components/MessageList.tsx (1592 lines)", "shortDescription": {"text": "Very large file: apps/web/src/components/MessageList.tsx (1592 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-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "1 test file(s) for 172 source file(s) (ratio 0.01). 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-d57b3f82d2270c5b", "name": "Node manifest has dependencies but no lockfile: apps/desktop/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: apps/desktop/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-d2fbf77fe73b8fa2", "name": "Node manifest has dependencies but no lockfile: apps/voice/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: apps/voice/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-d0c2205560692580", "name": "Node manifest has dependencies but no lockfile: apps/mobile/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: apps/mobile/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-4a9eb7dc7c6e3880", "name": "Node manifest has dependencies but no lockfile: apps/web/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: apps/web/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-cb3e52667c84fb86", "name": "Node manifest has dependencies but no lockfile: packages/types/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: packages/types/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-72b2a6250083a784", "name": "Placeholder or mock-heavy implementation detected", "shortDescription": {"text": "Placeholder or mock-heavy implementation detected"}, "fullDescription": {"text": "Found 123 placeholder/mock markers across 31 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-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-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-6ef2d151615fb37f", "name": "Commented-code block (9 lines) in apps/voice/src/signaling.ts:1", "shortDescription": {"text": "Commented-code block (9 lines) in apps/voice/src/signaling.ts:1"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-5bd0697c05328b9b", "name": "Legacy-named symbol `icon_url_v2` in apps/mobile/src/api.ts:89", "shortDescription": {"text": "Legacy-named symbol `icon_url_v2` in apps/mobile/src/api.ts:89"}, "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-3af65d4011bc4986", "name": "Legacy-named symbol `icon_url_v2` in apps/mobile/src/screens/HomeScreen.tsx:141", "shortDescription": {"text": "Legacy-named symbol `icon_url_v2` in apps/mobile/src/screens/HomeScreen.tsx:141"}, "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-ae2d7db7017287f4", "name": "Legacy-named symbol `icon_url_v2` in apps/web/src/api.ts:37", "shortDescription": {"text": "Legacy-named symbol `icon_url_v2` in apps/web/src/api.ts:37"}, "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-de1a225025fce190", "name": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/store.ts:376", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/store.ts:376"}, "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-ad97e20d196ffdb7", "name": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/UserSettingsModal.tsx:129", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/UserSettingsModal.tsx:129"}, "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-1b08684b41b867e0", "name": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/AddFriendModal.tsx:72", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/AddFriendModal.tsx:72"}, "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-acf9e3bacd827e4c", "name": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/GifPicker.tsx:47", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/GifPicker.tsx:47"}, "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-9b1da8390fa1c8d9", "name": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/CreateGuildModal.tsx:83", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/CreateGuildModal.tsx:83"}, "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-3176cf2400901777", "name": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/MessageInput.tsx:146", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/MessageInput.tsx:146"}, "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-e47cc01fddb64549", "name": "Legacy-named symbol `icon_url_v2` in apps/web/src/components/ServerSettingsModal.tsx:209", "shortDescription": {"text": "Legacy-named symbol `icon_url_v2` in apps/web/src/components/ServerSettingsModal.tsx:209"}, "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-3b8769515921eadb", "name": "Legacy-named symbol `icon_url_v2` in apps/web/src/components/ServerRail.tsx:190", "shortDescription": {"text": "Legacy-named symbol `icon_url_v2` in apps/web/src/components/ServerRail.tsx:190"}, "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-d0b17c8c07a7421d", "name": "8 env vars used in code but missing from .env.example", "shortDescription": {"text": "8 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `API_INTERNAL_URL`, `MS_ANNOUNCED_IP`, `MS_LISTEN_IP`, `MS_RTC_MAX_PORT`, `MS_RTC_MIN_PORT`, `SIDCORD_JWT_SECRET`, `VOICE_CONTROL_SECRET`, `VOICE_HTTP_PORT`. 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}}]}}, "automationDetails": {"id": "repobility/19857"}, "properties": {"repository": "slymnysr/sidcord", "repoUrl": "https://github.com/slymnysr/sidcord", "branch": "main"}, "results": [{"ruleId": "scanner-3090f658001a2d98", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/App.tsx:662"}, "properties": {"repobilityId": "9dd2be8e09997a2f", "scanner": "scanner-primary", "fingerprint": "3090f658001a2d98", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b4aadb6614e93626", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ForwardModal.tsx:116"}, "properties": {"repobilityId": "977335e7549486b5", "scanner": "scanner-primary", "fingerprint": "b4aadb6614e93626", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a6ee0c48a69a9d5d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelSettingsModal.tsx:38"}, "properties": {"repobilityId": "9facb88cc6fbb4ab", "scanner": "scanner-primary", "fingerprint": "a6ee0c48a69a9d5d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-df8f6ba4e426446c", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/QuickSwitcher.tsx:162"}, "properties": {"repobilityId": "b0b187e437313acf", "scanner": "scanner-primary", "fingerprint": "df8f6ba4e426446c", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-73088057af3d9404", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ForumView.tsx:55"}, "properties": {"repobilityId": "6df2e6f714570670", "scanner": "scanner-primary", "fingerprint": "73088057af3d9404", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-8f92a6c05f25fc83", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/UserSettingsModal.tsx:86"}, "properties": {"repobilityId": "b4e9b2341306b23a", "scanner": "scanner-primary", "fingerprint": "8f92a6c05f25fc83", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-413d3974d1b79356", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MediaView.tsx:36"}, "properties": {"repobilityId": "e6e65ba18a5f9936", "scanner": "scanner-primary", "fingerprint": "413d3974d1b79356", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-69ab4e2bc5348a11", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/UserProfileCard.tsx:219"}, "properties": {"repobilityId": "bd6d445c9c3d30e5", "scanner": "scanner-primary", "fingerprint": "69ab4e2bc5348a11", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-33905864012cb52a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/StageView.tsx:122"}, "properties": {"repobilityId": "c495bee0aa53d95f", "scanner": "scanner-primary", "fingerprint": "33905864012cb52a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-ecbee4f0dfae1af5", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/AddFriendModal.tsx:263"}, "properties": {"repobilityId": "4507a5fd8244669b", "scanner": "scanner-primary", "fingerprint": "ecbee4f0dfae1af5", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-8deb903feae5f021", "level": "none", "message": {"text": "TODO/FIXME marker in shipping code \u2014 apps/web/src/components/AddFriendModal.tsx:99"}, "properties": {"repobilityId": "f412e80f1ce961fc", "scanner": "scanner-primary", "fingerprint": "8deb903feae5f021", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.todo-marker"]}}, {"ruleId": "scanner-e171f89726dc2680", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ScheduleMessageModal.tsx:122"}, "properties": {"repobilityId": "60ed028bd28f7e65", "scanner": "scanner-primary", "fingerprint": "e171f89726dc2680", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-443de6927374a02e", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/SearchModal.tsx:217"}, "properties": {"repobilityId": "68690e2346a532d8", "scanner": "scanner-primary", "fingerprint": "443de6927374a02e", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-61e31c06ac147a36", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/DMSidebar.tsx:160"}, "properties": {"repobilityId": "a0eb4b4452efea35", "scanner": "scanner-primary", "fingerprint": "61e31c06ac147a36", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-2a5d7d0694326b8d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/DiscoverPage.tsx:127"}, "properties": {"repobilityId": "2271152010865c85", "scanner": "scanner-primary", "fingerprint": "2a5d7d0694326b8d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a6cdf31b80df7fe1", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/OnboardingGate.tsx:114"}, "properties": {"repobilityId": "10e6dbeb3b0b05e1", "scanner": "scanner-primary", "fingerprint": "a6cdf31b80df7fe1", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-fac784b39112cf50", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/SavedMessagesModal.tsx:79"}, "properties": {"repobilityId": "6a6dcb679963961c", "scanner": "scanner-primary", "fingerprint": "fac784b39112cf50", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-36a8dfd27fc3613f", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MemberList.tsx:475"}, "properties": {"repobilityId": "c4834b057ba0c24c", "scanner": "scanner-primary", "fingerprint": "36a8dfd27fc3613f", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-871511608d9fac6d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelList.tsx:238"}, "properties": {"repobilityId": "d93835d1134c419d", "scanner": "scanner-primary", "fingerprint": "871511608d9fac6d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-e571a3ec05a90c28", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MessageInput.tsx:461"}, "properties": {"repobilityId": "e3d1910dd73fcfe6", "scanner": "scanner-primary", "fingerprint": "e571a3ec05a90c28", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-81cd27ed442c84f3", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/VoiceStatusBar.tsx:82"}, "properties": {"repobilityId": "8107b00d80fc1306", "scanner": "scanner-primary", "fingerprint": "81cd27ed442c84f3", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b4ccd0a943308388", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ServerSettingsModal.tsx:113"}, "properties": {"repobilityId": "c8eb88124def1145", "scanner": "scanner-primary", "fingerprint": "b4ccd0a943308388", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f7010dba6f6dd378", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/JoinGuildModal.tsx:94"}, "properties": {"repobilityId": "3f224b61f2adc1c3", "scanner": "scanner-primary", "fingerprint": "f7010dba6f6dd378", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-da4ac5f6064c3ee3", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/DMUserPanel.tsx:280"}, "properties": {"repobilityId": "86563212df1e18cf", "scanner": "scanner-primary", "fingerprint": "da4ac5f6064c3ee3", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-444e38950ea5bbdd", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/NewDMModal.tsx:164"}, "properties": {"repobilityId": "1ed72f6f85b5adff", "scanner": "scanner-primary", "fingerprint": "444e38950ea5bbdd", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-03d2bd500e1be198", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelHeader.tsx:62"}, "properties": {"repobilityId": "6eb6bdc1101d5f18", "scanner": "scanner-primary", "fingerprint": "03d2bd500e1be198", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-40011492c74d8355", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MentionPicker.tsx:136"}, "properties": {"repobilityId": "74a0ef38f4b1dfa7", "scanner": "scanner-primary", "fingerprint": "40011492c74d8355", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-644b9bc8c9ee6948", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/ChannelPermissionsModal.tsx:184"}, "properties": {"repobilityId": "beecb958f9b8a90d", "scanner": "scanner-primary", "fingerprint": "644b9bc8c9ee6948", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-5f7f9d6f982bc2f1", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/MessageList.tsx:647"}, "properties": {"repobilityId": "e32df37b48b5c3a9", "scanner": "scanner-primary", "fingerprint": "5f7f9d6f982bc2f1", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-8561d79c7e750e95", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 apps/web/src/components/FollowChannelModal.tsx:105"}, "properties": {"repobilityId": "a05e3c3b53c15c97", "scanner": "scanner-primary", "fingerprint": "8561d79c7e750e95", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-ae8f401ea3b16d98", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: golang:1.22-alpine"}, "properties": {"repobilityId": "713e58fd122742e7", "scanner": "scanner-primary", "fingerprint": "ae8f401ea3b16d98", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-e9a2abc56354d4d8", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: alpine:3.19"}, "properties": {"repobilityId": "78cea9423f8446f7", "scanner": "scanner-primary", "fingerprint": "e9a2abc56354d4d8", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/Dockerfile"}, "region": {"startLine": 9}}}]}, {"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-0cb3d9a9d0160cb2", "level": "warning", "message": {"text": "Insecure pattern 'weak_hash' in apps/api/internal/auth/totp.go:67"}, "properties": {"repobilityId": "91f5c92fe5550031", "scanner": "scanner-primary", "fingerprint": "0cb3d9a9d0160cb2", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "weak_hash"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/api/internal/auth/totp.go"}, "region": {"startLine": 67}}}]}, {"ruleId": "scanner-4ee81336338680de", "level": "warning", "message": {"text": "Insecure pattern 'cors_wildcard' in apps/voice/src/presence_http.ts:16"}, "properties": {"repobilityId": "85b98c22f71a1065", "scanner": "scanner-primary", "fingerprint": "4ee81336338680de", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "cors_wildcard"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/voice/src/presence_http.ts"}, "region": {"startLine": 16}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "54c8f1b47dd62535", "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": 66}}}]}, {"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": 51}}}]}, {"ruleId": "scanner-0a5ab549038c1cc1", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "5bd36feff7fd1cce", "scanner": "scanner-primary", "fingerprint": "0a5ab549038c1cc1", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/desktop.yml"}, "region": {"startLine": 66}}}]}, {"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-dbacdf77955ed696", "level": "note", "message": {"text": "Very large file: apps/web/src/components/UserSettingsModal.tsx (1905 lines)"}, "properties": {"repobilityId": "154fde757db960be", "scanner": "scanner-primary", "fingerprint": "dbacdf77955ed696", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-61112eb60d32f78d", "level": "note", "message": {"text": "Very large file: apps/web/src/components/ChannelList.tsx (1345 lines)"}, "properties": {"repobilityId": "7fa988fcfce24791", "scanner": "scanner-primary", "fingerprint": "61112eb60d32f78d", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-aef2d60a22b34a0a", "level": "note", "message": {"text": "Very large file: apps/web/src/components/ServerSettingsModal.tsx (2515 lines)"}, "properties": {"repobilityId": "06baf08bf304c417", "scanner": "scanner-primary", "fingerprint": "aef2d60a22b34a0a", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-5537999221020194", "level": "note", "message": {"text": "Very large file: apps/web/src/components/MessageList.tsx (1592 lines)"}, "properties": {"repobilityId": "65487f9571fa0154", "scanner": "scanner-primary", "fingerprint": "5537999221020194", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"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": "5ce2e0617a0c127b", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-d57b3f82d2270c5b", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: apps/desktop/package.json"}, "properties": {"repobilityId": "a5d1a254ecc349f8", "scanner": "scanner-primary", "fingerprint": "d57b3f82d2270c5b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/desktop/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-d2fbf77fe73b8fa2", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: apps/voice/package.json"}, "properties": {"repobilityId": "30dbd61fc163a62f", "scanner": "scanner-primary", "fingerprint": "d2fbf77fe73b8fa2", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/voice/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-d0c2205560692580", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: apps/mobile/package.json"}, "properties": {"repobilityId": "b3dfed7bb3d70ed3", "scanner": "scanner-primary", "fingerprint": "d0c2205560692580", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/mobile/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-4a9eb7dc7c6e3880", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: apps/web/package.json"}, "properties": {"repobilityId": "6c1704bf24cf19ac", "scanner": "scanner-primary", "fingerprint": "4a9eb7dc7c6e3880", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "apps/web/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-cb3e52667c84fb86", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: packages/types/package.json"}, "properties": {"repobilityId": "b5e2784f829944e6", "scanner": "scanner-primary", "fingerprint": "cb3e52667c84fb86", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "packages/types/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-72b2a6250083a784", "level": "warning", "message": {"text": "Placeholder or mock-heavy implementation detected"}, "properties": {"repobilityId": "31919ed0bf7b8cae", "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": "cfd3b76ab8587281", "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": "01c0f0b21f6b3ad3", "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": "936c777ce3345c07", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-ea8f3013f588db25", "level": "note", "message": {"text": "Shallow git history limits provenance confidence"}, "properties": {"repobilityId": "6b05b20ccbaec68e", "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": "6763dc41a00979ac", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-6ef2d151615fb37f", "level": "none", "message": {"text": "Commented-code block (9 lines) in apps/voice/src/signaling.ts:1"}, "properties": {"repobilityId": "ee1f5001f05be173", "scanner": "scanner-primary", "fingerprint": "6ef2d151615fb37f", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-5bd0697c05328b9b", "level": "note", "message": {"text": "Legacy-named symbol `icon_url_v2` in apps/mobile/src/api.ts:89"}, "properties": {"repobilityId": "08f2cf96b8d364dc", "scanner": "scanner-primary", "fingerprint": "5bd0697c05328b9b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-3af65d4011bc4986", "level": "note", "message": {"text": "Legacy-named symbol `icon_url_v2` in apps/mobile/src/screens/HomeScreen.tsx:141"}, "properties": {"repobilityId": "792000bd08592d03", "scanner": "scanner-primary", "fingerprint": "3af65d4011bc4986", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-ae2d7db7017287f4", "level": "note", "message": {"text": "Legacy-named symbol `icon_url_v2` in apps/web/src/api.ts:37"}, "properties": {"repobilityId": "186c2168fa6bd65e", "scanner": "scanner-primary", "fingerprint": "ae2d7db7017287f4", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-de1a225025fce190", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/store.ts:376"}, "properties": {"repobilityId": "d5005bb4c8b28b9d", "scanner": "scanner-primary", "fingerprint": "de1a225025fce190", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-ad97e20d196ffdb7", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/UserSettingsModal.tsx:129"}, "properties": {"repobilityId": "bae15f25dc3bdfc0", "scanner": "scanner-primary", "fingerprint": "ad97e20d196ffdb7", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-1b08684b41b867e0", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/AddFriendModal.tsx:72"}, "properties": {"repobilityId": "5d3448dd0a8bd517", "scanner": "scanner-primary", "fingerprint": "1b08684b41b867e0", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-acf9e3bacd827e4c", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/GifPicker.tsx:47"}, "properties": {"repobilityId": "dfa2f1bb6229a0f2", "scanner": "scanner-primary", "fingerprint": "acf9e3bacd827e4c", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-9b1da8390fa1c8d9", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/CreateGuildModal.tsx:83"}, "properties": {"repobilityId": "4b5026563dc7b6ce", "scanner": "scanner-primary", "fingerprint": "9b1da8390fa1c8d9", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-3176cf2400901777", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 apps/web/src/components/MessageInput.tsx:146"}, "properties": {"repobilityId": "f01e82e523f68978", "scanner": "scanner-primary", "fingerprint": "3176cf2400901777", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-e47cc01fddb64549", "level": "note", "message": {"text": "Legacy-named symbol `icon_url_v2` in apps/web/src/components/ServerSettingsModal.tsx:209"}, "properties": {"repobilityId": "7ce1d5d27dff1c0e", "scanner": "scanner-primary", "fingerprint": "e47cc01fddb64549", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-3b8769515921eadb", "level": "note", "message": {"text": "Legacy-named symbol `icon_url_v2` in apps/web/src/components/ServerRail.tsx:190"}, "properties": {"repobilityId": "1d4f0d934f81e246", "scanner": "scanner-primary", "fingerprint": "3b8769515921eadb", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-d0b17c8c07a7421d", "level": "note", "message": {"text": "8 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "17fe720e8247f9df", "scanner": "scanner-primary", "fingerprint": "d0b17c8c07a7421d", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}]}]}