MishkaCmsCore.Runtime.PageBuilder.Strict (Mishka CMS Core v0.0.1)

Copy Markdown View Source

What the editor refuses to let past in development, and forgives in production.

Why this exists

Nine bugs were found in the editor's history over one stretch of work, and eight of them were silent: a filter comparing against a pinned nil, which Postgres reads as = NULL and never matches; a relationship that was never preloaded, so every row claimed to be by "System administrator"; a capped list used as a "did anything change?" signal, which saturated and stopped the editor recording anything at all. None raised. Each degraded to something that looks exactly like a legitimate empty answer, and each was found by somebody noticing that a screen looked wrong.

The forgiving behaviour is right in production — an editor that takes itself down because one plugin returned the wrong shape is worse than one that carries on. It is wrong everywhere else, because during development an empty answer that should have been impossible is the single most valuable thing you can be told about.

So the two are separated. Every check here raises in :dev and :test and compiles to nothing in :prod — check!/2 and its friends are macros, so a release contains no call, no closure and no branch.

config :mishka_cms_core, builder_strict: false

What to check with it

Conditions that are impossible unless something is already broken. Not user error, not a refused op, not a document that failed to parse — those are answers. A dangling child id in a document, a write to a table that is not there, a history entry pointing at nothing: those are bugs, and every one of them used to travel silently to somewhere far away from its cause.

Summary

Functions

Raises where: why unless condition holds. Compiles to nothing in production.

Whether the strict checks are compiled in. False in a release.

Every way a document can be internally inconsistent, in one predicate.

Raises when a document is internally inconsistent. Compiles to nothing in production.

Raises outright — for a branch that should be unreachable. Compiles to nothing in production.

Functions

check!(condition, where, why)

(macro)

Raises where: why unless condition holds. Compiles to nothing in production.

The condition is not evaluated at all in a release, so an expensive check costs a developer time and costs a deployment nothing.

enabled?()

@spec enabled?() :: boolean()

Whether the strict checks are compiled in. False in a release.

inspect_tree(tree)

@spec inspect_tree(MishkaCmsCore.Runtime.PageBuilder.Tree.t()) ::
  :ok | {:error, String.t()}

Every way a document can be internally inconsistent, in one predicate.

A children list naming an id that is not in nodes is the one that matters most: the serializer is deliberately total, so it skips what it cannot find — and a save writes what the serializer produced. A subtree that vanished this way leaves markup that parses perfectly, so the save's own "is this readable?" check cannot see it. The document is simply smaller than it was, silently.

Returns :ok or {:error, reason}; tree!/2 is the raising form the mutation funnel uses.

tree!(tree, where)

(macro)

Raises when a document is internally inconsistent. Compiles to nothing in production.

violation!(where, why)

(macro)

Raises outright — for a branch that should be unreachable. Compiles to nothing in production.