14

Report schema

The JSON ProjectReport produced by --json, field by field

3 min read5 sections

cleanlens --json prints a ProjectReport. The types are defined in src/types/index.ts. This document describes every field.

ProjectReport

FieldTypeDescription
schemaVersionnumber2 for the commit-diff engine
generatedAtstring (ISO 8601)When the report was created
engine"commit-diff"Attribution engine used ("head-blame" was the old one)
analysisConfigHashstringHash of rules + excludes + scoring (also the cache key); equal hashes mean comparable reports
developerCountnumberNumber of developers after identity merging
totalViolationsnumberViolations in the current code
unattributedViolationsnumberViolations whose file could not be read
analyzedFilesnumberFiles analyzed in the HEAD scan
analyzedCommitsnumberCommits replayed
developersDeveloper[]See below
violationsViolation[]See below, sorted by severity, then path, then line

Developer

FieldTypeDescription
idstringdev-1, dev-2, … by commit count. Only stable within one report. Match developers across reports by emails.
displayNamestringName (merged names are joined with -)
emailsstring[]Lowercased author emails
cleanCodeScorenumber | null0–100, rounded; null = no analyzed code
scoreExactnumber | nullUnrounded score
scoreByCategoryobject{ duplication, structure, hygiene }, each { density, subScore }; density is after shrinkage
violationCountnumberIntroduced violations with high/medium confidence
weightedViolationPointsnumberΣ weights of those violations
analyzedLinesnumberLines added/changed in analyzed commits
attributedCodeLinesnumberSame value (historical name)
violationDensitynumberWeighted points per KLOC, before shrinkage
confidenceLevelinsufficient | provisional | reliable | highly_reliableFrom analyzed lines
rankablebooleanHas a score and enough lines to be ranked
contributionPercentnumber 0–1Share of all analyzed lines
breakdownobjectSee below
activeDaysnumberDistinct UTC days with a commit (whole history)
firstContribution, lastContributionstring (ISO)First/last commit date (whole history)

breakdown

FieldDescription
introducedIntroduced violations with high/medium confidence (same as violationCount)
fixedViolations removed by their commits
existingPre-existing violations in files they changed (informational)
excludedAlways 0 at developer level (kept for schema stability)
unattributedViolations their commits made unanalyzable (informational)
introducedWeightedΣ weights of introduced
fixedWeightedΣ weights of fixed
netQualityImpactintroducedWeighted − fixedWeighted (positive = more debt added than removed)

Remember that introduced and fixed are historical counts over the analyzed commits, while violations[] lists only what is in the code now.

Violation

FieldTypeDescription
idstringHash of rule + path + line + message; unique within the report
ruleIdstringOne of the 14 rule ids
messagestringHuman-readable detail, e.g. Function load has 58 lines (limit 40).
severitycritical | high | medium | lowFrom the rule config
weightnumberSeverity weight
categoryduplication | structure | hygiene
filePathstringRepo-relative, forward slashes
startLine, endLinenumber1-based; endLine may be absent
symbolNamestring?Enclosing function/class
fingerprintstringStable identity (see 07)
statusintroduced | existing | fixed | excluded | unattributedAttribution status
confidencehigh | medium | lowAttribution confidence
developerIdstring?The developer it is scored against (only high/medium)
introducedBystring?The developer whose commit introduced it (any confidence)
introducedCommitstring?Commit hash
introducedAtstring?Commit author date (ISO)
source"internal"Always internal today (eslint, ruff, pylint are reserved)

Example

json
{
  "schemaVersion": 2,
  "generatedAt": "2026-09-30T10:12:44.120Z",
  "engine": "commit-diff",
  "analysisConfigHash": "1x9k2ab",
  "developerCount": 2,
  "totalViolations": 1,
  "unattributedViolations": 0,
  "analyzedFiles": 12,
  "analyzedCommits": 40,
  "developers": [
    {
      "id": "dev-1",
      "displayName": "Alice",
      "emails": ["alice@example.com"],
      "cleanCodeScore": 82,
      "scoreExact": 81.7,
      "scoreByCategory": {
        "duplication": { "density": 0.8, "subScore": 95 },
        "structure": { "density": 9.1, "subScore": 82 },
        "hygiene": { "density": 12.4, "subScore": 72 }
      },
      "violationCount": 9,
      "weightedViolationPoints": 27,
      "analyzedLines": 2400,
      "attributedCodeLines": 2400,
      "violationDensity": 11.25,
      "confidenceLevel": "reliable",
      "rankable": true,
      "contributionPercent": 0.8,
      "breakdown": {
        "introduced": 9, "existing": 3, "fixed": 4, "excluded": 0, "unattributed": 0,
        "introducedWeighted": 27, "fixedWeighted": 10, "netQualityImpact": 17
      },
      "activeDays": 21,
      "firstContribution": "2026-05-02T09:00:00+03:00",
      "lastContribution": "2026-09-28T17:40:00+03:00"
    }
  ],
  "violations": [
    {
      "id": "k2j3h1",
      "ruleId": "maxComplexity",
      "message": "Function parse has complexity 14 (limit 10).",
      "severity": "high",
      "weight": 5,
      "category": "structure",
      "filePath": "src/parser.ts",
      "startLine": 40,
      "endLine": 96,
      "symbolName": "parse",
      "fingerprint": "1a2b3c",
      "status": "introduced",
      "confidence": "high",
      "developerId": "dev-1",
      "introducedBy": "dev-1",
      "introducedCommit": "3f9e1c…",
      "introducedAt": "2026-08-14T11:02:00+03:00",
      "source": "internal"
    }
  ]
}

(Values are illustrative.)

Useful queries with jq

bash
# Scores, lowest first
jq -r '.developers | sort_by(.cleanCodeScore) | .[] | "\(.cleanCodeScore)\t\(.displayName)"' report.json

# Critical violations and who introduced them
jq -r '.violations[] | select(.severity=="critical") | "\(.filePath):\(.startLine)\t\(.introducedBy // "-")"' report.json

# Violation count per rule
jq -r '.violations | group_by(.ruleId) | map("\(length)\t\(.[0].ruleId)") | .[]' report.json