Sharpee
Chord / Project & Files / Tooling / Reading diagnostics

Reading diagnostics

Every gate speaks the same line format:

<file>:<line>:<column> <severity> [<code>] <message>

For example:

zoo.story:42:3 error [analysis.irreversible-state] `intact` is
declared before `trampled`; a `change` back is a load error unless the
set is `states, reversible: …`.

The <code> is the stable identifier: the same code this reference cites throughout (analysis.irreversible-state, parse.react-refusal, and so on). The <message> usually carries the fix. error severity means the story will not load; warning means it loads but something reads oddly (the fragment-terminator warnings on description markers are the common one).

The governing idea is that loading is atomic: a story either passes every gate and produces usable IR, or it fails and produces none. There is no partial load. This is why the reference can promise that a compiling example really works: "compiles" is not a syntax check, it is the full parse-and-analyze pass that the runtime itself depends on.

The parser is built to give you one diagnostic per mistake rather than a cascade. After it reports a parse error, it resynchronizes at the next end line or top-level keyword and carries on, so a single missing end on produces a single message pointing at the clause, not a wall of confused errors from everything after it. When you do see several diagnostics at once, they are genuinely several problems: fix the first and recompile.

The gates come in two families, distinguished by their code prefix. parse.* gates are structural: a tab in the indentation, a missing end, a removed construct. analysis.* gates are semantic: they fire after a clean parse, when the shapes are right but the meaning is not. The analyzer gates you are most likely to meet, each named where it is first explained:

  • analysis.irreversible-state: a change backward through a non-reversible state set.
  • analysis.state-collision: two composed traits declaring the same state name.
  • analysis.closed-condition-selection: any/no/each over a closed condition.
  • analysis.open-condition-truth: a bare open condition used as a truth test.
  • analysis.negated-requirement: refuse when not …, which is a requirement in disguise; use must.
  • analysis.unbound-marker: a {marker} naming no declared phrase or hatch.
  • analysis.remove-player: remove the player, which has no defined meaning.
  • analysis.match-outside-each: the match used outside an each body.

The three-ring boolean-state gate deserves its own mention, because it catches the single most common instinct carried over from other systems: reaching for a boolean. If you declare a state set that looks like a flag (true/false, a platform pair like open/closed, or a negation pair like fed/unfed), the analyzer refuses it (analysis.boolean-state, analysis.shadow-state, analysis.negated-state) and tells you to name what the thing is in each state, or to compose the trait that already owns that state. A state names a condition of the thing, never the absence of another state.