Skip to content
Content modellingCMMF 1.3.0-beta.1 · Experimental

Document-level validation hints

Document-level validation hints for experimental CMMF 1.3.0-beta.1.

Experimental: CMMF 1.3.0-beta.1. This branch defaults to the beta throughout. Declare specVersion: "1.3.0-beta.1" in the manifest. Stable 1.2.0 remains canonical on main; adopting hints requires explicitly selecting the beta.

Some intent belongs to a whole document: an external article needs a source URL; an article needs an author or a source; search exclusion needs an explanation. Field-level validations cannot describe these dependencies by themselves.

validationHints captures that intent without promising universal CMS support. A hint does not enforce content checks by itself. Translators must explain what they preserved, weakened, or could not map. Studio and other editors can use the structured declarations without executing expressions.

Every hint requires an id and meaningful description. IDs use the same syntax as field IDs and are unique within the model. Severity defaults to error, with warning and info also available. Each hint uses exactly one representation.

validationHints:
- id: external-requires-source
description: External articles must provide a source URL.
when:
field: article_type
equals: external
then:
require: [source_url]
- id: author-or-source
description: Provide an author or a source URL.
then:
atLeastOneOf: [author, source_url]

when is optional; then is required for structured hints. Conditions can nest using allOf, anyOf, and not. Predicates have a direct field ID and exactly one operator. Actions are require, forbid, atLeastOneOf, atMostOneOf, and exactlyOneOf. Multiple actions in one then apply together. forbid describes an expected empty field; it never authorises deletion of content.

All structured references resolve to fields in the same model. No nested paths, list-element inspection, or cross-document rules are supported by this vocabulary.

validationHints:
- id: quarterly-price-bound
description: Quarterly price must exceed three times the monthly price.
expression:
dialect: jsonlogic
rule: {">": [{"var": "quarterly_price"}, {"*": [3, {"var": "monthly_price"}]}]}

Expressions use an existing, explicitly declared language. CMMF does not invent an expression language or require any implementation. jsonlogic is an example, not a preferred default. The rule follows that dialect’s semantics, including its own truthiness and coercion. CMMF’s structured emptiness rules do not override them. Rules may concern only the current document, without external side effects.

An expression is the whole assertion; it cannot share a hint with when or then. Expressions are best-effort and non-portable. Unknown dialects must never be executed. The core checker validates the wrapper, not the dialect’s rule.

validationHints:
- id: check-source-rights
description: Confirm permission to republish external source material.
severity: info

Prose keeps intent available when no structured declaration fits. It still has an ID, and translators must still log its disposition. A prose hint must not have a when: a trigger without a consequence would be ambiguous.

require means non-empty, not just that a key exists. Empty means absent, null, "", or []. false, 0, whitespace-only strings, and {} are non-empty. All actions and the isEmpty / isNotEmpty predicates use that definition.

Comparisons do not coerce types: 1 differs from "1". They apply to singular scalar fields; numeric comparisons apply only to numbers. in compares a scalar with a set, rather than inspecting list members. matches applies to plain-text fields and uses an ECMAScript regex string without delimiters or flags.

An absent field makes comparison predicates false, even notEquals and notIn. Use isEmpty to test absence explicitly. not negates normally, so not: {field: article_type, equals: external} is true if article_type is absent. Null can be compared explicitly; incompatible present types make comparisons false. The normative spec defines the type matrix.

A malformed hint makes the declaration invalid regardless of its severity. A valid hint whose assertion fails for some content does not make the model definition invalid. See the three validation concerns.

The schema checks structure. The declaration checker adds field resolution, unique IDs, type compatibility, and regex syntax. Neither evaluates content or expressions. Try the article and subscription examples with npm run validate.

Every translated hint must have a disposition identifying the model and hint, with a reason: mapped, degraded, or unmapped. Guidance text without preserved checks is degraded; an unknown dialect without usable output is unmapped. See the worked log and translation contract.