Requirements¶
Requirements says what must exist before the rule is answerable at all.
If a requirement is not met the rule is skipped for that dataset. A skip is its own outcome — not a pass, not a finding, not an error — and it is reported as such.
Requirements:
Variables:
All: ["AESTDTC"]
Where Scope answers "is this rule about this dataset?", Requirements answers
"can this rule say anything useful about it?"
⛔ The one rule that matters more than the syntax¶
A requirement is for a thing whose absence means there is nothing to check — never for a thing whose absence is the defect.
A rule that reports a missing AEENDTC must not require AEENDTC. Requiring it skips the
rule on exactly the datasets it exists to judge, and a skip looks like a clean result.
# ⛔ WRONG — this rule can never fire
Requirements:
Variables:
All: ["AEENDTC"]
Check:
expression: 'empty(AEENDTC)'
Nothing errors. Nothing warns. The rule simply never reports, on every study, forever. This is the most expensive mistake in this chapter, and it is invisible from the outside.
Require what the check needs in order to ask its question. Never what the check is asking about.
Variables — three facets, ANDed¶
Requirements:
Variables:
All: ["AESTDTC", "AEENDTC"]
Any: ["AEDECOD", "AETERM"]
None: ["AEENDY"]
All three, and Scope, must hold together.
All — every entry must be present¶
The common case. Use it for the columns the check reads in order to function.
Any — an AND of ORs¶
Any is a list of groups. Each group is satisfied when at least one of its entries is
present, and all the groups must be satisfied.
Any: ["AEDECOD", "AETERM"] # ONE group: either will do
Any: [["AEDECOD", "AETERM"], ["AESTDTC", "AESTDY"]] # TWO groups: one from each
A flat list is one group. A list of lists is one group per inner list. That distinction is the whole feature, and it is easy to write the wrong one by accident.
Four shapes are rejected at load rather than interpreted:
| you write | what happens |
|---|---|
Any: ["A", ["B","C"]] |
load error — flat and nested mixed in one list |
Any: ["A"] |
load error — a group needs two or more entries; a one-entry OR is an All |
Any: [] |
load error — zero groups is unsatisfiable |
Any: AESEV |
load error — a bare scalar, not a list |
A group's failure names the group, not a variable. A group is unmet only when every entry in it is absent, so no single entry is at fault — which is why the skip reason reads differently from an
Allmiss.
None — no entry may be present¶
The rule runs only when none of the listed columns exists. Use it for a rule whose question is meaningless once a richer column is available.
⚠
Nonehas no rules using it today. The engine supports it and it is tested, but nothing in the corpus exercises it, so you are the first reader of any error it produces. PreferAllorAnywhere either expresses the same thing.
What an entry may be¶
The same vocabulary on all three facets:
| entry | means |
|---|---|
AESTDTC |
that column, literally |
--STDTC |
the domain-prefix placeholder, resolved to the dataset in hand |
SUPPAE.QNAM |
a qualified entry — that column in that dataset |
AE* |
a glob |
/^AE.*DTC$/ |
a regular expression |
Any of these may carry a type suffix — AESTDY:N,
DM.AGE:N, "/^AE.*DTC$/:C" — on the All and Any facets.
A qualified entry is how you require a column in a dataset other than the one the rule is running on — usually one you are about to join.
Demanding a type as well as presence¶
An All or Any entry may end in a type suffix, so the entry demands that the column is
numeric or character as well as present:
Requirements:
Variables:
All:
- "AESTDY:N" # must exist AND be numeric
- "AETERM:C" # must exist AND be character
Four spellings, case-insensitive, and the short and long forms mean exactly the same thing:
| suffix | demands |
|---|---|
:N · :Num |
a numeric column |
:C · :Char |
a character column |
An unmet type is a SKIP, not a finding. The rule stands down for that dataset and the reason
names both the demanded and the actual type. This is the whole point of the feature: without it, a
rule inapplicable to a character --ORRES had only one behaviour available, and it was an
ERROR.
Use it when the rule's arithmetic or comparison only makes sense on one type. A check that does
num(--STRESN) > 0is not applicable to a character--STRESN; saying--STRESN:Nturns that from an error into an honest "not applicable".
The type is the dataset's own¶
The suffix reads DataTableColumnMeta's declared type — what the delivered data says.
⛔ Never the CDISC Library's type, and never Define-XML's. Those are different questions and the language names them apart:
var_type("LIBRARY")andvar_type("DEFINE"). If your rule is about what was promised rather than what was delivered, the suffix is the wrong tool.
A type the engine cannot classify does not block. The entry fails only on a type that positively contradicts it, so an unclassifiable column is still met.
Two cases resolve the type elsewhere:
- A qualified entry —
DM.AGE:N— takes the type from the qualifier's dataset. For a split domain, it is the type every member carrying the column agrees on; where the members disagree, the entry makes no type demand rather than guessing. - A variable delivered through the SUPP-QNAM pivot takes that
SUPPxxtable'sQVALtype, because that is how its values actually arrive.
⛔ None does not accept a suffix¶
None: ["AESTDY:N"] # load error
It would have to mean "no numeric variable of that name may be present" — which a variable of the other type also satisfies, making the requirement meaningless. The loader rejects it by name.
⚠ Two entries differing only by suffix are one entry¶
Any: ["AVAL:N", "AVAL:C"] # load error
An Any group needs two or more distinct entries, and the suffix is folded when distinctness
is counted — so this is the degenerate one-column group in disguise. Read it aloud and it is just
"AVAL is present", which is an All entry.
Malformed suffixes are rejected, not guessed¶
X:, X:Z, X:NN, X:Numeric, X:Character and A:B:C are all load errors. Only a valid
trailing tag is stripped, so a colon-bearing entry is never silently read as a column named X.
The tag is removed before the entry's regex test and before the qualifier split, so it composes
with every other entry form — "/^AE.*DTC$/:C" and "TRTxxPN:N" both work.
An entry without a suffix is unchanged¶
Adding the feature changed nothing for entries that do not use it — same matching, same skip reasons, same message text.
Datasets — a whole dataset must be present¶
Requirements:
Datasets: ["DM"]
The named datasets must be present in the run. Presence is widened: a split domain counts as
present, so requiring LB is satisfied by LB1 and LB2 without naming them.
Use it when the check reaches into another dataset — a join, or a cross-dataset reference — and cannot answer anything without it.
Variable_Universe — which variables the rule iterates¶
Variable_Universe: "Define"
Data (the default when the key is absent) or Define.
It decides which set of variables a rule iterates when it walks variables rather than rows:
Data— the columns the dataset actually has. The right choice when the rule is about delivered data.Define— the variables Define-XML declares. The right choice when the rule is about what was promised: a variable declared and not delivered is visible to aDefinerule and invisible to aDataone.
Choose
Defineonly when the mismatch between promise and delivery is the point. A rule that checks values cannot use it — Define-XML declares variables, not data.
skipIfLibraryDefined¶
skipIfLibraryDefined: true
When true, the rule stands down if the CDISC Library already enforces the same constraint, so a
sponsor does not receive the same finding twice from two authorities.
Set it when your rule restates something the Library defines. Leave it absent otherwise.
Not yours to write¶
Requirements.Library Requirements.Define Requirements.Dictionary
These three record whether the rule needs a CDISC Library provider, a sponsor Define-XML overlay, or an external dictionary. The loader derives them from what your check actually references.
Writing them by hand is at best redundant and at worst a claim that contradicts what the rule does. State a dependency by referencing the thing, not by declaring the requirement.
Next: The check — the expression itself.