Stable structured diagnostics for Core-0.
Core-0 Diagnostic Contract
Status: normative for Core-0; stable clause family C0-DIAG
ZergLang diagnostics are a compiler API. Every diagnostic must be available as both canonical structured data and human-readable text. Rendered prose may improve without an edition change; codes, structured meanings, and source locations are the compatibility surface used by AI tools, editors, and compile-fail tests.
C0-DIAG-001 — Required envelope
The canonical JSON representation has this shape:
{
"schema": "zerg.diagnostic/1",
"edition": "core-0",
"severity": "error",
"code": "ZL-OWN-0017",
"phase": "ownership",
"title": "cannot move a borrowed value",
"primary": {
"module": "io.buffered",
"file": "src/io/buffered.zl",
"span": {
"byte_start": 418,
"byte_end": 430,
"line_start": 19,
"column_start": 24,
"line_end": 19,
"column_end": 36
},
"semantic_id": "local:buffer"
},
"labels": [],
"facts": [],
"causes": [],
"fixes": []
}
Required top-level fields are schema, edition, severity, code, phase,
title, primary, labels, facts, causes, and fixes. A consumer must
ignore unknown fields so the schema can grow compatibly.
severity is one of error, warning, note, or help. Only an error
prevents checked-module emission. A build policy may promote a warning code to
an error, but the emitted diagnostic retains its original code and adds a
promoted_from field.
phase is one of:
lex parse module interface authority name type message generic
ownership initialization drop allocation effect domain preset internal
The initial stable code families are:
ZL-LEX ZL-PARSE ZL-MODULE ZL-INTERFACE
ZL-AUTHORITY ZL-NAME ZL-TYPE ZL-MSG
ZL-GENERIC ZL-OWN ZL-INIT ZL-DROP
ZL-ALLOC ZL-EFFECT ZL-DOMAIN ZL-PRESET
ZL-INTERNAL
Codes are never reassigned to a different condition. Removing a condition retires its code rather than recycling it.
ZL-DOMAIN-0001 has one fixed Core-0 meaning: a syntactically recognized
workflow, compute, state, or optimize message cannot be executed by the
Core-0 edition. It is not reported as an unknown keyword or parsed as an
algorithmic body.
The bounded ZLM1 schema-1.8 value substrate reserves these additional exact meanings. The title column is stable machine-facing vocabulary; explanatory rendering may add context without changing it.
| Code | Phase | Stable title and condition |
|---|---|---|
ZL-TYPE-0004 |
type |
unsupported bounded Stage0 value form — a recognized value declaration uses a field count, visibility, mutability, scalar type, initializer shape, or excluded construct outside the schema-1.8 profile |
ZL-OWN-0002 |
ownership |
named non-Copy owner requires explicit move — a named non-Copy value is consumed without move(name) |
ZL-OWN-0003 |
ownership |
use of moved value — an operation requires an owner that is moved on at least one reachable predecessor |
ZL-INIT-0001 |
initialization |
bounded value field is not initialized exactly once — Self { ... } omits, repeats, misnames, or mistypes the bounded value’s sole field |
ZL-INIT-0002 |
initialization |
Self construction is outside its declaring initializer — Self { ... } appears outside the body of that Self value’s initializer or permits Self to escape before complete construction |
ZL-MODULE-0003 |
module |
malformed or noncanonical checked module — an untrusted checked artifact violates its active schema’s closed tags, references, scalar representation, ownership dataflow, or cleanup invariants |
For ZL-TYPE-0004, facts include the selected implementation profile and the
rejected dimension and observed declaration value. ZL-OWN-0002 includes the
move path, exact type ID, attempted consumption, and required move action.
ZL-OWN-0003 additionally includes the original move span, later-use span, and
relevant CFG predecessor or join. ZL-INIT-0001 includes the initializer and
field semantic IDs, the expected occurrence count one, and the observed count.
ZL-INIT-0002 includes both the construction and declaring-initializer semantic
IDs. For schema-1.8 ZL-MODULE-0003, facts identify the descriptor,
instruction, ownership path, or cleanup edge index and the violated invariant.
C0-DIAG-002 — Locations and entities
Every diagnostic has exactly one primary source range or one module-level primary entity. Source spans are half-open UTF-8 byte ranges. Byte offsets are authoritative; one-based Unicode-scalar line and column values are included for display. Tabs advance by one scalar in the canonical coordinates; a renderer may separately compute visual columns.
semantic_id is present when resolution created an entity. Parse diagnostics
may omit it. Related declarations use the same stable semantic IDs exposed by
the checked module.
Each secondary label contains:
{
"role": "loan_origin",
"span": {
"byte_start": 300,
"byte_end": 306,
"line_start": 14,
"column_start": 9,
"line_end": 14,
"column_end": 15
},
"semantic_id": "loan:12",
"message": "shared borrow begins here"
}
role is stable structured vocabulary. message is explanatory prose and is
not a stable matching key.
C0-DIAG-003 — Phase-specific facts
The facts array contains tagged objects. At minimum, a conforming compiler
provides the following data when applicable:
- Lex/parse: observed token, expected token classes, parser state category, and chosen recovery boundary.
- Module/interface: requested path, resolved path, import cycle, generated
.zliidentity, checked-module identity, and both semantic signatures for a stale or non-canonical interface mismatch. - Authority: required
.zl.mdpath/count/content identity, optional.zli.mdidentity, named alignment obligation, verification status, and the public or implementation scope of the prose. A missing or duplicate.zl.mdis a module error. - Name: queried namespace, queried name, lookup path, visible candidates, and inaccessible candidates.
- Type: expected and actual canonical type IDs plus the failed type relation.
- Message: receiver type, selector ID, located dispatch contract, rejected argument index, required receiver ownership, openness, and whether the selector is a name or a closed operator token/arity.
- Generic: concrete substitutions and a requirement-satisfaction tree whose leaves identify satisfied or missing message contracts.
- Ownership: place/move path, attempted action, active loan kind and ID, loan origin, conflict point, later use, and relevant CFG join.
- Initialization/drop: each not-definitely-initialized path or cleanup edge and the control-flow predecessor responsible for it.
- Allocation: allocator type, typed allocation error
A, initializer domain errorE, expectedInitError<A, E>shape, allocation site, and the base- initialization edge that reuses the most-derived allocation. - Effect: caller set, callee set, missing effect, and the transitive call edge that introduced it.
- Domain: declared domain, active edition, and the boundary or edition needed to make the operation legal.
- Preset: selected
exact/modular/approximatepreset, operator, numeric types, required approximation contract, and the artifact or call boundary whose preset is incompatible.
Facts must refer to canonical type and semantic IDs rather than requiring a consumer to parse rendered type strings.
C0-DIAG-004 — Causes and cascade control
causes contains diagnostic IDs for independently emitted root diagnostics
that made this diagnostic possible. A node poisoned solely by an earlier error
does not emit another error; the compiler records the suppressed relation in
its diagnostic summary.
The canonical output order is:
- module path;
- primary byte offset;
- phase order as listed above; and
- diagnostic code.
Parallel checking must not change this order.
An internal compiler failure uses ZL-INTERNAL-*, identifies the last valid
phase and semantic entity, and prevents checked-module emission. It must not be
reported as invalid user syntax or a type error.
C0-DIAG-005 — Fixes
Each fix contains:
{
"applicability": "machine_applicable",
"description": "move this operation after the borrow's final use",
"requires_source_hash": "sha256:...",
"edits": [
{
"file": "src/io/buffered.zl",
"byte_start": 418,
"byte_end": 430,
"replacement": ""
}
]
}
applicability is machine_applicable, maybe_incorrect, or
informational. A machine-applicable edit must parse and must not overlap
another edit in the same fix. Applying a fix requires an exact content-hash
match; tooling must not apply it to a changed file by offset alone.
A suggested fix is never evidence that the modified program type-checks. Tools must re-run the complete front end after applying it.
C0-DIAG-006 — Conformance behavior
A conforming implementation must:
- produce the same error code and phase for the same normative rejection, regardless of native or interpreted target;
- retain enough ownership and requirement evidence for a tool to explain why a repair is valid;
- make the JSON stream available without scraping console prose;
- emit no checked module while any error remains; and
- reject execution of a parsed-only, unresolved, or unchecked module.
Exact prose, color, contextual source excerpts, and terminal layout are not normative.