diff --git a/versions/1.2.md b/versions/1.2.md index f321557..89324c3 100644 --- a/versions/1.2.md +++ b/versions/1.2.md @@ -204,6 +204,32 @@ seeds: - **No type tags.** Blocked by the safe parser. - **Quote unquoted braces in scalars.** `to: {member.email}` is parsed by YAML as an object, not a string - write `to: member.email`. Braces are only for `{...}` interpolation inside `subject` / `body` text. - **An event-binding key is `event:`, never `on:`** - YAML 1.1 resolves a bare `on` (and `off` / `yes` / `no`) to a boolean. An action key is `do:`. +- **Only the keys this specification declares exist, and they are case-sensitive.** An invented key, or a case slip (`Required:` for `required:`), is an authoring error - never a key that is accepted and ignored. + +#### Unrecognised keys + +A typed mapping normally drops a key it does not know. That silence is the worst failure this format can have: the file is accepted, generation succeeds, the application deploys, and the only symptom is that the promise the author wrote is absent at runtime - with every step of the pipeline reporting success. The rule is therefore the same one the format applies to a reference it cannot resolve. + +> **Normative.** +> A conforming generator MUST report a key it does not recognise as an authoring error rather than +> ignoring it, and the report MUST name the key, where it appears, and - where one exists - the +> nearest declared name. Key names are **case-sensitive**: a key differing from a declared one only +> in case is unrecognised, and the report SHOULD say so, since it is the slip hardest to see by eye. +> This applies equally to a [seed row](#seeds), whose keys are the target entity's own names rather +> than this specification's. A map whose keys are drawn from the model being described (a `map:` +> projection, a relation's `where:`, a widget's `at:`, a delegate's injected `fields:`) is validated +> against that model, not against this vocabulary. + +Being written as a mapping does not make a block free-form. A process [`trigger:`](#processes), an +[`abortOn:`](#aborton--cancel-the-instance-on-a-terminal-status), a glue [`event:`](#notifications) +binding, a step's [`args:`](#processes) and the blocks nested inside them are each a fixed +vocabulary, and a key outside it is unrecognised like any other. + +> **Normative.** +> A step's `args:` are recognised **per step kind**: an argument declared on a kind that does not +> read it (a decision's `if` on a user task, a boundary `timeout` on a service task) MUST be reported +> like an unrecognised one, and the report SHOULD name the kind that does read it. This is the same +> failure and not a lesser one - the step reads nothing, so the argument does nothing. ## Entities & fields @@ -1538,7 +1564,7 @@ Generates a seed-import descriptor + CSV per seed. Two shapes: - **`file: data/.csv`** — an authored CSV under a `data/` subfolder, right for bulk nomenclatures and prepopulated demo data. A foreign key is set by the relation name (`Country: 34`). > **Normative.** -> Row keys must match a field or relation name **exactly** (case-sensitive). A key matching neither is an authoring error — a silently dropped column becomes a NOT NULL failure at import time. +> Row keys must match a field name, a **to-one** relation name (a collection has no column to set), or the `stage` marker below, **exactly** (case-sensitive). A key matching none of those is an authoring error, reported with the nearest declared name — see [unrecognised keys](#unrecognised-keys). Accepting it would drop the column, and a dropped NOT NULL foreign key makes the import skip **every** row: a nomenclature that imports as zero rows, behind a fully green pipeline. A seed with `language: ` is a **translation** seed: it fills the per-language values of a `multilingual: true` entity, carrying the base row's `id` plus the translatable fields only.