Report schema
The JSON ProjectReport produced by --json, field by field
cleanlens --json prints a ProjectReport. The types are defined in
src/types/index.ts. This document describes every field.
ProjectReport
| Field | Type | Description |
|---|---|---|
schemaVersion | number | 2 for the commit-diff engine |
generatedAt | string (ISO 8601) | When the report was created |
engine | "commit-diff" | Attribution engine used ("head-blame" was the old one) |
analysisConfigHash | string | Hash of rules + excludes + scoring (also the cache key); equal hashes mean comparable reports |
developerCount | number | Number of developers after identity merging |
totalViolations | number | Violations in the current code |
unattributedViolations | number | Violations whose file could not be read |
analyzedFiles | number | Files analyzed in the HEAD scan |
analyzedCommits | number | Commits replayed |
developers | Developer[] | See below |
violations | Violation[] | See below, sorted by severity, then path, then line |
Developer
| Field | Type | Description |
|---|---|---|
id | string | dev-1, dev-2, … by commit count. Only stable within one report. Match developers across reports by emails. |
displayName | string | Name (merged names are joined with -) |
emails | string[] | Lowercased author emails |
cleanCodeScore | number | null | 0–100, rounded; null = no analyzed code |
scoreExact | number | null | Unrounded score |
scoreByCategory | object | { duplication, structure, hygiene }, each { density, subScore }; density is after shrinkage |
violationCount | number | Introduced violations with high/medium confidence |
weightedViolationPoints | number | Σ weights of those violations |
analyzedLines | number | Lines added/changed in analyzed commits |
attributedCodeLines | number | Same value (historical name) |
violationDensity | number | Weighted points per KLOC, before shrinkage |
confidenceLevel | insufficient | provisional | reliable | highly_reliable | From analyzed lines |
rankable | boolean | Has a score and enough lines to be ranked |
contributionPercent | number 0–1 | Share of all analyzed lines |
breakdown | object | See below |
activeDays | number | Distinct UTC days with a commit (whole history) |
firstContribution, lastContribution | string (ISO) | First/last commit date (whole history) |
breakdown
| Field | Description |
|---|---|
introduced | Introduced violations with high/medium confidence (same as violationCount) |
fixed | Violations removed by their commits |
existing | Pre-existing violations in files they changed (informational) |
excluded | Always 0 at developer level (kept for schema stability) |
unattributed | Violations their commits made unanalyzable (informational) |
introducedWeighted | Σ weights of introduced |
fixedWeighted | Σ weights of fixed |
netQualityImpact | introducedWeighted − 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
| Field | Type | Description |
|---|---|---|
id | string | Hash of rule + path + line + message; unique within the report |
ruleId | string | One of the 14 rule ids |
message | string | Human-readable detail, e.g. Function load has 58 lines (limit 40). |
severity | critical | high | medium | low | From the rule config |
weight | number | Severity weight |
category | duplication | structure | hygiene | |
filePath | string | Repo-relative, forward slashes |
startLine, endLine | number | 1-based; endLine may be absent |
symbolName | string? | Enclosing function/class |
fingerprint | string | Stable identity (see 07) |
status | introduced | existing | fixed | excluded | unattributed | Attribution status |
confidence | high | medium | low | Attribution confidence |
developerId | string? | The developer it is scored against (only high/medium) |
introducedBy | string? | The developer whose commit introduced it (any confidence) |
introducedCommit | string? | Commit hash |
introducedAt | string? | Commit author date (ISO) |
source | "internal" | Always internal today (eslint, ruff, pylint are reserved) |
Example
{
"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
# 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