{"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-f26d201cc80e37b2", "name": "Stray `console.log` in TS/JS \u2014 test_client_profile.js:9", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 test_client_profile.js:9"}, "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-afa793cef626b357", "name": "Stray `console.log` in TS/JS \u2014 src/test/e2e/cashbook.spec.ts:50", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 src/test/e2e/cashbook.spec.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-020820c88c428666", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/DataTable.tsx:258", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/DataTable.tsx:258"}, "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-922c1e209dccd626", "name": "`dangerouslySetInnerHTML` used in a React component \u2014 src/components/PrintLayout.tsx:657", "shortDescription": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/components/PrintLayout.tsx:657"}, "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-09a850d7230264f9", "name": "`truncate` class without `title=` for hover reveal \u2014 src/components/Layout.tsx:339", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/Layout.tsx:339"}, "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-9d3e47364d4e1b6a", "name": "Stray `console.log` in TS/JS \u2014 src/lib/logger.ts:15", "shortDescription": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/logger.ts:15"}, "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-6d4543a58fc8589c", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/inventory/ExpiryPage.tsx:106", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/inventory/ExpiryPage.tsx:106"}, "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-f9f50f787e041dc5", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/OrderDetailPage.tsx:812", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/OrderDetailPage.tsx:812"}, "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-1d3125945cb748c4", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/MobileOrderPage.tsx:483", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/MobileOrderPage.tsx:483"}, "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-b9f532c7cd6dc139", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/POSPage.tsx:1462", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/POSPage.tsx:1462"}, "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-f54cbc11724b8958", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/OrderEditModal.tsx:289", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/OrderEditModal.tsx:289"}, "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-3fee44ed1537362b", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/promotions/PromotionsPage.tsx:430", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/promotions/PromotionsPage.tsx:430"}, "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-4a0996ac09f2f9a3", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/dashboard/DashboardPage.tsx:221", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/dashboard/DashboardPage.tsx:221"}, "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-3e077e3d297029d0", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/goods-receipts/GoodsReceiptFormPage.tsx:1439", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/goods-receipts/GoodsReceiptFormPage.tsx:1439"}, "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-10b3cb18a23f65ca", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdProjectListPage.tsx:165", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdProjectListPage.tsx:165"}, "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-1f62d3900ca039e8", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdsManagePage.tsx:207", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdsManagePage.tsx:207"}, "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-a2d64199024eb16c", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdProjectDetailPage.tsx:1554", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdProjectDetailPage.tsx:1554"}, "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-069f922735c51406", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdMembersSection.tsx:104", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdMembersSection.tsx:104"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-1b404b98cfc5ad46", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerListPage.tsx:230", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerListPage.tsx:230"}, "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-9963c17827bc9563", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerMapPage.tsx:1138", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerMapPage.tsx:1138"}, "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-d7e55d54f4dc9152", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerQuickView.tsx:103", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerQuickView.tsx:103"}, "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-546ed34d453eb9be", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerDetailPage.tsx:1930", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerDetailPage.tsx:1930"}, "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-340585c3aecd2b23", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CollectDebtModal.tsx:78", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CollectDebtModal.tsx:78"}, "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-cdf210da0ce3e160", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/suppliers/SupplierListPage.tsx:341", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/suppliers/SupplierListPage.tsx:341"}, "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-40cda28786a92f94", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/pipeline/PipelinePage.tsx:850", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/pipeline/PipelinePage.tsx:850"}, "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-dd26e2aa83dddf8a", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/cashbook/CashbookReports.tsx:291", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/cashbook/CashbookReports.tsx:291"}, "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-666f5187861108bb", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/cashbook/CashbookOverview.tsx:82", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/cashbook/CashbookOverview.tsx:82"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-da0853bca7d1f796", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/cashbook/CashbookPage.tsx:1267", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/cashbook/CashbookPage.tsx:1267"}, "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-64e40aae58a409bc", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/reports/StrategicProductsReportPage.tsx:249", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/reports/StrategicProductsReportPage.tsx:249"}, "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-524b9e0a46cce909", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/reports/InventoryValuationReportPage.tsx:200", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/reports/InventoryValuationReportPage.tsx:200"}, "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-4e80e55a63a94d5d", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/ProductListPage.tsx:194", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/ProductListPage.tsx:194"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-1a5721d732512697", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/AddProductModal.tsx:798", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/AddProductModal.tsx:798"}, "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-132b4d0a7e12bd6f", "name": "\"active\" state uses light bg in a dark theme \u2014 src/pages/products/AddProductModal.tsx:470", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/pages/products/AddProductModal.tsx:470"}, "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-38474408cae38e7b", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/EditProductModal.tsx:758", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/EditProductModal.tsx:758"}, "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-a83599b0ae4c4c4f", "name": "\"active\" state uses light bg in a dark theme \u2014 src/pages/products/EditProductModal.tsx:435", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/pages/products/EditProductModal.tsx:435"}, "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-d0de97ecd3814567", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/ProductDetailPage.tsx:992", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/ProductDetailPage.tsx:992"}, "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-ba5e2ac8217f0fc1", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/PriceListPage.tsx:358", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/PriceListPage.tsx:358"}, "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-718c3c949b4d2860", "name": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/ProductQuickView.tsx:86", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/ProductQuickView.tsx:86"}, "fullDescription": {"text": "A truncated value should reveal the full text on hover. Pass the full string via `title={...}` so the user can read it.\n\nWhy: P2 in CHECKLIST.md \u2014 truncate without hover-reveal.\nRule id: fq.truncate.no-title"}, "properties": {"scanner": "scanner-primary", "layer": "frontend", "severity": "info", "confidence": 1.0}}, {"id": "scanner-550a976ef6c27c8a", "name": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/ph_n_quy_n_vai_tr_chu_n_h_a_ui/code.ht", "shortDescription": {"text": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/ph_n_quy_n_vai_tr_chu_n_h_a_ui/code.html:340"}, "fullDescription": {"text": "Found a known-risky pattern (direct_innerhtml_assignment). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-f804102e8059cbe2", "name": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/i_so_t_ch_t_ca_l_m_vi_c/code.html:388", "shortDescription": {"text": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/i_so_t_ch_t_ca_l_m_vi_c/code.html:388"}, "fullDescription": {"text": "Found a known-risky pattern (direct_innerhtml_assignment). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-e8b456471f277ceb", "name": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/qu_n_l_b_ng_gi/code.html:600", "shortDescription": {"text": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/qu_n_l_b_ng_gi/code.html:600"}, "fullDescription": {"text": "Found a known-risky pattern (direct_innerhtml_assignment). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-5236cb6ea9094d40", "name": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/ph_n_quy_n_vai_tr/code.html:460", "shortDescription": {"text": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/ph_n_quy_n_vai_tr/code.html:460"}, "fullDescription": {"text": "Found a known-risky pattern (direct_innerhtml_assignment). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-9c371ff15082a705", "name": "Insecure pattern 'dangerous_innerhtml' in playwright-report/index.html:58", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in playwright-report/index.html:58"}, "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-9029cfde635dd36d", "name": "Insecure pattern 'direct_innerhtml_assignment' in playwright-report/index.html:57", "shortDescription": {"text": "Insecure pattern 'direct_innerhtml_assignment' in playwright-report/index.html:57"}, "fullDescription": {"text": "Found a known-risky pattern (direct_innerhtml_assignment). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-d08faa886fee4992", "name": "Insecure pattern 'dangerous_innerhtml' in src/components/PrintLayout.tsx:657", "shortDescription": {"text": "Insecure pattern 'dangerous_innerhtml' in src/components/PrintLayout.tsx:657"}, "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-1c32c299c69c52a9", "name": "Very large file: src/pages/inventory/InventoryPage.tsx (3066 lines)", "shortDescription": {"text": "Very large file: src/pages/inventory/InventoryPage.tsx (3066 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-21fc15031d62e22a", "name": "Very large file: src/pages/orders/OrderDetailPage.tsx (1329 lines)", "shortDescription": {"text": "Very large file: src/pages/orders/OrderDetailPage.tsx (1329 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-668e72370968beb0", "name": "Very large file: src/pages/orders/POSPage.tsx (2741 lines)", "shortDescription": {"text": "Very large file: src/pages/orders/POSPage.tsx (2741 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-b965b630f63efa79", "name": "Very large file: src/pages/goods-receipts/GoodsReceiptFormPage.tsx (1766 lines)", "shortDescription": {"text": "Very large file: src/pages/goods-receipts/GoodsReceiptFormPage.tsx (1766 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-473b85068982a423", "name": "Very large file: src/pages/herd-projects/HerdProjectDetailPage.tsx (2685 lines)", "shortDescription": {"text": "Very large file: src/pages/herd-projects/HerdProjectDetailPage.tsx (2685 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-219b47804ba989e6", "name": "Very large file: src/pages/customers/CustomerMapPage.tsx (1489 lines)", "shortDescription": {"text": "Very large file: src/pages/customers/CustomerMapPage.tsx (1489 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-18fbd808f3c7e73e", "name": "Very large file: src/pages/customers/CustomerDetailPage.tsx (3962 lines)", "shortDescription": {"text": "Very large file: src/pages/customers/CustomerDetailPage.tsx (3962 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-cdaef361f6558eb1", "name": "Very large file: src/pages/system/DisplaySettingsTab.tsx (996 lines)", "shortDescription": {"text": "Very large file: src/pages/system/DisplaySettingsTab.tsx (996 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-81273de155b2e6fa", "name": "Very large file: src/pages/system/SystemSettingsPage.tsx (2356 lines)", "shortDescription": {"text": "Very large file: src/pages/system/SystemSettingsPage.tsx (2356 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-af9552180f64b985", "name": "Very large file: src/pages/pipeline/PipelinePage.tsx (1519 lines)", "shortDescription": {"text": "Very large file: src/pages/pipeline/PipelinePage.tsx (1519 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-c035d890094a1059", "name": "Very large file: src/pages/cashbook/CashbookPage.tsx (2738 lines)", "shortDescription": {"text": "Very large file: src/pages/cashbook/CashbookPage.tsx (2738 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-b7ec39e0e86d1158", "name": "Very large file: src/pages/reports/StrategicProductsReportPage.tsx (946 lines)", "shortDescription": {"text": "Very large file: src/pages/reports/StrategicProductsReportPage.tsx (946 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f9a62a4ce07fbf3b", "name": "Very large file: src/pages/products/ActiveIngredientsPage.tsx (1573 lines)", "shortDescription": {"text": "Very large file: src/pages/products/ActiveIngredientsPage.tsx (1573 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-abd8e7a27fbaebab", "name": "Very large file: src/pages/products/ProductDetailPage.tsx (1061 lines)", "shortDescription": {"text": "Very large file: src/pages/products/ProductDetailPage.tsx (1061 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-708e80442810c054", "name": "Very large file: src/pages/products/DiseasesPage.tsx (1689 lines)", "shortDescription": {"text": "Very large file: src/pages/products/DiseasesPage.tsx (1689 lines)"}, "fullDescription": {"text": "Files with >800 lines often hide complexity hotspots and discourage tests."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ea3b5e389d8c9c0f", "name": "Low test-to-source ratio", "shortDescription": {"text": "Low test-to-source ratio"}, "fullDescription": {"text": "17 tests / 111 src (ratio 0.15)."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "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-72b2a6250083a784", "name": "Placeholder or mock-heavy implementation detected", "shortDescription": {"text": "Placeholder or mock-heavy implementation detected"}, "fullDescription": {"text": "Found 351 placeholder/mock markers across 50 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-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. Treat this as a contract gap: the agent is guided, but the generated output is not yet guarded by the controls that make it repeatable."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-ea8f3013f588db25", "name": "Shallow git history limits provenance confidence", "shortDescription": {"text": "Shallow git history limits provenance confidence"}, "fullDescription": {"text": "The repository is a shallow clone. Origin/evolution analysis cannot distinguish fresh generation, imported legacy code, or long-lived human code with high confidence."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8424db9c75e04ba4", "name": "Very short observed git history", "shortDescription": {"text": "Very short observed git history"}, "fullDescription": {"text": "The repo has multiple source files but two or fewer visible commits. This is not a failure by itself, but it lowers confidence in evolution-based diagnosis."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-8c1803f23ad8cbca", "name": "Commented-code block (9 lines) in tailwind.config.js:43", "shortDescription": {"text": "Commented-code block (9 lines) in tailwind.config.js:43"}, "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-6f938c411f20d3d1", "name": "Commented-code block (6 lines) in src/App.tsx:11", "shortDescription": {"text": "Commented-code block (6 lines) in src/App.tsx:11"}, "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-1e3bd5e54e1839ca", "name": "Commented-code block (6 lines) in src/components/Skeleton.tsx:3", "shortDescription": {"text": "Commented-code block (6 lines) in src/components/Skeleton.tsx:3"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-049fd9300f5a75b1", "name": "Commented-code block (5 lines) in src/lib/posDraftStorage.ts:5", "shortDescription": {"text": "Commented-code block (5 lines) in src/lib/posDraftStorage.ts:5"}, "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-98121bc008b32b4a", "name": "Commented-code block (8 lines) in src/lib/queryClient.ts:3", "shortDescription": {"text": "Commented-code block (8 lines) in src/lib/queryClient.ts:3"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-b6b743aa463a72fa", "name": "Commented-code block (5 lines) in src/lib/lunarDate.ts:1", "shortDescription": {"text": "Commented-code block (5 lines) in src/lib/lunarDate.ts:1"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-fcaab80304e68440", "name": "Commented-code block (6 lines) in src/lib/exporters/documentPdf.tsx:4", "shortDescription": {"text": "Commented-code block (6 lines) in src/lib/exporters/documentPdf.tsx:4"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-858a8893ab7fbd39", "name": "Commented-code block (6 lines) in src/lib/exporters/documentXlsx.ts:3", "shortDescription": {"text": "Commented-code block (6 lines) in src/lib/exporters/documentXlsx.ts:3"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-918319c72870e27b", "name": "Commented-code block (6 lines) in src/pages/reports/StrategicProductsReportPage.tsx:33", "shortDescription": {"text": "Commented-code block (6 lines) in src/pages/reports/StrategicProductsReportPage.tsx:33"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-3f5304c5c762fa3c", "name": "Commented-code block (8 lines) in src/hooks/queries/useStrategicProducts.ts:6", "shortDescription": {"text": "Commented-code block (8 lines) in src/hooks/queries/useStrategicProducts.ts:6"}, "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-7d7e838e2a61e8d7", "name": "Commented-code block (6 lines) in src/hooks/queries/useCustomers.ts:54", "shortDescription": {"text": "Commented-code block (6 lines) in src/hooks/queries/useCustomers.ts:54"}, "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-82c97def35671596", "name": "Commented-code block (5 lines) in src/hooks/queries/useInventoryValuation.ts:6", "shortDescription": {"text": "Commented-code block (5 lines) in src/hooks/queries/useInventoryValuation.ts:6"}, "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-250f57e8a1dbd3c5", "name": "4 env vars used in code but missing from .env.example", "shortDescription": {"text": "4 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `CI`, `E2E_ADMIN_EMAIL`, `E2E_ADMIN_PASSWORD`, `PLAYWRIGHT_BASE_URL`. Add them (with a placeholder/comment) to .env.example so onboarding doesn't break."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-cb07a36b9b4572a8", "name": "Frontend route `/auth/callback` has no Link/navigate to it \u2014 src/App.tsx", "shortDescription": {"text": "Frontend route `/auth/callback` has no Link/navigate to it \u2014 src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-3481e66bf3b8afd3", "name": "Frontend route `/customers/:id` has no Link/navigate to it \u2014 src/App.tsx", "shortDescription": {"text": "Frontend route `/customers/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-3ac147fb291ca389", "name": "Frontend route `/products/:id` has no Link/navigate to it \u2014 src/App.tsx", "shortDescription": {"text": "Frontend route `/products/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-e306fca6a9a1d98d", "name": "Frontend route `/suppliers/:id` has no Link/navigate to it \u2014 src/App.tsx", "shortDescription": {"text": "Frontend route `/suppliers/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-9816085fd6262343", "name": "Frontend route `/goods-receipts/:id` has no Link/navigate to it \u2014 src/App.tsx", "shortDescription": {"text": "Frontend route `/goods-receipts/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-9b449976a3f733c3", "name": "Frontend route `/orders/:id` has no Link/navigate to it \u2014 src/App.tsx", "shortDescription": {"text": "Frontend route `/orders/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-1654c1b654fe5c2e", "name": "Frontend route `/herd-projects/:id` has no Link/navigate to it \u2014 src/App.tsx", "shortDescription": {"text": "Frontend route `/herd-projects/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a559691cd127132e", "name": "Frontend route `/print-preview` has no Link/navigate to it \u2014 src/App.tsx", "shortDescription": {"text": "Frontend route `/print-preview` has no Link/navigate to it \u2014 src/App.tsx"}, "fullDescription": {"text": "The route is registered but no `<Link to=\u2026>` or `navigate(\u2026)` in the codebase navigates here. Either it's reachable only via direct URL (intentional), it's dead, or the link broke during a refactor."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/21138"}, "properties": {"repository": "thephuong8xvn-lang/CRMSANHLONG", "repoUrl": "https://github.com/thephuong8xvn-lang/CRMSANHLONG", "branch": "main"}, "results": [{"ruleId": "scanner-f26d201cc80e37b2", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 test_client_profile.js:9"}, "properties": {"repobilityId": "ad14aa06b480b2c6", "scanner": "scanner-primary", "fingerprint": "f26d201cc80e37b2", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-afa793cef626b357", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 src/test/e2e/cashbook.spec.ts:50"}, "properties": {"repobilityId": "9f3cfe83548c42e1", "scanner": "scanner-primary", "fingerprint": "afa793cef626b357", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-020820c88c428666", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/DataTable.tsx:258"}, "properties": {"repobilityId": "a3c45b1f00369da1", "scanner": "scanner-primary", "fingerprint": "020820c88c428666", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-922c1e209dccd626", "level": "warning", "message": {"text": "`dangerouslySetInnerHTML` used in a React component \u2014 src/components/PrintLayout.tsx:657"}, "properties": {"repobilityId": "31d42e6a3e32c200", "scanner": "scanner-primary", "fingerprint": "922c1e209dccd626", "layer": "frontend", "severity": "medium", "confidence": 1.0, "tags": ["frontend-quality", "fq.dangerous-html"]}}, {"ruleId": "scanner-09a850d7230264f9", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/components/Layout.tsx:339"}, "properties": {"repobilityId": "daab328f104c4d01", "scanner": "scanner-primary", "fingerprint": "09a850d7230264f9", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-9d3e47364d4e1b6a", "level": "note", "message": {"text": "Stray `console.log` in TS/JS \u2014 src/lib/logger.ts:15"}, "properties": {"repobilityId": "d91dbb6e420e1181", "scanner": "scanner-primary", "fingerprint": "9d3e47364d4e1b6a", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.console-leak"]}}, {"ruleId": "scanner-6d4543a58fc8589c", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/inventory/ExpiryPage.tsx:106"}, "properties": {"repobilityId": "714cec741da5e0b6", "scanner": "scanner-primary", "fingerprint": "6d4543a58fc8589c", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f9f50f787e041dc5", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/OrderDetailPage.tsx:812"}, "properties": {"repobilityId": "3110c0aed1eb05a8", "scanner": "scanner-primary", "fingerprint": "f9f50f787e041dc5", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1d3125945cb748c4", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/MobileOrderPage.tsx:483"}, "properties": {"repobilityId": "46f1c813c59e679e", "scanner": "scanner-primary", "fingerprint": "1d3125945cb748c4", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-b9f532c7cd6dc139", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/POSPage.tsx:1462"}, "properties": {"repobilityId": "9bd4be0931e97817", "scanner": "scanner-primary", "fingerprint": "b9f532c7cd6dc139", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f54cbc11724b8958", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/orders/OrderEditModal.tsx:289"}, "properties": {"repobilityId": "98de4a889b9464da", "scanner": "scanner-primary", "fingerprint": "f54cbc11724b8958", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-3fee44ed1537362b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/promotions/PromotionsPage.tsx:430"}, "properties": {"repobilityId": "9a104fc7063fea7a", "scanner": "scanner-primary", "fingerprint": "3fee44ed1537362b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4a0996ac09f2f9a3", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/dashboard/DashboardPage.tsx:221"}, "properties": {"repobilityId": "5ca39a7136beaa46", "scanner": "scanner-primary", "fingerprint": "4a0996ac09f2f9a3", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-3e077e3d297029d0", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/goods-receipts/GoodsReceiptFormPage.tsx:1439"}, "properties": {"repobilityId": "9a77366c775232c0", "scanner": "scanner-primary", "fingerprint": "3e077e3d297029d0", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-10b3cb18a23f65ca", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdProjectListPage.tsx:165"}, "properties": {"repobilityId": "3d7a85dcbb50e526", "scanner": "scanner-primary", "fingerprint": "10b3cb18a23f65ca", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1f62d3900ca039e8", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdsManagePage.tsx:207"}, "properties": {"repobilityId": "882ee76ed92f93f0", "scanner": "scanner-primary", "fingerprint": "1f62d3900ca039e8", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a2d64199024eb16c", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdProjectDetailPage.tsx:1554"}, "properties": {"repobilityId": "c15f40f3c8f67e26", "scanner": "scanner-primary", "fingerprint": "a2d64199024eb16c", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-069f922735c51406", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/herd-projects/HerdMembersSection.tsx:104"}, "properties": {"repobilityId": "f86d7bbd80eaa3f4", "scanner": "scanner-primary", "fingerprint": "069f922735c51406", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1b404b98cfc5ad46", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerListPage.tsx:230"}, "properties": {"repobilityId": "ff5bc65f089854e2", "scanner": "scanner-primary", "fingerprint": "1b404b98cfc5ad46", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-9963c17827bc9563", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerMapPage.tsx:1138"}, "properties": {"repobilityId": "d8f73950a8530fbe", "scanner": "scanner-primary", "fingerprint": "9963c17827bc9563", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-d7e55d54f4dc9152", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerQuickView.tsx:103"}, "properties": {"repobilityId": "c110514406d9c2e4", "scanner": "scanner-primary", "fingerprint": "d7e55d54f4dc9152", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-546ed34d453eb9be", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CustomerDetailPage.tsx:1930"}, "properties": {"repobilityId": "a0d41583e0f5de63", "scanner": "scanner-primary", "fingerprint": "546ed34d453eb9be", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-340585c3aecd2b23", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/customers/CollectDebtModal.tsx:78"}, "properties": {"repobilityId": "75a68ada01ce3ef7", "scanner": "scanner-primary", "fingerprint": "340585c3aecd2b23", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-cdf210da0ce3e160", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/suppliers/SupplierListPage.tsx:341"}, "properties": {"repobilityId": "ec401c59dfa11426", "scanner": "scanner-primary", "fingerprint": "cdf210da0ce3e160", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-40cda28786a92f94", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/pipeline/PipelinePage.tsx:850"}, "properties": {"repobilityId": "4d0d08a43eb94652", "scanner": "scanner-primary", "fingerprint": "40cda28786a92f94", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-dd26e2aa83dddf8a", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/cashbook/CashbookReports.tsx:291"}, "properties": {"repobilityId": "aed927e2155b8749", "scanner": "scanner-primary", "fingerprint": "dd26e2aa83dddf8a", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-666f5187861108bb", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/cashbook/CashbookOverview.tsx:82"}, "properties": {"repobilityId": "6832e64586629ff5", "scanner": "scanner-primary", "fingerprint": "666f5187861108bb", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-da0853bca7d1f796", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/cashbook/CashbookPage.tsx:1267"}, "properties": {"repobilityId": "17f53088dbcf986b", "scanner": "scanner-primary", "fingerprint": "da0853bca7d1f796", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-64e40aae58a409bc", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/reports/StrategicProductsReportPage.tsx:249"}, "properties": {"repobilityId": "7e906ac0c63bdf2a", "scanner": "scanner-primary", "fingerprint": "64e40aae58a409bc", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-524b9e0a46cce909", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/reports/InventoryValuationReportPage.tsx:200"}, "properties": {"repobilityId": "0d6979e179105706", "scanner": "scanner-primary", "fingerprint": "524b9e0a46cce909", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-4e80e55a63a94d5d", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/ProductListPage.tsx:194"}, "properties": {"repobilityId": "9ed743b82dba2e61", "scanner": "scanner-primary", "fingerprint": "4e80e55a63a94d5d", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-1a5721d732512697", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/AddProductModal.tsx:798"}, "properties": {"repobilityId": "f57bc08a8f995e65", "scanner": "scanner-primary", "fingerprint": "1a5721d732512697", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-132b4d0a7e12bd6f", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/pages/products/AddProductModal.tsx:470"}, "properties": {"repobilityId": "65bf77430d60c440", "scanner": "scanner-primary", "fingerprint": "132b4d0a7e12bd6f", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-38474408cae38e7b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/EditProductModal.tsx:758"}, "properties": {"repobilityId": "fdb249fc15409e26", "scanner": "scanner-primary", "fingerprint": "38474408cae38e7b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a83599b0ae4c4c4f", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 src/pages/products/EditProductModal.tsx:435"}, "properties": {"repobilityId": "4c3dabac4063ca7a", "scanner": "scanner-primary", "fingerprint": "a83599b0ae4c4c4f", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-d0de97ecd3814567", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/ProductDetailPage.tsx:992"}, "properties": {"repobilityId": "814cad0ee1de8ee5", "scanner": "scanner-primary", "fingerprint": "d0de97ecd3814567", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-ba5e2ac8217f0fc1", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/PriceListPage.tsx:358"}, "properties": {"repobilityId": "874896d29d89bb97", "scanner": "scanner-primary", "fingerprint": "ba5e2ac8217f0fc1", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-718c3c949b4d2860", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 src/pages/products/ProductQuickView.tsx:86"}, "properties": {"repobilityId": "92a0687eb52b04c3", "scanner": "scanner-primary", "fingerprint": "718c3c949b4d2860", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-550a976ef6c27c8a", "level": "warning", "message": {"text": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/ph_n_quy_n_vai_tr_chu_n_h_a_ui/code.html:340"}, "properties": {"repobilityId": "9543a54ead77ac2e", "scanner": "scanner-primary", "fingerprint": "550a976ef6c27c8a", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "direct_innerhtml_assignment"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "stitch_h_th_ng_qu_n_l_t_i_ch_nh/ph_n_quy_n_vai_tr_chu_n_h_a_ui/code.html"}, "region": {"startLine": 340}}}]}, {"ruleId": "scanner-f804102e8059cbe2", "level": "warning", "message": {"text": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/i_so_t_ch_t_ca_l_m_vi_c/code.html:388"}, "properties": {"repobilityId": "56f25abb731b1e9a", "scanner": "scanner-primary", "fingerprint": "f804102e8059cbe2", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "direct_innerhtml_assignment"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "stitch_h_th_ng_qu_n_l_t_i_ch_nh/i_so_t_ch_t_ca_l_m_vi_c/code.html"}, "region": {"startLine": 388}}}]}, {"ruleId": "scanner-e8b456471f277ceb", "level": "warning", "message": {"text": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/qu_n_l_b_ng_gi/code.html:600"}, "properties": {"repobilityId": "fce1cd48bc1c42a1", "scanner": "scanner-primary", "fingerprint": "e8b456471f277ceb", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "direct_innerhtml_assignment"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "stitch_h_th_ng_qu_n_l_t_i_ch_nh/qu_n_l_b_ng_gi/code.html"}, "region": {"startLine": 600}}}]}, {"ruleId": "scanner-5236cb6ea9094d40", "level": "warning", "message": {"text": "Insecure pattern 'direct_innerhtml_assignment' in stitch_h_th_ng_qu_n_l_t_i_ch_nh/ph_n_quy_n_vai_tr/code.html:460"}, "properties": {"repobilityId": "66f46e50ebc9fa2d", "scanner": "scanner-primary", "fingerprint": "5236cb6ea9094d40", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "direct_innerhtml_assignment"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "stitch_h_th_ng_qu_n_l_t_i_ch_nh/ph_n_quy_n_vai_tr/code.html"}, "region": {"startLine": 460}}}]}, {"ruleId": "scanner-9c371ff15082a705", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in playwright-report/index.html:58"}, "properties": {"repobilityId": "5c1a4d4daf334529", "scanner": "scanner-primary", "fingerprint": "9c371ff15082a705", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "playwright-report/index.html"}, "region": {"startLine": 58}}}]}, {"ruleId": "scanner-9029cfde635dd36d", "level": "warning", "message": {"text": "Insecure pattern 'direct_innerhtml_assignment' in playwright-report/index.html:57"}, "properties": {"repobilityId": "72bf5b0e0e2b9155", "scanner": "scanner-primary", "fingerprint": "9029cfde635dd36d", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "direct_innerhtml_assignment"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "playwright-report/index.html"}, "region": {"startLine": 57}}}]}, {"ruleId": "scanner-d08faa886fee4992", "level": "warning", "message": {"text": "Insecure pattern 'dangerous_innerhtml' in src/components/PrintLayout.tsx:657"}, "properties": {"repobilityId": "1a0a80b1094400be", "scanner": "scanner-primary", "fingerprint": "d08faa886fee4992", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "dangerous_innerhtml"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "src/components/PrintLayout.tsx"}, "region": {"startLine": 657}}}]}, {"ruleId": "scanner-1c32c299c69c52a9", "level": "note", "message": {"text": "Very large file: src/pages/inventory/InventoryPage.tsx (3066 lines)"}, "properties": {"repobilityId": "90df805e574b1f40", "scanner": "scanner-primary", "fingerprint": "1c32c299c69c52a9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-21fc15031d62e22a", "level": "note", "message": {"text": "Very large file: src/pages/orders/OrderDetailPage.tsx (1329 lines)"}, "properties": {"repobilityId": "e08ae85129c42d95", "scanner": "scanner-primary", "fingerprint": "21fc15031d62e22a", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-668e72370968beb0", "level": "note", "message": {"text": "Very large file: src/pages/orders/POSPage.tsx (2741 lines)"}, "properties": {"repobilityId": "7b34b7a6b6312847", "scanner": "scanner-primary", "fingerprint": "668e72370968beb0", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-b965b630f63efa79", "level": "note", "message": {"text": "Very large file: src/pages/goods-receipts/GoodsReceiptFormPage.tsx (1766 lines)"}, "properties": {"repobilityId": "973c773218dff235", "scanner": "scanner-primary", "fingerprint": "b965b630f63efa79", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-473b85068982a423", "level": "note", "message": {"text": "Very large file: src/pages/herd-projects/HerdProjectDetailPage.tsx (2685 lines)"}, "properties": {"repobilityId": "23a595935eef4a91", "scanner": "scanner-primary", "fingerprint": "473b85068982a423", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-219b47804ba989e6", "level": "note", "message": {"text": "Very large file: src/pages/customers/CustomerMapPage.tsx (1489 lines)"}, "properties": {"repobilityId": "6c30c7a7e6bcfade", "scanner": "scanner-primary", "fingerprint": "219b47804ba989e6", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-18fbd808f3c7e73e", "level": "note", "message": {"text": "Very large file: src/pages/customers/CustomerDetailPage.tsx (3962 lines)"}, "properties": {"repobilityId": "1dc6e0b87ad084cc", "scanner": "scanner-primary", "fingerprint": "18fbd808f3c7e73e", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-cdaef361f6558eb1", "level": "note", "message": {"text": "Very large file: src/pages/system/DisplaySettingsTab.tsx (996 lines)"}, "properties": {"repobilityId": "5a23765ff7d74c54", "scanner": "scanner-primary", "fingerprint": "cdaef361f6558eb1", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-81273de155b2e6fa", "level": "note", "message": {"text": "Very large file: src/pages/system/SystemSettingsPage.tsx (2356 lines)"}, "properties": {"repobilityId": "4ffc609c0112d148", "scanner": "scanner-primary", "fingerprint": "81273de155b2e6fa", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-af9552180f64b985", "level": "note", "message": {"text": "Very large file: src/pages/pipeline/PipelinePage.tsx (1519 lines)"}, "properties": {"repobilityId": "de12c3db71930797", "scanner": "scanner-primary", "fingerprint": "af9552180f64b985", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-c035d890094a1059", "level": "note", "message": {"text": "Very large file: src/pages/cashbook/CashbookPage.tsx (2738 lines)"}, "properties": {"repobilityId": "36d282ed72e96309", "scanner": "scanner-primary", "fingerprint": "c035d890094a1059", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-b7ec39e0e86d1158", "level": "note", "message": {"text": "Very large file: src/pages/reports/StrategicProductsReportPage.tsx (946 lines)"}, "properties": {"repobilityId": "5a9f1d1ca5675d31", "scanner": "scanner-primary", "fingerprint": "b7ec39e0e86d1158", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-f9a62a4ce07fbf3b", "level": "note", "message": {"text": "Very large file: src/pages/products/ActiveIngredientsPage.tsx (1573 lines)"}, "properties": {"repobilityId": "05b39c6f8e2be878", "scanner": "scanner-primary", "fingerprint": "f9a62a4ce07fbf3b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-abd8e7a27fbaebab", "level": "note", "message": {"text": "Very large file: src/pages/products/ProductDetailPage.tsx (1061 lines)"}, "properties": {"repobilityId": "2d8863fdfc2644d3", "scanner": "scanner-primary", "fingerprint": "abd8e7a27fbaebab", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-708e80442810c054", "level": "note", "message": {"text": "Very large file: src/pages/products/DiseasesPage.tsx (1689 lines)"}, "properties": {"repobilityId": "caadc517a802437c", "scanner": "scanner-primary", "fingerprint": "708e80442810c054", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["complexity"]}}, {"ruleId": "scanner-ea3b5e389d8c9c0f", "level": "note", "message": {"text": "Low test-to-source ratio"}, "properties": {"repobilityId": "ef7b2552cc00a375", "scanner": "scanner-primary", "fingerprint": "ea3b5e389d8c9c0f", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["tests"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "24e469fa39e77cae", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-72b2a6250083a784", "level": "warning", "message": {"text": "Placeholder or mock-heavy implementation detected"}, "properties": {"repobilityId": "347b1f59ca75f86a", "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": "140dbd1a4800aa20", "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": "43624fde94063277", "scanner": "scanner-primary", "fingerprint": "2d0c7b7ab8f8aacf", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "critical-flow", "generated-repo-pattern"]}}, {"ruleId": "scanner-749d4bc1bd66df5f", "level": "warning", "message": {"text": "Agent instructions exist but release-hardening basics are missing"}, "properties": {"repobilityId": "10f797296f5f54bc", "scanner": "scanner-primary", "fingerprint": "749d4bc1bd66df5f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["agent-instructions", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-ea8f3013f588db25", "level": "note", "message": {"text": "Shallow git history limits provenance confidence"}, "properties": {"repobilityId": "41f98ac5d25c5030", "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": "e966d1f832c4071c", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-8c1803f23ad8cbca", "level": "none", "message": {"text": "Commented-code block (9 lines) in tailwind.config.js:43"}, "properties": {"repobilityId": "6951d379b10f496e", "scanner": "scanner-primary", "fingerprint": "8c1803f23ad8cbca", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-6f938c411f20d3d1", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/App.tsx:11"}, "properties": {"repobilityId": "8c4bd7777ed28e96", "scanner": "scanner-primary", "fingerprint": "6f938c411f20d3d1", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-1e3bd5e54e1839ca", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/components/Skeleton.tsx:3"}, "properties": {"repobilityId": "59298e31e3606100", "scanner": "scanner-primary", "fingerprint": "1e3bd5e54e1839ca", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-049fd9300f5a75b1", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/lib/posDraftStorage.ts:5"}, "properties": {"repobilityId": "c80e38b28c2b9ae2", "scanner": "scanner-primary", "fingerprint": "049fd9300f5a75b1", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-98121bc008b32b4a", "level": "none", "message": {"text": "Commented-code block (8 lines) in src/lib/queryClient.ts:3"}, "properties": {"repobilityId": "0ab1961ef21a07c2", "scanner": "scanner-primary", "fingerprint": "98121bc008b32b4a", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-b6b743aa463a72fa", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/lib/lunarDate.ts:1"}, "properties": {"repobilityId": "dd82ca9faf75416d", "scanner": "scanner-primary", "fingerprint": "b6b743aa463a72fa", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-fcaab80304e68440", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/lib/exporters/documentPdf.tsx:4"}, "properties": {"repobilityId": "d610cd8c05584705", "scanner": "scanner-primary", "fingerprint": "fcaab80304e68440", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-858a8893ab7fbd39", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/lib/exporters/documentXlsx.ts:3"}, "properties": {"repobilityId": "6a8c90da3d778a10", "scanner": "scanner-primary", "fingerprint": "858a8893ab7fbd39", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-918319c72870e27b", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/pages/reports/StrategicProductsReportPage.tsx:33"}, "properties": {"repobilityId": "b444f81ca348e514", "scanner": "scanner-primary", "fingerprint": "918319c72870e27b", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-3f5304c5c762fa3c", "level": "none", "message": {"text": "Commented-code block (8 lines) in src/hooks/queries/useStrategicProducts.ts:6"}, "properties": {"repobilityId": "8fbbfc4103eb77d2", "scanner": "scanner-primary", "fingerprint": "3f5304c5c762fa3c", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-7d7e838e2a61e8d7", "level": "none", "message": {"text": "Commented-code block (6 lines) in src/hooks/queries/useCustomers.ts:54"}, "properties": {"repobilityId": "dbd1872622da6e35", "scanner": "scanner-primary", "fingerprint": "7d7e838e2a61e8d7", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-82c97def35671596", "level": "none", "message": {"text": "Commented-code block (5 lines) in src/hooks/queries/useInventoryValuation.ts:6"}, "properties": {"repobilityId": "d1c55b673f182912", "scanner": "scanner-primary", "fingerprint": "82c97def35671596", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-250f57e8a1dbd3c5", "level": "none", "message": {"text": "4 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "57584f22b735b5ee", "scanner": "scanner-primary", "fingerprint": "250f57e8a1dbd3c5", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-cb07a36b9b4572a8", "level": "warning", "message": {"text": "Frontend route `/auth/callback` has no Link/navigate to it \u2014 src/App.tsx"}, "properties": {"repobilityId": "89437733215e6393", "scanner": "scanner-primary", "fingerprint": "cb07a36b9b4572a8", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-3481e66bf3b8afd3", "level": "warning", "message": {"text": "Frontend route `/customers/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "properties": {"repobilityId": "cbd184810c38aa4a", "scanner": "scanner-primary", "fingerprint": "3481e66bf3b8afd3", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-3ac147fb291ca389", "level": "warning", "message": {"text": "Frontend route `/products/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "properties": {"repobilityId": "872d05dcbe18dffc", "scanner": "scanner-primary", "fingerprint": "3ac147fb291ca389", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-e306fca6a9a1d98d", "level": "warning", "message": {"text": "Frontend route `/suppliers/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "properties": {"repobilityId": "47ea210b2944fad2", "scanner": "scanner-primary", "fingerprint": "e306fca6a9a1d98d", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-9816085fd6262343", "level": "warning", "message": {"text": "Frontend route `/goods-receipts/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "properties": {"repobilityId": "9506c57256632c2a", "scanner": "scanner-primary", "fingerprint": "9816085fd6262343", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-9b449976a3f733c3", "level": "warning", "message": {"text": "Frontend route `/orders/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "properties": {"repobilityId": "35e3881691a72683", "scanner": "scanner-primary", "fingerprint": "9b449976a3f733c3", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-1654c1b654fe5c2e", "level": "warning", "message": {"text": "Frontend route `/herd-projects/:id` has no Link/navigate to it \u2014 src/App.tsx"}, "properties": {"repobilityId": "b7675b7cc48ffcb0", "scanner": "scanner-primary", "fingerprint": "1654c1b654fe5c2e", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}, {"ruleId": "scanner-a559691cd127132e", "level": "warning", "message": {"text": "Frontend route `/print-preview` has no Link/navigate to it \u2014 src/App.tsx"}, "properties": {"repobilityId": "b3e9fa6d56aaf2ce", "scanner": "scanner-primary", "fingerprint": "a559691cd127132e", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "orphan-page", "wiring"]}}]}]}