{"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-e392e15446aacbf8", "name": "Stray `console.log` in TS/JS \u2014 scripts/export-catalog-snapshot.js:32", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 scripts/export-catalog-snapshot.js:32"}, "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-dc1463eb646795b8", "name": "Stray `console.log` in TS/JS \u2014 scripts/check-pnl-calc.js:39", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 scripts/check-pnl-calc.js:39"}, "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-b6629d1999eb5a16", "name": "Stray `console.log` in TS/JS \u2014 scripts/import-catalog-icons.js:73", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 scripts/import-catalog-icons.js:73"}, "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-37b63d9eeddeb722", "name": "Stray `console.log` in TS/JS \u2014 server/index.js:80", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/index.js:80"}, "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-b93b7789d2d7d2fb", "name": "Stray `console.log` in TS/JS \u2014 server/db.js:347", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/db.js:347"}, "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-6bb1a06705561895", "name": "Stray `console.log` in TS/JS \u2014 server/jobs/runner.js:19", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/runner.js:19"}, "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-bec71db765459287", "name": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/payment-reminder.js:44", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/payment-reminder.js:44"}, "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-17c2aaf6a0ba2eae", "name": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/send-invoice-email.js:42", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/send-invoice-email.js:42"}, "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-b16d208a194e6791", "name": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/email-sequence.js:60", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/email-sequence.js:60"}, "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-3b2b88bc6a03100f", "name": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/calendar-sync.js:70", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/calendar-sync.js:70"}, "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-29709d37cc3838ac", "name": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/send-quote-email.js:42", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/send-quote-email.js:42"}, "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-d8f1dda51be86e1e", "name": "Stray `console.log` in TS/JS \u2014 server/middleware/apiKey.js:50", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/middleware/apiKey.js:50"}, "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-a2f60592380f76ce", "name": "TODO/FIXME marker in shipping code \u2014 server/services/stripe.js:3", "shortDescription": {"text": "TODO/FIXME marker in shipping code \u2014 server/services/stripe.js:3"}, "fullDescription": {"text": "Track in /reviews or /issues, not as a code comment that rots.\n\nWhy: Drift control \u2014 shouldn't be the same as Quality TODO scanner.\nRule id: fq.todo-marker"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-48a523b869e58aef", "name": "Stray `console.log` in TS/JS \u2014 server/services/stripe.js:21", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/services/stripe.js:21"}, "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-f1f3c41ed821c75d", "name": "Stray `console.log` in TS/JS \u2014 server/services/pdf.js:969", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/services/pdf.js:969"}, "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-da3254a07c604821", "name": "TODO/FIXME marker in shipping code \u2014 server/services/google-calendar.js:3", "shortDescription": {"text": "TODO/FIXME marker in shipping code \u2014 server/services/google-calendar.js:3"}, "fullDescription": {"text": "Track in /reviews or /issues, not as a code comment that rots.\n\nWhy: Drift control \u2014 shouldn't be the same as Quality TODO scanner.\nRule id: fq.todo-marker"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-c979324df6c6bb90", "name": "Stray `console.log` in TS/JS \u2014 server/services/google-calendar.js:52", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/services/google-calendar.js:52"}, "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-0ca8487513514ae5", "name": "TODO/FIXME marker in shipping code \u2014 server/services/storage.js:5", "shortDescription": {"text": "TODO/FIXME marker in shipping code \u2014 server/services/storage.js:5"}, "fullDescription": {"text": "Track in /reviews or /issues, not as a code comment that rots.\n\nWhy: Drift control \u2014 shouldn't be the same as Quality TODO scanner.\nRule id: fq.todo-marker"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-d9d70ec7d7feb48a", "name": "Stray `console.log` in TS/JS \u2014 server/services/email.js:21", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 server/services/email.js:21"}, "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-503e081258714a1f", "name": "Stray `console.log` in TS/JS \u2014 prisma/seed-templates.js:402", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-templates.js:402"}, "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-da6e417a16e6ba15", "name": "Stray `console.log` in TS/JS \u2014 prisma/generate-api-key.js:21", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/generate-api-key.js:21"}, "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-7bdddbd6cca29819", "name": "Stray `console.log` in TS/JS \u2014 prisma/seed.js:314", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed.js:314"}, "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-4d04b3f6410bebb2", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/CRMSidebar.tsx:173", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/CRMSidebar.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-7baf92ba4c71e114", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/StaffWeekView.tsx:515", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/StaffWeekView.tsx:515"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-bc8db55a8c9ab9c8", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/Sidebar.tsx:169", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/Sidebar.tsx:169"}, "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-dcdc26d5f0f6650b", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/SurveyTool.tsx:979", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/SurveyTool.tsx:979"}, "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-ada07d142bd34e47", "name": "\"active\" state uses light bg in a dark theme \u2014 client/src/components/PipelineTracker.tsx:136", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 client/src/components/PipelineTracker.tsx:136"}, "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-f38281a95a936d57", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/StatCard.tsx:19", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/StatCard.tsx:19"}, "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-c69e546435c363cf", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/QuoteBuilder.tsx:1229", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/QuoteBuilder.tsx:1229"}, "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-3fb0430f2b686365", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/partner/Leads.tsx:124", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/partner/Leads.tsx:124"}, "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-dc7e8eab5d4595f2", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/partner/Commissions.tsx:114", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/partner/Commissions.tsx:114"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-37533c5ed0faf48b", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/partner/Dashboard.tsx:427", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/partner/Dashboard.tsx:427"}, "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-4ae7e7940ed0c975", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMContractor.tsx:233", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMContractor.tsx:233"}, "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-3141d458c7695345", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMCustomerDetail.tsx:61", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMCustomerDetail.tsx:61"}, "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-7e68b320130c50dc", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRM.tsx:112", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRM.tsx:112"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-9c3ac35fd942bbbc", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMSettings.tsx:980", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMSettings.tsx:980"}, "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-c71155dc1a095509", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/Partners.tsx:587", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/Partners.tsx:587"}, "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-962e7ab35a6d613d", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMJobs.tsx:525", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMJobs.tsx:525"}, "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-235d0ab1d2e6a3c0", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMPlanner.tsx:376", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMPlanner.tsx:376"}, "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-a248117be7d0f82b", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMDetail.tsx:1594", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMDetail.tsx:1594"}, "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-2c5d40f59c16ddcb", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMContractJobs.tsx:93", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMContractJobs.tsx:93"}, "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-6d3714bef7b4c154", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/Dashboard.tsx:122", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/Dashboard.tsx:122"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-43c1c4f156aa4a40", "name": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/settings/AnalyticsTab.tsx:308", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/settings/AnalyticsTab.tsx:308"}, "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-4f2aef919efea69e", "name": "Possible secret in .env.example", "shortDescription": {"text": "Possible secret in .env.example"}, "fullDescription": {"text": "Detected pattern matching generic_api_key. Rotate the credential and move to a secret manager."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "critical", "confidence": 1.0}}, {"id": "scanner-a0e117e5170d68a8", "name": "Insecure pattern 'local_storage_auth_token' in client/src/contexts/AuthContext.tsx:53", "shortDescription": {"text": "Insecure pattern 'local_storage_auth_token' in client/src/contexts/AuthContext.tsx:53"}, "fullDescription": {"text": "Found a known-risky pattern (local_storage_auth_token). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-02e5be5391c148eb", "name": "Insecure pattern 'document_write' in client/src/components/SurveyReport.tsx:314", "shortDescription": {"text": "Insecure pattern 'document_write' in client/src/components/SurveyReport.tsx:314"}, "fullDescription": {"text": "Found a known-risky pattern (document_write). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "low", "confidence": 1.0}}, {"id": "scanner-cb639d9a10a47b23", "name": "package.json defines install-time lifecycle scripts", "shortDescription": {"text": "package.json defines install-time lifecycle scripts"}, "fullDescription": {"text": "preinstall/install/postinstall/prepare scripts execute during dependency installation. Review them carefully for network calls, obfuscation, shell execution, or credential access."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "low", "confidence": 1.0}}, {"id": "scanner-28730d09f88a3ea7", "name": "Very large file: client/src/components/StaffWeekView.tsx (1518 lines)", "shortDescription": {"text": "Very large file: client/src/components/StaffWeekView.tsx (1518 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d69ba02318f52d71", "name": "Very large file: client/src/components/SurveyTool.tsx (1333 lines)", "shortDescription": {"text": "Very large file: client/src/components/SurveyTool.tsx (1333 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-99a15fad5fce3a92", "name": "Very large file: client/src/components/QuoteBuilder.tsx (2850 lines)", "shortDescription": {"text": "Very large file: client/src/components/QuoteBuilder.tsx (2850 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a16c6d20dbd23816", "name": "Very large file: client/src/pages/admin/CRMSettings.tsx (3384 lines)", "shortDescription": {"text": "Very large file: client/src/pages/admin/CRMSettings.tsx (3384 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-96b06b7e1f9ad4ae", "name": "Very large file: client/src/pages/admin/CRMPlanner.tsx (2386 lines)", "shortDescription": {"text": "Very large file: client/src/pages/admin/CRMPlanner.tsx (2386 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-7bebb75494c0c527", "name": "Very large file: client/src/pages/admin/CRMDetail.tsx (1832 lines)", "shortDescription": {"text": "Very large file: client/src/pages/admin/CRMDetail.tsx (1832 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "1 test file(s) for 114 source file(s) (ratio 0.01). Consider adding integration or unit tests for critical paths."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-141b30a41e03817b", "name": "No license file detected", "shortDescription": {"text": "No license file detected"}, "fullDescription": {"text": "No LICENSE/COPYING/NOTICE file was found. Generated repositories often omit licensing, which blocks reuse and automated intake."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3ab5d313dda8e5f9", "name": "Debug logging residue appears in source files", "shortDescription": {"text": "Debug logging residue appears in source files"}, "fullDescription": {"text": "Found 64 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 252 placeholder/mock markers across 27 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-9d79c4077342a7d0", "name": "Runtime service client appears to use placeholder configuration", "shortDescription": {"text": "Runtime service client appears to use placeholder configuration"}, "fullDescription": {"text": "A runtime source file appears to wire Supabase/Firebase/AI/payment-style clients to placeholder URLs, keys, or fallback values. In the Fable corpus this often means the UI/API shape is present while the backend service is not actually configured."}, "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. Opus verification showed these co-occurring gaps are a better readiness signal than reading each flag in isolation."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-cc55229a7a3c078d", "name": "Agent authority lacks a verifier contract: .mcp.json", "shortDescription": {"text": "Agent authority lacks a verifier contract: .mcp.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-4dec532851aa42d1", "name": "Commented-code block (5 lines) in server/lib/wage-calc.js:89", "shortDescription": {"text": "Commented-code block (5 lines) in server/lib/wage-calc.js:89"}, "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-9188b9134e58e3ee", "name": "Commented-code block (6 lines) in server/services/stripe.js:15", "shortDescription": {"text": "Commented-code block (6 lines) in server/services/stripe.js:15"}, "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-9fa00db5aceb9173", "name": "Commented-code block (6 lines) in server/services/google-calendar.js:9", "shortDescription": {"text": "Commented-code block (6 lines) in server/services/google-calendar.js: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-de7ecea596ef226d", "name": "Commented-code block (15 lines) in server/services/storage.js:55", "shortDescription": {"text": "Commented-code block (15 lines) in server/services/storage.js: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-d7a4e1d91af3f52e", "name": "Commented-code block (6 lines) in server/routes/contract-jobs.js:505", "shortDescription": {"text": "Commented-code block (6 lines) in server/routes/contract-jobs.js:505"}, "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-9e46a5f186f3c2d4", "name": "`fetch()` without try/.catch or AbortSignal \u2014 server/routes/crm.js:621", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 server/routes/crm.js:621"}, "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-dcc4fccfe2b7b7a1", "name": "Legacy-named symbol `crm_estimate_sent_slot_v1` in server/routes/settings.js:104", "shortDescription": {"text": "Legacy-named symbol `crm_estimate_sent_slot_v1` in server/routes/settings.js:104"}, "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-9cb19c51e48d40de", "name": "Commented-code block (6 lines) in server/routes/settings.js:75", "shortDescription": {"text": "Commented-code block (6 lines) in server/routes/settings.js:75"}, "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-d310016ab7466ad1", "name": "Commented-code block (5 lines) in server/routes/planner.js:783", "shortDescription": {"text": "Commented-code block (5 lines) in server/routes/planner.js:783"}, "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-5e3ae5bdab8986b3", "name": "Commented-code block (8 lines) in prisma/seed-templates.js:407", "shortDescription": {"text": "Commented-code block (8 lines) in prisma/seed-templates.js:407"}, "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-cf78a148a8c175f8", "name": "Commented-code block (5 lines) in client/src/components/StaffWeekView.tsx:152", "shortDescription": {"text": "Commented-code block (5 lines) in client/src/components/StaffWeekView.tsx:152"}, "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-2c04e10e9d5b8dee", "name": "Commented-code block (5 lines) in client/src/components/SurveyTool.tsx:811", "shortDescription": {"text": "Commented-code block (5 lines) in client/src/components/SurveyTool.tsx:811"}, "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-a4dc5d353c58846d", "name": "Commented-code block (6 lines) in client/src/components/QuoteBuilder.tsx:1073", "shortDescription": {"text": "Commented-code block (6 lines) in client/src/components/QuoteBuilder.tsx:1073"}, "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-36b9a22d54b3b238", "name": "Commented-code block (6 lines) in client/src/pages/admin/CRMSettings.tsx:685", "shortDescription": {"text": "Commented-code block (6 lines) in client/src/pages/admin/CRMSettings.tsx:685"}, "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-b334d875f2339fa1", "name": "5 env vars used in code but missing from .env.example", "shortDescription": {"text": "5 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `API_KEY`, `CORS_ORIGINS`, `CRM_URL`, `GOOGLE_MAPS_API_KEY`, `RAILWAY_API_KEY`. Add them (with a placeholder/comment) to .env.example so onboarding doesn't break."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-23134c7198da2c1d", "name": "Frontend route `/auth/handoff` has no Link/navigate to it \u2014 client/src/App.tsx", "shortDescription": {"text": "Frontend route `/auth/handoff` has no Link/navigate to it \u2014 client/src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-acb7ddc70b7aecc0", "name": "Frontend route `/partner/leads/:id` has no Link/navigate to it \u2014 client/src/App.tsx", "shortDescription": {"text": "Frontend route `/partner/leads/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-7479a535ca4034a9", "name": "Frontend route `/admin/leads/:id` has no Link/navigate to it \u2014 client/src/App.tsx", "shortDescription": {"text": "Frontend route `/admin/leads/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-e2cca49ac50c85eb", "name": "Frontend route `/admin/crm/contract-jobs/:id` has no Link/navigate to it \u2014 client/src/App.tsx", "shortDescription": {"text": "Frontend route `/admin/crm/contract-jobs/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-c5a6cf00d962fa26", "name": "Frontend route `/admin/crm/contract-jobs/:id/invoices/:invoiceId` has no Link/navigate to it \u2014 client/src/App.tsx", "shortDescription": {"text": "Frontend route `/admin/crm/contract-jobs/:id/invoices/:invoiceId` has no Link/navigate to it \u2014 client/src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-7784e26b5196aa32", "name": "Frontend route `/admin/crm/customers/:id` has no Link/navigate to it \u2014 client/src/App.tsx", "shortDescription": {"text": "Frontend route `/admin/crm/customers/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-8bf49afcda77b23a", "name": "Frontend route `/admin/crm/:id` has no Link/navigate to it \u2014 client/src/App.tsx", "shortDescription": {"text": "Frontend route `/admin/crm/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-55797a351c67cf72", "name": "JS POST `/auth/admin-users` admin endpoint without auth \u2014 client/src/pages/admin/CRMSettings.tsx:1711", "shortDescription": {"text": "JS POST `/auth/admin-users` admin endpoint without auth \u2014 client/src/pages/admin/CRMSettings.tsx:1711"}, "fullDescription": {"text": "Admin-scoped JS route with no recognizable auth: no middleware-position guard, no router-level guard above it in this file, and no inline permission call within the first 15 lines of the handler. If auth is applied where this router is mounted, dismiss with reason `by_design` or tag the route `// public-by-design`."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-3ada8456b38b10a4", "name": "JS PUT `/auth/admin-users/${editAdminForm.id}` admin endpoint without auth \u2014 client/src/pages/admin/CRMSettings.tsx:1797", "shortDescription": {"text": "JS PUT `/auth/admin-users/${editAdminForm.id}` admin endpoint without auth \u2014 client/src/pages/admin/CRMSettings.tsx:1797"}, "fullDescription": {"text": "Admin-scoped JS route with no recognizable auth: no middleware-position guard, no router-level guard above it in this file, and no inline permission call within the first 15 lines of the handler. If auth is applied where this router is mounted, dismiss with reason `by_design` or tag the route `// public-by-design`."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-f6177dfb1456dd5f", "name": "JS DELETE `/auth/admin-users/${confirmDeleteAdmin?.id}` admin endpoint without auth \u2014 client/src/pages/admin/CRMSettings", "shortDescription": {"text": "JS DELETE `/auth/admin-users/${confirmDeleteAdmin?.id}` admin endpoint without auth \u2014 client/src/pages/admin/CRMSettings.tsx:1875"}, "fullDescription": {"text": "Admin-scoped JS route with no recognizable auth: no middleware-position guard, no router-level guard above it in this file, and no inline permission call within the first 15 lines of the handler. If auth is applied where this router is mounted, dismiss with reason `by_design` or tag the route `// public-by-design`."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-a35469737dea03da", "name": "Dangling fetch: GET https://router.project-osrm.org/route/v1/driving/${coordStr}?overview=false (server/routes/crm.js:64", "shortDescription": {"text": "Dangling fetch: GET https://router.project-osrm.org/route/v1/driving/${coordStr}?overview=false (server/routes/crm.js:648)"}, "fullDescription": {"text": "`server/routes/crm.js:648` calls `GET https://router.project-osrm.org/route/v1/driving/${coordStr}?overview=false` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/router.project-osrm.org/route/v1/driving/<p>`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-6eb452fbfb454d20", "name": "Unused endpoint: USE /api/auth", "shortDescription": {"text": "Unused endpoint: USE /api/auth"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/auth` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-c5deac614037b912", "name": "Unused endpoint: USE /api/leads", "shortDescription": {"text": "Unused endpoint: USE /api/leads"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/leads` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ab32a18646b0ef62", "name": "Unused endpoint: USE /api/partners", "shortDescription": {"text": "Unused endpoint: USE /api/partners"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/partners` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-dbdbc13210e7149b", "name": "Unused endpoint: USE /api/dashboard", "shortDescription": {"text": "Unused endpoint: USE /api/dashboard"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/dashboard` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ffd3a143720d928f", "name": "Unused endpoint: USE /api/crm", "shortDescription": {"text": "Unused endpoint: USE /api/crm"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/crm` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-b9a63b778a1bea48", "name": "Unused endpoint: USE /api/crm-proxy", "shortDescription": {"text": "Unused endpoint: USE /api/crm-proxy"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/crm-proxy` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-530274a2ae45a5dc", "name": "Unused endpoint: USE /api/customers", "shortDescription": {"text": "Unused endpoint: USE /api/customers"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/customers` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-898909707d118b2e", "name": "Unused endpoint: USE /api/planner", "shortDescription": {"text": "Unused endpoint: USE /api/planner"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/planner` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-93ad07f7cdd089c6", "name": "Unused endpoint: USE /api/wages", "shortDescription": {"text": "Unused endpoint: USE /api/wages"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/wages` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8ca4664c9cda1cd6", "name": "Unused endpoint: USE /api/settings", "shortDescription": {"text": "Unused endpoint: USE /api/settings"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/settings` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8db4f4c5420e1e33", "name": "Unused endpoint: USE /api/contracts", "shortDescription": {"text": "Unused endpoint: USE /api/contracts"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/contracts` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f3ce55f0d928068e", "name": "Unused endpoint: USE /api/contract-jobs", "shortDescription": {"text": "Unused endpoint: USE /api/contract-jobs"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/contract-jobs` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d803e7e5650befd4", "name": "Unused endpoint: USE /api/analytics", "shortDescription": {"text": "Unused endpoint: USE /api/analytics"}, "fullDescription": {"text": "`server/index.js` declares `USE /api/analytics` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4756b4c4da7d2088", "name": "Unused endpoint: GET /api/health", "shortDescription": {"text": "Unused endpoint: GET /api/health"}, "fullDescription": {"text": "`server/index.js` declares `GET /api/health` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-c4f0e54bd69a7e4c", "name": "Unused endpoint: GET /contractors/:cid/items", "shortDescription": {"text": "Unused endpoint: GET /contractors/:cid/items"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `GET /contractors/:cid/items` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-4d2c0545e6732733", "name": "Unused endpoint: POST /contractors/:cid/items", "shortDescription": {"text": "Unused endpoint: POST /contractors/:cid/items"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `POST /contractors/:cid/items` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2a04a52d11698fc0", "name": "Unused endpoint: PUT /contractors/:cid/items/:id", "shortDescription": {"text": "Unused endpoint: PUT /contractors/:cid/items/:id"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `PUT /contractors/:cid/items/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-97cfaec59c051b5b", "name": "Unused endpoint: DELETE /contractors/:cid/items/:id", "shortDescription": {"text": "Unused endpoint: DELETE /contractors/:cid/items/:id"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `DELETE /contractors/:cid/items/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f06a82ae347f0a1b", "name": "Unused endpoint: GET /contractors/:cid/jobs", "shortDescription": {"text": "Unused endpoint: GET /contractors/:cid/jobs"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `GET /contractors/:cid/jobs` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-09ee72aea5a0a2b7", "name": "Unused endpoint: GET /jobs/:id", "shortDescription": {"text": "Unused endpoint: GET /jobs/:id"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `GET /jobs/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8b5951da143a1206", "name": "Unused endpoint: POST /contractors/:cid/jobs", "shortDescription": {"text": "Unused endpoint: POST /contractors/:cid/jobs"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `POST /contractors/:cid/jobs` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8db42a8441c3771a", "name": "Unused endpoint: PUT /jobs/:id", "shortDescription": {"text": "Unused endpoint: PUT /jobs/:id"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `PUT /jobs/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-7591cd3582101c4b", "name": "Unused endpoint: DELETE /jobs/:id", "shortDescription": {"text": "Unused endpoint: DELETE /jobs/:id"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `DELETE /jobs/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-6ddec6c436c9374c", "name": "Unused endpoint: GET /contractors/:cid/invoices", "shortDescription": {"text": "Unused endpoint: GET /contractors/:cid/invoices"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `GET /contractors/:cid/invoices` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e3562e44ca70bba8", "name": "Unused endpoint: GET /invoices/:id", "shortDescription": {"text": "Unused endpoint: GET /invoices/:id"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `GET /invoices/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-32bb21bd89d19b04", "name": "Unused endpoint: POST /contractors/:cid/invoices/auto", "shortDescription": {"text": "Unused endpoint: POST /contractors/:cid/invoices/auto"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `POST /contractors/:cid/invoices/auto` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-16dd2cf278ca8d4f", "name": "Unused endpoint: PUT /invoices/:id", "shortDescription": {"text": "Unused endpoint: PUT /invoices/:id"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `PUT /invoices/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f8e1da8776d9b552", "name": "Unused endpoint: PATCH /invoices/:id/status", "shortDescription": {"text": "Unused endpoint: PATCH /invoices/:id/status"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `PATCH /invoices/:id/status` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-356138f2da46d2c2", "name": "Unused endpoint: DELETE /invoices/:id", "shortDescription": {"text": "Unused endpoint: DELETE /invoices/:id"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `DELETE /invoices/:id` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-22293f41daa8cc95", "name": "Unused endpoint: GET /invoices/:id/pdf", "shortDescription": {"text": "Unused endpoint: GET /invoices/:id/pdf"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `GET /invoices/:id/pdf` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-261bb727cc9ddfaf", "name": "Unused endpoint: POST /invoices/:id/send-email", "shortDescription": {"text": "Unused endpoint: POST /invoices/:id/send-email"}, "fullDescription": {"text": "`server/routes/contract-jobs.js` declares `POST /invoices/:id/send-email` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ff30f4b5b5319e28", "name": "Unused endpoint: GET /pending-leads", "shortDescription": {"text": "Unused endpoint: GET /pending-leads"}, "fullDescription": {"text": "`server/routes/crm.js` declares `GET /pending-leads` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-205fa0ca983dee40", "name": "Unused endpoint: GET /jobs/summary", "shortDescription": {"text": "Unused endpoint: GET /jobs/summary"}, "fullDescription": {"text": "`server/routes/crm.js` declares `GET /jobs/summary` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1008c575819b3d37", "name": "Unused endpoint: GET /jobs", "shortDescription": {"text": "Unused endpoint: GET /jobs"}, "fullDescription": {"text": "`server/routes/crm.js` declares `GET /jobs` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d2e6e7e9516a29ab", "name": "Unused endpoint: GET /jobs/:id/audit-trail", "shortDescription": {"text": "Unused endpoint: GET /jobs/:id/audit-trail"}, "fullDescription": {"text": "`server/routes/crm.js` declares `GET /jobs/:id/audit-trail` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2b73face5b06aa67", "name": "Unused endpoint: POST /jobs", "shortDescription": {"text": "Unused endpoint: POST /jobs"}, "fullDescription": {"text": "`server/routes/crm.js` declares `POST /jobs` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f4f90d0b79f6524a", "name": "Unused endpoint: POST /jobs/:id/duplicate", "shortDescription": {"text": "Unused endpoint: POST /jobs/:id/duplicate"}, "fullDescription": {"text": "`server/routes/crm.js` declares `POST /jobs/:id/duplicate` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-43b45af76bb4dfab", "name": "Unused endpoint: POST /jobs/:id/activities", "shortDescription": {"text": "Unused endpoint: POST /jobs/:id/activities"}, "fullDescription": {"text": "`server/routes/crm.js` declares `POST /jobs/:id/activities` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f3df4d8f18bc7933", "name": "Unused endpoint: PUT /jobs/:id/activities/:actId", "shortDescription": {"text": "Unused endpoint: PUT /jobs/:id/activities/:actId"}, "fullDescription": {"text": "`server/routes/crm.js` declares `PUT /jobs/:id/activities/:actId` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a28dfd97a18c0246", "name": "Unused endpoint: DELETE /jobs/:id/activities/:actId", "shortDescription": {"text": "Unused endpoint: DELETE /jobs/:id/activities/:actId"}, "fullDescription": {"text": "`server/routes/crm.js` declares `DELETE /jobs/:id/activities/:actId` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2bd438c952572458", "name": "Unused endpoint: POST /import/:leadId", "shortDescription": {"text": "Unused endpoint: POST /import/:leadId"}, "fullDescription": {"text": "`server/routes/crm.js` declares `POST /import/:leadId` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-95e13e199903e566", "name": "Unused endpoint: POST /route-info", "shortDescription": {"text": "Unused endpoint: POST /route-info"}, "fullDescription": {"text": "`server/routes/crm.js` declares `POST /route-info` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d3f9cc6318878777", "name": "Unused endpoint: POST /jobs/:id/send-survey-email", "shortDescription": {"text": "Unused endpoint: POST /jobs/:id/send-survey-email"}, "fullDescription": {"text": "`server/routes/crm.js` declares `POST /jobs/:id/send-survey-email` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e6b90dd318626a82", "name": "Unused endpoint: GET /jobs/:id/attachments", "shortDescription": {"text": "Unused endpoint: GET /jobs/:id/attachments"}, "fullDescription": {"text": "`server/routes/crm.js` declares `GET /jobs/:id/attachments` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-cd7ba4150d0095d7", "name": "Unused endpoint: POST /jobs/:id/attachments", "shortDescription": {"text": "Unused endpoint: POST /jobs/:id/attachments"}, "fullDescription": {"text": "`server/routes/crm.js` declares `POST /jobs/:id/attachments` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-488302847bfcfbc6", "name": "Unused endpoint: DELETE /jobs/:id/attachments/:docId", "shortDescription": {"text": "Unused endpoint: DELETE /jobs/:id/attachments/:docId"}, "fullDescription": {"text": "`server/routes/crm.js` declares `DELETE /jobs/:id/attachments/:docId` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ac59d5ab24dd78e4", "name": "Unused endpoint: GET /jobs/:id/attachments/:docId/download", "shortDescription": {"text": "Unused endpoint: GET /jobs/:id/attachments/:docId/download"}, "fullDescription": {"text": "`server/routes/crm.js` declares `GET /jobs/:id/attachments/:docId/download` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-dd29b2de817f5eae", "name": "Unused endpoint: GET /jobs/:id/survey", "shortDescription": {"text": "Unused endpoint: GET /jobs/:id/survey"}, "fullDescription": {"text": "`server/routes/crm.js` declares `GET /jobs/:id/survey` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d84d3c0da3f7f328", "name": "Unused endpoint: PUT /jobs/:id/survey", "shortDescription": {"text": "Unused endpoint: PUT /jobs/:id/survey"}, "fullDescription": {"text": "`server/routes/crm.js` declares `PUT /jobs/:id/survey` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e7c935c5fee51876", "name": "Unused endpoint: GET /jobs/:id/quote-state", "shortDescription": {"text": "Unused endpoint: GET /jobs/:id/quote-state"}, "fullDescription": {"text": "`server/routes/crm.js` declares `GET /jobs/:id/quote-state` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/25437"}, "properties": {"repository": "DKcode4life/imove-partners", "repoUrl": "https://github.com/DKcode4life/imove-partners", "branch": "main"}, "results": [{"ruleId": "scanner-e392e15446aacbf8", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 scripts/export-catalog-snapshot.js:32"}, "properties": {"repobilityId": "6cdca4167b2a197d", "scanner": "scanner-primary", "fingerprint": "e392e15446aacbf8", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-dc1463eb646795b8", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 scripts/check-pnl-calc.js:39"}, "properties": {"repobilityId": "72744a4b8585d15f", "scanner": "scanner-primary", "fingerprint": "dc1463eb646795b8", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-b6629d1999eb5a16", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 scripts/import-catalog-icons.js:73"}, "properties": {"repobilityId": "116ff44eb4aaab30", "scanner": "scanner-primary", "fingerprint": "b6629d1999eb5a16", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-37b63d9eeddeb722", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/index.js:80"}, "properties": {"repobilityId": "21e6b3de2b3dd856", "scanner": "scanner-primary", "fingerprint": "37b63d9eeddeb722", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-b93b7789d2d7d2fb", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/db.js:347"}, "properties": {"repobilityId": "0c27e1750d84b73e", "scanner": "scanner-primary", "fingerprint": "b93b7789d2d7d2fb", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-6bb1a06705561895", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/runner.js:19"}, "properties": {"repobilityId": "d560271624bc2ca8", "scanner": "scanner-primary", "fingerprint": "6bb1a06705561895", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-bec71db765459287", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/payment-reminder.js:44"}, "properties": {"repobilityId": "504f933aa63a082e", "scanner": "scanner-primary", "fingerprint": "bec71db765459287", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-17c2aaf6a0ba2eae", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/send-invoice-email.js:42"}, "properties": {"repobilityId": "ea1d20b844e56b0e", "scanner": "scanner-primary", "fingerprint": "17c2aaf6a0ba2eae", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-b16d208a194e6791", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/email-sequence.js:60"}, "properties": {"repobilityId": "11f7430625f3adaa", "scanner": "scanner-primary", "fingerprint": "b16d208a194e6791", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-3b2b88bc6a03100f", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/calendar-sync.js:70"}, "properties": {"repobilityId": "45cfae442dfe04ea", "scanner": "scanner-primary", "fingerprint": "3b2b88bc6a03100f", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-29709d37cc3838ac", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/jobs/handlers/send-quote-email.js:42"}, "properties": {"repobilityId": "f354bf4f22014d72", "scanner": "scanner-primary", "fingerprint": "29709d37cc3838ac", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-d8f1dda51be86e1e", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/middleware/apiKey.js:50"}, "properties": {"repobilityId": "01aecb7a0a3519ba", "scanner": "scanner-primary", "fingerprint": "d8f1dda51be86e1e", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-a2f60592380f76ce", "level": "none", "message": {"text": "TODO/FIXME marker in shipping code \u2014 server/services/stripe.js:3"}, "properties": {"repobilityId": "c48bea9ccff36e10", "scanner": "scanner-primary", "fingerprint": "a2f60592380f76ce", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.todo-marker"]}}, {"ruleId": "scanner-48a523b869e58aef", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/services/stripe.js:21"}, "properties": {"repobilityId": "898f2591be5da88b", "scanner": "scanner-primary", "fingerprint": "48a523b869e58aef", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-f1f3c41ed821c75d", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/services/pdf.js:969"}, "properties": {"repobilityId": "b3f5359d354e4d9c", "scanner": "scanner-primary", "fingerprint": "f1f3c41ed821c75d", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-da3254a07c604821", "level": "none", "message": {"text": "TODO/FIXME marker in shipping code \u2014 server/services/google-calendar.js:3"}, "properties": {"repobilityId": "d5def58876fa1a1e", "scanner": "scanner-primary", "fingerprint": "da3254a07c604821", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.todo-marker"]}}, {"ruleId": "scanner-c979324df6c6bb90", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/services/google-calendar.js:52"}, "properties": {"repobilityId": "7434ce833de150f9", "scanner": "scanner-primary", "fingerprint": "c979324df6c6bb90", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-0ca8487513514ae5", "level": "none", "message": {"text": "TODO/FIXME marker in shipping code \u2014 server/services/storage.js:5"}, "properties": {"repobilityId": "9ea90e65228bf9cb", "scanner": "scanner-primary", "fingerprint": "0ca8487513514ae5", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.todo-marker"]}}, {"ruleId": "scanner-d9d70ec7d7feb48a", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 server/services/email.js:21"}, "properties": {"repobilityId": "f8581150beb6b1ff", "scanner": "scanner-primary", "fingerprint": "d9d70ec7d7feb48a", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-503e081258714a1f", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-templates.js:402"}, "properties": {"repobilityId": "565c81b88c6f51b6", "scanner": "scanner-primary", "fingerprint": "503e081258714a1f", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-da6e417a16e6ba15", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/generate-api-key.js:21"}, "properties": {"repobilityId": "4fdac6a7a6596676", "scanner": "scanner-primary", "fingerprint": "da6e417a16e6ba15", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-7bdddbd6cca29819", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed.js:314"}, "properties": {"repobilityId": "811c4f12ca772b62", "scanner": "scanner-primary", "fingerprint": "7bdddbd6cca29819", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-4d04b3f6410bebb2", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/CRMSidebar.tsx:173"}, "properties": {"repobilityId": "441918697feefd2d", "scanner": "scanner-primary", "fingerprint": "4d04b3f6410bebb2", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-7baf92ba4c71e114", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/StaffWeekView.tsx:515"}, "properties": {"repobilityId": "69ab079b1ed443a7", "scanner": "scanner-primary", "fingerprint": "7baf92ba4c71e114", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-bc8db55a8c9ab9c8", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/Sidebar.tsx:169"}, "properties": {"repobilityId": "b0d21d23421e736f", "scanner": "scanner-primary", "fingerprint": "bc8db55a8c9ab9c8", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-dcdc26d5f0f6650b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/SurveyTool.tsx:979"}, "properties": {"repobilityId": "138282892c0fb09e", "scanner": "scanner-primary", "fingerprint": "dcdc26d5f0f6650b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-ada07d142bd34e47", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 client/src/components/PipelineTracker.tsx:136"}, "properties": {"repobilityId": "23558a46197ad575", "scanner": "scanner-primary", "fingerprint": "ada07d142bd34e47", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-f38281a95a936d57", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/StatCard.tsx:19"}, "properties": {"repobilityId": "08e305396198f024", "scanner": "scanner-primary", "fingerprint": "f38281a95a936d57", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-c69e546435c363cf", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/components/QuoteBuilder.tsx:1229"}, "properties": {"repobilityId": "e911996695b97cd5", "scanner": "scanner-primary", "fingerprint": "c69e546435c363cf", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-3fb0430f2b686365", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/partner/Leads.tsx:124"}, "properties": {"repobilityId": "0b22f212d8cca31f", "scanner": "scanner-primary", "fingerprint": "3fb0430f2b686365", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-dc7e8eab5d4595f2", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/partner/Commissions.tsx:114"}, "properties": {"repobilityId": "5d8d98397a3031cf", "scanner": "scanner-primary", "fingerprint": "dc7e8eab5d4595f2", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-37533c5ed0faf48b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/partner/Dashboard.tsx:427"}, "properties": {"repobilityId": "9e42de13c97c43b2", "scanner": "scanner-primary", "fingerprint": "37533c5ed0faf48b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4ae7e7940ed0c975", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMContractor.tsx:233"}, "properties": {"repobilityId": "bfe1e826937e24ad", "scanner": "scanner-primary", "fingerprint": "4ae7e7940ed0c975", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-3141d458c7695345", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMCustomerDetail.tsx:61"}, "properties": {"repobilityId": "875b80eeb6bfcf1d", "scanner": "scanner-primary", "fingerprint": "3141d458c7695345", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-7e68b320130c50dc", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRM.tsx:112"}, "properties": {"repobilityId": "0056cf3f1ad7f096", "scanner": "scanner-primary", "fingerprint": "7e68b320130c50dc", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-9c3ac35fd942bbbc", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMSettings.tsx:980"}, "properties": {"repobilityId": "9bc55f4213234eb1", "scanner": "scanner-primary", "fingerprint": "9c3ac35fd942bbbc", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-c71155dc1a095509", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/Partners.tsx:587"}, "properties": {"repobilityId": "716794d899c4de79", "scanner": "scanner-primary", "fingerprint": "c71155dc1a095509", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-962e7ab35a6d613d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMJobs.tsx:525"}, "properties": {"repobilityId": "502a23d75bc11df3", "scanner": "scanner-primary", "fingerprint": "962e7ab35a6d613d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-235d0ab1d2e6a3c0", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMPlanner.tsx:376"}, "properties": {"repobilityId": "1a2e36d1c5db8f18", "scanner": "scanner-primary", "fingerprint": "235d0ab1d2e6a3c0", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a248117be7d0f82b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMDetail.tsx:1594"}, "properties": {"repobilityId": "08f0a4d989d864f3", "scanner": "scanner-primary", "fingerprint": "a248117be7d0f82b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-2c5d40f59c16ddcb", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/CRMContractJobs.tsx:93"}, "properties": {"repobilityId": "3a37775900e06993", "scanner": "scanner-primary", "fingerprint": "2c5d40f59c16ddcb", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-6d3714bef7b4c154", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/Dashboard.tsx:122"}, "properties": {"repobilityId": "ea6fcd0f27e9c0a5", "scanner": "scanner-primary", "fingerprint": "6d3714bef7b4c154", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-43c1c4f156aa4a40", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 client/src/pages/admin/settings/AnalyticsTab.tsx:308"}, "properties": {"repobilityId": "3dd83068d5a91ee8", "scanner": "scanner-primary", "fingerprint": "43c1c4f156aa4a40", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4f2aef919efea69e", "level": "error", "message": {"text": "Possible secret in .env.example"}, "properties": {"repobilityId": "93cd72ec8a582b1e", "scanner": "scanner-primary", "fingerprint": "4f2aef919efea69e", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".env.example"}, "region": {"startLine": 21}}}]}, {"ruleId": "scanner-a0e117e5170d68a8", "level": "warning", "message": {"text": "Insecure pattern 'local_storage_auth_token' in client/src/contexts/AuthContext.tsx:53"}, "properties": {"repobilityId": "cd82c29a21320658", "scanner": "scanner-primary", "fingerprint": "a0e117e5170d68a8", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "local_storage_auth_token"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "client/src/contexts/AuthContext.tsx"}, "region": {"startLine": 53}}}]}, {"ruleId": "scanner-02e5be5391c148eb", "level": "note", "message": {"text": "Insecure pattern 'document_write' in client/src/components/SurveyReport.tsx:314"}, "properties": {"repobilityId": "e19a3be3da2f48bf", "scanner": "scanner-primary", "fingerprint": "02e5be5391c148eb", "layer": "security", "severity": "low", "confidence": 1.0, "tags": ["owasp", "document_write"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "client/src/components/SurveyReport.tsx"}, "region": {"startLine": 314}}}]}, {"ruleId": "scanner-cb639d9a10a47b23", "level": "note", "message": {"text": "package.json defines install-time lifecycle scripts"}, "properties": {"repobilityId": "edeab51902066991", "scanner": "scanner-primary", "fingerprint": "cb639d9a10a47b23", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "npm", "install-scripts"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-28730d09f88a3ea7", "level": "note", "message": {"text": "Very large file: client/src/components/StaffWeekView.tsx (1518 lines)"}, "properties": {"repobilityId": "94669e41cbca6c61", "scanner": "scanner-primary", "fingerprint": "28730d09f88a3ea7", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-d69ba02318f52d71", "level": "note", "message": {"text": "Very large file: client/src/components/SurveyTool.tsx (1333 lines)"}, "properties": {"repobilityId": "7777e1a540105751", "scanner": "scanner-primary", "fingerprint": "d69ba02318f52d71", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-99a15fad5fce3a92", "level": "note", "message": {"text": "Very large file: client/src/components/QuoteBuilder.tsx (2850 lines)"}, "properties": {"repobilityId": "1e5f67e2a7989650", "scanner": "scanner-primary", "fingerprint": "99a15fad5fce3a92", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-a16c6d20dbd23816", "level": "note", "message": {"text": "Very large file: client/src/pages/admin/CRMSettings.tsx (3384 lines)"}, "properties": {"repobilityId": "dc585a2217ce778c", "scanner": "scanner-primary", "fingerprint": "a16c6d20dbd23816", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-96b06b7e1f9ad4ae", "level": "note", "message": {"text": "Very large file: client/src/pages/admin/CRMPlanner.tsx (2386 lines)"}, "properties": {"repobilityId": "b3dba0a535e9f580", "scanner": "scanner-primary", "fingerprint": "96b06b7e1f9ad4ae", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-7bebb75494c0c527", "level": "note", "message": {"text": "Very large file: client/src/pages/admin/CRMDetail.tsx (1832 lines)"}, "properties": {"repobilityId": "502ad31449583afb", "scanner": "scanner-primary", "fingerprint": "7bebb75494c0c527", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-6893a6c8b0861585", "level": "warning", "message": {"text": "Very low test-to-source ratio"}, "properties": {"repobilityId": "54a7de3f06314bf0", "scanner": "scanner-primary", "fingerprint": "6893a6c8b0861585", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["tests", "coverage"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "cdcf5daccf353089", "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": "4bbbc82fa8e20fb8", "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": "3430d278efd42f42", "scanner": "scanner-primary", "fingerprint": "72b2a6250083a784", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "incomplete", "generated-repo-pattern"]}}, {"ruleId": "scanner-9d79c4077342a7d0", "level": "warning", "message": {"text": "Runtime service client appears to use placeholder configuration"}, "properties": {"repobilityId": "b169dc398714846d", "scanner": "scanner-primary", "fingerprint": "9d79c4077342a7d0", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "runtime-config", "service-client", "generated-repo-pattern"]}}, {"ruleId": "scanner-2d0c7b7ab8f8aacf", "level": "warning", "message": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "properties": {"repobilityId": "6ec7dfe90f3e7742", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-b9088664ace7f748", "level": "note", "message": {"text": "Composite production-readiness gap"}, "properties": {"repobilityId": "537d7abe232a3b46", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-cc55229a7a3c078d", "level": "warning", "message": {"text": "Agent authority lacks a verifier contract: .mcp.json"}, "properties": {"repobilityId": "51942fb3d5b8b5b4", "scanner": "scanner-primary", "fingerprint": "cc55229a7a3c078d", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["agent-instructions", "verification", "mcp_config"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".mcp.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-4dec532851aa42d1", "level": "none", "message": {"text": "Commented-code block (5 lines) in server/lib/wage-calc.js:89"}, "properties": {"repobilityId": "92f0d8ef875bb0d1", "scanner": "scanner-primary", "fingerprint": "4dec532851aa42d1", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-9188b9134e58e3ee", "level": "none", "message": {"text": "Commented-code block (6 lines) in server/services/stripe.js:15"}, "properties": {"repobilityId": "b4179c44d7390823", "scanner": "scanner-primary", "fingerprint": "9188b9134e58e3ee", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-9fa00db5aceb9173", "level": "none", "message": {"text": "Commented-code block (6 lines) in server/services/google-calendar.js:9"}, "properties": {"repobilityId": "af9ae2dfaff009de", "scanner": "scanner-primary", "fingerprint": "9fa00db5aceb9173", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-de7ecea596ef226d", "level": "none", "message": {"text": "Commented-code block (15 lines) in server/services/storage.js:55"}, "properties": {"repobilityId": "86bdd2aab398478c", "scanner": "scanner-primary", "fingerprint": "de7ecea596ef226d", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-d7a4e1d91af3f52e", "level": "none", "message": {"text": "Commented-code block (6 lines) in server/routes/contract-jobs.js:505"}, "properties": {"repobilityId": "ce98ebe34fa5881d", "scanner": "scanner-primary", "fingerprint": "d7a4e1d91af3f52e", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-9e46a5f186f3c2d4", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 server/routes/crm.js:621"}, "properties": {"repobilityId": "b4ac21741213a41e", "scanner": "scanner-primary", "fingerprint": "9e46a5f186f3c2d4", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-dcc4fccfe2b7b7a1", "level": "note", "message": {"text": "Legacy-named symbol `crm_estimate_sent_slot_v1` in server/routes/settings.js:104"}, "properties": {"repobilityId": "73fb9f7d5a69e9db", "scanner": "scanner-primary", "fingerprint": "dcc4fccfe2b7b7a1", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-9cb19c51e48d40de", "level": "none", "message": {"text": "Commented-code block (6 lines) in server/routes/settings.js:75"}, "properties": {"repobilityId": "4c0ab20e22d4aa08", "scanner": "scanner-primary", "fingerprint": "9cb19c51e48d40de", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-d310016ab7466ad1", "level": "none", "message": {"text": "Commented-code block (5 lines) in server/routes/planner.js:783"}, "properties": {"repobilityId": "29e84f0a5ffa29dc", "scanner": "scanner-primary", "fingerprint": "d310016ab7466ad1", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-5e3ae5bdab8986b3", "level": "none", "message": {"text": "Commented-code block (8 lines) in prisma/seed-templates.js:407"}, "properties": {"repobilityId": "9e711d0e40605256", "scanner": "scanner-primary", "fingerprint": "5e3ae5bdab8986b3", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-cf78a148a8c175f8", "level": "none", "message": {"text": "Commented-code block (5 lines) in client/src/components/StaffWeekView.tsx:152"}, "properties": {"repobilityId": "626c1f2b989da07f", "scanner": "scanner-primary", "fingerprint": "cf78a148a8c175f8", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-2c04e10e9d5b8dee", "level": "none", "message": {"text": "Commented-code block (5 lines) in client/src/components/SurveyTool.tsx:811"}, "properties": {"repobilityId": "0b601c1328f79c32", "scanner": "scanner-primary", "fingerprint": "2c04e10e9d5b8dee", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-a4dc5d353c58846d", "level": "none", "message": {"text": "Commented-code block (6 lines) in client/src/components/QuoteBuilder.tsx:1073"}, "properties": {"repobilityId": "58d98ae37cd4a299", "scanner": "scanner-primary", "fingerprint": "a4dc5d353c58846d", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-36b9a22d54b3b238", "level": "none", "message": {"text": "Commented-code block (6 lines) in client/src/pages/admin/CRMSettings.tsx:685"}, "properties": {"repobilityId": "dc7a3ba676c3b3bf", "scanner": "scanner-primary", "fingerprint": "36b9a22d54b3b238", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-b334d875f2339fa1", "level": "note", "message": {"text": "5 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "faa38682016f5d53", "scanner": "scanner-primary", "fingerprint": "b334d875f2339fa1", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-23134c7198da2c1d", "level": "warning", "message": {"text": "Frontend route `/auth/handoff` has no Link/navigate to it \u2014 client/src/App.tsx"}, "properties": {"repobilityId": "e51736191f2302d9", "scanner": "scanner-primary", "fingerprint": "23134c7198da2c1d", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-acb7ddc70b7aecc0", "level": "warning", "message": {"text": "Frontend route `/partner/leads/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "properties": {"repobilityId": "5e2cb4dd17ff9ab0", "scanner": "scanner-primary", "fingerprint": "acb7ddc70b7aecc0", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-7479a535ca4034a9", "level": "warning", "message": {"text": "Frontend route `/admin/leads/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "properties": {"repobilityId": "91b70c62c88fb9e7", "scanner": "scanner-primary", "fingerprint": "7479a535ca4034a9", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-e2cca49ac50c85eb", "level": "warning", "message": {"text": "Frontend route `/admin/crm/contract-jobs/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "properties": {"repobilityId": "08fb00c8b163a4ad", "scanner": "scanner-primary", "fingerprint": "e2cca49ac50c85eb", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-c5a6cf00d962fa26", "level": "warning", "message": {"text": "Frontend route `/admin/crm/contract-jobs/:id/invoices/:invoiceId` has no Link/navigate to it \u2014 client/src/App.tsx"}, "properties": {"repobilityId": "e1b010aaa90a172d", "scanner": "scanner-primary", "fingerprint": "c5a6cf00d962fa26", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-7784e26b5196aa32", "level": "warning", "message": {"text": "Frontend route `/admin/crm/customers/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "properties": {"repobilityId": "1a122dbf52a16291", "scanner": "scanner-primary", "fingerprint": "7784e26b5196aa32", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-8bf49afcda77b23a", "level": "warning", "message": {"text": "Frontend route `/admin/crm/:id` has no Link/navigate to it \u2014 client/src/App.tsx"}, "properties": {"repobilityId": "62282be21a72ddeb", "scanner": "scanner-primary", "fingerprint": "8bf49afcda77b23a", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-55797a351c67cf72", "level": "error", "message": {"text": "JS POST `/auth/admin-users` admin endpoint without auth \u2014 client/src/pages/admin/CRMSettings.tsx:1711"}, "properties": {"repobilityId": "3a41a2f8c2ff4df5", "scanner": "scanner-primary", "fingerprint": "55797a351c67cf72", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.js.admin_unauth"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "client/src/pages/admin/CRMSettings.tsx"}, "region": {"startLine": 1711}}}]}, {"ruleId": "scanner-3ada8456b38b10a4", "level": "error", "message": {"text": "JS PUT `/auth/admin-users/${editAdminForm.id}` admin endpoint without auth \u2014 client/src/pages/admin/CRMSettings.tsx:1797"}, "properties": {"repobilityId": "3fcb186907ecb6f2", "scanner": "scanner-primary", "fingerprint": "3ada8456b38b10a4", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.js.admin_unauth"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "client/src/pages/admin/CRMSettings.tsx"}, "region": {"startLine": 1797}}}]}, {"ruleId": "scanner-f6177dfb1456dd5f", "level": "error", "message": {"text": "JS DELETE `/auth/admin-users/${confirmDeleteAdmin?.id}` admin endpoint without auth \u2014 client/src/pages/admin/CRMSettings.tsx:1875"}, "properties": {"repobilityId": "ad5f55b0117dc005", "scanner": "scanner-primary", "fingerprint": "f6177dfb1456dd5f", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["auth", "owasp", "auth.js.admin_unauth"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "client/src/pages/admin/CRMSettings.tsx"}, "region": {"startLine": 1875}}}]}, {"ruleId": "scanner-a35469737dea03da", "level": "error", "message": {"text": "Dangling fetch: GET https://router.project-osrm.org/route/v1/driving/${coordStr}?overview=false (server/routes/crm.js:648)"}, "properties": {"repobilityId": "dc8758ec364fbed4", "scanner": "scanner-primary", "fingerprint": "a35469737dea03da", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-6eb452fbfb454d20", "level": "note", "message": {"text": "Unused endpoint: USE /api/auth"}, "properties": {"repobilityId": "998ca44ee62afef2", "scanner": "scanner-primary", "fingerprint": "6eb452fbfb454d20", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-c5deac614037b912", "level": "note", "message": {"text": "Unused endpoint: USE /api/leads"}, "properties": {"repobilityId": "25b37e4dba2d46ea", "scanner": "scanner-primary", "fingerprint": "c5deac614037b912", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ab32a18646b0ef62", "level": "note", "message": {"text": "Unused endpoint: USE /api/partners"}, "properties": {"repobilityId": "a763dbbaa570704b", "scanner": "scanner-primary", "fingerprint": "ab32a18646b0ef62", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-dbdbc13210e7149b", "level": "note", "message": {"text": "Unused endpoint: USE /api/dashboard"}, "properties": {"repobilityId": "e6f65ad4c4bd0902", "scanner": "scanner-primary", "fingerprint": "dbdbc13210e7149b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ffd3a143720d928f", "level": "note", "message": {"text": "Unused endpoint: USE /api/crm"}, "properties": {"repobilityId": "c63ce7f3f3a74ba3", "scanner": "scanner-primary", "fingerprint": "ffd3a143720d928f", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-b9a63b778a1bea48", "level": "note", "message": {"text": "Unused endpoint: USE /api/crm-proxy"}, "properties": {"repobilityId": "3809dcc4a12eb941", "scanner": "scanner-primary", "fingerprint": "b9a63b778a1bea48", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-530274a2ae45a5dc", "level": "note", "message": {"text": "Unused endpoint: USE /api/customers"}, "properties": {"repobilityId": "c8a4a5ba6cc5b129", "scanner": "scanner-primary", "fingerprint": "530274a2ae45a5dc", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-898909707d118b2e", "level": "note", "message": {"text": "Unused endpoint: USE /api/planner"}, "properties": {"repobilityId": "dbe4da52e06ce7fb", "scanner": "scanner-primary", "fingerprint": "898909707d118b2e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-93ad07f7cdd089c6", "level": "note", "message": {"text": "Unused endpoint: USE /api/wages"}, "properties": {"repobilityId": "92ae0ec63fafc7db", "scanner": "scanner-primary", "fingerprint": "93ad07f7cdd089c6", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8ca4664c9cda1cd6", "level": "note", "message": {"text": "Unused endpoint: USE /api/settings"}, "properties": {"repobilityId": "de04cc0c686e6aae", "scanner": "scanner-primary", "fingerprint": "8ca4664c9cda1cd6", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8db4f4c5420e1e33", "level": "note", "message": {"text": "Unused endpoint: USE /api/contracts"}, "properties": {"repobilityId": "e2f9b28704248356", "scanner": "scanner-primary", "fingerprint": "8db4f4c5420e1e33", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f3ce55f0d928068e", "level": "note", "message": {"text": "Unused endpoint: USE /api/contract-jobs"}, "properties": {"repobilityId": "3397023e1d15a22f", "scanner": "scanner-primary", "fingerprint": "f3ce55f0d928068e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d803e7e5650befd4", "level": "note", "message": {"text": "Unused endpoint: USE /api/analytics"}, "properties": {"repobilityId": "b860f1f6a0748809", "scanner": "scanner-primary", "fingerprint": "d803e7e5650befd4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4756b4c4da7d2088", "level": "note", "message": {"text": "Unused endpoint: GET /api/health"}, "properties": {"repobilityId": "0d2a6e55cb055de8", "scanner": "scanner-primary", "fingerprint": "4756b4c4da7d2088", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-c4f0e54bd69a7e4c", "level": "note", "message": {"text": "Unused endpoint: GET /contractors/:cid/items"}, "properties": {"repobilityId": "51f24bc475ecce7a", "scanner": "scanner-primary", "fingerprint": "c4f0e54bd69a7e4c", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4d2c0545e6732733", "level": "note", "message": {"text": "Unused endpoint: POST /contractors/:cid/items"}, "properties": {"repobilityId": "bde6692ccca30119", "scanner": "scanner-primary", "fingerprint": "4d2c0545e6732733", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2a04a52d11698fc0", "level": "note", "message": {"text": "Unused endpoint: PUT /contractors/:cid/items/:id"}, "properties": {"repobilityId": "4847d06c00b2d35a", "scanner": "scanner-primary", "fingerprint": "2a04a52d11698fc0", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-97cfaec59c051b5b", "level": "note", "message": {"text": "Unused endpoint: DELETE /contractors/:cid/items/:id"}, "properties": {"repobilityId": "6f98e85c953e83d8", "scanner": "scanner-primary", "fingerprint": "97cfaec59c051b5b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f06a82ae347f0a1b", "level": "note", "message": {"text": "Unused endpoint: GET /contractors/:cid/jobs"}, "properties": {"repobilityId": "eb6e376fcd65eab5", "scanner": "scanner-primary", "fingerprint": "f06a82ae347f0a1b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-09ee72aea5a0a2b7", "level": "note", "message": {"text": "Unused endpoint: GET /jobs/:id"}, "properties": {"repobilityId": "66ab8b5816c73f0a", "scanner": "scanner-primary", "fingerprint": "09ee72aea5a0a2b7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8b5951da143a1206", "level": "note", "message": {"text": "Unused endpoint: POST /contractors/:cid/jobs"}, "properties": {"repobilityId": "35d579450377c608", "scanner": "scanner-primary", "fingerprint": "8b5951da143a1206", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8db42a8441c3771a", "level": "note", "message": {"text": "Unused endpoint: PUT /jobs/:id"}, "properties": {"repobilityId": "b86bb904294258f6", "scanner": "scanner-primary", "fingerprint": "8db42a8441c3771a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7591cd3582101c4b", "level": "note", "message": {"text": "Unused endpoint: DELETE /jobs/:id"}, "properties": {"repobilityId": "e5117f4244768360", "scanner": "scanner-primary", "fingerprint": "7591cd3582101c4b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-6ddec6c436c9374c", "level": "note", "message": {"text": "Unused endpoint: GET /contractors/:cid/invoices"}, "properties": {"repobilityId": "9ed278926cbf253c", "scanner": "scanner-primary", "fingerprint": "6ddec6c436c9374c", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e3562e44ca70bba8", "level": "note", "message": {"text": "Unused endpoint: GET /invoices/:id"}, "properties": {"repobilityId": "e154dc8097157124", "scanner": "scanner-primary", "fingerprint": "e3562e44ca70bba8", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-32bb21bd89d19b04", "level": "note", "message": {"text": "Unused endpoint: POST /contractors/:cid/invoices/auto"}, "properties": {"repobilityId": "511a57081ba0db90", "scanner": "scanner-primary", "fingerprint": "32bb21bd89d19b04", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-16dd2cf278ca8d4f", "level": "note", "message": {"text": "Unused endpoint: PUT /invoices/:id"}, "properties": {"repobilityId": "4cf351fd17a34248", "scanner": "scanner-primary", "fingerprint": "16dd2cf278ca8d4f", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f8e1da8776d9b552", "level": "note", "message": {"text": "Unused endpoint: PATCH /invoices/:id/status"}, "properties": {"repobilityId": "34116b4580ed2175", "scanner": "scanner-primary", "fingerprint": "f8e1da8776d9b552", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-356138f2da46d2c2", "level": "note", "message": {"text": "Unused endpoint: DELETE /invoices/:id"}, "properties": {"repobilityId": "6445286e7cbc5fdd", "scanner": "scanner-primary", "fingerprint": "356138f2da46d2c2", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-22293f41daa8cc95", "level": "note", "message": {"text": "Unused endpoint: GET /invoices/:id/pdf"}, "properties": {"repobilityId": "0858ae6166be4c3c", "scanner": "scanner-primary", "fingerprint": "22293f41daa8cc95", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-261bb727cc9ddfaf", "level": "note", "message": {"text": "Unused endpoint: POST /invoices/:id/send-email"}, "properties": {"repobilityId": "928276338610f95a", "scanner": "scanner-primary", "fingerprint": "261bb727cc9ddfaf", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ff30f4b5b5319e28", "level": "note", "message": {"text": "Unused endpoint: GET /pending-leads"}, "properties": {"repobilityId": "1d401d9ddbcb91cc", "scanner": "scanner-primary", "fingerprint": "ff30f4b5b5319e28", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-205fa0ca983dee40", "level": "note", "message": {"text": "Unused endpoint: GET /jobs/summary"}, "properties": {"repobilityId": "7f41147ba4cea3a6", "scanner": "scanner-primary", "fingerprint": "205fa0ca983dee40", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-1008c575819b3d37", "level": "note", "message": {"text": "Unused endpoint: GET /jobs"}, "properties": {"repobilityId": "af64486ba5eabbdb", "scanner": "scanner-primary", "fingerprint": "1008c575819b3d37", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d2e6e7e9516a29ab", "level": "note", "message": {"text": "Unused endpoint: GET /jobs/:id/audit-trail"}, "properties": {"repobilityId": "3244e57cd6c3ab9e", "scanner": "scanner-primary", "fingerprint": "d2e6e7e9516a29ab", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2b73face5b06aa67", "level": "note", "message": {"text": "Unused endpoint: POST /jobs"}, "properties": {"repobilityId": "ddf721fb3b863154", "scanner": "scanner-primary", "fingerprint": "2b73face5b06aa67", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f4f90d0b79f6524a", "level": "note", "message": {"text": "Unused endpoint: POST /jobs/:id/duplicate"}, "properties": {"repobilityId": "5762d079a647be8e", "scanner": "scanner-primary", "fingerprint": "f4f90d0b79f6524a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-43b45af76bb4dfab", "level": "note", "message": {"text": "Unused endpoint: POST /jobs/:id/activities"}, "properties": {"repobilityId": "c2a7c569f7f27d57", "scanner": "scanner-primary", "fingerprint": "43b45af76bb4dfab", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f3df4d8f18bc7933", "level": "note", "message": {"text": "Unused endpoint: PUT /jobs/:id/activities/:actId"}, "properties": {"repobilityId": "87ac40329d685877", "scanner": "scanner-primary", "fingerprint": "f3df4d8f18bc7933", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a28dfd97a18c0246", "level": "note", "message": {"text": "Unused endpoint: DELETE /jobs/:id/activities/:actId"}, "properties": {"repobilityId": "c11aefecaf5d9d77", "scanner": "scanner-primary", "fingerprint": "a28dfd97a18c0246", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-2bd438c952572458", "level": "note", "message": {"text": "Unused endpoint: POST /import/:leadId"}, "properties": {"repobilityId": "9dec5ad0b76692c3", "scanner": "scanner-primary", "fingerprint": "2bd438c952572458", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-95e13e199903e566", "level": "note", "message": {"text": "Unused endpoint: POST /route-info"}, "properties": {"repobilityId": "df42be1ce98bd586", "scanner": "scanner-primary", "fingerprint": "95e13e199903e566", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d3f9cc6318878777", "level": "note", "message": {"text": "Unused endpoint: POST /jobs/:id/send-survey-email"}, "properties": {"repobilityId": "6979d2a1ea073bb9", "scanner": "scanner-primary", "fingerprint": "d3f9cc6318878777", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e6b90dd318626a82", "level": "note", "message": {"text": "Unused endpoint: GET /jobs/:id/attachments"}, "properties": {"repobilityId": "f3ed3f40dad188f9", "scanner": "scanner-primary", "fingerprint": "e6b90dd318626a82", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-cd7ba4150d0095d7", "level": "note", "message": {"text": "Unused endpoint: POST /jobs/:id/attachments"}, "properties": {"repobilityId": "eb4542476892cea5", "scanner": "scanner-primary", "fingerprint": "cd7ba4150d0095d7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-488302847bfcfbc6", "level": "note", "message": {"text": "Unused endpoint: DELETE /jobs/:id/attachments/:docId"}, "properties": {"repobilityId": "657a6b24def038ff", "scanner": "scanner-primary", "fingerprint": "488302847bfcfbc6", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ac59d5ab24dd78e4", "level": "note", "message": {"text": "Unused endpoint: GET /jobs/:id/attachments/:docId/download"}, "properties": {"repobilityId": "5e76df62a4ccb849", "scanner": "scanner-primary", "fingerprint": "ac59d5ab24dd78e4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-dd29b2de817f5eae", "level": "note", "message": {"text": "Unused endpoint: GET /jobs/:id/survey"}, "properties": {"repobilityId": "38f241cdacc95f2d", "scanner": "scanner-primary", "fingerprint": "dd29b2de817f5eae", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-d84d3c0da3f7f328", "level": "note", "message": {"text": "Unused endpoint: PUT /jobs/:id/survey"}, "properties": {"repobilityId": "c3ee8eb490c48413", "scanner": "scanner-primary", "fingerprint": "d84d3c0da3f7f328", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e7c935c5fee51876", "level": "note", "message": {"text": "Unused endpoint: GET /jobs/:id/quote-state"}, "properties": {"repobilityId": "b8126269e5a81c77", "scanner": "scanner-primary", "fingerprint": "e7c935c5fee51876", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}