Core-0normative target; implementation partial

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 .zli identity, checked-module identity, and both semantic signatures for a stale or non-canonical interface mismatch.
  • Authority: required .zl.md path/count/content identity, optional .zli.md identity, named alignment obligation, verification status, and the public or implementation scope of the prose. A missing or duplicate .zl.md is 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 error E, expected InitError<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/approximate preset, 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:

  1. module path;
  2. primary byte offset;
  3. phase order as listed above; and
  4. 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.

Projected fromspec/editions/core-0/diagnostics.md