Skip to content

Versioned JSON result contract (v1) - #95

Merged
james-d12 merged 4 commits into
mainfrom
feature/json-result-contract-66
Oct 13, 2026
Merged

james-d12 merged 4 commits into
mainfrom
feature/json-result-contract-66

Conversation

@james-d12

Copy link
Copy Markdown
Owner

Closes #66

Summary

validate --format json no longer serialises the internal ValidationResult. It writes an explicit, versioned ValidationReportV1 DTO (CodeGuard.Reporting/Contracts/), built by ValidationReportMapper.ToV1.

  • Adds schemaVersion ("1.0"), toolVersion, durationMs, and a metrics block.
  • status keeps the existing values: passed, failed, partiallyEvaluated.
  • Publishes a JSON Schema (draft 2020-12) at CodeGuard.Reporting/Schemas/validation-report.v1.schema.json, embedded as a resource. Every object has additionalProperties: false.
  • Tests validate real reporter output against the schema: with violations, with none, and with evaluation errors and analysis warnings. A separate test checks that the schema is itself valid Draft 2020-12.
  • Docs: docs/architecture/RESULT_CONTRACT.md (shape, field meanings, versioning policy), linked from docs/USAGE.md and docs/README.md.

This is a breaking change to --format json. The rule counts (rulesEvaluated, rulesPassed, rulesFailed, rulesErrored) moved under metrics. Violation and error field names are unchanged.

Sample output

{
  "schemaVersion": "1.0",
  "toolVersion": "0.1.4-alpha.0.27",
  "status": "failed",
  "evaluatedAtUtc": "2026-10-13T14:42:10.7202958+00:00",
  "durationMs": 6705,
  "metrics": {
    "rulesEvaluated": 11,
    "rulesPassed": 7,
    "rulesFailed": 4,
    "rulesErrored": 0,
    "violationCount": 4,
    "violationsBySeverity": { "info": 0, "warning": 0, "error": 3, "critical": 1 },
    "evaluationErrorCount": 0,
    "analysisWarningCount": 0
  },
  "violations": [ { "ruleId": "DDD-ENTITY-001", "ruleVersion": 1, "severity": "error", "...": "..." } ],
  "evaluationErrors": [],
  "analysisWarnings": []
}

Design decisions

  • Status is derived from the post---severity-threshold result, the same as before. It describes the report, not the exit code. --fail-on can still give exit 0 with status: "failed".
  • durationMs is an integer, measured from the start of the validate action until just before the report is written. Library callers that do not measure get 0.
  • toolVersion comes from the CLI assembly's informational version with the +commit suffix stripped. Reporting cannot read it itself because MinVer is only on the CLI project.
  • Duration and version are passed through the JsonViolationReporter constructor, not IViolationReporter.WriteAsync, so the other reporters are untouched.
  • Enums map through explicit switch expressions, so renaming an internal enum member cannot change the wire format.
  • Optional fields (file, line, symbol, ...) are omitted when unknown, as before. line/column may be 0 for unknown locations, so the schema allows 0.

Not in v1 (deferred)

From roadmap section 15: rulesVersion, repository, commit, branch, and a separate timestamp. Also not included: projects and types analysed. None of these is on ValidationResult, so they need run context passed into the reporter.

Test plan

  • dotnet build: 0 errors, 0 warnings
  • dotnet test: 945 passed (1 + 220 + 49 + 460 + 7 + 117 + 67 + 24 across 8 projects)
  • dotnet format --verify-no-changes: clean
  • validate --format json on the integration fixture: output shape confirmed by hand
  • Independent JSON Schema validator run on CLI output (none installed locally; covered by the in-repo schema tests)

🤖 Generated with Claude Code

https://claude.ai/code/session_01Xouw37Lmze9pVQhpCJZKix

james-d12 and others added 3 commits October 13, 2026 15:44
JsonViolationReporter now serialises an explicit ValidationReportV1 DTO built by ValidationReportMapper, instead of the internal ValidationResult. The output gains schemaVersion, toolVersion, durationMs and a metrics block. Status keeps its existing wire values. A JSON Schema (draft 2020-12) is embedded in CodeGuard.Reporting and reporter output is tested against it. This is a breaking change to --format json: the rule counts moved under metrics.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Xouw37Lmze9pVQhpCJZKix
Adds docs/architecture/RESULT_CONTRACT.md, links it from the docs index and USAGE, records the design in IMPLEMENTATION_STATUS, and narrows the open result-contract item in the docs index to CI governance.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>

Claude-Session: https://claude.ai/code/session_01Xouw37Lmze9pVQhpCJZKix
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xouw37Lmze9pVQhpCJZKix
@james-d12
james-d12 force-pushed the feature/json-result-contract-66 branch from b9cc1dc to 323f5ee Compare October 13, 2026 14:45
@james-d12
james-d12 enabled auto-merge (squash) October 13, 2026 19:27
@sonarqubecloud

Copy link
Copy Markdown

@james-d12
james-d12 merged commit 8578fc5 into main Oct 13, 2026
5 checks passed
@james-d12
james-d12 deleted the feature/json-result-contract-66 branch October 13, 2026 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Versioned JSON result contract (v1)

1 participant