diagnostics
Shared type definitions for validation diagnostics, report structures, detail levels, filtering, and performance
metrics. Every reporting crate in the workspace depends on diagnostics - it defines the common language for reporting
validation results, building on the template vocabulary (SourceSpan, JsonValue, EntityType) owned by
template-model and the rule metadata owned by rules.
How It Works
All validation phases (parsing, schema validation, lint rules) surface as Diagnostic values. The schema validator
and rule engines construct them directly; the parser emits plain template_model::ParseDefect findings that
diagnostic_from_parse_defect converts, attaching severity, category, and origin from the rule registry. Each diagnostic carries a
rule ID, severity, message, location, resource context, and optional metadata. The ValidationReport aggregates
diagnostics with summary counts and performance metrics. A report is projected to an output::ValidationReport for
serialization; the requested DetailLevel controls whether per-diagnostic enrichment is populated.
┌─────────────┐ ┌──────────────┐ ┌──────────────────┐
│ Diagnostic │────▶│ FilterConfig │────▶│ ValidationReport │
│ (per-issue) │ │ (include/ │ │ (diagnostics + │
│ │ │ exclude) │ │ summary + │
└─────────────┘ └──────────────┘ │ metadata) │
└──────────────────┘
│
to_report(DetailLevel)
│
▼
output::ValidationReport
Severity
| Level | Ord | Meaning |
|---|---|---|
Fatal |
4 | Structural schema violation - deployment will fail |
Error |
3 | Semantic error - likely deployment failure or incorrect behavior |
Warn |
2 | Security concern, deprecation, or risky pattern |
Info |
1 | Best practice suggestion |
Debug |
0 | Internal diagnostic detail |
Diagnostic
Each Diagnostic contains:
| Field | Type | Purpose |
|---|---|---|
rule_id |
String |
Stable identifier (e.g., E3012, F3003) |
severity |
Severity |
Fatal / Error / Warn / Info / Debug |
message |
String |
Human-readable description |
source |
RuleOrigin |
Where the rule originates (Schema, CfnLint, Engine, etc.) |
entity |
Option<Entity> |
The named template entity the finding targets: logical_id, entity_type (Resource, Parameter, Output, Mapping, Condition, or Rule), and resource_type when the entity is a resource |
property_path |
Option<String> |
JSON path to offending property |
location |
Option<SourceSpan> |
Start/end line and column in source file |
category |
Option<String> |
Rule category (Schema, Structure, Intrinsic Function, etc.) |
suggested_fix |
Option<String> |
Actionable fix suggestion |
documentation_url |
Option<String> |
Link to rule documentation |
rule_description |
Option<String> |
Short description of the rule |
phase |
Option<Phase> |
Validation phase (Parse, Schema, Lint) |
related_resources |
Option<Vec<RelatedResource>> |
Cross-resource references |
condition_scenario |
Option<HashMap<String, bool>> |
Condition truth values that trigger this diagnostic |
context |
Option<ViolationContext> |
Structured violation details (Detailed level only) |
output::Diagnostic
output::Diagnostic is the single flattened public diagnostic model: it keeps the nested entity struct and flattens
location into individual line/column fields. Diagnostic::to_report(DetailLevel) produces it at either detail level.
At Standard the enrichment fields (documentation_url, rule_description, phase, and context) are left None,
so serialization omits them; at Detailed they are populated. Detailed output is therefore a superset of standard
output.
EntityType (defined in template-model alongside TopLevelSection) has one variant per documented template
section - Resource, Parameter, Output, Mapping, Metadata, Rule, Condition, Transform,
FormatVersion, Description - the singular form of the section the entity is declared in. Built-in rules currently
attribute findings to the sections whose children are addressable by a logical ID (resources, parameters, outputs,
mappings, conditions, and template rules).
ViolationContext
| Field | Type | Purpose |
|---|---|---|
actual_value |
Option<JsonValue> |
The value that caused the violation |
expected_constraint |
Option<String> |
What the schema or rule expected |
property |
Option<String> |
Specific property name |
lifecycle |
Option<String> |
Resource lifecycle context |
resolution_source |
Option<String> |
How a value was resolved |
extra |
Option<HashMap<String, JsonValue>> |
Additional structured data |
Report Types
The serialized output::ValidationReport carries: file_path, status (Ok/AnalysisIncomplete/Error), version,
metadata, performance, diagnostics.
ReportMetadata: rules_evaluated, cfn_lint_version, resource_schema_version, resources_scanned, counts
(Summary by severity), suppressed, strict, severity_level, and optional budget_exhaustions. The optional field
is absent when no deterministic budget was exhausted. Each record contains a stable kind, a human-readable
description sentence, the numeric limit, and analysis_incomplete. A false analysis_incomplete value means the
budget curtailed only diagnostic context, so the report can remain Ok; requiredPropertyCombinations is the current
context-only budget. rules_evaluated is 0 when no rules ran.
Source versions use canonical https://github.com/aws-cloudformation/<source>@<version> values.
Detail Level
| Variant | Behavior | Use Case |
|---|---|---|
Standard |
Leaves documentation_url, rule_description, phase, and context unset (omitted) |
IDE annotations, developer workflows |
Detailed |
Populates the same model, including context, phase, and rule_description |
AI agents, deep debugging |
Detailed is the default.
Phase
| Variant | Serde |
|---|---|
Parse |
"PARSE" |
Schema |
"SCHEMA" |
Lint |
"LINT" |
Filtering
FilterConfig supports include and exclude rules, evaluated in order:
- If include filters are non-empty, a diagnostic must match at least one
- Any diagnostic matching an exclude filter is removed
Performance Metrics
PerformanceMetrics tracks duration_ms per pipeline phase: schema_init, engine_init, model_build,
schema_validate, rule_evaluation, diagnostic_finalize, validate_total.