RFC 0054 — Structured Diagnostics Contract and Reporting
- Issue: #54
- Status: Proposed
- Owner: @JerrettDavis/agent-jarvis
- Last updated: 2026-03-27
1) Summary
Define a single diagnostics contract used across WrapGod pipeline stages (extract, plan, generate, analyze, fix), with clear severity semantics, CLI exit-code behavior, and deterministic mapping to SARIF.
This RFC standardizes:
- A canonical JSON diagnostic schema (
wg.diagnostic.v1) - Diagnostic code catalog classes and ownership (
WG1xxx,WG2xxx,WG3xxx, plus existing legacy classes) - Severity and policy model (
error|warning|note|none) - CLI exit-code policy for automation and CI
- SARIF mapping guidance (
SARIF 2.1.0)
2) Goals and non-goals
Goals
- One machine-readable model for all diagnostics in WrapGod.
- Stable, grep-friendly code taxonomy with documented class ownership.
- Unambiguous mapping from diagnostics to process exit codes.
- First-class CI/security tooling interoperability via SARIF.
- Backward compatibility path for current diagnostics (including
WG2001,WG2002, and config merge codesWG6001-WG6004).
Non-goals
- Full implementation of every formatter/transport in this RFC.
- Deciding every future specific diagnostic code.
- IDE UX policy beyond what naturally follows from Roslyn and SARIF semantics.
3) Terminology
- Diagnostic: One finding emitted by WrapGod tooling.
- Rule/Code: Stable identifier (
WG####) for a diagnostic type. - Stage: Pipeline phase emitting a diagnostic (
extract|plan|generate|analyze|fix|cli|config). - Policy level: Effective severity after config/editorconfig/CLI overrides.
- Report: Aggregate output in console, JSON, or SARIF.
4) Canonical contract (wg.diagnostic.v1)
4.1 Required fields
Each diagnostic record MUST include:
schema(string): exact contract ID, currentlywg.diagnostic.v1code(string): WrapGod code, pattern^WG[0-9]{4}$severity(enum):error|warning|note|nonestage(enum):extract|plan|generate|analyze|fix|cli|configmessage(string): human-readable explanationsource(object): emitter identity (tool, optionalcomponent)location(object|null): file/span context if applicablehelpUri(string|null): documentation URL for this codetimestampUtc(ISO-8601 string)
4.2 Recommended fields
category(string): high-level category (compatibility,migration,typemap,config, etc.)tags(string[]): additional traits (breaking,autofixable,performance)relatedLocations(array): additional source locationsproperties(object): extension bag for machine metadatafingerprint(string): stable dedupe keysuppression(object|null): suppression metadata (kind,justification,source)
4.3 JSON shape (normative draft)
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://wrapgod.dev/schemas/wg.diagnostic.v1.json",
"title": "WrapGod Diagnostic v1",
"type": "object",
"required": [
"schema",
"code",
"severity",
"stage",
"message",
"source",
"timestampUtc"
],
"properties": {
"schema": { "const": "wg.diagnostic.v1" },
"code": { "type": "string", "pattern": "^WG[0-9]{4}$" },
"severity": { "enum": ["error", "warning", "note", "none"] },
"stage": {
"enum": ["extract", "plan", "generate", "analyze", "fix", "cli", "config"]
},
"category": { "type": "string" },
"message": { "type": "string", "minLength": 1 },
"source": {
"type": "object",
"required": ["tool"],
"properties": {
"tool": { "type": "string", "minLength": 1 },
"component": { "type": "string" },
"version": { "type": "string" }
},
"additionalProperties": true
},
"location": {
"type": ["object", "null"],
"properties": {
"uri": { "type": "string" },
"line": { "type": "integer", "minimum": 1 },
"column": { "type": "integer", "minimum": 1 },
"endLine": { "type": "integer", "minimum": 1 },
"endColumn": { "type": "integer", "minimum": 1 },
"symbol": { "type": "string" }
},
"additionalProperties": true
},
"relatedLocations": {
"type": "array",
"items": { "$ref": "#/$defs/location" }
},
"helpUri": { "type": ["string", "null"], "format": "uri" },
"fingerprint": { "type": "string" },
"properties": { "type": "object", "additionalProperties": true },
"suppression": {
"type": ["object", "null"],
"properties": {
"kind": { "enum": ["editorconfig", "pragma", "global", "cli", "baseline"] },
"justification": { "type": "string" },
"source": { "type": "string" }
},
"additionalProperties": true
},
"timestampUtc": { "type": "string", "format": "date-time" }
},
"$defs": {
"location": {
"type": "object",
"properties": {
"uri": { "type": "string" },
"line": { "type": "integer", "minimum": 1 },
"column": { "type": "integer", "minimum": 1 },
"endLine": { "type": "integer", "minimum": 1 },
"endColumn": { "type": "integer", "minimum": 1 },
"symbol": { "type": "string" }
},
"additionalProperties": true
}
},
"additionalProperties": true
}
Note:
relatedLocationsandlocationallow either file-based and symbol-based diagnostics.
5) WG code catalog classes (baseline)
This RFC confirms catalog ownership and code-family semantics.
5.1 Canonical classes in-scope
| Class | Area | Typical stage(s) | Meaning |
|---|---|---|---|
WG1xxx |
Compatibility/versioning | extract, plan, generate |
API compatibility, version diff and contract drift findings |
WG2xxx |
Migration/analyzers | analyze, fix |
Direct usage, migration opportunities, unsafe rewrite blockers |
WG3xxx |
Type mapping | plan, generate, analyze |
Mapping completeness, ambiguity, unsupported conversion patterns |
5.2 Existing/legacy classes retained
| Class | Area |
|---|---|
WG6xxx |
Configuration merge/precedence conflicts (already in docs and code) |
WG6001-WG6004 remain valid and are brought under this contract without renumbering.
5.3 Reservation guidance
To avoid collisions, reserve future bands now:
WG4xxx: generator/template output integrity and deterministic rendering checksWG5xxx: extractor/planner infrastructure/runtime environment diagnosticsWG7xxx: CLI/reporting/automation integration diagnosticsWG8xxx-WG9xxx: reserved for future product areas
6) Severity model
6.1 Effective severities
error: must fail quality gatewarning: actionable but not always failing by defaultnote: informational/suggestionnone: suppressed/not emitted in human-facing channels
6.2 Default severity baseline
- Safety/correctness-breaking findings default to
error - Migration guidance and non-blocking drift default to
warning - Hints/telemetry-style findings default to
note
Overrides MAY come from editorconfig, analyzerconfig, project config, or CLI switches.
7) Exit-code policy (CLI/automation)
7.1 Standard exit codes
0: success; no effectiveerrordiagnostics1: command/runtime failure (exception, bad args, IO failure, infra fault)2: diagnostics gate failed due toerrordiagnostics3: diagnostics gate failed due to warnings when warnings-as-errors is enabled
7.2 Gate evaluation rules
- Apply suppression/override policy to derive effective severities.
- If command fails technically, return
1regardless of diagnostics. - If any effective
errorexists, return2. - Else if
warningsAsErrorspolicy is enabled and any effectivewarningexists, return3. - Else return
0.
7.3 Why split 1 vs 2/3
CI and scripts can distinguish:
- tool/system failures (retry/infrastructure action) vs
- product-quality gate failures (code/config action)
8) SARIF mapping guidance (SARIF 2.1.0)
WrapGod SARIF emitter SHOULD use one run per WrapGod invocation with stable tool.driver.name = "WrapGod".
8.1 Field mapping
| WrapGod field | SARIF target |
|---|---|
code |
result.ruleId |
message |
result.message.text |
severity |
result.level (error -> error, warning -> warning, note -> note) |
helpUri |
tool.driver.rules[].helpUri |
category, tags, properties |
result.properties / rule.properties.tags |
location |
result.locations[0].physicalLocation |
relatedLocations |
result.relatedLocations[] |
fingerprint |
result.fingerprints |
suppression |
result.suppressions[] |
8.2 Rule catalog behavior
- Emit each unique
WG####once intool.driver.rules[]. - Provide
shortDescriptionandfullDescriptionwhere available. - Include deterministic rule metadata (default severity and category).
8.3 URI handling
- Use repository-relative URIs where possible (
src/...) with SARIF base URI support. - Preserve absolute URIs only when required by host environment.
8.4 Interop notes
- Keep
ruleIdexactlyWG####to maintain parity with Roslyn/analyzer UX. - Preserve suppressed diagnostics in SARIF when requested (
--include-suppressed) so governance tooling can audit suppression use.
9) Output format contract
All formats should derive from the same in-memory model:
- Console: human-oriented summary + top diagnostics
- JSON: canonical list of
wg.diagnostic.v1records - SARIF: mapped output for CI/security systems
No formatter may invent data not present in canonical model except presentation-only fields.
10) Backward compatibility
- Existing analyzer IDs (
WG2001,WG2002) are unchanged. - Existing config diagnostics (
WG6001-WG6004) are unchanged. - Any legacy output without
schemashould be wrapped/adapted towg.diagnostic.v1before JSON/SARIF emission.
11) Follow-up implementation issues
- [x] #81 — Implement
wg.diagnostic.v1model + JSON emitter - [x] #82 — Implement SARIF emitter + rule catalog projection
- [x] #83 — Implement CLI gate evaluator and standardized exit codes
- [ ] Adopt contract in extractor/planner/generator/analyzer pipelines
12) Decision
Approve this RFC as the baseline diagnostics contract for MVP. Treat wg.diagnostic.v1 + exit-code policy + SARIF mapping as normative for all new diagnostic-producing features.