{"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-8dbad77e5ed53192", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/clients/page.tsx:83", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/clients/page.tsx:83"}, "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-cf70da0e6816ba31", "name": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/audit/page.tsx:71", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/audit/page.tsx:71"}, "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-7a5669de4d92f5b0", "name": "Stray `console.log` in TS/JS \u2014 prisma/seed-clients.ts:281", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-clients.ts:281"}, "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-48b98bb0dd80a874", "name": "Stray `console.log` in TS/JS \u2014 prisma/seed-services.js:72", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-services.js:72"}, "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-8f1d0543b0382b64", "name": "Stray `console.log` in TS/JS \u2014 prisma/seed-privacy-demo.js:36", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-privacy-demo.js:36"}, "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-e2f044ff6191d91a", "name": "Stray `console.log` in TS/JS \u2014 prisma/seed.ts:20", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed.ts:20"}, "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-aa59a1b7eddbfc78", "name": "Stray `console.log` in TS/JS \u2014 chatbot-mvp/gen-qr.js:12", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 chatbot-mvp/gen-qr.js:12"}, "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-c6353c0b0a7f1eb0", "name": "Stray `console.log` in TS/JS \u2014 chatbot-mvp/index.js:309", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 chatbot-mvp/index.js:309"}, "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-d63da3583b14afc0", "name": "Dockerfile runs as root: Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: Dockerfile"}, "fullDescription": {"text": "No non-root USER set. Containers running as root expand the blast radius of any vulnerability inside the image."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a35c6a00f751880f", "name": "Docker base image is tag-pinned but not digest-pinned: node:20-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-slim"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-d65d5fc2adcee37f", "name": "Dockerfile runs as root: chatbot-mvp/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: chatbot-mvp/Dockerfile"}, "fullDescription": {"text": "No non-root USER set. Containers running as root expand the blast radius of any vulnerability inside the image."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-b9d48bdf8c4711cd", "name": "Docker base image is tag-pinned but not digest-pinned: node:20-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-slim"}, "fullDescription": {"text": "Container tags can be retagged upstream. Pin production base images to a reviewed digest (`image@sha256:...`) when reproducibility and supply-chain integrity matter."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-a399389f5f17b106", "name": "Runtime dotenv file present in repo: frontend/.env.production", "shortDescription": {"text": "Runtime dotenv file present in repo: frontend/.env.production"}, "fullDescription": {"text": "`frontend/.env.production` looks like a runtime dotenv file. No high-confidence secret value was matched, but runtime dotenv files often drift into live credentials. Move real values to a secret manager and keep only `.env.example` style templates in source control."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-61ae6465cbea16c5", "name": "Runtime dotenv file present in repo: frontend/.env.development", "shortDescription": {"text": "Runtime dotenv file present in repo: frontend/.env.development"}, "fullDescription": {"text": "`frontend/.env.development` looks like a runtime dotenv file. No high-confidence secret value was matched, but runtime dotenv files often drift into live credentials. Move real values to a secret manager and keep only `.env.example` style templates in source control."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-e8fe8a85ac5e79f6", "name": "Insecure pattern 'local_storage_auth_token' in frontend/src/lib/auth.ts:14", "shortDescription": {"text": "Insecure pattern 'local_storage_auth_token' in frontend/src/lib/auth.ts:14"}, "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-0441f4b4d2024658", "name": "Possible secret in prisma/seed.ts", "shortDescription": {"text": "Possible secret in prisma/seed.ts"}, "fullDescription": {"text": "Detected pattern matching password_literal. Rotate the credential and move to a secret manager."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "critical", "confidence": 1.0}}, {"id": "scanner-90fcb44d9b461505", "name": "Possible secret in .claude/settings.local.json", "shortDescription": {"text": "Possible secret in .claude/settings.local.json"}, "fullDescription": {"text": "Detected pattern matching password_literal. Rotate the credential and move to a secret manager."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "critical", "confidence": 1.0}}, {"id": "scanner-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "8 test file(s) for 93 source file(s) (ratio 0.09). 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-faccb9061e9b52a0", "name": "No README detected", "shortDescription": {"text": "No README detected"}, "fullDescription": {"text": "No README file was found. Generated repos without README context are hard to operate, validate, or safely hand off."}, "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 31 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-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, operator-readme. Opus verification showed these co-occurring gaps are a better readiness signal than reading each flag in isolation."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-749d4bc1bd66df5f", "name": "Agent instructions exist but release-hardening basics are missing", "shortDescription": {"text": "Agent instructions exist but release-hardening basics are missing"}, "fullDescription": {"text": "AI-coder instruction files were found, but the repo is missing license, ci, operator-readme. Treat this as a contract gap: the agent is guided, but the generated output is not yet guarded by the controls that make it repeatable."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-505bc666a82f9849", "name": "Agent instruction/config may expose a secret: .claude/settings.local.json", "shortDescription": {"text": "Agent instruction/config may expose a secret: .claude/settings.local.json"}, "fullDescription": {"text": "Agent-facing files are routinely pasted into LLM/tool contexts. Move literal tokens, keys, and passwords into a secret manager or document them as placeholders only."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "high", "confidence": 1.0}}, {"id": "scanner-b126142b4c6c7d2d", "name": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/lib/api.ts:14", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/lib/api.ts:14"}, "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-bc2d97c1ed82289e", "name": "Legacy-named symbol `pi_old` in test/payments/payment-failure.spec.ts:95", "shortDescription": {"text": "Legacy-named symbol `pi_old` in test/payments/payment-failure.spec.ts:95"}, "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-022e6399d1ef2beb", "name": "12 env vars used in code but missing from .env.example", "shortDescription": {"text": "12 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `ALLOWED_NUMBERS`, `ANTHROPIC_API_KEY`, `BACKEND_URL`, `BOT_PERSONALITY`, `BUSINESS_NAME`, `CLAUDE_MODEL`, `HISTORY_LENGTH`, `META_ACCESS_TOKEN` + 4 more. 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-b18e1ba85845f571", "name": "Dangling fetch: POST https://graph.facebook.com/v18.0/${this.igBusinessId}/messages (src/modules/instagram/instagram.ser", "shortDescription": {"text": "Dangling fetch: POST https://graph.facebook.com/v18.0/${this.igBusinessId}/messages (src/modules/instagram/instagram.service.ts:116)"}, "fullDescription": {"text": "`src/modules/instagram/instagram.service.ts:116` calls `POST https://graph.facebook.com/v18.0/${this.igBusinessId}/messages` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/graph.facebook.com/v18.0/<p>/messages`\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-a22e4396af9d5790", "name": "Unused endpoint: POST /clients", "shortDescription": {"text": "Unused endpoint: POST /clients"}, "fullDescription": {"text": "`frontend/src/app/clients/new/page.tsx` declares `POST /clients` 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-5f8b73936c2ef8f0", "name": "Unused endpoint: GET /clients/by-phone/:phone", "shortDescription": {"text": "Unused endpoint: GET /clients/by-phone/:phone"}, "fullDescription": {"text": "`src/modules/clients/clients.controller.ts` declares `GET /clients/by-phone/:phone` 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-32ded11042c37436", "name": "Unused endpoint: GET /clients/:id", "shortDescription": {"text": "Unused endpoint: GET /clients/:id"}, "fullDescription": {"text": "`src/modules/clients/clients.controller.ts` declares `GET /clients/: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-661ab4c57cc3e1de", "name": "Unused endpoint: PATCH /clients/:id", "shortDescription": {"text": "Unused endpoint: PATCH /clients/:id"}, "fullDescription": {"text": "`src/modules/clients/clients.controller.ts` declares `PATCH /clients/: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-23d211e64518ed42", "name": "Unused endpoint: POST /whatsapp/webhook", "shortDescription": {"text": "Unused endpoint: POST /whatsapp/webhook"}, "fullDescription": {"text": "`src/modules/whatsapp/whatsapp.controller.ts` declares `POST /whatsapp/webhook` 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-0d06873a1803d9fd", "name": "Unused endpoint: POST /payments/create-intent", "shortDescription": {"text": "Unused endpoint: POST /payments/create-intent"}, "fullDescription": {"text": "`src/modules/payments/payment.controller.ts` declares `POST /payments/create-intent` 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-9eb5e4627d4bea19", "name": "Unused endpoint: POST /payments/checkout-session", "shortDescription": {"text": "Unused endpoint: POST /payments/checkout-session"}, "fullDescription": {"text": "`src/modules/payments/payment.controller.ts` declares `POST /payments/checkout-session` 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-45f5ee016d178666", "name": "Unused endpoint: POST /payments/webhook", "shortDescription": {"text": "Unused endpoint: POST /payments/webhook"}, "fullDescription": {"text": "`src/modules/payments/payment.controller.ts` declares `POST /payments/webhook` 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-ebecd8044aa9807e", "name": "Unused endpoint: GET /payments/mock-pay/:appointmentId", "shortDescription": {"text": "Unused endpoint: GET /payments/mock-pay/:appointmentId"}, "fullDescription": {"text": "`src/modules/payments/payment.controller.ts` declares `GET /payments/mock-pay/:appointmentId` 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-a6c32e5d8c2706e1", "name": "Unused endpoint: GET /payments/success", "shortDescription": {"text": "Unused endpoint: GET /payments/success"}, "fullDescription": {"text": "`src/modules/payments/payment.controller.ts` declares `GET /payments/success` 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-154a7c72fc964d0a", "name": "Unused endpoint: GET /payments/cancel", "shortDescription": {"text": "Unused endpoint: GET /payments/cancel"}, "fullDescription": {"text": "`src/modules/payments/payment.controller.ts` declares `GET /payments/cancel` 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-deadb5c66ef1e09f", "name": "Unused endpoint: GET /payments/:id", "shortDescription": {"text": "Unused endpoint: GET /payments/:id"}, "fullDescription": {"text": "`src/modules/payments/payment.controller.ts` declares `GET /payments/: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-8fdbacfe9430a6ed", "name": "Unused endpoint: POST /auth/login", "shortDescription": {"text": "Unused endpoint: POST /auth/login"}, "fullDescription": {"text": "`src/modules/auth/auth.controller.ts` declares `POST /auth/login` 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-3b2b425616406d33", "name": "Unused endpoint: POST /appointments/book-via-bot", "shortDescription": {"text": "Unused endpoint: POST /appointments/book-via-bot"}, "fullDescription": {"text": "`src/modules/appointments/appointments.controller.ts` declares `POST /appointments/book-via-bot` 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-fba978ed856f1cac", "name": "Unused endpoint: GET /appointments/availability", "shortDescription": {"text": "Unused endpoint: GET /appointments/availability"}, "fullDescription": {"text": "`src/modules/appointments/appointments.controller.ts` declares `GET /appointments/availability` 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-cf77ae784f5b6dce", "name": "Unused endpoint: GET /appointments/:id", "shortDescription": {"text": "Unused endpoint: GET /appointments/:id"}, "fullDescription": {"text": "`src/modules/appointments/appointments.controller.ts` declares `GET /appointments/: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-537fda1c8f5bea0e", "name": "Unused endpoint: PUT /appointments/reschedule", "shortDescription": {"text": "Unused endpoint: PUT /appointments/reschedule"}, "fullDescription": {"text": "`src/modules/appointments/appointments.controller.ts` declares `PUT /appointments/reschedule` 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-5ff2d0ef24cde454", "name": "Unused endpoint: POST /appointments/:id/reschedule", "shortDescription": {"text": "Unused endpoint: POST /appointments/:id/reschedule"}, "fullDescription": {"text": "`src/modules/appointments/appointments.controller.ts` declares `POST /appointments/:id/reschedule` 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-cb509a76796b77fc", "name": "Unused endpoint: POST /appointments/:id/cancel", "shortDescription": {"text": "Unused endpoint: POST /appointments/:id/cancel"}, "fullDescription": {"text": "`src/modules/appointments/appointments.controller.ts` declares `POST /appointments/:id/cancel` 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-978bf549ff527989", "name": "Unused endpoint: DELETE /appointments/:id", "shortDescription": {"text": "Unused endpoint: DELETE /appointments/:id"}, "fullDescription": {"text": "`src/modules/appointments/appointments.controller.ts` declares `DELETE /appointments/: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-e665ff22438e718d", "name": "Unused endpoint: POST /appointments/:id/no-show", "shortDescription": {"text": "Unused endpoint: POST /appointments/:id/no-show"}, "fullDescription": {"text": "`src/modules/appointments/appointments.controller.ts` declares `POST /appointments/:id/no-show` 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-1c09890728e89107", "name": "Unused endpoint: GET /analytics/summary", "shortDescription": {"text": "Unused endpoint: GET /analytics/summary"}, "fullDescription": {"text": "`src/modules/analytics/analytics.controller.ts` declares `GET /analytics/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-938dfbe762957f32", "name": "Unused endpoint: GET /analytics/waitlist-pressure", "shortDescription": {"text": "Unused endpoint: GET /analytics/waitlist-pressure"}, "fullDescription": {"text": "`src/modules/analytics/analytics.controller.ts` declares `GET /analytics/waitlist-pressure` 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-5fda21a55a32c9b4", "name": "Unused endpoint: GET /instagram/webhook", "shortDescription": {"text": "Unused endpoint: GET /instagram/webhook"}, "fullDescription": {"text": "`src/modules/instagram/instagram.controller.ts` declares `GET /instagram/webhook` 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-7b8f0a1fa14a5a8c", "name": "Unused endpoint: POST /instagram/webhook", "shortDescription": {"text": "Unused endpoint: POST /instagram/webhook"}, "fullDescription": {"text": "`src/modules/instagram/instagram.controller.ts` declares `POST /instagram/webhook` 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-4b068a0a4cf60198", "name": "Unused endpoint: GET /services/:id", "shortDescription": {"text": "Unused endpoint: GET /services/:id"}, "fullDescription": {"text": "`src/modules/services/services.controller.ts` declares `GET /services/: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-b2457a302b65417b", "name": "Unused endpoint: PATCH /relationships/:id/confirm", "shortDescription": {"text": "Unused endpoint: PATCH /relationships/:id/confirm"}, "fullDescription": {"text": "`src/modules/relationships/relationships.controller.ts` declares `PATCH /relationships/:id/confirm` 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/23974"}, "properties": {"repository": "aiagency40240157-web/Mystical", "repoUrl": "https://github.com/aiagency40240157-web/Mystical", "branch": "main"}, "results": [{"ruleId": "scanner-8dbad77e5ed53192", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/clients/page.tsx:83"}, "properties": {"repobilityId": "ab9c4e17affc985b", "scanner": "scanner-primary", "fingerprint": "8dbad77e5ed53192", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-cf70da0e6816ba31", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 frontend/src/app/audit/page.tsx:71"}, "properties": {"repobilityId": "9bc65a95f7a7ac5c", "scanner": "scanner-primary", "fingerprint": "cf70da0e6816ba31", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-7a5669de4d92f5b0", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-clients.ts:281"}, "properties": {"repobilityId": "75cbe6b05a870ce5", "scanner": "scanner-primary", "fingerprint": "7a5669de4d92f5b0", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-48b98bb0dd80a874", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-services.js:72"}, "properties": {"repobilityId": "0c40768700a07165", "scanner": "scanner-primary", "fingerprint": "48b98bb0dd80a874", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-8f1d0543b0382b64", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-privacy-demo.js:36"}, "properties": {"repobilityId": "a324bbee46be5101", "scanner": "scanner-primary", "fingerprint": "8f1d0543b0382b64", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-e2f044ff6191d91a", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed.ts:20"}, "properties": {"repobilityId": "f77d7e0fb34b08e2", "scanner": "scanner-primary", "fingerprint": "e2f044ff6191d91a", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-aa59a1b7eddbfc78", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 chatbot-mvp/gen-qr.js:12"}, "properties": {"repobilityId": "5d8e6ce278e6903e", "scanner": "scanner-primary", "fingerprint": "aa59a1b7eddbfc78", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-c6353c0b0a7f1eb0", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 chatbot-mvp/index.js:309"}, "properties": {"repobilityId": "a0c4373397590a2f", "scanner": "scanner-primary", "fingerprint": "c6353c0b0a7f1eb0", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-d63da3583b14afc0", "level": "warning", "message": {"text": "Dockerfile runs as root: Dockerfile"}, "properties": {"repobilityId": "a2ed1bd120e507db", "scanner": "scanner-primary", "fingerprint": "d63da3583b14afc0", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-a35c6a00f751880f", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-slim"}, "properties": {"repobilityId": "cfecaf616d88068b", "scanner": "scanner-primary", "fingerprint": "a35c6a00f751880f", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "Dockerfile"}, "region": {"startLine": 2}}}]}, {"ruleId": "scanner-a35c6a00f751880f", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-slim"}, "properties": {"repobilityId": "4d7d66a444ba19dd", "scanner": "scanner-primary", "fingerprint": "a35c6a00f751880f", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "Dockerfile"}, "region": {"startLine": 14}}}]}, {"ruleId": "scanner-d65d5fc2adcee37f", "level": "warning", "message": {"text": "Dockerfile runs as root: chatbot-mvp/Dockerfile"}, "properties": {"repobilityId": "0055eec8d36e19a0", "scanner": "scanner-primary", "fingerprint": "d65d5fc2adcee37f", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-b9d48bdf8c4711cd", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-slim"}, "properties": {"repobilityId": "5a4e6ea2edcdd6e3", "scanner": "scanner-primary", "fingerprint": "b9d48bdf8c4711cd", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "chatbot-mvp/Dockerfile"}, "region": {"startLine": 2}}}]}, {"ruleId": "scanner-a399389f5f17b106", "level": "error", "message": {"text": "Runtime dotenv file present in repo: frontend/.env.production"}, "properties": {"repobilityId": "f727d22a89e309c5", "scanner": "scanner-primary", "fingerprint": "a399389f5f17b106", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["secrets", "config", "env-file", "runtime-env"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/.env.production"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-61ae6465cbea16c5", "level": "error", "message": {"text": "Runtime dotenv file present in repo: frontend/.env.development"}, "properties": {"repobilityId": "85995dca4d2ac4b9", "scanner": "scanner-primary", "fingerprint": "61ae6465cbea16c5", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["secrets", "config", "env-file", "runtime-env"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/.env.development"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-e8fe8a85ac5e79f6", "level": "warning", "message": {"text": "Insecure pattern 'local_storage_auth_token' in frontend/src/lib/auth.ts:14"}, "properties": {"repobilityId": "fa82456966cc4f76", "scanner": "scanner-primary", "fingerprint": "e8fe8a85ac5e79f6", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "local_storage_auth_token"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "frontend/src/lib/auth.ts"}, "region": {"startLine": 14}}}]}, {"ruleId": "scanner-0441f4b4d2024658", "level": "error", "message": {"text": "Possible secret in prisma/seed.ts"}, "properties": {"repobilityId": "2c940e279f134002", "scanner": "scanner-primary", "fingerprint": "0441f4b4d2024658", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "prisma/seed.ts"}, "region": {"startLine": 8}}}]}, {"ruleId": "scanner-0441f4b4d2024658", "level": "error", "message": {"text": "Possible secret in prisma/seed.ts"}, "properties": {"repobilityId": "2c940e279f134002", "scanner": "scanner-primary", "fingerprint": "0441f4b4d2024658", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "prisma/seed.ts"}, "region": {"startLine": 9}}}]}, {"ruleId": "scanner-0441f4b4d2024658", "level": "error", "message": {"text": "Possible secret in prisma/seed.ts"}, "properties": {"repobilityId": "2c940e279f134002", "scanner": "scanner-primary", "fingerprint": "0441f4b4d2024658", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "prisma/seed.ts"}, "region": {"startLine": 10}}}]}, {"ruleId": "scanner-90fcb44d9b461505", "level": "error", "message": {"text": "Possible secret in .claude/settings.local.json"}, "properties": {"repobilityId": "31609f8f1b78960c", "scanner": "scanner-primary", "fingerprint": "90fcb44d9b461505", "layer": "security", "severity": "critical", "confidence": 1.0, "tags": ["secrets"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".claude/settings.local.json"}, "region": {"startLine": 99}}}]}, {"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": "5b99343ee4d0e0f1", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-faccb9061e9b52a0", "level": "note", "message": {"text": "No README detected"}, "properties": {"repobilityId": "e485d357afe3064b", "scanner": "scanner-primary", "fingerprint": "faccb9061e9b52a0", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["docs", "readme", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-3ab5d313dda8e5f9", "level": "note", "message": {"text": "Debug logging residue appears in source files"}, "properties": {"repobilityId": "7599245bdbc2626d", "scanner": "scanner-primary", "fingerprint": "3ab5d313dda8e5f9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["debug", "cleanup", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-9d79c4077342a7d0", "level": "warning", "message": {"text": "Runtime service client appears to use placeholder configuration"}, "properties": {"repobilityId": "4c83a6f7fdb09cbf", "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": "ce0122bbb23437cd", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-b9088664ace7f748", "level": "warning", "message": {"text": "Composite production-readiness gap"}, "properties": {"repobilityId": "126f8c6659c40b9e", "scanner": "scanner-primary", "fingerprint": "b9088664ace7f748", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["production-readiness", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-749d4bc1bd66df5f", "level": "warning", "message": {"text": "Agent instructions exist but release-hardening basics are missing"}, "properties": {"repobilityId": "16d36872c38f5ee6", "scanner": "scanner-primary", "fingerprint": "749d4bc1bd66df5f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["agent-instructions", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-505bc666a82f9849", "level": "error", "message": {"text": "Agent instruction/config may expose a secret: .claude/settings.local.json"}, "properties": {"repobilityId": "777970b0fce0a93b", "scanner": "scanner-primary", "fingerprint": "505bc666a82f9849", "layer": "security", "severity": "high", "confidence": 1.0, "tags": ["agent-instructions", "secrets", "claude_instruction"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".claude/settings.local.json"}, "region": {"startLine": 48}}}]}, {"ruleId": "scanner-b126142b4c6c7d2d", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 frontend/src/lib/api.ts:14"}, "properties": {"repobilityId": "9c246e42d018a1d5", "scanner": "scanner-primary", "fingerprint": "b126142b4c6c7d2d", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-bc2d97c1ed82289e", "level": "note", "message": {"text": "Legacy-named symbol `pi_old` in test/payments/payment-failure.spec.ts:95"}, "properties": {"repobilityId": "a62d71c421c7d85f", "scanner": "scanner-primary", "fingerprint": "bc2d97c1ed82289e", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "legacy-marker", "dead-code"]}}, {"ruleId": "scanner-022e6399d1ef2beb", "level": "note", "message": {"text": "12 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "7bf4178327da75a2", "scanner": "scanner-primary", "fingerprint": "022e6399d1ef2beb", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-b18e1ba85845f571", "level": "error", "message": {"text": "Dangling fetch: POST https://graph.facebook.com/v18.0/${this.igBusinessId}/messages (src/modules/instagram/instagram.service.ts:116)"}, "properties": {"repobilityId": "1acb82c81465fb48", "scanner": "scanner-primary", "fingerprint": "b18e1ba85845f571", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-a22e4396af9d5790", "level": "note", "message": {"text": "Unused endpoint: POST /clients"}, "properties": {"repobilityId": "7afefa88e53d9ba5", "scanner": "scanner-primary", "fingerprint": "a22e4396af9d5790", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5f8b73936c2ef8f0", "level": "note", "message": {"text": "Unused endpoint: GET /clients/by-phone/:phone"}, "properties": {"repobilityId": "ca9a3bcac7df4b50", "scanner": "scanner-primary", "fingerprint": "5f8b73936c2ef8f0", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-32ded11042c37436", "level": "note", "message": {"text": "Unused endpoint: GET /clients/:id"}, "properties": {"repobilityId": "06f7e4cbb5050780", "scanner": "scanner-primary", "fingerprint": "32ded11042c37436", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-661ab4c57cc3e1de", "level": "note", "message": {"text": "Unused endpoint: PATCH /clients/:id"}, "properties": {"repobilityId": "7664bc458b5f1dc6", "scanner": "scanner-primary", "fingerprint": "661ab4c57cc3e1de", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-23d211e64518ed42", "level": "note", "message": {"text": "Unused endpoint: POST /whatsapp/webhook"}, "properties": {"repobilityId": "82f8da4c68e1e1be", "scanner": "scanner-primary", "fingerprint": "23d211e64518ed42", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-0d06873a1803d9fd", "level": "note", "message": {"text": "Unused endpoint: POST /payments/create-intent"}, "properties": {"repobilityId": "8c8a514ea5c8b297", "scanner": "scanner-primary", "fingerprint": "0d06873a1803d9fd", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9eb5e4627d4bea19", "level": "note", "message": {"text": "Unused endpoint: POST /payments/checkout-session"}, "properties": {"repobilityId": "4a73b09fbbefa57d", "scanner": "scanner-primary", "fingerprint": "9eb5e4627d4bea19", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-45f5ee016d178666", "level": "note", "message": {"text": "Unused endpoint: POST /payments/webhook"}, "properties": {"repobilityId": "aba7f1ef0c733f3e", "scanner": "scanner-primary", "fingerprint": "45f5ee016d178666", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ebecd8044aa9807e", "level": "note", "message": {"text": "Unused endpoint: GET /payments/mock-pay/:appointmentId"}, "properties": {"repobilityId": "ea7b6e6f1ac8f6ab", "scanner": "scanner-primary", "fingerprint": "ebecd8044aa9807e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-a6c32e5d8c2706e1", "level": "note", "message": {"text": "Unused endpoint: GET /payments/success"}, "properties": {"repobilityId": "8a5fe6b3681373ef", "scanner": "scanner-primary", "fingerprint": "a6c32e5d8c2706e1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-154a7c72fc964d0a", "level": "note", "message": {"text": "Unused endpoint: GET /payments/cancel"}, "properties": {"repobilityId": "48b9d5327861f112", "scanner": "scanner-primary", "fingerprint": "154a7c72fc964d0a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-deadb5c66ef1e09f", "level": "note", "message": {"text": "Unused endpoint: GET /payments/:id"}, "properties": {"repobilityId": "d9e9a90fcdcacf0e", "scanner": "scanner-primary", "fingerprint": "deadb5c66ef1e09f", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8fdbacfe9430a6ed", "level": "note", "message": {"text": "Unused endpoint: POST /auth/login"}, "properties": {"repobilityId": "94913fd3493eec92", "scanner": "scanner-primary", "fingerprint": "8fdbacfe9430a6ed", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-3b2b425616406d33", "level": "note", "message": {"text": "Unused endpoint: POST /appointments/book-via-bot"}, "properties": {"repobilityId": "b3e4753aa017e924", "scanner": "scanner-primary", "fingerprint": "3b2b425616406d33", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-fba978ed856f1cac", "level": "note", "message": {"text": "Unused endpoint: GET /appointments/availability"}, "properties": {"repobilityId": "a832f8186f7b1f95", "scanner": "scanner-primary", "fingerprint": "fba978ed856f1cac", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-cf77ae784f5b6dce", "level": "note", "message": {"text": "Unused endpoint: GET /appointments/:id"}, "properties": {"repobilityId": "7f2d4e0192445a42", "scanner": "scanner-primary", "fingerprint": "cf77ae784f5b6dce", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-537fda1c8f5bea0e", "level": "note", "message": {"text": "Unused endpoint: PUT /appointments/reschedule"}, "properties": {"repobilityId": "fe85523bb5e03f67", "scanner": "scanner-primary", "fingerprint": "537fda1c8f5bea0e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5ff2d0ef24cde454", "level": "note", "message": {"text": "Unused endpoint: POST /appointments/:id/reschedule"}, "properties": {"repobilityId": "dd52f417a65495d4", "scanner": "scanner-primary", "fingerprint": "5ff2d0ef24cde454", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-cb509a76796b77fc", "level": "note", "message": {"text": "Unused endpoint: POST /appointments/:id/cancel"}, "properties": {"repobilityId": "c410dd977f369164", "scanner": "scanner-primary", "fingerprint": "cb509a76796b77fc", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-978bf549ff527989", "level": "note", "message": {"text": "Unused endpoint: DELETE /appointments/:id"}, "properties": {"repobilityId": "553c56ad38565cc0", "scanner": "scanner-primary", "fingerprint": "978bf549ff527989", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e665ff22438e718d", "level": "note", "message": {"text": "Unused endpoint: POST /appointments/:id/no-show"}, "properties": {"repobilityId": "1411c213b212235e", "scanner": "scanner-primary", "fingerprint": "e665ff22438e718d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-1c09890728e89107", "level": "note", "message": {"text": "Unused endpoint: GET /analytics/summary"}, "properties": {"repobilityId": "d86a105975ff4af4", "scanner": "scanner-primary", "fingerprint": "1c09890728e89107", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-938dfbe762957f32", "level": "note", "message": {"text": "Unused endpoint: GET /analytics/waitlist-pressure"}, "properties": {"repobilityId": "3ae16dd31614e97d", "scanner": "scanner-primary", "fingerprint": "938dfbe762957f32", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5fda21a55a32c9b4", "level": "note", "message": {"text": "Unused endpoint: GET /instagram/webhook"}, "properties": {"repobilityId": "d84bfbaeafa095e5", "scanner": "scanner-primary", "fingerprint": "5fda21a55a32c9b4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7b8f0a1fa14a5a8c", "level": "note", "message": {"text": "Unused endpoint: POST /instagram/webhook"}, "properties": {"repobilityId": "deb4ac35ebf0118f", "scanner": "scanner-primary", "fingerprint": "7b8f0a1fa14a5a8c", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4b068a0a4cf60198", "level": "note", "message": {"text": "Unused endpoint: GET /services/:id"}, "properties": {"repobilityId": "31e4ae9b598c5012", "scanner": "scanner-primary", "fingerprint": "4b068a0a4cf60198", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-b2457a302b65417b", "level": "note", "message": {"text": "Unused endpoint: PATCH /relationships/:id/confirm"}, "properties": {"repobilityId": "b5458d1ec226df7c", "scanner": "scanner-primary", "fingerprint": "b2457a302b65417b", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}