{"version": "2.1.0", "$schema": "https://json.schemastore.org/sarif-2.1.0.json", "runs": [{"tool": {"driver": {"name": "Repobility", "informationUri": "https://repobility.com", "rules": [{"id": "scanner-bead75b0f9233e05", "name": "No API endpoints detected", "shortDescription": {"text": "No API endpoints detected"}, "fullDescription": {"text": "The scanner did not find FastAPI/Flask/Express/NestJS/GraphQL/gRPC routes. If this repo exposes APIs, the framework may be unsupported."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "info", "confidence": 1.0}}, {"id": "scanner-3696e51c929a1708", "name": "Stray `console.log` in TS/JS \u2014 prisma/grant-plan.ts:55", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/grant-plan.ts:55"}, "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-c0654eb56e3cfac4", "name": "Stray `console.log` in TS/JS \u2014 prisma/add-discovery-source.ts:52", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/add-discovery-source.ts: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-7e55de8afa42d68a", "name": "Stray `console.log` in TS/JS \u2014 prisma/seed-opportunities.ts:25", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-opportunities.ts:25"}, "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-d2b67ab28dd501c8", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/settings/pending-invitations.tsx:94", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/settings/pending-invitations.tsx:94"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-f6b3d79c80496a43", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/settings/members-list.tsx:154", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/settings/members-list.tsx:154"}, "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-1b337a69cfb124a4", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/layout/sidebar.tsx:51", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/layout/sidebar.tsx:51"}, "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-e2642b54d68ea7f4", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/layout/notifications-bell.tsx:145", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/layout/notifications-bell.tsx:145"}, "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-b8a59d4ff72e60ea", "name": "\"active\" state uses light bg in a dark theme \u2014 src/components/layout/sidebar-nav.tsx:48", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/components/layout/sidebar-nav.tsx:48"}, "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-a5e8d49b62eb594d", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/boq/boq-review-screen.tsx:459", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/boq/boq-review-screen.tsx:459"}, "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-40797583b0032d4e", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/marketplace/directory-grid.tsx:88", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/marketplace/directory-grid.tsx:88"}, "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-1ebf73dec7f68c3f", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/marketplace/connections-list.tsx:83", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/marketplace/connections-list.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-0aac7eb223b76cd1", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/analytics/charts.tsx:208", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/analytics/charts.tsx:208"}, "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-01bfe89f499b32a4", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/ui/error-boundary.tsx:69", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/ui/error-boundary.tsx:69"}, "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-a8f8818e4bcbfadd", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/dashboard/recent-tenders.tsx:124", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/dashboard/recent-tenders.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-04c7453a372c746b", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/dashboard/upcoming-deadlines.tsx:67", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/dashboard/upcoming-deadlines.tsx:67"}, "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-89b1d10845449e1a", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/proposals/proposal-editor.tsx:216", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/proposals/proposal-editor.tsx:216"}, "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-f567f22e4c5bedd3", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/proposals/review-bar.tsx:87", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/proposals/review-bar.tsx:87"}, "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-679815c48423b51b", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 src/components/marketing/solution-toolkit.tsx:25", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/components/marketing/solution-toolkit.tsx:25"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2d9f1de2d25f5c83", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/tenders/tenders-list.tsx:141", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/tenders/tenders-list.tsx:141"}, "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-7fb4c677a0c68e69", "name": "\"active\" state uses light bg in a dark theme \u2014 src/components/tenders/tenders-list.tsx:85", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/components/tenders/tenders-list.tsx:85"}, "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-0ee336d1f756db25", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/onboarding/onboarding-wizard.tsx:543", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/onboarding/onboarding-wizard.tsx:543"}, "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-43c7434c52069f6a", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/pipeline/pipeline-board.tsx:138", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/pipeline/pipeline-board.tsx:138"}, "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-f4fd18491294f667", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/discovery/opportunity-card.tsx:55", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/discovery/opportunity-card.tsx:55"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-e3fd4b8aad89e88f", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/proposals/page.tsx:93", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/proposals/page.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-0be6d95eccb6ff0a", "name": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/discover/insights/page.tsx:25", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/discover/insights/page.tsx:25"}, "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-877f7ccc05222a0f", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(dashboard)/tenders/[id]/proposals/[proposalId]/preview/pa", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(dashboard)/tenders/[id]/proposals/[proposalId]/preview/page.tsx:155"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-090468af2dc3f608", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(marketing)/page.tsx:35", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(marketing)/page.tsx:35"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-f4590aeb473c19fe", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(marketing)/blog/page.tsx:34", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(marketing)/blog/page.tsx:34"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-5bce45b4c13f1337", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(marketing)/blog/[slug]/page.tsx:56", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(marketing)/blog/[slug]/page.tsx:56"}, "fullDescription": {"text": "Open XSS surface unless the input is provably trusted. Replace with explicit JSX or sanitize via a vetted library.\n\nWhy: OWASP basics. Already partially flagged by the security analyzer.\nRule id: fq.dangerous-html"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-8ebdbe94317f207c", "name": "Stray `console.log` in TS/JS \u2014 src/lib/ai/agents/extract-requirements.ts:145", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/ai/agents/extract-requirements.ts:145"}, "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-ec9fc0ef8fe9cdb0", "name": "Stray `console.log` in TS/JS \u2014 src/lib/ai/agents/generate-compliance.ts:220", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/ai/agents/generate-compliance.ts:220"}, "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-568210746cb81832", "name": "Stray `console.log` in TS/JS \u2014 src/lib/ai/agents/clarification-questions.ts:174", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/ai/agents/clarification-questions.ts:174"}, "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-eee25e3319543524", "name": "Stray `console.log` in TS/JS \u2014 src/lib/document-processing/pipeline.ts:50", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/document-processing/pipeline.ts: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-6cdc3fa6f331457e", "name": "Stray `console.log` in TS/JS \u2014 src/hooks/use-ai-job.ts:34", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 src/hooks/use-ai-job.ts:34"}, "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-ff2c953357069cb2", "name": "Dockerfile runs as root: deploy/enterprise/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: deploy/enterprise/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-7ea89be1e98a6405", "name": "Docker base image is tag-pinned but not digest-pinned: node:20-bookworm-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-bookworm-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-8295116d1f0eebb0", "name": "Insecure pattern 'dangerous_innerhtml' in src/components/marketing/solution-toolkit.tsx:25", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in src/components/marketing/solution-toolkit.tsx:25"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-4649d7caaec7a18e", "name": "Insecure pattern 'dangerous_innerhtml' in src/app/(dashboard)/tenders/[id]/proposals/[proposalId]/preview/page.tsx:155", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/(dashboard)/tenders/[id]/proposals/[proposalId]/preview/page.tsx:155"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-844cfb7bd2da5ad4", "name": "Insecure pattern 'dangerous_innerhtml' in src/app/(marketing)/page.tsx:35", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/(marketing)/page.tsx:35"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-7676eec286a45c4a", "name": "Insecure pattern 'dangerous_innerhtml' in src/app/(marketing)/blog/page.tsx:34", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/(marketing)/blog/page.tsx:34"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-b917619049505665", "name": "Insecure pattern 'dangerous_innerhtml' in src/app/(marketing)/blog/[slug]/page.tsx:56", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/(marketing)/blog/[slug]/page.tsx:56"}, "fullDescription": {"text": "Found a known-risky pattern (dangerous_innerhtml). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-3c16469d58e3bbd8", "name": "Insecure pattern 'node_child_process' in src/lib/document-processing/extract-scanned-ocr.ts:17", "shortDescription": {"text": "Insecure pattern 'node_child_process' in src/lib/document-processing/extract-scanned-ocr.ts:17"}, "fullDescription": {"text": "Found a known-risky pattern (node_child_process). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-27924aa79fa4a517", "name": "GitHub Action is tag-pinned rather than SHA-pinned", "shortDescription": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "fullDescription": {"text": "actions/checkout@v4 can move without a code change in this repo. Pin third-party actions to a reviewed 40-character commit SHA."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "low", "confidence": 1.0}}, {"id": "scanner-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-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "5 test file(s) for 395 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 32 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 62 placeholder/mock markers across 26 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-ea8f3013f588db25", "name": "Shallow git history limits provenance confidence", "shortDescription": {"text": "Shallow git history limits provenance confidence"}, "fullDescription": {"text": "The repository is a shallow clone. Origin/evolution analysis cannot distinguish fresh generation, imported legacy code, or long-lived human code with high confidence."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8424db9c75e04ba4", "name": "Very short observed git history", "shortDescription": {"text": "Very short observed git history"}, "fullDescription": {"text": "The repo has multiple source files but two or fewer visible commits. This is not a failure by itself, but it lowers confidence in evolution-based diagnosis."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-b8d91a5b0c806863", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/middleware.ts:47", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/middleware.ts:47"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-519acb1d0d83aa75", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/tenders/clarifications-panel.tsx:49", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/tenders/clarifications-panel.tsx:49"}, "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-83cd38ace4dcc22d", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/tenders/bid-decision-card.tsx:83", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/tenders/bid-decision-card.tsx:83"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-93f9680f898e30a5", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/requirements/generate-compliance-button.tsx:40", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/requirements/generate-compliance-button.tsx:40"}, "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-28579c6c18781bb2", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/requirements/extract-requirements-button.tsx:65", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/requirements/extract-requirements-button.tsx:65"}, "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-ef92da45136396ec", "name": "Commented-code block (8 lines) in src/lib/auth.ts:39", "shortDescription": {"text": "Commented-code block (8 lines) in src/lib/auth.ts:39"}, "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-eb5f28a1033fd605", "name": "Commented-code block (11 lines) in src/lib/rate-limit.ts:96", "shortDescription": {"text": "Commented-code block (11 lines) in src/lib/rate-limit.ts:96"}, "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-5215e17da1065275", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/auth/oidc.ts:64", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/auth/oidc.ts:64"}, "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-5605d9e049e61c95", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/ingestion/ocr-provider.ts:113", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/ingestion/ocr-provider.ts:113"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-17ee1b67a5eb43b6", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/document-processing/extract-scanned-ocr.ts:79", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/document-processing/extract-scanned-ocr.ts:79"}, "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-a490ba872709535b", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/hooks/use-ai-job.ts:37", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/hooks/use-ai-job.ts:37"}, "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-24cb5bdfbd32c063", "name": "`fetch()` without try/.catch or AbortSignal \u2014 src/hooks/use-file-upload.ts:160", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/hooks/use-file-upload.ts:160"}, "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-64bc033a45ab26f1", "name": "34 env vars used in code but missing from .env.example", "shortDescription": {"text": "34 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `ANALYTICS_ID_SALT`, `ANALYZE`, `CRON_SECRET`, `DESIGN_PARTNER`, `LLM_API_KEY`, `LLM_BASE_URL`, `LLM_MODEL`, `LOG_LEVEL` + 26 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-2c04133e54348533", "name": "Near-duplicate function bodies in 2 places", "shortDescription": {"text": "Near-duplicate function bodies in 2 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\ntraining/src/train_sft.py:load_cfg, training/src/train_dpo.py:load_cfg\n\nThis is *the* AI-coder failure mode (4\u00d7 more duplication in vibe-coded repos \u2014 see https://jw.hn/ai-code-hygiene). Consolidate or document why they're separate."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/17799"}, "properties": {"repository": "RAMYAL01/tenderos", "repoUrl": "https://github.com/RAMYAL01/tenderos", "branch": "main"}, "results": [{"ruleId": "scanner-bead75b0f9233e05", "level": "none", "message": {"text": "No API endpoints detected"}, "properties": {"repobilityId": "0f8bb852027c38f8", "scanner": "scanner-primary", "fingerprint": "bead75b0f9233e05", "layer": "api", "severity": "info", "confidence": 1.0, "tags": ["coverage"]}}, {"ruleId": "scanner-3696e51c929a1708", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/grant-plan.ts:55"}, "properties": {"repobilityId": "f4e65b3fd4488d34", "scanner": "scanner-primary", "fingerprint": "3696e51c929a1708", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-c0654eb56e3cfac4", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/add-discovery-source.ts:52"}, "properties": {"repobilityId": "08eccb2848d0ef20", "scanner": "scanner-primary", "fingerprint": "c0654eb56e3cfac4", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-7e55de8afa42d68a", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 prisma/seed-opportunities.ts:25"}, "properties": {"repobilityId": "37a4a54e0178218e", "scanner": "scanner-primary", "fingerprint": "7e55de8afa42d68a", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-d2b67ab28dd501c8", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/settings/pending-invitations.tsx:94"}, "properties": {"repobilityId": "15800472e2727742", "scanner": "scanner-primary", "fingerprint": "d2b67ab28dd501c8", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f6b3d79c80496a43", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/settings/members-list.tsx:154"}, "properties": {"repobilityId": "965763a3158e71ff", "scanner": "scanner-primary", "fingerprint": "f6b3d79c80496a43", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1b337a69cfb124a4", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/layout/sidebar.tsx:51"}, "properties": {"repobilityId": "71d53859fbb6eed7", "scanner": "scanner-primary", "fingerprint": "1b337a69cfb124a4", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-e2642b54d68ea7f4", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/layout/notifications-bell.tsx:145"}, "properties": {"repobilityId": "9ca1d5da431d8ae9", "scanner": "scanner-primary", "fingerprint": "e2642b54d68ea7f4", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b8a59d4ff72e60ea", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/components/layout/sidebar-nav.tsx:48"}, "properties": {"repobilityId": "62514235807f52d2", "scanner": "scanner-primary", "fingerprint": "b8a59d4ff72e60ea", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-a5e8d49b62eb594d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/boq/boq-review-screen.tsx:459"}, "properties": {"repobilityId": "af1e2c2f97691ca5", "scanner": "scanner-primary", "fingerprint": "a5e8d49b62eb594d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-40797583b0032d4e", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/marketplace/directory-grid.tsx:88"}, "properties": {"repobilityId": "eb1df049ecf91171", "scanner": "scanner-primary", "fingerprint": "40797583b0032d4e", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1ebf73dec7f68c3f", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/marketplace/connections-list.tsx:83"}, "properties": {"repobilityId": "fa7cbca91e12dfdb", "scanner": "scanner-primary", "fingerprint": "1ebf73dec7f68c3f", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-0aac7eb223b76cd1", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/analytics/charts.tsx:208"}, "properties": {"repobilityId": "69b8bc4772fc4d74", "scanner": "scanner-primary", "fingerprint": "0aac7eb223b76cd1", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-01bfe89f499b32a4", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/ui/error-boundary.tsx:69"}, "properties": {"repobilityId": "11d2a907a9826afc", "scanner": "scanner-primary", "fingerprint": "01bfe89f499b32a4", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a8f8818e4bcbfadd", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/dashboard/recent-tenders.tsx:124"}, "properties": {"repobilityId": "7a77ce3913bc9f80", "scanner": "scanner-primary", "fingerprint": "a8f8818e4bcbfadd", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-04c7453a372c746b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/dashboard/upcoming-deadlines.tsx:67"}, "properties": {"repobilityId": "5194d11b8ca8f21f", "scanner": "scanner-primary", "fingerprint": "04c7453a372c746b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-89b1d10845449e1a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/proposals/proposal-editor.tsx:216"}, "properties": {"repobilityId": "ff805b5fd5a66576", "scanner": "scanner-primary", "fingerprint": "89b1d10845449e1a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f567f22e4c5bedd3", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/proposals/review-bar.tsx:87"}, "properties": {"repobilityId": "cd4928994f09b439", "scanner": "scanner-primary", "fingerprint": "f567f22e4c5bedd3", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-679815c48423b51b", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/components/marketing/solution-toolkit.tsx:25"}, "properties": {"repobilityId": "558eab67b5d7b00c", "scanner": "scanner-primary", "fingerprint": "679815c48423b51b", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-2d9f1de2d25f5c83", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/tenders/tenders-list.tsx:141"}, "properties": {"repobilityId": "5965f820708c3204", "scanner": "scanner-primary", "fingerprint": "2d9f1de2d25f5c83", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-7fb4c677a0c68e69", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/components/tenders/tenders-list.tsx:85"}, "properties": {"repobilityId": "c9e3edcef7dc83a9", "scanner": "scanner-primary", "fingerprint": "7fb4c677a0c68e69", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-0ee336d1f756db25", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/onboarding/onboarding-wizard.tsx:543"}, "properties": {"repobilityId": "ba2706615ab95704", "scanner": "scanner-primary", "fingerprint": "0ee336d1f756db25", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-43c7434c52069f6a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/pipeline/pipeline-board.tsx:138"}, "properties": {"repobilityId": "2dc598741c8497e8", "scanner": "scanner-primary", "fingerprint": "43c7434c52069f6a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f4fd18491294f667", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/discovery/opportunity-card.tsx:55"}, "properties": {"repobilityId": "1c69187f68ccd923", "scanner": "scanner-primary", "fingerprint": "f4fd18491294f667", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-e3fd4b8aad89e88f", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/proposals/page.tsx:93"}, "properties": {"repobilityId": "3fbbdaf98bb3ebbf", "scanner": "scanner-primary", "fingerprint": "e3fd4b8aad89e88f", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-0be6d95eccb6ff0a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/app/(dashboard)/discover/insights/page.tsx:25"}, "properties": {"repobilityId": "5848fefb1b30cbb7", "scanner": "scanner-primary", "fingerprint": "0be6d95eccb6ff0a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-877f7ccc05222a0f", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(dashboard)/tenders/[id]/proposals/[proposalId]/preview/page.tsx:155"}, "properties": {"repobilityId": "c9b857042298723d", "scanner": "scanner-primary", "fingerprint": "877f7ccc05222a0f", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-090468af2dc3f608", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(marketing)/page.tsx:35"}, "properties": {"repobilityId": "3b9b79c882298b6e", "scanner": "scanner-primary", "fingerprint": "090468af2dc3f608", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-f4590aeb473c19fe", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(marketing)/blog/page.tsx:34"}, "properties": {"repobilityId": "2a3d24cb2d0d2611", "scanner": "scanner-primary", "fingerprint": "f4590aeb473c19fe", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-5bce45b4c13f1337", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/app/(marketing)/blog/[slug]/page.tsx:56"}, "properties": {"repobilityId": "722281a87c7c81c5", "scanner": "scanner-primary", "fingerprint": "5bce45b4c13f1337", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-8ebdbe94317f207c", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/ai/agents/extract-requirements.ts:145"}, "properties": {"repobilityId": "c28f6e0a473ef798", "scanner": "scanner-primary", "fingerprint": "8ebdbe94317f207c", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-ec9fc0ef8fe9cdb0", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/ai/agents/generate-compliance.ts:220"}, "properties": {"repobilityId": "8d601cfde0929236", "scanner": "scanner-primary", "fingerprint": "ec9fc0ef8fe9cdb0", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-568210746cb81832", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/ai/agents/clarification-questions.ts:174"}, "properties": {"repobilityId": "ec8116171e2d59a5", "scanner": "scanner-primary", "fingerprint": "568210746cb81832", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-eee25e3319543524", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/document-processing/pipeline.ts:50"}, "properties": {"repobilityId": "56f6af843a56f532", "scanner": "scanner-primary", "fingerprint": "eee25e3319543524", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-6cdc3fa6f331457e", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 src/hooks/use-ai-job.ts:34"}, "properties": {"repobilityId": "a649472b6efd33c8", "scanner": "scanner-primary", "fingerprint": "6cdc3fa6f331457e", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-ff2c953357069cb2", "level": "warning", "message": {"text": "Dockerfile runs as root: deploy/enterprise/Dockerfile"}, "properties": {"repobilityId": "9b6fa5252201dd3e", "scanner": "scanner-primary", "fingerprint": "ff2c953357069cb2", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-7ea89be1e98a6405", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-bookworm-slim"}, "properties": {"repobilityId": "f2d637054420070d", "scanner": "scanner-primary", "fingerprint": "7ea89be1e98a6405", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "deploy/enterprise/Dockerfile"}, "region": {"startLine": 4}}}]}, {"ruleId": "scanner-7ea89be1e98a6405", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-bookworm-slim"}, "properties": {"repobilityId": "b5bbe8f1afba820b", "scanner": "scanner-primary", "fingerprint": "7ea89be1e98a6405", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "deploy/enterprise/Dockerfile"}, "region": {"startLine": 14}}}]}, {"ruleId": "scanner-8295116d1f0eebb0", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in src/components/marketing/solution-toolkit.tsx:25"}, "properties": {"repobilityId": "2079df6a8dcbff88", "scanner": "scanner-primary", "fingerprint": "8295116d1f0eebb0", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/components/marketing/solution-toolkit.tsx"}, "region": {"startLine": 25}}}]}, {"ruleId": "scanner-4649d7caaec7a18e", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/(dashboard)/tenders/[id]/proposals/[proposalId]/preview/page.tsx:155"}, "properties": {"repobilityId": "cbf2182f65beb4cc", "scanner": "scanner-primary", "fingerprint": "4649d7caaec7a18e", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/app/(dashboard)/tenders/[id]/proposals/[proposalId]/preview/page.tsx"}, "region": {"startLine": 155}}}]}, {"ruleId": "scanner-844cfb7bd2da5ad4", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/(marketing)/page.tsx:35"}, "properties": {"repobilityId": "02614b81e7b9928d", "scanner": "scanner-primary", "fingerprint": "844cfb7bd2da5ad4", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/app/(marketing)/page.tsx"}, "region": {"startLine": 35}}}]}, {"ruleId": "scanner-7676eec286a45c4a", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/(marketing)/blog/page.tsx:34"}, "properties": {"repobilityId": "0a0489fdc1278bbc", "scanner": "scanner-primary", "fingerprint": "7676eec286a45c4a", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/app/(marketing)/blog/page.tsx"}, "region": {"startLine": 34}}}]}, {"ruleId": "scanner-b917619049505665", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in src/app/(marketing)/blog/[slug]/page.tsx:56"}, "properties": {"repobilityId": "dbe165bf10374c5b", "scanner": "scanner-primary", "fingerprint": "b917619049505665", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/app/(marketing)/blog/[slug]/page.tsx"}, "region": {"startLine": 56}}}]}, {"ruleId": "scanner-3c16469d58e3bbd8", "level": "warning", "message": {"text": "Insecure pattern 'node_child_process' in src/lib/document-processing/extract-scanned-ocr.ts:17"}, "properties": {"repobilityId": "547ff7852cefbb8f", "scanner": "scanner-primary", "fingerprint": "3c16469d58e3bbd8", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "node_child_process"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/lib/document-processing/extract-scanned-ocr.ts"}, "region": {"startLine": 17}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "ae16880318b99912", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 38}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "989a74409a402368", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 41}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "ae16880318b99912", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 77}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "989a74409a402368", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 80}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "bd7f3c1c34d83159", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 97}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "ae16880318b99912", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 110}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "989a74409a402368", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 113}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "ae16880318b99912", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 133}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "note", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "989a74409a402368", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 136}}}]}, {"ruleId": "scanner-27924aa79fa4a517", "level": "warning", "message": {"text": "GitHub Action is tag-pinned rather than SHA-pinned"}, "properties": {"repobilityId": "d8772e445ad1bf7d", "scanner": "scanner-primary", "fingerprint": "27924aa79fa4a517", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/ci.yml"}, "region": {"startLine": 149}}}]}, {"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-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": "4a02e1d3914b7f96", "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": "84da0ea6d4c75095", "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": "a024a37abe39fefb", "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": "99b52f5de5c2d391", "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": "50308c26fc94dd6f", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-ea8f3013f588db25", "level": "note", "message": {"text": "Shallow git history limits provenance confidence"}, "properties": {"repobilityId": "c440908d30cd5a0a", "scanner": "scanner-primary", "fingerprint": "ea8f3013f588db25", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-8424db9c75e04ba4", "level": "none", "message": {"text": "Very short observed git history"}, "properties": {"repobilityId": "33cbb8a5a837e281", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-b8d91a5b0c806863", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/middleware.ts:47"}, "properties": {"repobilityId": "b98ee006d6a2723d", "scanner": "scanner-primary", "fingerprint": "b8d91a5b0c806863", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-519acb1d0d83aa75", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/tenders/clarifications-panel.tsx:49"}, "properties": {"repobilityId": "08c549f0106980ec", "scanner": "scanner-primary", "fingerprint": "519acb1d0d83aa75", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-83cd38ace4dcc22d", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/tenders/bid-decision-card.tsx:83"}, "properties": {"repobilityId": "541dbbb0e0ab53c8", "scanner": "scanner-primary", "fingerprint": "83cd38ace4dcc22d", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-93f9680f898e30a5", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/requirements/generate-compliance-button.tsx:40"}, "properties": {"repobilityId": "25c1d8437755ef19", "scanner": "scanner-primary", "fingerprint": "93f9680f898e30a5", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-28579c6c18781bb2", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/components/requirements/extract-requirements-button.tsx:65"}, "properties": {"repobilityId": "0c9b25f45b254642", "scanner": "scanner-primary", "fingerprint": "28579c6c18781bb2", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-ef92da45136396ec", "level": "none", "message": {"text": "Commented-code block (8 lines) in src/lib/auth.ts:39"}, "properties": {"repobilityId": "4fa7a06bfbd9a0bf", "scanner": "scanner-primary", "fingerprint": "ef92da45136396ec", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-eb5f28a1033fd605", "level": "none", "message": {"text": "Commented-code block (11 lines) in src/lib/rate-limit.ts:96"}, "properties": {"repobilityId": "ae21cd43f4eeb610", "scanner": "scanner-primary", "fingerprint": "eb5f28a1033fd605", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-5215e17da1065275", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/auth/oidc.ts:64"}, "properties": {"repobilityId": "ca069d9440abdd00", "scanner": "scanner-primary", "fingerprint": "5215e17da1065275", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-5605d9e049e61c95", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/ingestion/ocr-provider.ts:113"}, "properties": {"repobilityId": "dd30ebc255d54c16", "scanner": "scanner-primary", "fingerprint": "5605d9e049e61c95", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-17ee1b67a5eb43b6", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/lib/document-processing/extract-scanned-ocr.ts:79"}, "properties": {"repobilityId": "4e47b837b4df9f56", "scanner": "scanner-primary", "fingerprint": "17ee1b67a5eb43b6", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-a490ba872709535b", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/hooks/use-ai-job.ts:37"}, "properties": {"repobilityId": "dc9f46b68c305fe3", "scanner": "scanner-primary", "fingerprint": "a490ba872709535b", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-24cb5bdfbd32c063", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 src/hooks/use-file-upload.ts:160"}, "properties": {"repobilityId": "78213e8dc8248d16", "scanner": "scanner-primary", "fingerprint": "24cb5bdfbd32c063", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-64bc033a45ab26f1", "level": "note", "message": {"text": "34 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "dab9f6f977f9c414", "scanner": "scanner-primary", "fingerprint": "64bc033a45ab26f1", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "965221155aee6afe", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "b8af245d86950b79", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}]}]}