{"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-00771c10e7f6a4a8", "name": "Possibly dead Python function: phone", "shortDescription": {"text": "Possibly dead Python function: phone"}, "fullDescription": {"text": "No callers detected by AST scan in this repo. Could be exported for external callers or a framework handler."}, "properties": {"scanner": "scanner-primary", "layer": "software", "severity": "low", "confidence": 1.0}}, {"id": "scanner-2c1aea99a47a9966", "name": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/Nav.tsx:313", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/Nav.tsx:313"}, "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-e40f570e670f502e", "name": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/RadioStation.tsx:456", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/RadioStation.tsx:456"}, "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-8f4909cac64de03a", "name": "\"active\" state uses light bg in a dark theme \u2014 Website/src/components/RadioStation.tsx:444", "shortDescription": {"text": "\"active\" state uses light bg in a dark theme \u2014 Website/src/components/RadioStation.tsx:444"}, "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-e6cee4afe7f71576", "name": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/Breakdowns.tsx:52", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/Breakdowns.tsx:52"}, "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-c88dcd92f9580cee", "name": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/Traffic.tsx:97", "shortDescription": {"text": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/Traffic.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-f9cefc7db21e015c", "name": "Insecure pattern 'cors_wildcard' in worker/src/index.ts:18", "shortDescription": {"text": "Insecure pattern 'cors_wildcard' in worker/src/index.ts:18"}, "fullDescription": {"text": "Found a known-risky pattern (cors_wildcard). Review and replace if possible."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-6372cebde0220094", "name": "No auth library detected", "shortDescription": {"text": "No auth library detected"}, "fullDescription": {"text": "The scanner did not find any standard auth library (JWT, OAuth, NextAuth, Auth0, etc.). The repo has auth/admin/session surface indicators, so auth may live in custom code, in a separate service, or be missing."}, "properties": {"scanner": "scanner-primary", "layer": "security", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-24a2353e77881d9e", "name": "GitHub Actions workflow grants broad write permissions", "shortDescription": {"text": "GitHub Actions workflow grants broad write permissions"}, "fullDescription": {"text": "CI tokens with write permissions increase blast radius when an action, dependency, or PR workflow is compromised. Prefer job-level least-privilege permissions."}, "properties": {"scanner": "scanner-primary", "layer": "cicd", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-6893a6c8b0861585", "name": "Very low test-to-source ratio", "shortDescription": {"text": "Very low test-to-source ratio"}, "fullDescription": {"text": "3 test file(s) for 78 source file(s) (ratio 0.04). Consider adding integration or unit tests for critical paths."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-141b30a41e03817b", "name": "No license file detected", "shortDescription": {"text": "No license file detected"}, "fullDescription": {"text": "No LICENSE/COPYING/NOTICE file was found. Generated repositories often omit licensing, which blocks reuse and automated intake."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-3ab5d313dda8e5f9", "name": "Debug logging residue appears in source files", "shortDescription": {"text": "Debug logging residue appears in source files"}, "fullDescription": {"text": "Found 83 console/debugger/print-style debug statements in non-test source. This is a common fast-generation residue before production cleanup."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-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-ed26c54e172bd208", "name": "Commented-code block (5 lines) in Website/scripts/gen-worldgeo.mjs:1", "shortDescription": {"text": "Commented-code block (5 lines) in Website/scripts/gen-worldgeo.mjs: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-1bea1d76ae84f27b", "name": "Commented-code block (5 lines) in Website/src/components/RadioStation.tsx:199", "shortDescription": {"text": "Commented-code block (5 lines) in Website/src/components/RadioStation.tsx:199"}, "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-e54d5e1d94f59a0b", "name": "Commented-code block (5 lines) in Website/src/components/useRadioAudio.ts:112", "shortDescription": {"text": "Commented-code block (5 lines) in Website/src/components/useRadioAudio.ts:112"}, "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-a4a2b1088b7d378f", "name": "Network/subprocess call without timeout or try/except \u2014 scripts/render-post.py:93", "shortDescription": {"text": "Network/subprocess call without timeout or try/except \u2014 scripts/render-post.py:93"}, "fullDescription": {"text": "`subprocess.run(...)` here lacks both a `timeout=` arg and an enclosing try/except. This is exactly the class of bug that took down our git-clone earlier (HTTP/2 stream cancel surfaced as a fatal). Add a `timeout=` and wrap in try/except, or use a wrapper that retries."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-a80d009ba226101f", "name": "Commented-code block (5 lines) in scripts/generate-radio.py:300", "shortDescription": {"text": "Commented-code block (5 lines) in scripts/generate-radio.py:300"}, "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-a60dfb09db42c148", "name": "Network/subprocess call without timeout or try/except \u2014 scripts/generate-radio.py:272", "shortDescription": {"text": "Network/subprocess call without timeout or try/except \u2014 scripts/generate-radio.py:272"}, "fullDescription": {"text": "`subprocess.run(...)` here lacks both a `timeout=` arg and an enclosing try/except. This is exactly the class of bug that took down our git-clone earlier (HTTP/2 stream cancel surfaced as a fatal). Add a `timeout=` and wrap in try/except, or use a wrapper that retries."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-0fe9f39e7a3eb831", "name": "`fetch()` without try/.catch or AbortSignal \u2014 worker/scripts/populate-traffic.mjs:27", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 worker/scripts/populate-traffic.mjs:27"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-51c4e577bc53750f", "name": "`fetch()` without try/.catch or AbortSignal \u2014 worker/scripts/populate.mjs:34", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 worker/scripts/populate.mjs:34"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-1f614fa6f0acfbb7", "name": "`fetch()` without try/.catch or AbortSignal \u2014 worker/src/routes/ghstats.ts:77", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 worker/src/routes/ghstats.ts:77"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-4357957fb15f2863", "name": "`fetch()` without try/.catch or AbortSignal \u2014 worker/src/routes/analytics.ts:77", "shortDescription": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 worker/src/routes/analytics.ts:77"}, "fullDescription": {"text": "Bare `fetch(...)` will throw an unhandled rejection on network failure. Wrap in try/catch, attach a `.catch(...)`, or pass an AbortSignal with a timeout."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "medium", "confidence": 1.0}}, {"id": "scanner-8e047ab7af03962f", "name": "7 env vars used in code but missing from .env.example", "shortDescription": {"text": "7 env vars used in code but missing from .env.example"}, "fullDescription": {"text": "Drift between code and config docs. The first few: `CF_ANALYTICS_TOKEN`, `CF_ZONE_TAG`, `GITHUB_TOKEN`, `HF_TOKEN`, `HUGGING_FACE_HUB_TOKEN`, `IDEOGRAM4_DIR`, `IDEOGRAM_API_KEY`. Add them (with a placeholder/comment) to .env.example so onboarding doesn't break."}, "properties": {"scanner": "scanner-primary", "layer": "quality", "severity": "low", "confidence": 1.0}}, {"id": "scanner-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:\nscripts/generate-audio.py:generate_waveform, scripts/generate-audio.py:generate\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-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:\nscripts/pick-disclaimer-voice.py:resample, scripts/pick-announcer-voices.py:resample, scripts/download-ad-voices.py:resample, scripts/download-voices.py:resample\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-77821f4749e69d3f", "name": "Dangling fetch: POST https://api.cloudflare.com/client/v4/graphql (worker/scripts/populate-traffic.mjs:27)", "shortDescription": {"text": "Dangling fetch: POST https://api.cloudflare.com/client/v4/graphql (worker/scripts/populate-traffic.mjs:27)"}, "fullDescription": {"text": "`worker/scripts/populate-traffic.mjs:27` calls `POST https://api.cloudflare.com/client/v4/graphql` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/api.cloudflare.com/client/v4/graphql`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-c62495d35926d60c", "name": "Dangling fetch: GET https://api.cloudflare.com/client/v4/zones?per_page=50&status=active (worker/scripts/populate-traffi", "shortDescription": {"text": "Dangling fetch: GET https://api.cloudflare.com/client/v4/zones?per_page=50&status=active (worker/scripts/populate-traffic.mjs:41)"}, "fullDescription": {"text": "`worker/scripts/populate-traffic.mjs:41` calls `GET https://api.cloudflare.com/client/v4/zones?per_page=50&status=active` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/api.cloudflare.com/client/v4/zones`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-0a108305a8684124", "name": "Dangling fetch: POST https://api.github.com/graphql (worker/scripts/populate.mjs:34)", "shortDescription": {"text": "Dangling fetch: POST https://api.github.com/graphql (worker/scripts/populate.mjs:34)"}, "fullDescription": {"text": "`worker/scripts/populate.mjs:34` calls `POST https://api.github.com/graphql` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/api.github.com/graphql`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-818eba3367444a8f", "name": "Dangling fetch: GET https://lunarportfolio.com/rss.xml (Website/src/components/LunarArticles.tsx:38)", "shortDescription": {"text": "Dangling fetch: GET https://lunarportfolio.com/rss.xml (Website/src/components/LunarArticles.tsx:38)"}, "fullDescription": {"text": "`Website/src/components/LunarArticles.tsx:38` calls `GET https://lunarportfolio.com/rss.xml` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/lunarportfolio.com/rss.xml`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-27f492dcff3cfc73", "name": "Dangling fetch: POST https://api.github.com/graphql (worker/src/routes/ghstats.ts:77)", "shortDescription": {"text": "Dangling fetch: POST https://api.github.com/graphql (worker/src/routes/ghstats.ts:77)"}, "fullDescription": {"text": "`worker/src/routes/ghstats.ts:77` calls `POST https://api.github.com/graphql` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/api.github.com/graphql`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-3927a507e1478d78", "name": "Dangling fetch: POST https://api.cloudflare.com/client/v4/graphql (worker/src/routes/analytics.ts:77)", "shortDescription": {"text": "Dangling fetch: POST https://api.cloudflare.com/client/v4/graphql (worker/src/routes/analytics.ts:77)"}, "fullDescription": {"text": "`worker/src/routes/analytics.ts:77` calls `POST https://api.cloudflare.com/client/v4/graphql` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/api.cloudflare.com/client/v4/graphql`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-5af750c624b1a53c", "name": "Dangling fetch: GET https://api.cloudflare.com/client/v4/zones?per_page=50&status=active (worker/src/routes/analytics.ts", "shortDescription": {"text": "Dangling fetch: GET https://api.cloudflare.com/client/v4/zones?per_page=50&status=active (worker/src/routes/analytics.ts:95)"}, "fullDescription": {"text": "`worker/src/routes/analytics.ts:95` calls `GET https://api.cloudflare.com/client/v4/zones?per_page=50&status=active` but no backend route matches that path. This is a runtime 404 waiting to happen.\n\nTool: fetch\nNormalized path used for matching: `/https:/api.cloudflare.com/client/v4/zones`\nIf this points at an external API, prefix it with `https://` so the matcher skips it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "high", "confidence": 1.0}}, {"id": "scanner-b3009f31646c769d", "name": "Unused endpoint: USE /api/radio-save", "shortDescription": {"text": "Unused endpoint: USE /api/radio-save"}, "fullDescription": {"text": "`Website/astro.config.mjs` declares `USE /api/radio-save` 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-bf1fb796885f0a7e", "name": "Unused endpoint: GET /ghstats", "shortDescription": {"text": "Unused endpoint: GET /ghstats"}, "fullDescription": {"text": "`worker/src/routes/ghstats.ts` declares `GET /ghstats` 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-5baa8971ebe192a1", "name": "Unused endpoint: GET /", "shortDescription": {"text": "Unused endpoint: GET /"}, "fullDescription": {"text": "`worker/src/routes/ghstats.ts` declares `GET /` 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-4629fc2f2a182ac9", "name": "Unused endpoint: GET /analytics", "shortDescription": {"text": "Unused endpoint: GET /analytics"}, "fullDescription": {"text": "`worker/src/routes/analytics.ts` declares `GET /analytics` but no frontend code we scanned calls it. This is fine if the endpoint serves external clients (mobile app, third-party, server-side webhooks). Otherwise it's dead code \u2014 consider removing or documenting who consumes it."}, "properties": {"scanner": "scanner-primary", "layer": "api", "severity": "low", "confidence": 1.0}}]}}, "automationDetails": {"id": "repobility/19911"}, "properties": {"repository": "Snazzie/SnazzieSpaceReact", "repoUrl": "https://github.com/Snazzie/SnazzieSpaceReact", "branch": "main"}, "results": [{"ruleId": "scanner-00771c10e7f6a4a8", "level": "note", "message": {"text": "Possibly dead Python function: phone"}, "properties": {"repobilityId": "0a13becf638b0704", "scanner": "scanner-primary", "fingerprint": "00771c10e7f6a4a8", "layer": "software", "severity": "low", "confidence": 1.0, "tags": ["dead-code"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "scripts/generate-radio-dia2.py:82"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-2c1aea99a47a9966", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/Nav.tsx:313"}, "properties": {"repobilityId": "251c2cb9a9fd31b2", "scanner": "scanner-primary", "fingerprint": "2c1aea99a47a9966", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-e40f570e670f502e", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/RadioStation.tsx:456"}, "properties": {"repobilityId": "ced845faf9a5c86e", "scanner": "scanner-primary", "fingerprint": "e40f570e670f502e", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-8f4909cac64de03a", "level": "note", "message": {"text": "\"active\" state uses light bg in a dark theme \u2014 Website/src/components/RadioStation.tsx:444"}, "properties": {"repobilityId": "7102d2fd94bc4a65", "scanner": "scanner-primary", "fingerprint": "8f4909cac64de03a", "layer": "frontend", "severity": "low", "confidence": 1.0, "tags": ["frontend-quality", "fq.active-light-bg"]}}, {"ruleId": "scanner-e6cee4afe7f71576", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/Breakdowns.tsx:52"}, "properties": {"repobilityId": "7e296f6faaa66e8e", "scanner": "scanner-primary", "fingerprint": "e6cee4afe7f71576", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-c88dcd92f9580cee", "level": "none", "message": {"text": "`truncate` class without `title=` for hover reveal \u2014 Website/src/components/Traffic.tsx:97"}, "properties": {"repobilityId": "b230a1bc900e286c", "scanner": "scanner-primary", "fingerprint": "c88dcd92f9580cee", "layer": "frontend", "severity": "info", "confidence": 1.0, "tags": ["frontend-quality", "fq.truncate.no-title"]}}, {"ruleId": "scanner-f9cefc7db21e015c", "level": "warning", "message": {"text": "Insecure pattern 'cors_wildcard' in worker/src/index.ts:18"}, "properties": {"repobilityId": "220f871ca200fb74", "scanner": "scanner-primary", "fingerprint": "f9cefc7db21e015c", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["owasp", "cors_wildcard"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": "worker/src/index.ts"}, "region": {"startLine": 18}}}]}, {"ruleId": "scanner-6372cebde0220094", "level": "warning", "message": {"text": "No auth library detected"}, "properties": {"repobilityId": "a5b6035a5bbf8054", "scanner": "scanner-primary", "fingerprint": "6372cebde0220094", "layer": "security", "severity": "medium", "confidence": 1.0, "tags": ["coverage", "auth"]}}, {"ruleId": "scanner-24a2353e77881d9e", "level": "warning", "message": {"text": "GitHub Actions workflow grants broad write permissions"}, "properties": {"repobilityId": "f80a287fd6f6b355", "scanner": "scanner-primary", "fingerprint": "24a2353e77881d9e", "layer": "cicd", "severity": "medium", "confidence": 1.0, "tags": ["supply-chain", "github-actions", "least-privilege"]}, "locations": [{"physicalLocation": {"artifactLocation": {"uri": ".github/workflows/deploy-website.yml"}, "region": {"startLine": 1}}}]}, {"ruleId": "scanner-6893a6c8b0861585", "level": "warning", "message": {"text": "Very low test-to-source ratio"}, "properties": {"repobilityId": "54a7de3f06314bf0", "scanner": "scanner-primary", "fingerprint": "6893a6c8b0861585", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["tests", "coverage"]}}, {"ruleId": "scanner-141b30a41e03817b", "level": "note", "message": {"text": "No license file detected"}, "properties": {"repobilityId": "64d198ee43296cc3", "scanner": "scanner-primary", "fingerprint": "141b30a41e03817b", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["license", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-3ab5d313dda8e5f9", "level": "note", "message": {"text": "Debug logging residue appears in source files"}, "properties": {"repobilityId": "3bf6dbc47746d56f", "scanner": "scanner-primary", "fingerprint": "3ab5d313dda8e5f9", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["debug", "cleanup", "repo-hardening", "generated-repo-pattern"]}}, {"ruleId": "scanner-2d0c7b7ab8f8aacf", "level": "warning", "message": {"text": "Critical user flow still appears backed by mock or placeholder data"}, "properties": {"repobilityId": "2daff9355adceb96", "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": "863080f68d9d09c9", "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": "01278a1556239ab1", "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": "4bbfe52cf55b9863", "scanner": "scanner-primary", "fingerprint": "8424db9c75e04ba4", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["provenance", "git-history", "generated-repo-pattern"]}}, {"ruleId": "scanner-ed26c54e172bd208", "level": "none", "message": {"text": "Commented-code block (5 lines) in Website/scripts/gen-worldgeo.mjs:1"}, "properties": {"repobilityId": "e45d76b6d2f44db4", "scanner": "scanner-primary", "fingerprint": "ed26c54e172bd208", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-1bea1d76ae84f27b", "level": "none", "message": {"text": "Commented-code block (5 lines) in Website/src/components/RadioStation.tsx:199"}, "properties": {"repobilityId": "18bc702e06d029d7", "scanner": "scanner-primary", "fingerprint": "1bea1d76ae84f27b", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-e54d5e1d94f59a0b", "level": "none", "message": {"text": "Commented-code block (5 lines) in Website/src/components/useRadioAudio.ts:112"}, "properties": {"repobilityId": "976e4922d27439c9", "scanner": "scanner-primary", "fingerprint": "e54d5e1d94f59a0b", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-a4a2b1088b7d378f", "level": "warning", "message": {"text": "Network/subprocess call without timeout or try/except \u2014 scripts/render-post.py:93"}, "properties": {"repobilityId": "0253572fa763392e", "scanner": "scanner-primary", "fingerprint": "a4a2b1088b7d378f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-a80d009ba226101f", "level": "none", "message": {"text": "Commented-code block (5 lines) in scripts/generate-radio.py:300"}, "properties": {"repobilityId": "664e0dc386abf8e4", "scanner": "scanner-primary", "fingerprint": "a80d009ba226101f", "layer": "quality", "severity": "info", "confidence": 1.0, "tags": ["integrity", "commented-code", "dead-code"]}}, {"ruleId": "scanner-a60dfb09db42c148", "level": "warning", "message": {"text": "Network/subprocess call without timeout or try/except \u2014 scripts/generate-radio.py:272"}, "properties": {"repobilityId": "d8c3e6210d25db94", "scanner": "scanner-primary", "fingerprint": "a60dfb09db42c148", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-0fe9f39e7a3eb831", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 worker/scripts/populate-traffic.mjs:27"}, "properties": {"repobilityId": "548ba428790fdfc6", "scanner": "scanner-primary", "fingerprint": "0fe9f39e7a3eb831", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-51c4e577bc53750f", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 worker/scripts/populate.mjs:34"}, "properties": {"repobilityId": "fc5e2e9716f36728", "scanner": "scanner-primary", "fingerprint": "51c4e577bc53750f", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-1f614fa6f0acfbb7", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 worker/src/routes/ghstats.ts:77"}, "properties": {"repobilityId": "a187be4989ae578b", "scanner": "scanner-primary", "fingerprint": "1f614fa6f0acfbb7", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-4357957fb15f2863", "level": "warning", "message": {"text": "`fetch()` without try/.catch or AbortSignal \u2014 worker/src/routes/analytics.ts:77"}, "properties": {"repobilityId": "451a4a8b9458099e", "scanner": "scanner-primary", "fingerprint": "4357957fb15f2863", "layer": "quality", "severity": "medium", "confidence": 1.0, "tags": ["integrity", "fragile-runtime", "robustness"]}}, {"ruleId": "scanner-8e047ab7af03962f", "level": "note", "message": {"text": "7 env vars used in code but missing from .env.example"}, "properties": {"repobilityId": "5a0455f6498c27ad", "scanner": "scanner-primary", "fingerprint": "8e047ab7af03962f", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "config-drift"]}}, {"ruleId": "scanner-2c04133e54348533", "level": "note", "message": {"text": "Near-duplicate function bodies in 2 places"}, "properties": {"repobilityId": "121c5cbdfc4a919a", "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": "cb27f5507b20946b", "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": "5e143a05f9ce143c", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-49c98f7cedd9c977", "level": "note", "message": {"text": "Near-duplicate function bodies in 4 places"}, "properties": {"repobilityId": "772313674dadef8f", "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": "54c78df3ea3e2d7d", "scanner": "scanner-primary", "fingerprint": "2c04133e54348533", "layer": "quality", "severity": "low", "confidence": 1.0, "tags": ["integrity", "duplicate", "dry"]}}, {"ruleId": "scanner-77821f4749e69d3f", "level": "error", "message": {"text": "Dangling fetch: POST https://api.cloudflare.com/client/v4/graphql (worker/scripts/populate-traffic.mjs:27)"}, "properties": {"repobilityId": "fd22345b99d6eb08", "scanner": "scanner-primary", "fingerprint": "77821f4749e69d3f", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-c62495d35926d60c", "level": "error", "message": {"text": "Dangling fetch: GET https://api.cloudflare.com/client/v4/zones?per_page=50&status=active (worker/scripts/populate-traffic.mjs:41)"}, "properties": {"repobilityId": "476dd4d643c5e69a", "scanner": "scanner-primary", "fingerprint": "c62495d35926d60c", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-0a108305a8684124", "level": "error", "message": {"text": "Dangling fetch: POST https://api.github.com/graphql (worker/scripts/populate.mjs:34)"}, "properties": {"repobilityId": "ceb9b314391ef664", "scanner": "scanner-primary", "fingerprint": "0a108305a8684124", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-818eba3367444a8f", "level": "error", "message": {"text": "Dangling fetch: GET https://lunarportfolio.com/rss.xml (Website/src/components/LunarArticles.tsx:38)"}, "properties": {"repobilityId": "c30b504bf3a6c986", "scanner": "scanner-primary", "fingerprint": "818eba3367444a8f", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-27f492dcff3cfc73", "level": "error", "message": {"text": "Dangling fetch: POST https://api.github.com/graphql (worker/src/routes/ghstats.ts:77)"}, "properties": {"repobilityId": "8730c4fa7d9ed59d", "scanner": "scanner-primary", "fingerprint": "27f492dcff3cfc73", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-3927a507e1478d78", "level": "error", "message": {"text": "Dangling fetch: POST https://api.cloudflare.com/client/v4/graphql (worker/src/routes/analytics.ts:77)"}, "properties": {"repobilityId": "61425623d8311b60", "scanner": "scanner-primary", "fingerprint": "3927a507e1478d78", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-5af750c624b1a53c", "level": "error", "message": {"text": "Dangling fetch: GET https://api.cloudflare.com/client/v4/zones?per_page=50&status=active (worker/src/routes/analytics.ts:95)"}, "properties": {"repobilityId": "9cf4e99ab78e195d", "scanner": "scanner-primary", "fingerprint": "5af750c624b1a53c", "layer": "api", "severity": "high", "confidence": 1.0, "tags": ["wiring", "dangling-fetch", "fetch"]}}, {"ruleId": "scanner-b3009f31646c769d", "level": "note", "message": {"text": "Unused endpoint: USE /api/radio-save"}, "properties": {"repobilityId": "6676cf4745eab9cf", "scanner": "scanner-primary", "fingerprint": "b3009f31646c769d", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-bf1fb796885f0a7e", "level": "note", "message": {"text": "Unused endpoint: GET /ghstats"}, "properties": {"repobilityId": "81be8a120856013c", "scanner": "scanner-primary", "fingerprint": "bf1fb796885f0a7e", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-5baa8971ebe192a1", "level": "note", "message": {"text": "Unused endpoint: GET /"}, "properties": {"repobilityId": "3d603600888770b3", "scanner": "scanner-primary", "fingerprint": "5baa8971ebe192a1", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}, {"ruleId": "scanner-4629fc2f2a182ac9", "level": "note", "message": {"text": "Unused endpoint: GET /analytics"}, "properties": {"repobilityId": "31ae1ce2e93283af", "scanner": "scanner-primary", "fingerprint": "4629fc2f2a182ac9", "layer": "api", "severity": "low", "confidence": 1.0, "tags": ["wiring", "unused-endpoint"]}}]}]}