This document is a normative part of the draft Stack 1.0 specification. It defines portable JSON representations for normalized compiler output, diagnostics, and canonical conformance expectations.
The JSON Schemas in schemas/ are normative for document shape. This document is normative for field meaning, ordering, and processing behavior.
The compiler interchange boundary follows language processing stages 1 through 4:
UTF-8 source
-> tokenization and parsing
-> identifier and default resolution
-> semantic and complexity validation
-> normalized diagram IR
Theme and icon resolution, layout solving, and rendering occur after this boundary. They MUST NOT add fields to normalized compiler IR.
A native compiler API MAY expose implementation-specific types. An implementation claiming portable conformance MUST be able to map its successful output and diagnostics to the JSON contracts defined here.
Every interchange document contains schemaVersion. Stack 1.0 defines schema version 1.0.
The schema version is independent of the Stack language version:
languageVersionidentifies the source grammar and semantics;schemaVersionidentifies the portable JSON representation.
Adding an optional field is a schema minor change. Removing a field, changing a field meaning, changing an enum meaning, or making an optional field required is a schema major change.
Consumers MUST reject unsupported schema major versions. They MUST NOT silently ignore unknown fields because an unknown field may carry required meaning.
A compiler produces normalized IR only when stages 1 through 4 contain no error diagnostics. Warning diagnostics may accompany successful IR.
The normalized document conforms to normalized-ir.schema.json.
Normalized IR MUST:
- include the declared language version;
- apply
defaultwhen no theme is authored; - apply
servicewhen no node kind is authored; - apply
flowwhen no edge kind is authored; - preserve node, group, edge, child, same-rank, and order list declaration order;
- represent absent optional values as JSON
null; - represent collections as arrays, including when empty;
- use source identifiers without case conversion;
- contain decoded string values rather than source escapes.
Normalized IR MUST NOT contain:
- source locations, comments, or formatting trivia;
- unresolved or partial declarations from invalid source;
- theme or icon catalog resolution results;
- coordinates, dimensions, edge paths, colors, typography, or SVG;
- implementation-specific filesystem, network, memory, or object handles.
JSON object member order has no meaning. Array order is normative.
| Field | Meaning |
|---|---|
schemaVersion |
Compiler interchange version; 1.0 for this document |
languageVersion |
Major and minor version declared by the source |
title |
Decoded visible diagram title |
themeId |
Authored theme identifier or default |
children |
Direct diagram children in declaration order |
nodes |
Every node in depth-first declaration order |
groups |
Every group in depth-first declaration order |
edges |
Diagram edges in declaration order |
layout |
Normalized diagram layout or null |
Each child reference contains type and id. The type is node or group. Although Stack identifiers are globally unique, the explicit type prevents consumers from inferring element category from another array.
A node contains its effective semantic kind and nearest containing group. parentGroupId is null for a root node. iconId and detail remain null when omitted; icon fallback and visual detail treatment are downstream concerns.
A group contains its nearest containing group, direct children, and group-scoped layout. parentGroupId is null for a root group. Group entries use depth-first declaration order: a parent precedes all descendants.
Containment is intentionally represented in both directions:
childrensupports ordered traversal of one scope;parentGroupIdsupports direct lookup from a node or group.
Both representations MUST agree.
from and to preserve the authored left and right endpoint order. direction is one of:
forwardfor->;bidirectionalfor<->;associationfor--.
Bidirectional and association edges preserve authored endpoint order even though duplicate-edge validation treats their endpoint order as equivalent.
Layout contains:
direction:right,down, ornull;sameRanks: same-rank identifier lists in declaration order;order: the authored order list ornull.
The identifiers remain scoped to the direct children of the diagram or group that owns the layout. Normalized IR does not contract edges or solve positions.
A portable diagnostic conforms to diagnostic.schema.json.
A position contains:
byteOffset: zero-based UTF-8 byte offset in the original source;line: one-based line number;column: one-based Unicode scalar column.
A range contains an inclusive start position and an exclusive end position. A point diagnostic has identical start and end positions. LF and CRLF each advance the line once; byte offsets still count their original encoded bytes.
code and its normative meaning are assigned by the language specification. severity is error or warning. message is concise human-readable text but its exact wording is not a compatibility guarantee.
help is either corrective guidance or null. related is always an array and identifies other source ranges involved in the diagnostic. Related-information message wording is not a compatibility guarantee.
Implementations may emit non-STK diagnostics. Canonical fixtures only require portable STK diagnostics unless a case explicitly documents an implementation extension.
The canonical compiler suite lives in conformance/valid/ and conformance/invalid/. Each compiler case is one directory named with a lowercase ASCII identifier. Formatter fixtures use a separate contract and layout defined in the Stack Canonical Formatter Specification.
A valid case contains:
conformance/valid/<case-id>/source.stack
conformance/valid/<case-id>/expected.ir.json
conformance/valid/<case-id>/expected.diagnostics.json # optional
The source MUST compile to normalized IR semantically equal to expected.ir.json. If expected.diagnostics.json is absent, no portable diagnostics are expected. When present, it normally contains warning expectations.
An invalid case contains:
conformance/invalid/<case-id>/source.stack
conformance/invalid/<case-id>/expected.diagnostics.json
The source MUST NOT produce normalized IR. Its portable diagnostics MUST match the expectation document.
Expectation documents conform to diagnostic-expectations.schema.json. Each expected diagnostic requires code, severity, and range.
Runners compare diagnostics in the deterministic order emitted by the compiler. They MUST compare the number of diagnostics and MUST NOT ignore additional portable diagnostics. They do not compare message, help, or related information.
A conforming runner MUST:
- discover case directories in bytewise identifier order;
- read
source.stackas bytes so encoding fixtures remain possible; - compile with catalog, layout, and renderer stages disabled;
- validate successful normalized output against the normalized IR schema;
- validate expectation documents against their schemas;
- compare JSON values semantically rather than by object-member order or whitespace;
- fail a case when required files are missing or unexpected files use reserved names;
- report the case identifier and mismatch location.
An implementation MUST record the specification release or commit revision used for its conformance run. Passing an older suite does not claim support for a newer specification revision.