Skip to main content

Code Quality Audit 2026-07-08 (MC #105042)

Proveo Code Quality Audit — basicfakta

MC #105042 | 2026-07-08 | Audit type: read-only (no code mutations, no deploy, no commits)

Project: /Users/makinja/projects/internal/basicfakta Note: BUILD-BLUEPRINT.md/CLAUDE.md describe this as a plain Node.js/Express serverless app (Vercel functions in api/, vanilla JS in src/), NOT the React/Next.js/TS stack implied in the dispatch description. Tests are hand-rolled Node scripts (no Jest), so "coverage" comes from c8 (Istanbul), not a framework-native coverage command.

Verdict: CONCERNS

No blocking defects — 0 lint errors, 0 type errors, all 139 tests pass. "CONCERNS" reflects real coverage gaps in security/data-layer code and a large amount of high-complexity, hard-to-maintain logic (esp. one 36-complexity, 270-line function) that should be refactored before this codebase grows further.


1. Lint

Command: npm run lint (eslint src tests) Result: 0 errors, 35 warnings, exit code 0. Full output: lint-output.txt

Breakdown by rule:

Rule Count
quotes (must use singlequote) 25 — all in tests/run-manual-tests.js (orphaned file, see §3)
no-unused-vars 7 (analyzer.js x2, heuristics.js, security.js, server.js, ssb-verifier.js, heuristics.test.js, unit-deep.test.js)
no-useless-escape 2 (heuristics.js regex patterns)

No errors anywhere. All fixable via --fix (eslint reports 25 auto-fixable).

2. Type check / Complexity

Command: npm run typecheck (tsc --noEmit) Result: clean, exit code 0, no output. Full output: typecheck-output.txt

Caveat (material): tsconfig.json has "checkJs": false and "strict": false, and include is scoped to src/**/*.js only (excludes api/, tests/). With checkJs: false, tsc does NOT type-check JS file bodies — this run only confirms the files parse as valid syntax. It is not meaningful type-safety verification. If real type coverage is wanted, checkJs: true needs enabling (out of scope for this read-only audit — flagging as a finding, not fixing).

Complexity (measured via one-off npx eslint --rule '{"complexity":["warn",10],...}' override, read-only, no config file changed). Full output: complexity-output.txt.

Top 10 most complex functions:

# Function File:line Complexity Lines
1 analyzeHeuristics src/heuristics.js:507 36 270
2 combineResults src/analyzer.js:576 29 120
3 analyzeText src/analyzer.js:231 23 151
4 getStats src/database.js:72 23
5 fetchTableData src/ssb-verifier.js:240 22
6 isPrivateIP src/url-extractor.js:28 18
7 extractWebPageContent src/url-extractor.js:272 17
8 extractYouTubeContent src/url-extractor.js:138 16
9 detectLanguage src/language-detector.js:58 15
10 runAllTests tests/run-tests.js:66 14 — (orphaned file, §3)

Also flagged: parseAIResponse (analyzer.js:505, complexity 11), an anonymous arrow fn (analyzer.js:519, complexity 19), verifyClaim (ssb-verifier.js:303, complexity 12), validateURL (url-extractor.js:63, complexity 12), one 5-deep nested block (ssb-verifier.js:267, max-depth 5 vs limit 4).

Largest files by LOC: heuristics.js (847), analyzer.js (717), ssb-verifier.js (500), url-extractor.js (381), middleware/security.js (372).

analyzeHeuristics, combineResults, and analyzeText are the three core pipeline functions and all exceed complexity 20 — these are the priority refactor candidates (see fix list).

3. Dead code detection

Ran both ts-prune and knip --no-config-hints (one-off npx, no devDependency added to repo). Full outputs: ts-prune-output.txt, knip-output.txt (also captured in deadcode-output.txt).

ts-prune (scoped to tsconfig's src/**/*.js include, so misses api/ and tests/): 10 items reported, but all are "(used in module)" — i.e. exported but only consumed inside their own file. These are export-hygiene items (could be de-exported), not actual dead code.

knip (wider scan, more useful signal here) reported:

  • Unused files (7): api/analyze.js, api/feedback.js, api/health.js, src/sentry.js, src/url-extractor.js, tests/run-manual-tests.js, tests/run-tests.js
    • False positives, verified by grep: the 3 api/*.js files are Vercel serverless entry points invoked by the platform router (per vercel.json rewrites), not imported by other modules — knip has no visibility into that root. src/sentry.js and src/url-extractor.js are both required by api/analyze.js (confirmed: grep -rn "require.*sentry" api/analyze.js and grep -rln "require.*url-extractor" api both hit) — knip misses this because it doesn't trace api/ as an entry root either.
    • Genuine findings: tests/run-manual-tests.js and tests/run-tests.js are NOT referenced by any package.json script, CI workflow, or other source file (grep confirmed empty). Superseded by tests/unit-deep.test.js / tests/heuristics.test.js per naming and content overlap. Safe deletion candidates.
  • Unused dependency (1): @sentry/node in package.json — flagged unused by knip's dependency graph, but this is also a false positive: src/sentry.js (line uses it) is itself only reached via the untraced api/ root, so the whole chain is invisible to knip. Do not remove.
  • Unused exports (27): concentrated in src/middleware/security.js (11 exports), src/rate-limiter.js (5), src/ssb-verifier.js (5), src/database.js (4), src/analyzer.js (2). Same caveat — many of these ARE used by api/*.js files knip can't see as roots. Not verified individually line-by-line (out of timebox); treat as "needs manual triage," not "confirmed dead."

Net dead-code finding with highest confidence: 2 orphaned test files (tests/run-manual-tests.js, tests/run-tests.js, ~11KB combined) plus their 25 lint warnings — both the code and its lint noise disappear if deleted.

4. Test coverage

Three test suites, all passing:

Suite Command Result
Heuristics npm test 50/50 passed
Unit-deep npm run test:unit 62/62 passed
API integration npm run test:api 27/27 passed
Total 139/139 passed, 0 failures

e2e (npm run test:e2e, Playwright) skipped per timebox instruction — unit+integration coverage sufficient for this audit; explicitly noting the skip, not silently omitting it.

Coverage (coverage/coverage-summary.json, file mtime 2026-07-01 — regenerated fresh during this audit via npx c8 over heuristics.test.js + unit-deep.test.js combined, and the numbers reproduced exactly match the existing file, so the "staleness" is cosmetic — the underlying source hasn't changed since Jul 1 in a way that would move these numbers):

Metric %
Statements 66.94
Lines 66.94
Branches 84.54
Functions 61.11

Per-file (only files touched by these two suites appear in the report — api/*.js, src/server.js, src/database.js, src/emailer.js, src/sentry.js are 0% / not instrumented at all, since api-integration.test.js tests API logic without importing the handler modules under c8):

10 worst-covered files (lines %, lowest first; only instrumented files listed):

File Lines % Functions % Branches %
src/analyzer.js 45.18 44.44 23.8
src/ssb-verifier.js 49.8 33.33 85.71
src/middleware/security.js 46.77 38.46 89.28
src/heuristics.js 94.33 100 93.27
src/rate-limiter.js 92.89 100 85.71
src/language-detector.js 97.05 100 87.5
Not instrumented (0%, no coverage data): api/analyze.js, api/feedback.js, api/health.js, src/server.js, src/database.js, src/emailer.js, src/sentry.js, src/url-extractor.js

analyzer.js, ssb-verifier.js, and middleware/security.js are the three weakest-covered files that DO have partial coverage — and two of them (analyzer.js, security.js) also contain the highest-complexity functions found in §2. High complexity + low coverage is the same code twice.


Top 5 Prioritized Issues

  1. analyzer.js combines the highest complexity in the codebase with the lowest coverage. combineResults (complexity 29) and analyzeText (complexity 23, the main pipeline entry) sit in a file at only 45.18% line / 23.8% branch coverage. This is the analysis pipeline's core — the least-tested, hardest-to-reason-about code is exactly where a regression would be most costly. Priority: add branch-level tests for the AI/heuristic-fallback paths, then refactor combineResults and analyzeText to extract sub-functions (target complexity <15 each).

  2. analyzeHeuristics (heuristics.js:507) has complexity 36 across 270 lines — the single highest-complexity function found. Coverage is good (94.33%) so behavior is protected, but maintainability is poor: any future pattern addition risks unintended interaction with existing branches. Recommend decomposing into per-category scoring functions before adding more patterns.

  3. security.js (auth/input-validation middleware) is only 46.77% line-covered and 38.46% function-covered, with 11 flagged (possibly-unused, needs manual triage) exports. Security middleware being the least-tested layer is a QA risk independent of the dead-code ambiguity — recommend a dedicated test pass on sanitize, validateAnalyzeInput, errorHandler, and corsConfig before touching complexity/dead-code cleanup here.

  4. typecheck is a no-op safety net. checkJs: false + strict: false means tsc --noEmit only validates syntax, not types — "0 type errors" in this report should not be read as "no type-related bugs." If type-safety is actually wanted here, enabling checkJs: true (as an incremental, separately-scoped change) would surface real signal; right now the script name is misleading about what it verifies.

  5. 2 orphaned test files (tests/run-manual-tests.js, tests/run-tests.js) contribute 25 of the 35 total lint warnings (all quotes) and are not wired into any script/CI. Low-risk, low-effort cleanup: delete both files, re-run lint to confirm warning count drops from 35→~9. (Note: api/*.js, src/sentry.js, src/url-extractor.js, and the 27 "unused exports" flagged by knip are NOT safe to delete — verified as false positives/needing manual triage, see §3.)


Evidence files (all under ~/system/evidence/105042/)

  • audit-report.md — this file
  • lint-output.txt — full npm run lint output
  • typecheck-output.txt — full npm run typecheck output
  • complexity-output.txt — eslint with complexity/max-depth/max-lines-per-function rules
  • deadcode-output.txt, ts-prune-output.txt, knip-output.txt — dead code detection raw outputs
  • coverage-summary.txt — copy of project's coverage/coverage-summary.json
  • coverage-run-output.txt — fresh c8 run, unit-deep suite only
  • coverage-combined-output.txt — fresh c8 run, heuristics + unit-deep combined (reproduces the committed coverage-summary.json exactly)
  • test-unit-run-output.txt, test-heuristics-output.txt, test-api-output.txt — full test logs for all 3 suites (139/139 passed)