Sakura Lang

Diagnostics

Reference for the JSON Lines diagnostics produced by sakura check --json, including record kinds, error codes, and fix impact classes.

Pre-alpha

The source-built compiler runs the core language and much of M3 on JavaScript: contracts, typed effects and failures, std handlers, permissions, LSP and MCP. M3 is still in progress; no release or stable compatibility contract exists. See the roadmap for implemented features and remaining gates.

Diagnostics are an API. Every diagnostic has a stable code, byte spans, structured expected and actual values, causal links, and fixes that declare their impact. The CLI, the LSP server, and the MCP server share one analysis library and one format.

sakura check --json
sakura test --json

--json writes JSON Lines: one record per line. Human-readable output is rendered from the same data.

Record kinds

kindMeaning
diagnosticAn error, warning, or note. Shape below.
holeA typed hole with its context.
obligationA claim about the program and its status: proved, runtime_checked, tested, or trusted.
progressProgress of a long run.
summaryEnd of run. summary.truncated is true if output hit the cap.

The diagnostic record

The program below omits Console from greet's effect row:

fn greet(name: String) -> Unit {
  Console.print("hello, {name}")
}

sakura check --json would report it as one line, shown here pretty-printed. Hashes and ids are shortened.

{
  "schema_version": "1.0",
  "kind": "diagnostic",
  "id": "d:7f3a",
  "code": "V3001",
  "severity": "error",
  "phase": "effect",
  "message": "function `greet` performs `Console`, which its signature does not allow",
  "snapshot": "sha256:91c0",
  "symbol_id": "hello::main::greet",
  "spans": [
    { "uri": "file:///work/hello/src/main.sakura", "content_hash": "sha256:4be2",
      "start_byte": 3, "end_byte": 8, "role": "primary", "label": "`greet` is declared pure" },
    { "uri": "file:///work/hello/src/main.sakura", "content_hash": "sha256:4be2",
      "start_byte": 35, "end_byte": 65, "role": "cause", "label": "`Console.print` introduces `Console` here" }
  ],
  "related_ids": [],
  "expected": { "render": "{}", "row": { "labels": [], "tail": null } },
  "actual": { "render": "{Console}", "row": { "labels": [{ "effect": "std::Console", "args": [] }], "tail": null } },
  "obligation": null,
  "counterexample": null,
  "explanation_uri": "sakura://explain/V3001",
  "fixes": [
    { "id": "f:01", "title": "Add `Console` to the signature of `greet`",
      "applicability": "suggested", "impact": "interface_change",
      "edits": [ { "span": { "uri": "file:///work/hello/src/main.sakura", "content_hash": "sha256:4be2",
                             "start_byte": 30, "end_byte": 30, "role": "primary", "label": "" },
                   "replacement": " ! {Console}" } ] }
  ]
}

For V3001, the design specifies two fixes: add the effect to the signature (interface_change) or handle it locally with with (local). Only the first is shown.

Fields

FieldTypeMeaning
schema_versionstringVersion of this format. "1.0" in v0.
kindstring"diagnostic".
idstringUnique per occurrence in this run.
codestringStable class, such as V3001. See codes.
severitystringerror, warning, or note.
phasestringlex, parse, resolve, type, effect, pattern, contract, capability, verify, package, or internal.
messagestringOne sentence naming the symbols involved in backticks.
snapshotstringHash of the workspace snapshot that was checked.
symbol_idstring or nullThe symbol the diagnostic is about.
spansarraySource locations, each with uri, content_hash, start_byte, end_byte, role, label.
related_idsarrayIds of root-cause diagnostics this one cascades from. Empty for a root cause.
expectedobject or nullWhat was required: a render string, and a structured row for effect rows.
actualobject or nullWhat was found, in the same shape.
obligationobject or nullid, clause (for example "ensures bounded"), and status.
counterexampleobject or nullinputs and a trace, when one is known.
explanation_uristringsakura://explain/<code>. Same content as sakura explain <code> and the MCP explain_diagnostic tool.
fixesarrayZero or more fixes. See below.

Span role is one of primary, cause, definition, or use.

Rules

  • Byte offsets are zero-based, half-open, and count UTF-8 bytes. There are no line or column numbers.
  • content_hash must match the file before any edit is applied.
  • The edits in one fix are applied atomically and rejected if they overlap.
  • Records are ordered root causes first (empty related_ids), then by position.
  • Output is capped at 200 diagnostics per run, with summary.truncated: true.

Fixes

FieldMeaning
idFix id, accepted by sakura fix --apply.
titleShort imperative description.
applicabilitymachine_applicable, suggested, or incomplete.
impactWhat the fix changes. See below.
editsList of { span, replacement }. A span with equal start and end is an insertion.

Impact classes

impactChangesSuggested agent policy
localCode inside one body; no signature changes.Apply if machine_applicable.
behavior_changeWhat the code does, without changing its signature.Apply only if it matches the task.
interface_changeA signature, effect row, or error union.Apply only if the task needs it, and report it for review.
contract_changeA requires, ensures, or where clause.Never apply unless a human asks.
authority_changePermissions or capabilities.Never apply unless a human asks.

Compiler fixes with interface_change, contract_change, or authority_change impact are never machine_applicable. No fix ever widens authority or weakens a contract by itself.

sakura fix lists fixes with their impact class. It applies only machine_applicable fixes unless given ids with --apply id,…, and it never applies contract_change or authority_change. --preview shows the edits without writing.

Frozen specs

sakura check --frozen-specs <symbols|all>, sakura fix, and the MCP apply_patch tool reject any patch that changes a frozen symbol's signature, effect row, error union, requires/ensures/where clauses, or any test/property body. The diagnostic is V8020 spec_frozen and names the clause. This stops an agent from passing a check by editing the spec.

Error codes

Codes are V + a phase digit + three digits for errors, W for warnings, and D for runtime defects. Codes are never reused or renumbered; retired codes stay documented. Every code has an explain page with a minimal pair: wrong program, diagnostic, fixed program.

Phase digitAreaExamples
0Lexing and parsingV0001 syntax error, V0007 reserved keyword, V0010 chained comparison, V0011 call-site type arguments, V0014 named argument
1Resolution and modulesV1002 unresolved name (offers the import as a fix), V1004 wrong casing, V1006 item not pub or opaque constructor, V1007 wrong kind of name, V1010 unknown attribute, V1030 import cycle, V1040 assignment to a let, V1041 jump outside a loop
2TypesV2031 Secret is not Show, V2032 constraint not satisfied, V2040 unused value, V2041 lambda or try body assigns an outer var, V2050 hole in build
3Effects and handlersV3001 effect not allowed, V3011 handler clauses do not match the operations, V3020 test needs a handler
4PatternsV4001 non-exhaustive match, V4002 redundant arm
5Contracts and refinementsV5001 predicate outside the contract subset
6Capabilities, resources, escapeV6002 capability escapes its scope, V6003 resource escapes, V6010 non-std effect in main
7Tests and verificationNone named in the design yet
8Packages, build, frozen specsV8020 spec frozen
9InternalCompiler bugs

Warnings named in the design include W1002 (a local shadows an import), W4010 (catch-all _ on an open error union), W5005 (an O(n) contract on a hot path), W7001 (property generator discard budget exceeded), and W8001 (a collection update copies in a loop).

Runtime defects are not diagnostics from sakura check. They terminate the task; if main defects, the program writes one defect record to stderr and exits with status 70:

{"schema_version":"1.0","kind":"defect","code":"D002","message":"division by zero"}
CodeRaised by
D001Int overflow
D002/ or % by zero
D003Int beyond ±(2^53−1) on the JavaScript backend
D004Float.round or Float.to_int_checked of NaN or ±∞
D010failed refinement in a checked introduction (T.from)
D011a contract predicate itself defected
D020, D021requires violated (caller blamed), ensures violated (callee blamed)
D030Option.expect on None
D031String.slice off a character boundary
D090, D091runtime-internal error, host operation failed

Exit codes

CodeMeaning
0OK.
1Diagnostics with errors, or main ended with an uncaught Fail (stderr: error: main failed with <Show of the error>).
2Usage error.
3Test failures.
70Defect at runtime.
75Permission denied at startup.

Next

Typed holes: writing a program one ?hole at a time.

Edit on GitHub

On this page