diff --git a/docs/spec/data.md b/docs/spec/data.md index d28763d..a5e3c41 100644 --- a/docs/spec/data.md +++ b/docs/spec/data.md @@ -36,7 +36,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`). ::: info 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](/spec/#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. diff --git a/docs/spec/index.md b/docs/spec/index.md index 7160085..51eb56f 100644 --- a/docs/spec/index.md +++ b/docs/spec/index.md @@ -167,6 +167,34 @@ These rules keep the file diff-stable, safe to parse, and friendly for both huma - **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. + +::: info 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](/spec/data#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:`](/spec/processes), +an [`abortOn:`](/spec/processes#aborton-cancel-the-instance-on-a-terminal-status), a glue +[`event:`](/spec/glue#notifications) binding, a step's [`args:`](/spec/processes) and the blocks +nested inside them are each a fixed vocabulary, and a key outside it is unrecognised like any other. + +::: info 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. +::: ## In this section