slovo/docs/language/DIAGNOSTICS.md

13 KiB

Slovo Diagnostics

This document defines the 1.0.0-beta.13 beta policy for Slovo machine diagnostics. It documents the existing slovo.diagnostic version 1 schema, the relationship between the S-expression and JSON encodings, the current golden diagnostic code catalog, and the migration rules for changing machine diagnostic fields or codes.

This is a diagnostics policy and catalog slice only. It does not add source language syntax, runtime behavior, stdlib APIs, ABI/layout guarantees, LSP, watch mode, SARIF, daemon protocols, stable Markdown output, or a stable 1.0.0 diagnostics freeze.

Schema Identity

The machine diagnostic schema name is slovo.diagnostic.

The current schema version is 1.

The S-expression form uses a root (diagnostic ...) object:

(diagnostic
  (schema slovo.diagnostic)
  (version 1)
  ...)

The JSON form uses a single JSON object:

{"schema":"slovo.diagnostic","version":1}

The schema name and version belong to the machine contract. Changing either one requires an explicit migration note, release-note entry, and matching Glagol snapshot or JSON fixture updates.

Encodings

S-expression diagnostics and JSON diagnostics are two encodings of the same diagnostic data model. They must not diverge semantically.

The default human diagnostics path may print human-readable prose and then the S-expression machine form for source diagnostics. Human prose, spacing, excerpts, hints, and surrounding text remain beta-flexible unless a later release freezes them explicitly. Tools should consume the machine form, not the human rendering.

--json-diagnostics emits JSON diagnostics on stderr. Each diagnostic is one complete JSON object on one line. There is no JSON array wrapper, no pretty printing, and no required trailing summary object for source failures. Consumers should parse stderr as newline-delimited JSON objects and should treat each line as an independent diagnostic record.

JSON and S-expression escaping must preserve the same string values. JSON uses standard JSON string escaping. S-expression strings use the Glagol diagnostic string escaping convention already used in golden .diag fixtures.

Fields

Every source-attached compiler diagnostic must include these machine fields:

Field S-expression JSON Meaning
Schema (schema slovo.diagnostic) "schema":"slovo.diagnostic" Diagnostic schema name.
Version (version 1) "version":1 Diagnostic schema version.
Severity (severity error) "severity":"error" Diagnostic severity.
Code (code TypeMismatch) "code":"TypeMismatch" Stable PascalCase diagnostic code for the condition.
Message (message "...") "message":"..." Concise beta-flexible human message for the machine record.
Source file (file "...") "file":"..." Source identity used by the invocation or project loader.
Span (span ...) "span":{...} Primary source span and line/column range.

Optional fields may appear when the compiler has precise data:

Field S-expression JSON Meaning
Expected (expected "...") "expected":"..." Expected type, arity, value, or form.
Found (found "...") "found":"..." Found type, arity, value, or form.
Hint (hint "...") "hint":"..." Safe repair or orientation hint.
Related spans repeated (related ...) "related":[...] Secondary source locations tied to the primary diagnostic.

Optional fields are additive when they do not replace an existing machine field or change an existing diagnostic code. Removing an optional field from an existing golden fixture is a migration-level change unless the release note states that the previous field was incorrect.

Severity

Current source diagnostics use severity error.

JSON source-less or invocation-level messages may use error for failures and note for informational tool output such as a machine-readable test-run summary. A note is not by itself a source failure; consumers should still use the process exit code and artifact manifest success field to determine command success.

Adding a new severity value is an additive schema change only when old consumers can safely ignore or display it. Reclassifying an existing failing diagnostic from error to another severity is migration-level.

Source And Range Semantics

file is the source identity reported by the compiler path, project loader, or workspace loader. It is not a promise of absolute path normalization, URI formatting, registry identity, or editor document identity.

Primary and related byte spans are zero-based and half-open: start is the first byte included, and end is the first byte after the highlighted source.

Line and column ranges are one-based and derived from the original source text. Columns are byte columns within the original UTF-8 source line; a tab counts as one input byte. The end column is the first byte column after the highlighted range on the end line.

Diagnostic locations are derived from source input, not formatter output, lowered IR, generated C, LLVM IR, native object code, or runtime stack traces.

Related spans identify secondary source locations such as an original declaration, previous duplicate, or conflicting arm. A related span never replaces the primary span.

In S-expression diagnostics, each related location is a repeated (related (span ...)) form. In JSON diagnostics, related locations are objects inside the related array. Each related object has its own file and span; it may also carry a message string.

Related messages are beta-flexible prose. The existence of a related span for a current golden fixture is part of the machine shape for that fixture and should change only intentionally.

Source-Less Diagnostics

Some diagnostics describe tool invocation or usage failures rather than a source range. Examples include invalid CLI arguments, missing inputs, and source-loading failures before a source span is available.

JSON source-less diagnostics use:

{"file":null,"span":null}

Source-less diagnostics must not invent dummy paths, byte offsets, or line/column ranges. Text-mode source-less diagnostics may remain human-only in current Glagol output; consumers that need machine-readable source-less diagnostics should request --json-diagnostics.

If a future release adds S-expression source-less diagnostics, absence of a source must be explicit and documented under slovo.diagnostic version 1 or a later migrated version. It must not be encoded as fake source coordinates.

Artifact Manifest Metadata

slovo.artifact-manifest records the diagnostic metadata for a tool invocation. The relevant fields are:

  • (diagnostics-schema-version 1): the diagnostic schema version used by the invocation.
  • (diagnostics-encoding sexpr) or (diagnostics-encoding json): the encoding selected for diagnostics.
  • (primary-output (kind diagnostics) ...): the primary output kind when the command failed by emitting diagnostics.
  • (diagnostic_artifacts ...): the diagnostic stream artifact metadata for project/package/workspace modes.
  • (diagnostics_count N): the project-level count when available.

The manifest points to or records diagnostic streams. It does not define a separate diagnostic schema, embed a parsed diagnostic catalog, freeze Markdown documentation structure, or replace the newline discipline of JSON diagnostic stderr.

Compatibility And Migration

Diagnostic changes are classified as follows.

Clarifying changes:

  • Rewording human-readable stderr prose.
  • Rewording message or hint text without changing the diagnostic code, source span, field set, severity, or expected/found semantics.
  • Improving documentation around an existing code or fixture.

Additive changes:

  • Adding a new diagnostic code for a newly covered boundary.
  • Adding a new golden fixture for a newly rejected form.
  • Adding an optional field when the old fields, code, severity, source span, and JSON-line discipline remain valid.
  • Adding related spans for a new fixture.

Migration changes:

  • Renaming, removing, splitting, or merging an existing diagnostic code covered by golden fixtures.
  • Changing required field names, schema name, schema version, span shape, range indexing, JSON null policy, or JSON-line discipline.
  • Removing an existing optional field or related span from a golden fixture without documenting the correction.
  • Changing a source-attached diagnostic into a source-less diagnostic, or the reverse, for an existing golden fixture.
  • Reclassifying an existing failing diagnostic away from severity error.
  • Changing artifact manifest diagnostic metadata fields or their meaning.

Every migration-level diagnostic change must update this document or the next release policy, docs/language/MIGRATION_POLICY.md if needed, docs/language/RELEASE_NOTES.md, and the matching Glagol golden snapshots or tests.

Current Golden Catalog

The current golden diagnostics contract is the snapshot inventory in compiler/tests/diagnostics_contract.rs. As of 1.0.0-beta.13, that contract references 358 .diag snapshots under tests/, and those snapshots contain 114 unique diagnostic codes.

This catalog inventories those codes. It is policy-focused: messages and fixture-specific prose remain in the snapshots.

Area Current codes
General calls, typing, signatures, and source shape ArityMismatch, ReturnTypeMismatch, SingleFileMainSignature, TypeMismatch, UnclosedList, UnknownFunction, UnknownTopLevelForm, UnsupportedBackendFeature, UnsupportedUnitSignatureType
Control flow and tests EmptyWhileBody, IfBranchTypeMismatch, IfConditionNotBool, MalformedIfForm, MalformedTestForm, MalformedWhileForm, NestedWhileUnsupported, TestExpressionNotBool, WhileBodyFormNotUnit, WhileConditionNotBool
Literals and strings I64LiteralOutOfRange, IntegerOutOfRange, InvalidI64Literal, UnsupportedFloatLiteral, UnsupportedStringConcatenation, UnsupportedStringEscape, UnsupportedStringLiteral
Locals, assignment, and name conflicts CannotAssignImmutableLocal, CannotAssignParameter, DuplicateFunction, DuplicateLocal, DuplicateTestName, InvalidSetTarget, InvalidTestName, LocalDeclarationInWhileBodyUnsupported, LocalDeclarationNotAllowed, LocalRedeclaresParameter, LocalShadowsCallable, ParameterShadowsCallable, UnknownVariable, UnsupportedLocalType
Type aliases, generics, maps, and sets DuplicateTypeAlias, MalformedTypeAlias, SelfTypeAlias, TypeAliasCycle, TypeAliasNameConflict, UnknownTypeAliasTarget, UnsupportedGenericFunction, UnsupportedGenericStandardLibraryCall, UnsupportedGenericTypeAlias, UnsupportedGenericTypeParameter, UnsupportedMapType, UnsupportedSetType, UnsupportedTypeAliasTarget
Structs and fields DuplicateStruct, DuplicateStructConstructorField, DuplicateStructField, EmptyStructUnsupported, FieldAccessOnNonStruct, MissingStructField, RecursiveStructFieldUnsupported, StructConstructorFieldOrderMismatch, UnknownStructField, UnknownStructType, UnsupportedStructFieldType
Arrays and vectors ArrayIndexNotI32, ArrayIndexOutOfBounds, EmptyArrayUnsupported, IndexOnNonArray, MutableArrayLocalUnsupported, UnsupportedArrayElementType, UnsupportedArrayEquality, UnsupportedArrayPrint, UnsupportedVectorElementType, UnsupportedVectorEquality, ZeroLengthArrayUnsupported
Options, results, and match DuplicateMatchArm, MalformedMatchPattern, MalformedOptionConstructor, MalformedResultConstructor, MalformedUnwrapForm, MatchArmTypeMismatch, MatchBindingCollision, MatchSubjectTypeMismatch, NonExhaustiveMatch, OptionObservationTypeMismatch, OptionUnwrapTypeMismatch, ResultObservationTypeMismatch, ResultUnwrapTypeMismatch, UnsupportedMatchContainer, UnsupportedMatchMutation, UnsupportedMatchPayloadType, UnsupportedOptionPayloadType, UnsupportedOptionResultEquality, UnsupportedOptionResultPrint, UnsupportedResultPayloadType
Enums DuplicateEnum, DuplicateEnumVariant, EmptyEnumUnsupported, EnumSubjectMismatch, InvalidEnumMatchArm, MixedEnumPayloadTypesUnsupported, RecursiveEnumPayloadStructUnsupported, UnknownEnumConstructor, UnknownVariantConstructor, UnsupportedEnumContainer, UnsupportedEnumEquality, UnsupportedEnumOrdering, UnsupportedEnumPayloadType, UnsupportedEnumPrint, VariantConstructorArity
Unsafe operations MalformedUnsafeForm, UnsafeRequired, UnsupportedUnsafeOperation
Standard-library reservation boundaries UnsupportedStandardLibraryCall

Future releases may add codes or split broad codes when the release scope requires more precise tooling behavior. Such changes must be documented using the compatibility classes above.

Explicit Deferrals

1.0.0-beta.13 does not define:

  • a stable 1.0.0 diagnostics freeze
  • LSP diagnostics, watch mode, SARIF, daemon protocols, or debug adapters
  • a stable Markdown documentation schema
  • stable source-map, DWARF, LLVM debug metadata, or runtime stack trace schema
  • warning, lint, or suggestion taxonomies beyond the current error and source-less note uses
  • localized diagnostic text
  • machine-readable remediation edits
  • a separate diagnostic catalog artifact emitted by the compiler
  • stable package registry, URI, or workspace identity semantics for file