{"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-bdc90ce438709f65", "name": "`truncate` class without `title=` for hover reveal \u2014 web/src/screens/ResultScreen.tsx:146", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 web/src/screens/ResultScreen.tsx:146"}, "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-d92cbe7a40cd4ef4", "name": "`truncate` class without `title=` for hover reveal \u2014 web/src/components/AppNav.tsx:87", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 web/src/components/AppNav.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-981d12285a4a1264", "name": "`truncate` class without `title=` for hover reveal \u2014 web/src/components/Roster.tsx:97", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 web/src/components/Roster.tsx:97"}, "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-72d375ca04da6c0b", "name": "`truncate` class without `title=` for hover reveal \u2014 web/src/components/MenuItemRow.tsx:37", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 web/src/components/MenuItemRow.tsx:37"}, "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-a1da9a2a35f4ac2e", "name": "Dockerfile runs as root: api/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: api/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-e8a3752fb7f9726f", "name": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-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-a5823f1252b6cda1", "name": "Dockerfile runs as root: web/Dockerfile", "shortDescription": {"text": "Dockerfile runs as root: web/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-45ff595622352c1b", "name": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine"}, "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-0f2f8d1aedc84788", "name": "Docker base image is tag-pinned but not digest-pinned: nginx:alpine", "shortDescription": {"text": "Docker base image is tag-pinned but not digest-pinned: nginx:alpine"}, "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-aa5acaa49eb8315b", "name": "Containers defined but no K8s/orchestration manifest found", "shortDescription": {"text": "Containers defined but no K8s/orchestration manifest found"}, "fullDescription": {"text": "Repo has Dockerfiles/compose but no Kubernetes/Nomad manifests. If the target deployment is K8s, the manifests may live in a separate ops repo."}, "properties": {"scanner": "scanner-primary", "layer": "hardware", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f12cfa59ab2159bc", "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-ea3b5e389d8c9c0f", "name": "Low test-to-source ratio", "shortDescription": {"text": "Low test-to-source ratio"}, "fullDescription": {"text": "6 tests / 59 src (ratio 0.10)."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2b3b4131c0cb2eaa", "name": "Node manifest has dependencies but no lockfile: shared/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: shared/package.json"}, "fullDescription": {"text": "`package.json` declares dependencies, but no same-directory npm/pnpm/yarn/bun lockfile was found. Generated projects without lockfiles are less reproducible and harder to secure-scan precisely."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f61e9dc22135856f", "name": "Node manifest has dependencies but no lockfile: web/package.json", "shortDescription": {"text": "Node manifest has dependencies but no lockfile: web/package.json"}, "fullDescription": {"text": "`package.json` declares dependencies, but no same-directory npm/pnpm/yarn/bun lockfile was found. Generated projects without lockfiles are less reproducible and harder to secure-scan precisely."}, "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 16 placeholder/mock markers across 4 source files. This often means the repo looks complete while core flows still use generated scaffolding or fake data."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-2d0c7b7ab8f8aacf", "name": "Critical user flow still appears backed by mock or placeholder data", "shortDescription": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "fullDescription": {"text": "A payment/auth/admin/order/billing-style flow contains mock, fake, TODO, dummy, or placeholder markers in runtime source. In the Fable corpus this is a high-leverage completeness smell: the app can look finished while the money, identity, or tenant flow is still scaffolded."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-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-cf4a715f415d6261", "name": "Likely N+1 query: `for s in \u2026` triggers a query per row \u2014 api/breakfast/admin.py:220", "shortDescription": {"text": "Likely N+1 query: `for s in \u2026` triggers a query per row \u2014 api/breakfast/admin.py:220"}, "fullDescription": {"text": "The loop iterates a Django queryset and accesses `s.restaurant.name` per row, which fires an additional database query each iteration. Add `.select_related('<fk_field>')` for FK / O2O relations or `.prefetch_related('<m2m_or_reverse>')` for many-related lookups, to load everything in 1-2 queries instead of N."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-20ff57f751c1b70b", "name": "Commented-code block (5 lines) in web/vite.config.ts:4", "shortDescription": {"text": "Commented-code block (5 lines) in web/vite.config.ts:4"}, "fullDescription": {"text": "A long run of `//` or `#` lines usually means abandoned code. Delete or move to git history. Keeps the canvas + dead-code detection honest."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "info", "confidence": 1.0}}, {"id": "scanner-1b5a76780c3df9aa", "name": "1 env vars used in code but missing from .env.example", "shortDescription": {"text": "1 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `DJANGO_SECRET_KEY`. 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-49c98f7cedd9c977", "name": "Near-duplicate function bodies in 4 places", "shortDescription": {"text": "Near-duplicate function bodies in 4 places"}, "fullDescription": {"text": "Functions with the same first-5-line body hash:\napi/breakfast/admin.py:get_queryset, api/breakfast/admin.py:get_queryset, api/breakfast/admin.py:get_queryset, api/breakfast/admin.py:get_queryset\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}}, {"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:\napi/breakfast/admin.py:state, api/breakfast/admin.py:state\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}}, {"id": "scanner-ac42422b23e45104", "name": "Unused endpoint: GET /auth/me", "shortDescription": {"text": "Unused endpoint: GET /auth/me"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `GET /auth/me` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-50dc933d47d98a46", "name": "Unused endpoint: GET /colleagues", "shortDescription": {"text": "Unused endpoint: GET /colleagues"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `GET /colleagues` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-8fdbacfe9430a6ed", "name": "Unused endpoint: POST /auth/login", "shortDescription": {"text": "Unused endpoint: POST /auth/login"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `POST /auth/login` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-c059f57186114027", "name": "Unused endpoint: POST /auth/logout", "shortDescription": {"text": "Unused endpoint: POST /auth/logout"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `POST /auth/logout` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e080739ac0ec63e3", "name": "Unused endpoint: GET /restaurants", "shortDescription": {"text": "Unused endpoint: GET /restaurants"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `GET /restaurants` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-fef973e09af3dbdf", "name": "Unused endpoint: POST /restaurants", "shortDescription": {"text": "Unused endpoint: POST /restaurants"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `POST /restaurants` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f8a390deddb86bf6", "name": "Unused endpoint: PATCH /restaurants/{rid}", "shortDescription": {"text": "Unused endpoint: PATCH /restaurants/{rid}"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `PATCH /restaurants/{rid}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-b15b7d9990ec1ef7", "name": "Unused endpoint: POST /restaurants/{rid}/items", "shortDescription": {"text": "Unused endpoint: POST /restaurants/{rid}/items"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `POST /restaurants/{rid}/items` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-f733c8556a6402b7", "name": "Unused endpoint: PATCH /restaurants/{rid}/items/{item_id}", "shortDescription": {"text": "Unused endpoint: PATCH /restaurants/{rid}/items/{item_id}"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `PATCH /restaurants/{rid}/items/{item_id}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-e1c48c5facb24cf5", "name": "Unused endpoint: DELETE /restaurants/{rid}/items/{item_id}", "shortDescription": {"text": "Unused endpoint: DELETE /restaurants/{rid}/items/{item_id}"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `DELETE /restaurants/{rid}/items/{item_id}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-24c73fd36695117e", "name": "Unused endpoint: GET /sessions/open", "shortDescription": {"text": "Unused endpoint: GET /sessions/open"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `GET /sessions/open` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-841a69baf0f13908", "name": "Unused endpoint: GET /sessions/current", "shortDescription": {"text": "Unused endpoint: GET /sessions/current"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `GET /sessions/current` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-92efb2dc9205e7a4", "name": "Unused endpoint: POST /sessions", "shortDescription": {"text": "Unused endpoint: POST /sessions"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `POST /sessions` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-77e497414a27bc4a", "name": "Unused endpoint: GET /sessions/{sid}", "shortDescription": {"text": "Unused endpoint: GET /sessions/{sid}"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `GET /sessions/{sid}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-1f2988160aeb8914", "name": "Unused endpoint: PUT /sessions/{sid}/order", "shortDescription": {"text": "Unused endpoint: PUT /sessions/{sid}/order"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `PUT /sessions/{sid}/order` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-981aea666832cbe3", "name": "Unused endpoint: DELETE /sessions/{sid}/order", "shortDescription": {"text": "Unused endpoint: DELETE /sessions/{sid}/order"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `DELETE /sessions/{sid}/order` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ff6635424ee67c98", "name": "Unused endpoint: POST /sessions/{sid}/close", "shortDescription": {"text": "Unused endpoint: POST /sessions/{sid}/close"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `POST /sessions/{sid}/close` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-228bbd21de47eef2", "name": "Unused endpoint: DELETE /sessions/{sid}", "shortDescription": {"text": "Unused endpoint: DELETE /sessions/{sid}"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `DELETE /sessions/{sid}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-044eae797c221cab", "name": "Unused endpoint: GET /sessions/{sid}/result", "shortDescription": {"text": "Unused endpoint: GET /sessions/{sid}/result"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `GET /sessions/{sid}/result` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-9898288afd45336c", "name": "Unused endpoint: PATCH /orders/{oid}", "shortDescription": {"text": "Unused endpoint: PATCH /orders/{oid}"}, "fullDescription": {"text": "`api/breakfast/api.py` declares `PATCH /orders/{oid}` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-7309bf2446873ccc", "name": "Unused endpoint: ANY /admin/", "shortDescription": {"text": "Unused endpoint: ANY /admin/"}, "fullDescription": {"text": "`api/morningcart/urls.py` declares `ANY /admin/` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}, {"id": "scanner-ce0a9b4397331ef4", "name": "Unused endpoint: ANY /api/", "shortDescription": {"text": "Unused endpoint: ANY /api/"}, "fullDescription": {"text": "`api/morningcart/urls.py` declares `ANY /api/` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/23611"}, "properties": {"repository": "zeyadesperado/morningcart", "repoUrl": "https://github.com/zeyadesperado/morningcart", "branch": "main"}, "results": [{"ruleId": "scanner-bdc90ce438709f65", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 web/src/screens/ResultScreen.tsx:146"}, "properties": {"repobilityId": "ab7bd3ba8b2fe7a8", "scanner": "scanner-primary", "fingerprint": "bdc90ce438709f65", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-d92cbe7a40cd4ef4", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 web/src/components/AppNav.tsx:87"}, "properties": {"repobilityId": "6cdfe26aec4c1521", "scanner": "scanner-primary", "fingerprint": "d92cbe7a40cd4ef4", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-981d12285a4a1264", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 web/src/components/Roster.tsx:97"}, "properties": {"repobilityId": "1dbfc97f2151c15f", "scanner": "scanner-primary", "fingerprint": "981d12285a4a1264", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-72d375ca04da6c0b", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 web/src/components/MenuItemRow.tsx:37"}, "properties": {"repobilityId": "2349053eae353ef1", "scanner": "scanner-primary", "fingerprint": "72d375ca04da6c0b", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-a1da9a2a35f4ac2e", "level": "warning", "message": {"text": "Dockerfile runs as root: api/Dockerfile"}, "properties": {"repobilityId": "d158f2064abae541", "scanner": "scanner-primary", "fingerprint": "a1da9a2a35f4ac2e", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-e8a3752fb7f9726f", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: python:3.12-slim"}, "properties": {"repobilityId": "de34b89e749e6511", "scanner": "scanner-primary", "fingerprint": "e8a3752fb7f9726f", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "api/Dockerfile"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-a5823f1252b6cda1", "level": "warning", "message": {"text": "Dockerfile runs as root: web/Dockerfile"}, "properties": {"repobilityId": "ee2f067d8416357d", "scanner": "scanner-primary", "fingerprint": "a5823f1252b6cda1", "layer": "hardware", "severity": "medium", "confidence": 1.0, "tags": ["security", "container"]}}, {"ruleId": "scanner-45ff595622352c1b", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: node:20-alpine"}, "properties": {"repobilityId": "013df42692d816ae", "scanner": "scanner-primary", "fingerprint": "45ff595622352c1b", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "web/Dockerfile"}, "region": {"startLine": 7}}}]}, {"ruleId": "scanner-0f2f8d1aedc84788", "level": "note", "message": {"text": "Docker base image is tag-pinned but not digest-pinned: nginx:alpine"}, "properties": {"repobilityId": "a4da511c255d66ea", "scanner": "scanner-primary", "fingerprint": "0f2f8d1aedc84788", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "docker", "pinned-dependencies"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "web/Dockerfile"}, "region": {"startLine": 26}}}]}, {"ruleId": "scanner-aa5acaa49eb8315b", "level": "note", "message": {"text": "Containers defined but no K8s/orchestration manifest found"}, "properties": {"repobilityId": "b230ea9b68736081", "scanner": "scanner-primary", "fingerprint": "aa5acaa49eb8315b", "layer": "hardware", "severity": "low", "confidence": 1.0, "tags": ["coverage", "deployment"]}}, {"ruleId": "scanner-f12cfa59ab2159bc", "level": "note", "message": {"text": "package.json defines install-time lifecycle scripts"}, "properties": {"repobilityId": "8886105707356b86", "scanner": "scanner-primary", "fingerprint": "f12cfa59ab2159bc", "layer": "cicd", "severity": "low", "confidence": 1.0, "tags": ["supply-chain", "npm", "install-scripts"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "shared/package.json"}, "region": {"startLine": 1}}}]}, {"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-2b3b4131c0cb2eaa", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: shared/package.json"}, "properties": {"repobilityId": "310fa61d19fba401", "scanner": "scanner-primary", "fingerprint": "2b3b4131c0cb2eaa", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "shared/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-f61e9dc22135856f", "level": "note", "message": {"text": "Node manifest has dependencies but no lockfile: web/package.json"}, "properties": {"repobilityId": "dd661d63588916a7", "scanner": "scanner-primary", "fingerprint": "f61e9dc22135856f", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["dependency", "lockfile", "reproducibility", "generated-repo-pattern"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "web/package.json"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-72b2a6250083a784", "level": "warning", "message": {"text": "Placeholder or mock-heavy implementation detected"}, "properties": {"repobilityId": "69ed3241d229b644", "scanner": "scanner-primary", "fingerprint": "72b2a6250083a784", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["placeholder", "mock-data", "incomplete", "generated-repo-pattern"]}}, {"ruleId": "scanner-2d0c7b7ab8f8aacf", "level": "warning", "message": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "properties": {"repobilityId": "4054ca9947c9196e", "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": "af3bbcbb3991fd27", "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": "683818fa231c36ec", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-cf4a715f415d6261", "level": "warning", "message": {"text": "Likely N+1 query: `for s in \u2026` triggers a query per row \u2014 api/breakfast/admin.py:220"}, "properties": {"repobilityId": "5071910de04864c1", "scanner": "scanner-primary", "fingerprint": "cf4a715f415d6261", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "n-plus-one", "performance"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "api/breakfast/admin.py"}, "region": {"startLine": 220}}}]}, {"ruleId": "scanner-20ff57f751c1b70b", "level": "none", "message": {"text": "Commented-code block (5 lines) in web/vite.config.ts:4"}, "properties": {"repobilityId": "3b4938ca7c6339b4", "scanner": "scanner-primary", "fingerprint": "20ff57f751c1b70b", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-1b5a76780c3df9aa", "level": "none", "message": {"text": "1 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "d04379b337b44a15", "scanner": "scanner-primary", "fingerprint": "1b5a76780c3df9aa", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-49c98f7cedd9c977", "level": "note", "message": {"text": "Near-duplicate function bodies in 4 places"}, "properties": {"repobilityId": "a6a0d0d39e6a8252", "scanner": "scanner-primary", "fingerprint": "49c98f7cedd9c977", "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": "5cbb927c7ec5331a", "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": "30ca545b23bff279", "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": "c6917ad8fedcf90b", "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": "0c49f0e29d7fab63", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-ac42422b23e45104", "level": "note", "message": {"text": "Unused endpoint: GET /auth/me"}, "properties": {"repobilityId": "7adeecd120fc09fd", "scanner": "scanner-primary", "fingerprint": "ac42422b23e45104", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-50dc933d47d98a46", "level": "note", "message": {"text": "Unused endpoint: GET /colleagues"}, "properties": {"repobilityId": "05f8546df0e0b500", "scanner": "scanner-primary", "fingerprint": "50dc933d47d98a46", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-8fdbacfe9430a6ed", "level": "note", "message": {"text": "Unused endpoint: POST /auth/login"}, "properties": {"repobilityId": "3a27cb36f47a9513", "scanner": "scanner-primary", "fingerprint": "8fdbacfe9430a6ed", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-c059f57186114027", "level": "note", "message": {"text": "Unused endpoint: POST /auth/logout"}, "properties": {"repobilityId": "95c2d2b092f602f5", "scanner": "scanner-primary", "fingerprint": "c059f57186114027", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e080739ac0ec63e3", "level": "note", "message": {"text": "Unused endpoint: GET /restaurants"}, "properties": {"repobilityId": "3c383b35e009fa94", "scanner": "scanner-primary", "fingerprint": "e080739ac0ec63e3", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-fef973e09af3dbdf", "level": "note", "message": {"text": "Unused endpoint: POST /restaurants"}, "properties": {"repobilityId": "a0318d38edb61361", "scanner": "scanner-primary", "fingerprint": "fef973e09af3dbdf", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f8a390deddb86bf6", "level": "note", "message": {"text": "Unused endpoint: PATCH /restaurants/{rid}"}, "properties": {"repobilityId": "55b169a772df1180", "scanner": "scanner-primary", "fingerprint": "f8a390deddb86bf6", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-b15b7d9990ec1ef7", "level": "note", "message": {"text": "Unused endpoint: POST /restaurants/{rid}/items"}, "properties": {"repobilityId": "92eae4a24a3a4ec0", "scanner": "scanner-primary", "fingerprint": "b15b7d9990ec1ef7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-f733c8556a6402b7", "level": "note", "message": {"text": "Unused endpoint: PATCH /restaurants/{rid}/items/{item_id}"}, "properties": {"repobilityId": "9d3892dfecbc02ad", "scanner": "scanner-primary", "fingerprint": "f733c8556a6402b7", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-e1c48c5facb24cf5", "level": "note", "message": {"text": "Unused endpoint: DELETE /restaurants/{rid}/items/{item_id}"}, "properties": {"repobilityId": "e805ed5635e74f40", "scanner": "scanner-primary", "fingerprint": "e1c48c5facb24cf5", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-24c73fd36695117e", "level": "note", "message": {"text": "Unused endpoint: GET /sessions/open"}, "properties": {"repobilityId": "81225c74f2459989", "scanner": "scanner-primary", "fingerprint": "24c73fd36695117e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-841a69baf0f13908", "level": "note", "message": {"text": "Unused endpoint: GET /sessions/current"}, "properties": {"repobilityId": "a2112b9ef44f9d8b", "scanner": "scanner-primary", "fingerprint": "841a69baf0f13908", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-92efb2dc9205e7a4", "level": "note", "message": {"text": "Unused endpoint: POST /sessions"}, "properties": {"repobilityId": "b55539d2b44aedfe", "scanner": "scanner-primary", "fingerprint": "92efb2dc9205e7a4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-77e497414a27bc4a", "level": "note", "message": {"text": "Unused endpoint: GET /sessions/{sid}"}, "properties": {"repobilityId": "d3b9ad92100cfd7a", "scanner": "scanner-primary", "fingerprint": "77e497414a27bc4a", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-1f2988160aeb8914", "level": "note", "message": {"text": "Unused endpoint: PUT /sessions/{sid}/order"}, "properties": {"repobilityId": "823daa8b664a70d5", "scanner": "scanner-primary", "fingerprint": "1f2988160aeb8914", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-981aea666832cbe3", "level": "note", "message": {"text": "Unused endpoint: DELETE /sessions/{sid}/order"}, "properties": {"repobilityId": "dd6f0606a0b836f2", "scanner": "scanner-primary", "fingerprint": "981aea666832cbe3", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ff6635424ee67c98", "level": "note", "message": {"text": "Unused endpoint: POST /sessions/{sid}/close"}, "properties": {"repobilityId": "7bdcb835441a0eb8", "scanner": "scanner-primary", "fingerprint": "ff6635424ee67c98", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-228bbd21de47eef2", "level": "note", "message": {"text": "Unused endpoint: DELETE /sessions/{sid}"}, "properties": {"repobilityId": "a7d96feff1550147", "scanner": "scanner-primary", "fingerprint": "228bbd21de47eef2", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-044eae797c221cab", "level": "note", "message": {"text": "Unused endpoint: GET /sessions/{sid}/result"}, "properties": {"repobilityId": "80eacfac54ac3755", "scanner": "scanner-primary", "fingerprint": "044eae797c221cab", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-9898288afd45336c", "level": "note", "message": {"text": "Unused endpoint: PATCH /orders/{oid}"}, "properties": {"repobilityId": "ef21ac3393c643b8", "scanner": "scanner-primary", "fingerprint": "9898288afd45336c", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-7309bf2446873ccc", "level": "note", "message": {"text": "Unused endpoint: ANY /admin/"}, "properties": {"repobilityId": "2ec69693ec5a5ac1", "scanner": "scanner-primary", "fingerprint": "7309bf2446873ccc", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-ce0a9b4397331ef4", "level": "note", "message": {"text": "Unused endpoint: ANY /api/"}, "properties": {"repobilityId": "f2b13ed8070c5a81", "scanner": "scanner-primary", "fingerprint": "ce0a9b4397331ef4", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}