Back to Blog

RIDDL 2.1.1 Released

RIDDL 2.1.1 is now available.

release riddl compiler

RIDDL 2.1.1 is now available. This release of the RIDDL compiler and language tooling includes the following changes:

What’s New

What’s New

This release tightens how riddlc validate reasons about message delivery and stream topology. Four rules changed or arrived, each ruled by the language author and each recorded in the RIDDL Computational Model (§7, §8.1, §17). The riddl-models corpus (190 models) validates clean against all of them.

Improvements

  • A tell needs a channel from its sender, and this is now an Error (msg-tell-target-unreachable). A tell is sugar for a send on the outlet connected to the target’s inlet (Computational Model §25.7), so the channel it implies must be modelled. Reachability is now computed from the sender’s OWN outlet — a processor publishes only through its own outlet, never through its context’s — where an earlier version had counted the enclosing context’s outlets as origins and silently accepted a sender with no outlet at all.

  • An adaptor may address only a context (adaptor-targets-context-only, Error). An adaptor translates between contexts; a tell, send or forward from an adaptor to an entity or repository inside its own context makes it a participant in that context’s business rather than its translator. Its own portlets are exempt, since that is how an adaptor emits at all.

  • A stream chain ends where its message is consumed, not at a sink shape. stream-source-reaches-no-sink used to ask whether a source reaches a processor with zero outlets. Because a sender must own the outlet it sends on, any terminal processor that also records what it received — an event log writing a Persist command to its repository — is a flow by arity, and every source above it was reported as reaching nothing. A chain tail is now a processor with an inlet that handles every message type its inlets admit (alternation members expanded, on other counting) and whose handling clauses never send, tell or forward a message of that same type onward. Writing a different type is a write, not a continuation. This mirrors the earlier chain-head ruling, which stopped requiring a source shape.

  • A stream graph may not contain a cycle (stream-graph-cycle, Error). Connectors carrying one message type that form a loop would let a message circulate forever. The check is per message type, so a request/response pair between two contexts — a command one way, an event back — is two chains, not a loop. A self-loop is a cycle of one.

  • Connectors between related domains are permitted. stream-crosses-domains now rejects only a connector between domains that share no ancestor; sibling domains under a common parent may be wired directly.

Bug Fixes

  • ESMSafetyTest had not scanned a bundle since the sbt 2 upgrade. The guard that keeps ESM-shim trigger patterns out of the published npm bundle looked for the bundle at the sbt 1 path, found nothing, and reported itself canceled on every run, locally and in CI. It now reads the sbt 2 output tree, and CI runs it on the JS row against the exact bundle that ships.

Internal

  • RuleId gains AdaptorTargetsContextOnly and GraphCycle; the append-only rule-id ledger records them. msg-tell-target-unreachable existed in 2.1.0 and changes severity only.
  • ValidationPass.isStreamTail is the single tail predicate, exposed to the streaming graph walk through one hook rather than a second copy.
  • Test fixtures that wired a processor’s outlet to its own inlet are now real chains.
  • Engineering notes for each ruling are in NOTEBOOK.md and CLAUDE.md.