StatifierBlocks.Compiler.Finding (StatifierBlocks v0.1.0)

Copy Markdown View Source

One thing the compiler has to say about one block (ADR-0004 decision 10).

Every finding names a block. There is no chart-level finding without an owner, which is what lets an editor render findings as annotations on the tree with no fallback presentation, and decision 5's totality is what buys it for the :chart stage - the one stage whose findings arrive with no idea that blocks exist.

The pipeline, and which stage produces what

StageErrors it produces
:document:invalid_document - Document.validate/1's reason
:resolve:unknown_block_type, :block_type_too_new, :migration_failed
:configvalidate_config/1 findings, one per {key, message} pair
:structureassignability (ADR-0003); slot arity and :undeclared_slot are sb-da9's
:emitemit/2 findings, :invalid_role, :unspliced_child, :unknown_attribution
:chartmapped statifier findings, both faults (decision 9)

The pipeline stops at the first stage that produces errors and reports every error from that stage. Stopping rather than accumulating across stages is deliberate: a document with an unresolvable block type has no meaningful structural check to run, and reporting a cascade of consequences beside the cause is how an error panel becomes noise. Within a stage every finding is reported, because those are siblings rather than consequences.

The :document stage is not in decision 10's table, and it is not a new decision either: decision 1 requires compile/3 never to raise, and Document.to_json/1 raises on a document that fails ADR-0001's structural rules. Checking first and reporting it as a finding is what totality costs. It runs before :resolve because a document that is not structurally a document has no blocks worth resolving.

fault: whose problem is this?

Decision 9 states the split for the :chart stage, where it is subtle because the finding was raised against generated SCXML by a validator that has never heard of blocks. The rule generalizes, and this module applies the generalized form at every stage:

  • :author - a document edit fixes it. Every :config finding, every :structure finding (an author placed the block), and every :chart finding whose owning span carries a config key.
  • :package - a bug in this package or in a host's block type, and no edit to the document will help. :resolve findings (the palette is the host's, not the author's), every :emit finding that names no config key, and every :chart finding whose owning span carries no config key: an author cannot express {:unresolved_target, id}, because the block vocabulary has no way to name a state id.

The editor renders the two differently, and "this cannot be fixed here" is the only honest message for the second.

severity

:error fails the compile; :warning rides on StatifierBlocks.Compiled's warnings and does not. Upstream warnings (st-ADR-0033) and decision 8's optional invoke-type lint are the two sources of warnings, and decision 8 is explicit that the lint is never an error.

Summary

Types

Whose problem this is. See the moduledoc.

The pipeline stage that produced this finding.

t()

Functions

reason's stable tag: the tuple's first element, or the reason itself when it is already an atom.

Types

fault()

@type fault() :: :package | :author

Whose problem this is. See the moduledoc.

stage()

@type stage() :: :document | :resolve | :config | :structure | :emit | :chart

The pipeline stage that produced this finding.

t()

@type t() :: %StatifierBlocks.Compiler.Finding{
  block_id: StatifierBlocks.Block.id() | nil,
  code: atom(),
  config_key: String.t() | nil,
  fault: fault(),
  message: String.t(),
  path: StatifierBlocks.Document.path() | nil,
  reason: term(),
  severity: :error | :warning,
  stage: stage()
}

Functions

code(reason)

@spec code(term()) :: atom()

reason's stable tag: the tuple's first element, or the reason itself when it is already an atom.

new(stage, reason, message, opts \\ [])

@spec new(stage(), term(), String.t(), keyword()) :: t()

Builds a finding.

opts carries :block_id, :path, :config_key, :severity, :fault and :code. code defaults to reason's own tag, which is the stable atom an editor switches on while reason keeps carrying the offending ids as data - the same split Statifier.Validator.Error.code/1 makes upstream. fault defaults to the stage's own rule, refined by whether a config key is present.