{"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-bead75b0f9233e05", "name": "No API endpoints detected", "shortDescription": {"text": "No API endpoints detected"}, "fullDescription": {"text": "The scanner did not find FastAPI/Flask/Express/NestJS/GraphQL/gRPC routes. If this repo exposes APIs, the framework may be unsupported."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "info", "confidence": 1.0}}, {"id": "scanner-bc40f377b6a40d3a", "name": "Stray `console.log` in TS/JS \u2014 scripts/migrate-csv.ts:105", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 scripts/migrate-csv.ts:105"}, "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-c02f59462b7a5dc7", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/layout/Topbar.tsx:98", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/layout/Topbar.tsx:98"}, "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-595ee3e0c2a6b799", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/upload/UploadDropzone.tsx:49", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/upload/UploadDropzone.tsx:49"}, "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-ef665e9ff1b88268", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/library/TryLater.tsx:231", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/library/TryLater.tsx:231"}, "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-fdd4be41a3446ce8", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/EngagementPanel.tsx:231", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/EngagementPanel.tsx:231"}, "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-5a606f1ed5f8a71a", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/StudentVideos.tsx:220", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/StudentVideos.tsx:220"}, "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-14f3516f1033ab2b", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/home/ActionRequiredPanel.tsx:70", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/home/ActionRequiredPanel.tsx:70"}, "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-279889c242fa32eb", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/home/StudentCrmRow.tsx:60", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/home/StudentCrmRow.tsx:60"}, "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-725093a38687105f", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/videos/PlanillaSidebar.tsx:134", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/videos/PlanillaSidebar.tsx:134"}, "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-d6ce8a939a5a7ff5", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/videos/LessonRow.tsx:164", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/videos/LessonRow.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-b8496ffa5f905dae", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/videos/SemanaCard.tsx:68", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/videos/SemanaCard.tsx:68"}, "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-e207470936a7cedf", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/setter/Kanban.tsx:194", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/setter/Kanban.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-5a1a056cd066fc9e", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/setter/LeadDrawer.tsx:96", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/setter/LeadDrawer.tsx:96"}, "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-d0a7c2dbba41a984", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/profile/TimelineTab.tsx:104", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/profile/TimelineTab.tsx:104"}, "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-3410e460a6c6ec82", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/profile/CrmHeader.tsx:139", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/profile/CrmHeader.tsx:139"}, "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-527c7a8ed6fc0933", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/onboarding/Step2Program.tsx:82", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/onboarding/Step2Program.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-a7a954677d334b2c", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/cursos/UserMenu.tsx:56", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/cursos/UserMenu.tsx:56"}, "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-b5848d46096a7fe3", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/cursos/viewer/CourseViewer.tsx:95", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/cursos/viewer/CourseViewer.tsx:95"}, "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-e1beea1fc48e8dee", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/cursos/viewer/CourseLessonNav.tsx:58", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/cursos/viewer/CourseLessonNav.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-3af367faf32c0f7b", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 src/components/cursos/viewer/MaterialDeEstudio.tsx:76", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/components/cursos/viewer/MaterialDeEstudio.tsx:76"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-f134cf9356dca987", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/video/CustomVideoPlayer.tsx:566", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/video/CustomVideoPlayer.tsx:566"}, "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-4fb0fdef85e3b20a", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/layout.tsx:50", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/layout.tsx:50"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-69a9457ccc0d7c23", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/upload/page.tsx:223", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/upload/page.tsx:223"}, "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-f56e9be004e8314c", "name": "\"active\" state uses light bg in a dark theme \u2014 src/app/(dashboard)/upload/page.tsx:84", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/app/(dashboard)/upload/page.tsx:84"}, "fullDescription": {"text": "A ternary like `active ? 'bg-white' : '...'` (or bg-gray-100/200) on a dark theme produces jarring white pills. Use a dark-emphasized active state instead \u2014 border + ring or slightly brighter dark bg. Example: `active ? 'bg-gray-800 border-gray-500 ring-1 ring-blue-500/30' : '\u2026'`.\n\nWhy: P-E in CHECKLIST.md \u2014 light bg in a dark theme is a class of regression.\nRule id: fq.active-light-bg"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f798a41292538a46", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/library/page.tsx:428", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/library/page.tsx:428"}, "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-ee708453e5a7aab4", "name": "\"active\" state uses light bg in a dark theme \u2014 src/app/(dashboard)/library/page.tsx:310", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/app/(dashboard)/library/page.tsx:310"}, "fullDescription": {"text": "A ternary like `active ? 'bg-white' : '...'` (or bg-gray-100/200) on a dark theme produces jarring white pills. Use a dark-emphasized active state instead \u2014 border + ring or slightly brighter dark bg. Example: `active ? 'bg-gray-800 border-gray-500 ring-1 ring-blue-500/30' : '\u2026'`.\n\nWhy: P-E in CHECKLIST.md \u2014 light bg in a dark theme is a class of regression.\nRule id: fq.active-light-bg"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-fa390c6008711ab0", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/competitions/page.tsx:395", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/competitions/page.tsx:395"}, "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-65ddd47386d64649", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/journal/page.tsx:329", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/journal/page.tsx:329"}, "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-15eb197620759786", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/events/page.tsx:314", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/events/page.tsx:314"}, "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-f7ac229d4e6b4f02", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/leaderboard/page.tsx:173", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/leaderboard/page.tsx:173"}, "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-5b35ad6ef5389efa", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/maquina-tiempo/page.tsx:395", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/maquina-tiempo/page.tsx:395"}, "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-aa1c5a1601e286ad", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/profile/page.tsx:422", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/profile/page.tsx:422"}, "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-2c7f6ed7bf391e6e", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/layout.tsx:109", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/layout.tsx:109"}, "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-4b6d7e6851edafb6", "name": "\"active\" state uses light bg in a dark theme \u2014 src/app/(admin)/layout.tsx:175", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/app/(admin)/layout.tsx:175"}, "fullDescription": {"text": "A ternary like `active ? 'bg-white' : '...'` (or bg-gray-100/200) on a dark theme produces jarring white pills. Use a dark-emphasized active state instead \u2014 border + ring or slightly brighter dark bg. Example: `active ? 'bg-gray-800 border-gray-500 ring-1 ring-blue-500/30' : '\u2026'`.\n\nWhy: P-E in CHECKLIST.md \u2014 light bg in a dark theme is a class of regression.\nRule id: fq.active-light-bg"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-7e6e4aef462f2b11", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/page.tsx:481", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/page.tsx:481"}, "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-4207e4625cae5f6e", "name": "\"active\" state uses light bg in a dark theme \u2014 src/app/(admin)/admin/page.tsx:75", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/app/(admin)/admin/page.tsx:75"}, "fullDescription": {"text": "A ternary like `active ? 'bg-white' : '...'` (or bg-gray-100/200) on a dark theme produces jarring white pills. Use a dark-emphasized active state instead \u2014 border + ring or slightly brighter dark bg. Example: `active ? 'bg-gray-800 border-gray-500 ring-1 ring-blue-500/30' : '\u2026'`.\n\nWhy: P-E in CHECKLIST.md \u2014 light bg in a dark theme is a class of regression.\nRule id: fq.active-light-bg"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ebf7c588d7b740a5", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/analytics/page.tsx:186", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/analytics/page.tsx:186"}, "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-8e004aa08c6441a1", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/[userId]/page.tsx:913", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/[userId]/page.tsx:913"}, "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-9565161cea1d30e5", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/reviews/page.tsx:297", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/reviews/page.tsx:297"}, "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-139c82fc50c81718", "name": "Stray `console.log` in TS/JS \u2014 src/app/(admin)/admin/reviews/page.tsx:162", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 src/app/(admin)/admin/reviews/page.tsx:162"}, "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-d9cadde83311416f", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/soporte/page.tsx:99", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/soporte/page.tsx:99"}, "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-1a3e0865100f4b7c", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/youtube-import/page.tsx:186", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/youtube-import/page.tsx:186"}, "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-efd0f4f81ecd4464", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/tags/page.tsx:92", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/tags/page.tsx:92"}, "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-0d2701913e02529b", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/diaries/page.tsx:239", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/diaries/page.tsx:239"}, "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-1c70a79ed586b738", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(cursos)/cursos/admin-cursos/page.tsx:48", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(cursos)/cursos/admin-cursos/page.tsx:48"}, "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-94db601018d2b711", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(cursos)/cursos/admin-cursos/curso/[id]/CourseEditor.tsx:31", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(cursos)/cursos/admin-cursos/curso/[id]/CourseEditor.tsx:311"}, "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-de943ba21a6ae132", "name": "Insecure pattern 'dangerous_innerhtml' in src/components/cursos/viewer/MaterialDeEstudio.tsx:76", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in src/components/cursos/viewer/MaterialDeEstudio.tsx:76"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a267942e55a71235", "name": "Insecure pattern 'dangerous_innerhtml' in src/app/layout.tsx:50", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/layout.tsx:50"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-4601e3ad3bb28677", "name": "No CI/CD pipelines detected", "shortDescription": {"text": "No CI/CD pipelines detected"}, "fullDescription": {"text": "No GitHub Actions, GitLab CI, or CircleCI configs found. Without CI you can't gate deploys on tests/lints."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "1 test file(s) for 332 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-3ab5d313dda8e5f9", "name": "Debug logging residue appears in source files", "shortDescription": {"text": "Debug logging residue appears in source files"}, "fullDescription": {"text": "Found 122 console/debugger/print-style debug statements in non-test source. This is a common fast-generation residue before production cleanup."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-72b2a6250083a784", "name": "Placeholder or mock-heavy implementation detected", "shortDescription": {"text": "Placeholder or mock-heavy implementation detected"}, "fullDescription": {"text": "Found 204 placeholder/mock markers across 62 source files. This often means the repo looks complete while core flows still use generated scaffolding or fake data."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2d0c7b7ab8f8aacf", "name": "Critical user flow still appears backed by mock or placeholder data", "shortDescription": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "fullDescription": {"text": "A payment/auth/admin/order/billing-style flow contains mock, fake, TODO, dummy, or placeholder markers in runtime source. In the Fable corpus this is a high-leverage completeness smell: the app can look finished while the money, identity, or tenant flow is still scaffolded."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-b9088664ace7f748", "name": "Composite production-readiness gap", "shortDescription": {"text": "Composite production-readiness gap"}, "fullDescription": {"text": "Multiple low-cost hardening controls are missing together: license, ci, tests. 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-749d4bc1bd66df5f", "name": "Agent instructions exist but release-hardening basics are missing", "shortDescription": {"text": "Agent instructions exist but release-hardening basics are missing"}, "fullDescription": {"text": "AI-coder instruction files were found, but the repo is missing license, ci, tests. Treat this as a contract gap: the agent is guided, but the generated output is not yet guarded by the controls that make it repeatable."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-ea8f3013f588db25", "name": "Shallow git history limits provenance confidence", "shortDescription": {"text": "Shallow git history limits provenance confidence"}, "fullDescription": {"text": "The repository is a shallow clone. Origin/evolution analysis cannot distinguish fresh generation, imported legacy code, or long-lived human code with high confidence."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8424db9c75e04ba4", "name": "Very short observed git history", "shortDescription": {"text": "Very short observed git history"}, "fullDescription": {"text": "The repo has multiple source files but two or fewer visible commits. This is not a failure by itself, but it lowers confidence in evolution-based diagnosis."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-2c5f98b152cddb6d", "name": "Agent authority lacks a verifier contract: .claude/launch.json", "shortDescription": {"text": "Agent authority lacks a verifier contract: .claude/launch.json"}, "fullDescription": {"text": "This agent instruction grants code or shell authority but does not state the verification gate that decides promotion. The recurring safe pattern is: LLM proposes; deterministic tests/build/security checks verify; only verified code promotes."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-e725d2ab884fbd49", "name": "Multiple root agent instruction files without precedence", "shortDescription": {"text": "Multiple root agent instruction files without precedence"}, "fullDescription": {"text": "The repo has multiple top-level AI-coder instruction files. Without precedence rules, different agents may follow different policies."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-117ba6157ca73216", "name": "Commented-code block (5 lines) in scripts/apply-yt-batch-2026-06-08.mjs:1", "shortDescription": {"text": "Commented-code block (5 lines) in scripts/apply-yt-batch-2026-06-08.mjs: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-313616ac088c1688", "name": "Legacy-named symbol `sales_copy` in migration/import.mjs:8", "shortDescription": {"text": "Legacy-named symbol `sales_copy` in migration/import.mjs:8"}, "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-d26a8ca1f26a4bd6", "name": "Commented-code block (5 lines) in public/sw.js:127", "shortDescription": {"text": "Commented-code block (5 lines) in public/sw.js:127"}, "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-633d04e6ba7c63d6", "name": "Commented-code block (5 lines) in src/components/VersionCheck.tsx:33", "shortDescription": {"text": "Commented-code block (5 lines) in src/components/VersionCheck.tsx:33"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-598e95d226db9331", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/layout/NotificationBell.tsx:61", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/layout/NotificationBell.tsx:61"}, "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-13de315fda67c783", "name": "Commented-code block (5 lines) in src/components/library/MyMoves.tsx:396", "shortDescription": {"text": "Commented-code block (5 lines) in src/components/library/MyMoves.tsx:396"}, "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-b2cf70c27a163645", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/library/MyMoves.tsx:445", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/library/MyMoves.tsx:445"}, "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-41be74dd384f7f83", "name": "Commented-code block (6 lines) in src/components/consultoria/EvaluationQuiz.tsx:675", "shortDescription": {"text": "Commented-code block (6 lines) in src/components/consultoria/EvaluationQuiz.tsx:675"}, "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-3360f5f57b17abad", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/consultoria/EvaluationQuiz.tsx:731", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/consultoria/EvaluationQuiz.tsx:731"}, "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-0d526d64feb4a7f1", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/admin/videos/LessonRow.tsx:111", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/admin/videos/LessonRow.tsx:111"}, "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-3579bc8d8fede184", "name": "Commented-code block (5 lines) in src/components/admin/setter/Kanban.tsx:25", "shortDescription": {"text": "Commented-code block (5 lines) in src/components/admin/setter/Kanban.tsx:25"}, "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-27afc0746a8533e1", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/admin/profile/NotesTab.tsx:55", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/admin/profile/NotesTab.tsx:55"}, "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-c9b58c73e17783e8", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/admin/profile/LlamadasTab.tsx:53", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/admin/profile/LlamadasTab.tsx:53"}, "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-b6c6fb6073be8237", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/onboarding/Step4Notifications.tsx:45", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/onboarding/Step4Notifications.tsx:45"}, "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-c107b920749d84e7", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/onboarding/Orchestrator.tsx:23", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/onboarding/Orchestrator.tsx:23"}, "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-dc09e31b44a43022", "name": "Legacy-named symbol `sales_copy` in src/components/cursos/BundleBand.tsx:8", "shortDescription": {"text": "Legacy-named symbol `sales_copy` in src/components/cursos/BundleBand.tsx:8"}, "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-9424ae19bf5439ae", "name": "Commented-code block (5 lines) in src/components/cursos/viewer/MaterialDeEstudio.tsx:1", "shortDescription": {"text": "Commented-code block (5 lines) in src/components/cursos/viewer/MaterialDeEstudio.tsx: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-ba026d4ab657978e", "name": "Commented-code block (6 lines) in src/providers/UserProvider.tsx:42", "shortDescription": {"text": "Commented-code block (6 lines) in src/providers/UserProvider.tsx:42"}, "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-4114884e52483004", "name": "Commented-code block (7 lines) in src/app/api/admin/update-lesson-video/route.ts:55", "shortDescription": {"text": "Commented-code block (7 lines) in src/app/api/admin/update-lesson-video/route.ts:55"}, "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-7e4d589776497131", "name": "Commented-code block (6 lines) in src/app/api/admin/load-planilla/route.ts:48", "shortDescription": {"text": "Commented-code block (6 lines) in src/app/api/admin/load-planilla/route.ts:48"}, "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-3b846c80cc0c5113", "name": "Commented-code block (5 lines) in src/app/api/admin/llamadas/route.ts:9", "shortDescription": {"text": "Commented-code block (5 lines) in src/app/api/admin/llamadas/route.ts:9"}, "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-7d499efc08a77959", "name": "Commented-code block (6 lines) in src/app/api/dashboard-stats/route.ts:206", "shortDescription": {"text": "Commented-code block (6 lines) in src/app/api/dashboard-stats/route.ts:206"}, "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-8508239677e5fbfa", "name": "Commented-code block (5 lines) in src/app/api/webhooks/calendly/route.ts:94", "shortDescription": {"text": "Commented-code block (5 lines) in src/app/api/webhooks/calendly/route.ts:94"}, "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-b91e334ffc2a5086", "name": "Commented-code block (8 lines) in src/app/api/course-data/route.ts:99", "shortDescription": {"text": "Commented-code block (8 lines) in src/app/api/course-data/route.ts:99"}, "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-e16c48acc0e91cbd", "name": "Commented-code block (5 lines) in src/app/(dashboard)/weekly/page.tsx:124", "shortDescription": {"text": "Commented-code block (5 lines) in src/app/(dashboard)/weekly/page.tsx:124"}, "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-411b881816e3d82e", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/weekly/page.tsx:130", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/weekly/page.tsx:130"}, "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-72bf3f1bffc9156a", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/journal/page.tsx:266", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/journal/page.tsx:266"}, "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-298c8f154d5d40c0", "name": "Commented-code block (5 lines) in src/app/(dashboard)/chat/page.tsx:179", "shortDescription": {"text": "Commented-code block (5 lines) in src/app/(dashboard)/chat/page.tsx:179"}, "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-0064bc6c6fa159ff", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/chat/page.tsx:132", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/chat/page.tsx:132"}, "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-12edb931de0f55cd", "name": "Commented-code block (5 lines) in src/app/(dashboard)/modules/[moduleId]/page.tsx:61", "shortDescription": {"text": "Commented-code block (5 lines) in src/app/(dashboard)/modules/[moduleId]/page.tsx:61"}, "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-b53be23cb787ab43", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/maquina-tiempo/page.tsx:113", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/maquina-tiempo/page.tsx:113"}, "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-da4b17978b73101e", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/profile/page.tsx:144", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/profile/page.tsx:144"}, "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-21e7499db1dc740b", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/members/[memberId]/page.tsx:35", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/members/[memberId]/page.tsx:35"}, "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-8d5bfccd3e743d65", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(admin)/admin/[userId]/page.tsx:226", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(admin)/admin/[userId]/page.tsx:226"}, "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-3676e99b478d9546", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(admin)/admin/anuncios/page.tsx:38", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(admin)/admin/anuncios/page.tsx:38"}, "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-e437d6b64623b4fb", "name": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/admin-cursos/curso/[id]/CourseEditor.tsx:166", "shortDescription": {"text": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/admin-cursos/curso/[id]/CourseEditor.tsx:166"}, "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-6cfd34e05805eaa4", "name": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/admin-cursos/curso/[id]/SalesCopyEditor.tsx:37", "shortDescription": {"text": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/admin-cursos/curso/[id]/SalesCopyEditor.tsx: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-a6fede6ebcf9e716", "name": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/(tienda)/curso/[slug]/page.tsx:28", "shortDescription": {"text": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/(tienda)/curso/[slug]/page.tsx:28"}, "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-fa91a4debe952f28", "name": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/(tienda)/pack/[slug]/page.tsx:29", "shortDescription": {"text": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/(tienda)/pack/[slug]/page.tsx:29"}, "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-147fd7fefef02903", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/google-drive.ts:144", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/google-drive.ts:144"}, "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-040bf0e93a06ceee", "name": "Commented-code block (6 lines) in src/lib/planillas.ts:33", "shortDescription": {"text": "Commented-code block (6 lines) in src/lib/planillas.ts:33"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-983f91294a43a8a3", "name": "Commented-code block (5 lines) in src/lib/lead-webhook.ts:1", "shortDescription": {"text": "Commented-code block (5 lines) in src/lib/lead-webhook.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-31802df72019612f", "name": "Commented-code block (5 lines) in src/lib/crm.ts:18", "shortDescription": {"text": "Commented-code block (5 lines) in src/lib/crm.ts:18"}, "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-eb79fc7f26a09fae", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/youtube.ts:45", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/youtube.ts:45"}, "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-2d939f3e43dc6eb1", "name": "Commented-code block (7 lines) in src/lib/whatsapp.ts:3", "shortDescription": {"text": "Commented-code block (7 lines) in src/lib/whatsapp.ts:3"}, "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-7843bf0e91813335", "name": "Commented-code block (5 lines) in src/lib/admin-students-bulk.ts:160", "shortDescription": {"text": "Commented-code block (5 lines) in src/lib/admin-students-bulk.ts:160"}, "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-d55f6ed81cbe7a05", "name": "Commented-code block (6 lines) in src/lib/logger.ts:44", "shortDescription": {"text": "Commented-code block (6 lines) in src/lib/logger.ts:44"}, "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-2c246a5779609dc1", "name": "Commented-code block (7 lines) in src/lib/supabase/middleware.ts:56", "shortDescription": {"text": "Commented-code block (7 lines) in src/lib/supabase/middleware.ts:56"}, "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-c276fce9501e5ae4", "name": "Commented-code block (5 lines) in src/lib/supabase/client.ts:4", "shortDescription": {"text": "Commented-code block (5 lines) in src/lib/supabase/client.ts:4"}, "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-3913b5e72d094397", "name": "Legacy-named symbol `sales_copy` in src/lib/cursos/types.ts:13", "shortDescription": {"text": "Legacy-named symbol `sales_copy` in src/lib/cursos/types.ts:13"}, "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}}]}}, "automationDetails": {"id": "repobility/19172"}, "properties": {"repository": "sebbvinat/JJL-APP", "repoUrl": "https://github.com/sebbvinat/JJL-APP", "branch": "main"}, "results": [{"ruleId": "scanner-bead75b0f9233e05", "level": "none", "message": {"text": "No API endpoints detected"}, "properties": {"repobilityId": "0f8bb852027c38f8", "scanner": "scanner-primary", "fingerprint": "bead75b0f9233e05", "layer": "api", "severity": "info", "confidence": 1.0, "tags": ["coverage"]}}, {"ruleId": "scanner-bc40f377b6a40d3a", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 scripts/migrate-csv.ts:105"}, "properties": {"repobilityId": "285b957412c6ca6e", "scanner": "scanner-primary", "fingerprint": "bc40f377b6a40d3a", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-c02f59462b7a5dc7", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/layout/Topbar.tsx:98"}, "properties": {"repobilityId": "32c3331e95ce22bf", "scanner": "scanner-primary", "fingerprint": "c02f59462b7a5dc7", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-595ee3e0c2a6b799", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/upload/UploadDropzone.tsx:49"}, "properties": {"repobilityId": "4f2443935da41534", "scanner": "scanner-primary", "fingerprint": "595ee3e0c2a6b799", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-ef665e9ff1b88268", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/library/TryLater.tsx:231"}, "properties": {"repobilityId": "aa4992e3dd28c133", "scanner": "scanner-primary", "fingerprint": "ef665e9ff1b88268", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-fdd4be41a3446ce8", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/EngagementPanel.tsx:231"}, "properties": {"repobilityId": "883f4bb9ec0f03a2", "scanner": "scanner-primary", "fingerprint": "fdd4be41a3446ce8", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-5a606f1ed5f8a71a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/StudentVideos.tsx:220"}, "properties": {"repobilityId": "c30be98d09078bb9", "scanner": "scanner-primary", "fingerprint": "5a606f1ed5f8a71a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-14f3516f1033ab2b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/home/ActionRequiredPanel.tsx:70"}, "properties": {"repobilityId": "ccaedb932b4d8a32", "scanner": "scanner-primary", "fingerprint": "14f3516f1033ab2b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-279889c242fa32eb", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/home/StudentCrmRow.tsx:60"}, "properties": {"repobilityId": "931f39158c4615b8", "scanner": "scanner-primary", "fingerprint": "279889c242fa32eb", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-725093a38687105f", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/videos/PlanillaSidebar.tsx:134"}, "properties": {"repobilityId": "60aa25f38a006f23", "scanner": "scanner-primary", "fingerprint": "725093a38687105f", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-d6ce8a939a5a7ff5", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/videos/LessonRow.tsx:164"}, "properties": {"repobilityId": "bc6274ab034d9f76", "scanner": "scanner-primary", "fingerprint": "d6ce8a939a5a7ff5", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b8496ffa5f905dae", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/videos/SemanaCard.tsx:68"}, "properties": {"repobilityId": "f9054c6ad8c752af", "scanner": "scanner-primary", "fingerprint": "b8496ffa5f905dae", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-e207470936a7cedf", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/setter/Kanban.tsx:194"}, "properties": {"repobilityId": "2a73ff6d3c042200", "scanner": "scanner-primary", "fingerprint": "e207470936a7cedf", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-5a1a056cd066fc9e", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/setter/LeadDrawer.tsx:96"}, "properties": {"repobilityId": "9a1a1e6b1de15464", "scanner": "scanner-primary", "fingerprint": "5a1a056cd066fc9e", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-d0a7c2dbba41a984", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/profile/TimelineTab.tsx:104"}, "properties": {"repobilityId": "6192b1927aa18982", "scanner": "scanner-primary", "fingerprint": "d0a7c2dbba41a984", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-3410e460a6c6ec82", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/admin/profile/CrmHeader.tsx:139"}, "properties": {"repobilityId": "543025c118aa8886", "scanner": "scanner-primary", "fingerprint": "3410e460a6c6ec82", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-527c7a8ed6fc0933", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/onboarding/Step2Program.tsx:82"}, "properties": {"repobilityId": "ab2545ab741945fb", "scanner": "scanner-primary", "fingerprint": "527c7a8ed6fc0933", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a7a954677d334b2c", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/cursos/UserMenu.tsx:56"}, "properties": {"repobilityId": "19b7c4bacc9d498a", "scanner": "scanner-primary", "fingerprint": "a7a954677d334b2c", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b5848d46096a7fe3", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/cursos/viewer/CourseViewer.tsx:95"}, "properties": {"repobilityId": "ff2cd3cdf11bd77d", "scanner": "scanner-primary", "fingerprint": "b5848d46096a7fe3", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-e1beea1fc48e8dee", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/cursos/viewer/CourseLessonNav.tsx:58"}, "properties": {"repobilityId": "99baf4acbc953cb3", "scanner": "scanner-primary", "fingerprint": "e1beea1fc48e8dee", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-3af367faf32c0f7b", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/components/cursos/viewer/MaterialDeEstudio.tsx:76"}, "properties": {"repobilityId": "2f0f14a464cb8228", "scanner": "scanner-primary", "fingerprint": "3af367faf32c0f7b", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-f134cf9356dca987", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/video/CustomVideoPlayer.tsx:566"}, "properties": {"repobilityId": "abfa19afc591766d", "scanner": "scanner-primary", "fingerprint": "f134cf9356dca987", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4fb0fdef85e3b20a", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/layout.tsx:50"}, "properties": {"repobilityId": "0d72350965068f5b", "scanner": "scanner-primary", "fingerprint": "4fb0fdef85e3b20a", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-69a9457ccc0d7c23", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/upload/page.tsx:223"}, "properties": {"repobilityId": "9fa43eb60eab0cfb", "scanner": "scanner-primary", "fingerprint": "69a9457ccc0d7c23", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f56e9be004e8314c", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/app/(dashboard)/upload/page.tsx:84"}, "properties": {"repobilityId": "45f3b5469f53f760", "scanner": "scanner-primary", "fingerprint": "f56e9be004e8314c", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-f798a41292538a46", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/library/page.tsx:428"}, "properties": {"repobilityId": "0d6b27f404427f9d", "scanner": "scanner-primary", "fingerprint": "f798a41292538a46", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-ee708453e5a7aab4", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/app/(dashboard)/library/page.tsx:310"}, "properties": {"repobilityId": "647e3e0baba53829", "scanner": "scanner-primary", "fingerprint": "ee708453e5a7aab4", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-fa390c6008711ab0", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/competitions/page.tsx:395"}, "properties": {"repobilityId": "1fdbf11d499ba3de", "scanner": "scanner-primary", "fingerprint": "fa390c6008711ab0", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-65ddd47386d64649", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/journal/page.tsx:329"}, "properties": {"repobilityId": "8967a711066cdc73", "scanner": "scanner-primary", "fingerprint": "65ddd47386d64649", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-15eb197620759786", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/events/page.tsx:314"}, "properties": {"repobilityId": "2f5f7c85a151725c", "scanner": "scanner-primary", "fingerprint": "15eb197620759786", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f7ac229d4e6b4f02", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/leaderboard/page.tsx:173"}, "properties": {"repobilityId": "32d6da5390a43421", "scanner": "scanner-primary", "fingerprint": "f7ac229d4e6b4f02", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-5b35ad6ef5389efa", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/maquina-tiempo/page.tsx:395"}, "properties": {"repobilityId": "efda677a4de3aab4", "scanner": "scanner-primary", "fingerprint": "5b35ad6ef5389efa", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-aa1c5a1601e286ad", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/profile/page.tsx:422"}, "properties": {"repobilityId": "342cac9e008e671a", "scanner": "scanner-primary", "fingerprint": "aa1c5a1601e286ad", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-2c7f6ed7bf391e6e", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/layout.tsx:109"}, "properties": {"repobilityId": "b9fd2e885d42b17a", "scanner": "scanner-primary", "fingerprint": "2c7f6ed7bf391e6e", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4b6d7e6851edafb6", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/app/(admin)/layout.tsx:175"}, "properties": {"repobilityId": "c0835e126562e1af", "scanner": "scanner-primary", "fingerprint": "4b6d7e6851edafb6", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-7e6e4aef462f2b11", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/page.tsx:481"}, "properties": {"repobilityId": "238b474c16de20c3", "scanner": "scanner-primary", "fingerprint": "7e6e4aef462f2b11", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4207e4625cae5f6e", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/app/(admin)/admin/page.tsx:75"}, "properties": {"repobilityId": "34bb20057d8b3167", "scanner": "scanner-primary", "fingerprint": "4207e4625cae5f6e", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-ebf7c588d7b740a5", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/analytics/page.tsx:186"}, "properties": {"repobilityId": "68d49ffa054be62c", "scanner": "scanner-primary", "fingerprint": "ebf7c588d7b740a5", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-8e004aa08c6441a1", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/[userId]/page.tsx:913"}, "properties": {"repobilityId": "085671447ab2561c", "scanner": "scanner-primary", "fingerprint": "8e004aa08c6441a1", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-9565161cea1d30e5", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/reviews/page.tsx:297"}, "properties": {"repobilityId": "83151f85e18ccc59", "scanner": "scanner-primary", "fingerprint": "9565161cea1d30e5", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-139c82fc50c81718", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 src/app/(admin)/admin/reviews/page.tsx:162"}, "properties": {"repobilityId": "30387d419f4f8188", "scanner": "scanner-primary", "fingerprint": "139c82fc50c81718", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-d9cadde83311416f", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/soporte/page.tsx:99"}, "properties": {"repobilityId": "1e666e025dd2b484", "scanner": "scanner-primary", "fingerprint": "d9cadde83311416f", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1a3e0865100f4b7c", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/youtube-import/page.tsx:186"}, "properties": {"repobilityId": "9ccb83706ac81931", "scanner": "scanner-primary", "fingerprint": "1a3e0865100f4b7c", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-efd0f4f81ecd4464", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/tags/page.tsx:92"}, "properties": {"repobilityId": "b56512a216071273", "scanner": "scanner-primary", "fingerprint": "efd0f4f81ecd4464", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-0d2701913e02529b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(admin)/admin/diaries/page.tsx:239"}, "properties": {"repobilityId": "acac03ca08a99352", "scanner": "scanner-primary", "fingerprint": "0d2701913e02529b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1c70a79ed586b738", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(cursos)/cursos/admin-cursos/page.tsx:48"}, "properties": {"repobilityId": "e4c46dd50f816fde", "scanner": "scanner-primary", "fingerprint": "1c70a79ed586b738", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-94db601018d2b711", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(cursos)/cursos/admin-cursos/curso/[id]/CourseEditor.tsx:311"}, "properties": {"repobilityId": "bf4e3c15ab5d15f0", "scanner": "scanner-primary", "fingerprint": "94db601018d2b711", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-de943ba21a6ae132", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in src/components/cursos/viewer/MaterialDeEstudio.tsx:76"}, "properties": {"repobilityId": "95d59fac4ba4fe39", "scanner": "scanner-primary", "fingerprint": "de943ba21a6ae132", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/components/cursos/viewer/MaterialDeEstudio.tsx"}, "region": {"startLine": 76}}}]}, {"ruleId": "scanner-a267942e55a71235", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/layout.tsx:50"}, "properties": {"repobilityId": "0bca654fa2052eb0", "scanner": "scanner-primary", "fingerprint": "a267942e55a71235", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/app/layout.tsx"}, "region": {"startLine": 50}}}]}, {"ruleId": "scanner-4601e3ad3bb28677", "level": "warning", "message": {"text": "No CI/CD pipelines detected"}, "properties": {"repobilityId": "c3ee439bce2bc51e", "scanner": "scanner-primary", "fingerprint": "4601e3ad3bb28677", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["coverage"]}}, {"ruleId": "scanner-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": "86305f1eecc07d31", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-3ab5d313dda8e5f9", "level": "note", "message": {"text": "Debug logging residue appears in source files"}, "properties": {"repobilityId": "aa59d5d18a7a0904", "scanner": "scanner-primary", "fingerprint": "3ab5d313dda8e5f9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["debug", "cleanup", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-72b2a6250083a784", "level": "warning", "message": {"text": "Placeholder or mock-heavy implementation detected"}, "properties": {"repobilityId": "a71cda0c560b6c16", "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": "8ca1026977034384", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-b9088664ace7f748", "level": "warning", "message": {"text": "Composite production-readiness gap"}, "properties": {"repobilityId": "3c50096281fbac1c", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-749d4bc1bd66df5f", "level": "warning", "message": {"text": "Agent instructions exist but release-hardening basics are missing"}, "properties": {"repobilityId": "680513d4a3ccb20c", "scanner": "scanner-primary", "fingerprint": "749d4bc1bd66df5f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["agent-instructions", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-ea8f3013f588db25", "level": "note", "message": {"text": "Shallow git history limits provenance confidence"}, "properties": {"repobilityId": "7dbaaeacddd986a7", "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": "e6e87cf1883853d4", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-2c5f98b152cddb6d", "level": "warning", "message": {"text": "Agent authority lacks a verifier contract: .claude/launch.json"}, "properties": {"repobilityId": "0de48c0f4ab303d8", "scanner": "scanner-primary", "fingerprint": "2c5f98b152cddb6d", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["agent-instructions", "verification", "claude_instruction"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".claude/launch.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-e725d2ab884fbd49", "level": "note", "message": {"text": "Multiple root agent instruction files without precedence"}, "properties": {"repobilityId": "1953db6c89508d22", "scanner": "scanner-primary", "fingerprint": "e725d2ab884fbd49", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["agent-instructions", "governance"]}}, {"ruleId": "scanner-117ba6157ca73216", "level": "none", "message": {"text": "Commented-code block (5 lines) in scripts/apply-yt-batch-2026-06-08.mjs:1"}, "properties": {"repobilityId": "6c4decb3995f498d", "scanner": "scanner-primary", "fingerprint": "117ba6157ca73216", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-313616ac088c1688", "level": "note", "message": {"text": "Legacy-named symbol `sales_copy` in migration/import.mjs:8"}, "properties": {"repobilityId": "9679c29d5fe08318", "scanner": "scanner-primary", "fingerprint": "313616ac088c1688", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-d26a8ca1f26a4bd6", "level": "none", "message": {"text": "Commented-code block (5 lines) in public/sw.js:127"}, "properties": {"repobilityId": "92eee39ed37efbb6", "scanner": "scanner-primary", "fingerprint": "d26a8ca1f26a4bd6", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-633d04e6ba7c63d6", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/components/VersionCheck.tsx:33"}, "properties": {"repobilityId": "5c46edcbac3a5c20", "scanner": "scanner-primary", "fingerprint": "633d04e6ba7c63d6", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-598e95d226db9331", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/layout/NotificationBell.tsx:61"}, "properties": {"repobilityId": "096b3dfe06b58e4a", "scanner": "scanner-primary", "fingerprint": "598e95d226db9331", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-13de315fda67c783", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/components/library/MyMoves.tsx:396"}, "properties": {"repobilityId": "2a1f2283b3c7dfab", "scanner": "scanner-primary", "fingerprint": "13de315fda67c783", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-b2cf70c27a163645", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/library/MyMoves.tsx:445"}, "properties": {"repobilityId": "5234132b8d819f52", "scanner": "scanner-primary", "fingerprint": "b2cf70c27a163645", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-41be74dd384f7f83", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/components/consultoria/EvaluationQuiz.tsx:675"}, "properties": {"repobilityId": "2a2167497a521791", "scanner": "scanner-primary", "fingerprint": "41be74dd384f7f83", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-3360f5f57b17abad", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/consultoria/EvaluationQuiz.tsx:731"}, "properties": {"repobilityId": "7f72569468fa7b8d", "scanner": "scanner-primary", "fingerprint": "3360f5f57b17abad", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-0d526d64feb4a7f1", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/admin/videos/LessonRow.tsx:111"}, "properties": {"repobilityId": "544a691a3fa70408", "scanner": "scanner-primary", "fingerprint": "0d526d64feb4a7f1", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-3579bc8d8fede184", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/components/admin/setter/Kanban.tsx:25"}, "properties": {"repobilityId": "6090cd6e57ea451a", "scanner": "scanner-primary", "fingerprint": "3579bc8d8fede184", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-27afc0746a8533e1", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/admin/profile/NotesTab.tsx:55"}, "properties": {"repobilityId": "410f2c17da135605", "scanner": "scanner-primary", "fingerprint": "27afc0746a8533e1", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-c9b58c73e17783e8", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/admin/profile/LlamadasTab.tsx:53"}, "properties": {"repobilityId": "cfc9818d9d112b69", "scanner": "scanner-primary", "fingerprint": "c9b58c73e17783e8", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-b6c6fb6073be8237", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/onboarding/Step4Notifications.tsx:45"}, "properties": {"repobilityId": "c345d54d315f9698", "scanner": "scanner-primary", "fingerprint": "b6c6fb6073be8237", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-c107b920749d84e7", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/onboarding/Orchestrator.tsx:23"}, "properties": {"repobilityId": "87d33de8edb226a1", "scanner": "scanner-primary", "fingerprint": "c107b920749d84e7", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-dc09e31b44a43022", "level": "note", "message": {"text": "Legacy-named symbol `sales_copy` in src/components/cursos/BundleBand.tsx:8"}, "properties": {"repobilityId": "09646d43bd841ef4", "scanner": "scanner-primary", "fingerprint": "dc09e31b44a43022", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-9424ae19bf5439ae", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/components/cursos/viewer/MaterialDeEstudio.tsx:1"}, "properties": {"repobilityId": "164b60804bbac962", "scanner": "scanner-primary", "fingerprint": "9424ae19bf5439ae", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-ba026d4ab657978e", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/providers/UserProvider.tsx:42"}, "properties": {"repobilityId": "a6ac51325abdd8d0", "scanner": "scanner-primary", "fingerprint": "ba026d4ab657978e", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-4114884e52483004", "level": "none", "message": {"text": "Commented-code block (7 lines) in src/app/api/admin/update-lesson-video/route.ts:55"}, "properties": {"repobilityId": "db18d74e867bd7ff", "scanner": "scanner-primary", "fingerprint": "4114884e52483004", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-7e4d589776497131", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/app/api/admin/load-planilla/route.ts:48"}, "properties": {"repobilityId": "782df140824ab879", "scanner": "scanner-primary", "fingerprint": "7e4d589776497131", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-3b846c80cc0c5113", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/app/api/admin/llamadas/route.ts:9"}, "properties": {"repobilityId": "cc6a07b9a5695c30", "scanner": "scanner-primary", "fingerprint": "3b846c80cc0c5113", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-7d499efc08a77959", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/app/api/dashboard-stats/route.ts:206"}, "properties": {"repobilityId": "08014d7117faffb5", "scanner": "scanner-primary", "fingerprint": "7d499efc08a77959", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-8508239677e5fbfa", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/app/api/webhooks/calendly/route.ts:94"}, "properties": {"repobilityId": "17f46301b6e7b5f8", "scanner": "scanner-primary", "fingerprint": "8508239677e5fbfa", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-b91e334ffc2a5086", "level": "none", "message": {"text": "Commented-code block (8 lines) in src/app/api/course-data/route.ts:99"}, "properties": {"repobilityId": "c2934f6ff9ac1b0e", "scanner": "scanner-primary", "fingerprint": "b91e334ffc2a5086", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-e16c48acc0e91cbd", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/app/(dashboard)/weekly/page.tsx:124"}, "properties": {"repobilityId": "bf57e5a795e3d454", "scanner": "scanner-primary", "fingerprint": "e16c48acc0e91cbd", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-411b881816e3d82e", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/weekly/page.tsx:130"}, "properties": {"repobilityId": "1babf1935a4f3dff", "scanner": "scanner-primary", "fingerprint": "411b881816e3d82e", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-72bf3f1bffc9156a", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/journal/page.tsx:266"}, "properties": {"repobilityId": "d8ab4110959c2e10", "scanner": "scanner-primary", "fingerprint": "72bf3f1bffc9156a", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-298c8f154d5d40c0", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/app/(dashboard)/chat/page.tsx:179"}, "properties": {"repobilityId": "09d3a69eb22310aa", "scanner": "scanner-primary", "fingerprint": "298c8f154d5d40c0", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-0064bc6c6fa159ff", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/chat/page.tsx:132"}, "properties": {"repobilityId": "f815a91ee22dd768", "scanner": "scanner-primary", "fingerprint": "0064bc6c6fa159ff", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-12edb931de0f55cd", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/app/(dashboard)/modules/[moduleId]/page.tsx:61"}, "properties": {"repobilityId": "39a7239eb8737711", "scanner": "scanner-primary", "fingerprint": "12edb931de0f55cd", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-b53be23cb787ab43", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/maquina-tiempo/page.tsx:113"}, "properties": {"repobilityId": "229f16aed370b22c", "scanner": "scanner-primary", "fingerprint": "b53be23cb787ab43", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-da4b17978b73101e", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/profile/page.tsx:144"}, "properties": {"repobilityId": "7597ff72ffccbe6a", "scanner": "scanner-primary", "fingerprint": "da4b17978b73101e", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-21e7499db1dc740b", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(dashboard)/members/[memberId]/page.tsx:35"}, "properties": {"repobilityId": "5d2b43952f2cca5d", "scanner": "scanner-primary", "fingerprint": "21e7499db1dc740b", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-8d5bfccd3e743d65", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(admin)/admin/[userId]/page.tsx:226"}, "properties": {"repobilityId": "a9209ab2a2eaab67", "scanner": "scanner-primary", "fingerprint": "8d5bfccd3e743d65", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-3676e99b478d9546", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/app/(admin)/admin/anuncios/page.tsx:38"}, "properties": {"repobilityId": "554e5150ee0aeca1", "scanner": "scanner-primary", "fingerprint": "3676e99b478d9546", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-e437d6b64623b4fb", "level": "note", "message": {"text": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/admin-cursos/curso/[id]/CourseEditor.tsx:166"}, "properties": {"repobilityId": "4ea24e62567c21d7", "scanner": "scanner-primary", "fingerprint": "e437d6b64623b4fb", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-6cfd34e05805eaa4", "level": "note", "message": {"text": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/admin-cursos/curso/[id]/SalesCopyEditor.tsx:37"}, "properties": {"repobilityId": "21ed4a333feb8071", "scanner": "scanner-primary", "fingerprint": "6cfd34e05805eaa4", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-a6fede6ebcf9e716", "level": "note", "message": {"text": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/(tienda)/curso/[slug]/page.tsx:28"}, "properties": {"repobilityId": "a8b2e0f14caa72d3", "scanner": "scanner-primary", "fingerprint": "a6fede6ebcf9e716", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-fa91a4debe952f28", "level": "note", "message": {"text": "Legacy-named symbol `sales_copy` in src/app/(cursos)/cursos/(tienda)/pack/[slug]/page.tsx:29"}, "properties": {"repobilityId": "89d5d1c6075b176a", "scanner": "scanner-primary", "fingerprint": "fa91a4debe952f28", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-147fd7fefef02903", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/google-drive.ts:144"}, "properties": {"repobilityId": "45183f8cd44efd6b", "scanner": "scanner-primary", "fingerprint": "147fd7fefef02903", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-040bf0e93a06ceee", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/lib/planillas.ts:33"}, "properties": {"repobilityId": "49e6f878c31d5e1b", "scanner": "scanner-primary", "fingerprint": "040bf0e93a06ceee", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-983f91294a43a8a3", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/lib/lead-webhook.ts:1"}, "properties": {"repobilityId": "6b8c5ca46cd9de1a", "scanner": "scanner-primary", "fingerprint": "983f91294a43a8a3", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-31802df72019612f", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/lib/crm.ts:18"}, "properties": {"repobilityId": "5cb63aad09fdeff5", "scanner": "scanner-primary", "fingerprint": "31802df72019612f", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-eb79fc7f26a09fae", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/youtube.ts:45"}, "properties": {"repobilityId": "b096a4567b8e487c", "scanner": "scanner-primary", "fingerprint": "eb79fc7f26a09fae", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-2d939f3e43dc6eb1", "level": "none", "message": {"text": "Commented-code block (7 lines) in src/lib/whatsapp.ts:3"}, "properties": {"repobilityId": "ec6985eafbbe1784", "scanner": "scanner-primary", "fingerprint": "2d939f3e43dc6eb1", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-7843bf0e91813335", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/lib/admin-students-bulk.ts:160"}, "properties": {"repobilityId": "1e76562bf1a27e27", "scanner": "scanner-primary", "fingerprint": "7843bf0e91813335", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-d55f6ed81cbe7a05", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/lib/logger.ts:44"}, "properties": {"repobilityId": "921c9b1fcbf4f274", "scanner": "scanner-primary", "fingerprint": "d55f6ed81cbe7a05", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-2c246a5779609dc1", "level": "none", "message": {"text": "Commented-code block (7 lines) in src/lib/supabase/middleware.ts:56"}, "properties": {"repobilityId": "cbc6f785e400bb81", "scanner": "scanner-primary", "fingerprint": "2c246a5779609dc1", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-c276fce9501e5ae4", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/lib/supabase/client.ts:4"}, "properties": {"repobilityId": "67a6421d620af306", "scanner": "scanner-primary", "fingerprint": "c276fce9501e5ae4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-3913b5e72d094397", "level": "note", "message": {"text": "Legacy-named symbol `sales_copy` in src/lib/cursos/types.ts:13"}, "properties": {"repobilityId": "4b8bbeab4866050c", "scanner": "scanner-primary", "fingerprint": "3913b5e72d094397", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}]}]}