Rules at a glance¶
The principles and every rule's title, generated from the rule files. Each title states its rule; the statement a reviewer approves, the detail, conditions and evidence are in the rule's file.
Principles¶
P1. Everything is declared. Columns, types, keys, joins, row construction, order and checks are written in the specification. Nothing is inferred from data, from file contents, from a same-named field or from a host default. Enforced by SPEC-4, INPUT-5, OUTPUT-5 and INPUT-1.
P2. Values never convert silently. An operation never converts its inputs. A value converts once, to its column's declared type, by one table, and a failed conversion is a named failure. Enforced by VALUE-2, VALUE-3 and INPUT-7.
P3. Missing is a value. Missing is distinct from every string, number and the empty string; no text spells it, every type admits it, and every operation states what it does with it. Enforced by VALUE-25, FORMULA-4, COLUMN-10, FORMULA-24 and INPUT-8.
P4. Ambiguity fails. Two values for one key, several matching records without a declared selection, an unmapped value or text that does not parse fails with a named condition instead of choosing. Enforced by COLUMN-2, LOOKUP-10, FORMULA-20 and NAME-13.
P5. Order is data. Stored record order, construction order and declared order terms decide every tie. No operation reorders records or chooses an order of its own. Enforced by ROW-7, VALUE-23, FORMULA-19 and INPUT-2.
P6. Values are exact. Integers are exact 64-bit values and floats are binary64 computed exactly as written. Nothing is rounded except where a specification declares it. Enforced by VALUE-7, VALUE-9, FORMULA-26 and CSV-8.
P7. Vocabularies are closed. Verbs, grammars, functions, column types, storage profiles and conditions are closed lists. Extending one is a rule change. Enforced by VALUE-1, EXPR-1, FORMULA-18 and COLUMN-15.
P8. Inheritance is deterministic. Layers compose in one fixed order, and the resolved specification is the same whatever spelling its layers used. Enforced by LAYER-3, LAYER-5 and LAYER-14.
P9. Faults are found before data. A fault that does not depend on data fails during validation, before any input record is read. Enforced by LAYER-12, FILE-11, INPUT-1 and VALUE-24.
P10. Artifacts are reproducible. The same specification and inputs produce the same artifact bytes, and an artifact is published whole or not at all. Enforced by CSV-3, OUTPUT-8 and DEFINE-23.
P11. A package is consistent and traceable. The datasets, transport files, run reports and Define-XML documents a project publishes come from one set of resolved specifications and agree on every fact they share. Every published fact names its source: an identifier derives from declared identifiers, metadata from the specification that built the data, and an origin is declared, never inferred. Enforced by JSON-5, JSON-6, DEFINE-9, SUB-19 and INPUT-11.
Specification structure¶
Declare root fields, unique identifiers, column derivation coverage, internal and copied columns, and ASCII source.
Root fields and identifiers¶
- SPEC-1. A specification derives one output dataset from the root fields it declares
- SPEC-2. Mapping keys, dataset identifiers, column names and row IDs are each unique
Columns¶
- SPEC-3. The artifact's columns are declared, never generated from source fields
- SPEC-4. Every declared column is derived, never filled from a same-named source variable
- SPEC-5. A column without a column-level derivation is derived in every row template
- SPEC-6. A row-local column-level derivation is a default that each row template may override
- SPEC-7. A declared column outside
output.columnsis internal and is evaluated like an output column - SPEC-9. A
copyentry declares the listed columns of a schema-linked input under their names, with the producer's type and label
Language source¶
- SPEC-8. Language source is ASCII
Inheritance¶
Resolve inherited layers into one minimal, ordered specification.
Layers¶
- LAYER-1. A specification is its entry file composed with the chain of parents and the fragments it reaches
- LAYER-2. A parent or a fragment is one local YAML file resolved from the layer that names it
- LAYER-3. Layers contribute from the root ancestor to the entry, each after its fragments, later layers taking precedence
- LAYER-4. Every layer is a valid partial specification of the language version it declares
Composition¶
- LAYER-5. Keyed collections compose member by member, the blocks
outputandsubmissionfield by field, and every other root field replaces whole - LAYER-6. A matching member merges recursively: classes by field, mappings by key, scalars and lists by replacement
- LAYER-7. Requiredness and defaults apply to the composed member, never to one contribution
- LAYER-8. A named window composes by name like every keyed member, and every reference uses the final definition
- LAYER-9. YAML null is the missing value, and a layer clears an inherited field only by listing it in
clear - LAYER-10. A path keeps its declaring layer's base and authored spelling
The resolved specification¶
- LAYER-11. Declarations that cannot affect the artifact or an assertion are pruned
- LAYER-12. Name and reference validation applies after pruning
- LAYER-13. A layered specification's resolved columns follow dependency order with a stable tie-break
- LAYER-14. The resolved specification is canonical
Name binding¶
Resolve input datasets, qualified and bare names, driver reads, and ODM item reads.
Input datasets¶
- NAME-1.
inputdeclares every dataset a specification reads, each under its own identifier - NAME-2. No input dataset takes the output dataset's name
Variables¶
- NAME-3. A qualified name reads a declared dataset or lookup, and a bare name reads an output column
- NAME-4. A qualified read of the driver reads its current record, or in a group the group's key
- NAME-5. A
variablefield names exactly one variable, never an expression - NAME-6. A structured
sourceadds handlers and a record filter to one variable
ODM item reads¶
- NAME-7. An
odmexpression reads one collected item named asDATASET.ItemOID - NAME-8. An ODM input binds its eleven fixed text fields by case-folded name, checked at validation
- NAME-9. Every ODM input record carries the seven required identifiers
- NAME-10. A row's ODM scope is the set of ODM input records the row was built from
- NAME-11. An
odmexpression evaluates only for a row whose ODM scope covers the input it names - NAME-12. An
odmread identifies the scope records of its item that meet its OID lists and filter - NAME-13. An
odmread gives the identified record'sValue, missing for none, and fails for several
Values¶
Define column types, missing values, numbers, text, dates, datetimes and times, conversion, and order.
Column types and conversion¶
- VALUE-1. A column declares exactly one of six types, and every type also admits missing
- VALUE-2. An operation never converts its inputs, and an input of an incompatible type fails
- VALUE-3. A completed result converts to its column's type by one table, or fails
- VALUE-24. A derivation whose result type can never convert to its declared type fails validation
Missing values¶
- VALUE-25. Missing is one value distinct from every other, and each operation states what it does with it
- VALUE-4. A non-finite float becomes missing before any consumer can see it
Numbers¶
- VALUE-5. An int is a signed 64-bit integer, and leaving that range fails with integer_overflow
- VALUE-6. Numeric text parses by one grammar, and every other spelling fails
- VALUE-7. Conversion to int succeeds only for an exactly integral value within range
- VALUE-8. An int widens to the nearest binary64, and a number converts to one canonical text
- VALUE-9. Values are used unrounded, and presentation rounding never feeds back
- VALUE-10. Each arithmetic operator and numeric function returns a fixed numeric type
Text¶
- VALUE-11. A string is a sequence of Unicode scalar values, decoded strictly where it enters
- VALUE-12. Text is never normalized, and two strings are equal only scalar for scalar
Dates, datetimes and times¶
- VALUE-13. A date names one calendar day, a datetime one civil second and a time one second of the day, with no gaps
- VALUE-14. A datetime carries no zone, offset or fractional second, and never shifts implicitly
- VALUE-15. Text becomes a date, datetime or time only in one zero-padded extended form
- VALUE-16. Every temporal value is complete and records its collected precision on one ladder
- VALUE-17. A temporal value is written in one canonical text that carries its fields alone
- VALUE-18. A date, a datetime and a time never convert into one another or enter arithmetic
Comparison and order¶
- VALUE-19. An int and a float compare exactly; every other type compares only with itself
- VALUE-20. Strings order by scalar value, position by position
- VALUE-21. Values of one temporal type order chronologically, whatever their collected precision
- VALUE-22. An order term sorts by its type's order and direction, and missing sorts lowest unless nulls places it
- VALUE-23. Rows equal on every order term keep their construction order
Inputs¶
Select input profiles, keep stored record order, and type source fields without inferring values.
Profiles¶
- INPUT-1. The input path's extension selects the profile that reads it, and nothing is sniffed
Records¶
- INPUT-2. A reader returns records in stored order, and nothing reorders them
- INPUT-3. An input may declare a generated field holding each record's one-based stored position
- INPUT-4. A generated ordinal must not collide with a stored field or join an ODM input
Field types¶
- INPUT-5. Every input field has one type, from its container or its declaration, never from its values
- INPUT-6. A types entry may only type an existing field of a source that supplies no type
- INPUT-7. Stored text parses into its field's declared type, or fails ingestion before any derivation
Missing values¶
- INPUT-8. A null or an empty field is missing, and no other text spells missing
- INPUT-9. Each input declares whether a stored empty string is missing or present
Producing specifications¶
- INPUT-10. A schema link types a stored artifact from its producing specification without running it
- INPUT-11. A linked artifact's fields are exactly its producer's output columns, with their types
Row construction¶
Construct output rows from declared input records or groups, or from the distinct keys of the base records.
Row templates¶
- ROW-1. Each row template has a unique id and builds its rows from one declared driver
- ROW-2. An intermediate drives rows only when it reads an input and exposes typed fields
- ROW-3. A row template without group_by is record-driven and builds one candidate row per driver record
- ROW-4. A row template with group_by builds one candidate row per group of driver records, then filters it
- ROW-5. A grouped row derivation reads a driver field only as a group key or through an aggregate
- ROW-6. A row filter names only columns its row template derives, and only values complete at its phase
Rows and their order¶
- ROW-7. Row templates are ordered sections, and each retained driver record or group yields one row
Rows without row templates¶
- ROW-8. Without row templates, the output rows are the distinct key combinations of the base records
- ROW-9. A root filter selects base records before the distinct-keys step and reads only base fields
Column derivation¶
Sequence a run, order column dependencies, complete each value's lifecycle, handle conditions at their site, and name the phase and rule each condition reports.
Run order¶
- COLUMN-1. A run validates, builds rows, derives columns, verifies, orders and publishes, in that order
- COLUMN-2. A column derivation yields exactly one value per row and never changes the row count
Dependencies¶
- COLUMN-3. Dependencies come from every reference an expression makes, closed grammars included
- COLUMN-4. Row derivations follow their template's dependency graph and never read a value only column derivation produces
- COLUMN-5. Columns follow declaration order except for causal backward row reads
- COLUMN-6. A column dependency cycle fails unless every cycle crosses a causal backward row read
- COLUMN-7. Without row templates, a key is computed from one base record and never from a non-key output column
Value lifecycle¶
- COLUMN-8. Every derived value is evaluated, converted and handled before anything reads it, then verified
- COLUMN-9. A row filter reads candidate values after stages 1 to 3 and never hides a failed derivation
Local handlers¶
- COLUMN-10. A local handler answers its condition with a literal, and an omitted handler gives missing for a missing single input or absent record and leaves every other condition fatal
- COLUMN-11.
absentanswers a lookup that finds no record, andmissinganswers a missing input value - COLUMN-12. A structured source carries its own handlers, and order_by with keep selects one of several records
- COLUMN-13. A result wrapper's unconvertible replaces only a failed conversion to the column type
- COLUMN-14. Every handler path reports how many records it answered as a report row, default substitutions and zero included
Diagnostics¶
- COLUMN-15. A language diagnostic cites the rule that owns its failure; only listed implementation conditions cite none
- COLUMN-16. Every condition reports one phase from a closed list, which names the part of the run that decides it
Expressions¶
Register and dispatch expressions, give each one result type, restrict nesting, and copy, select and classify values.
Registry and evaluation¶
- EXPR-1. A derivation holds exactly one registered expression keyword, which owns its payload
- EXPR-2. An expression yields one value per row, and only windows and aggregates read other rows
- EXPR-3. Expressions nest only in case results, key match values and a nearest selection's
to - EXPR-14. Every expression has one declared result type function, and every context reads its type
Values and shorthand¶
- EXPR-4. A reference or a structured source copies a named variable, and a literal returns its value unchanged
- EXPR-5. An expression field reads a bare name as a reference and quoted text as a literal
- EXPR-6. An expression that selects a value returns it unchanged, with its collected precision
Conditional selection¶
- EXPR-7. case returns the value of its first TRUE branch, then otherwise, else missing
- EXPR-8. flag returns a declared value for each of TRUE, FALSE and UNKNOWN
- EXPR-9. first_available returns the first source that is not missing
- EXPR-10. greatest and least return the largest or smallest non-missing source
Classification¶
- EXPR-11. mapping replaces a string source with its dictionary value
- EXPR-12. A case-insensitive mapping folds ASCII letters, and its folded keys must be unique
- EXPR-15. decode replaces a coded source with its item's decode in a codelist the project file declares
- EXPR-13. cut assigns a numeric source to one of its labeled break intervals
Formulas¶
Read the one closed expression language in its predicate, aggregate and expression fields, and evaluate it exactly as written.
The language¶
- FORMULA-1. An expression is one text in the closed expression grammar
- FORMULA-2. Keywords and the names of functions and reducers are case-insensitive, and a sign binds tightest and OR loosest
- FORMULA-3. A literal has a fixed runtime type, an integer literal fits int, and a temporal literal needs its keyword
- FORMULA-27. The field an expression is written in fixes its root and the constructs it admits
- FORMULA-9. An identifier names a value visible at its site, and any other name fails
Predicates¶
- FORMULA-4. A predicate is TRUE, FALSE or UNKNOWN, and only TRUE retains a row or record
- FORMULA-5. Two non-missing operands compare only when their runtime types are mutually comparable
- FORMULA-6. IN and BETWEEN expand into comparisons, and their NOT forms negate the result
- FORMULA-7. LIKE matches text scalar by scalar, case-sensitively, with an optional one-scalar ESCAPE
- FORMULA-8. str_contains is the one truth-valued function and searches its source for a portable regex
Arithmetic¶
- FORMULA-12. Every operand of arithmetic or of a numeric function must be numeric
- FORMULA-13. The numeric functions are a closed list, each with a fixed argument count
- FORMULA-14. A missing operand makes arithmetic and numeric functions missing, except NULLIF's second argument
- FORMULA-15. Division by zero, an invalid root, logarithm, power or probability, and int overflow fail the run
- FORMULA-16. There is one rounding: half away from zero, with near ties treated as ties
Aggregate expressions¶
- FORMULA-17. aggregate reduces one relation to one value with a closed reducer expression
- FORMULA-18. The reducers are exactly SUM, COUNT, MIN, MAX, MEAN, ONLY, STR_JOIN, MEDIAN, Q1, Q3, QUANTILE, STDDEV, VARIANCE and GEOMEAN
- FORMULA-19. SUM adds in relation record order, MEAN divides that SUM by COUNT, and VARIANCE, STDDEV and GEOMEAN add in the same order
- FORMULA-20. ONLY returns the value of a group's one record and fails on more than one
- FORMULA-21. Reductions do not nest
- FORMULA-22. An identifier outside a reduction must name a grouping column
- FORMULA-23. A reduction keeps the type it reduces, and arithmetic over reductions is numeric
- FORMULA-24. Value reducers skip missing values, and a group with no record reduces to missing
Evaluation¶
- FORMULA-26. Expressions evaluate deterministically and exactly as written
Lookup and joins¶
Match declared keys, narrow and select records, answer absence, and scope aggregates to one relation.
The lookup model¶
- LOOKUP-25. Every lookup runs the same four steps, match, narrow, select and answer absence, whatever its kind
- LOOKUP-9. Match keeps the records whose keys equal the current row's match values and whose bounds hold its range value
- LOOKUP-8. Narrow keeps the matched records for which the lookup's filter is TRUE
- LOOKUP-10. Select chooses the first or last candidate by order_by, and an aggregate reduces every candidate
- LOOKUP-26. A named intermediate's nearest selection chooses the candidate whose date or datetime lies nearest the current row's reference
- LOOKUP-28. A named intermediate's pivot exposes each listed value of one donor field as a field of its selection
- LOOKUP-24. A lookup with no candidate answers absence, missing by default, unless require_match fails it
- LOOKUP-14. Lookup handler counts, failures and reviews report the match in one vocabulary
Keys¶
- LOOKUP-5. A key pairs each column of the lookup's relation with a current-row match value
- LOOKUP-6. A key match value may be an expression whose static result type is checked before matching
The implicit join¶
- LOOKUP-1. A dataset-qualified source reads through the implicit join on the input's declared key
- LOOKUP-2. Row construction reads another dataset through the same join, using only values available before column derivation
Named intermediates¶
- LOOKUP-3. A named intermediate declares an id, a dataset and a key
- LOOKUP-4. A named intermediate must narrow, derive or reshape its dataset
- LOOKUP-7. A named intermediate may read SELF, the completed rows of earlier row templates
- LOOKUP-11. A lookup-qualified variable reads a column of the selected record
- LOOKUP-12. A lookup matches once per row when first read and never changes the row count
Intermediate derivations¶
- LOOKUP-15. Intermediate derivations add per-record fields to the donor records
- LOOKUP-16. An intermediate derivation may read another intermediate's selection for its donor record
- LOOKUP-17. An intermediate's unique verification asserts that no donor column combination repeats, warning instead only where a selection chooses
Aggregates over a relation¶
- LOOKUP-18. An aggregate reduces one declared dataset, the constructed output rows, or the current input group
- LOOKUP-19. A qualified aggregate groups by output keys and an unqualified one by output columns
- LOOKUP-22. A qualified aggregate's derivations compute typed per-record values before reduction
The pair relation¶
- LOOKUP-27. A named intermediate that writes inner_join is a pair relation, one record for each matching pair of its two sides
Windows¶
Declare complete named windows and compute partitions, ranks, neighbors, carried values, and baseline flags.
Named windows¶
- WINDOW-1. A window reference names one complete definition declared in root windows
- WINDOW-2. A named reference expands to an independent copy of its definition before analysis
Partitions¶
- WINDOW-3. A window partitions the rows of its evaluation context by group_by and preserves row count
- WINDOW-11. A column-level window reads a driver field only when every row template has that driver
- WINDOW-4. A window filter excludes rows before partitioning, and an excluded row receives missing
- WINDOW-5. Positional window operations require window.order_by, and baseline_flag defaults it to its date
Window operations¶
- WINDOW-6. row_number numbers positions from 1, and rank gives rows tied on every term one number
- WINDOW-7. row_value reads the source from the row a nonzero offset away along the declared order
- WINDOW-12. Strictly backward row_value reads can carry calculated history in one independently ordered column group
- WINDOW-8. locf carries the closest strictly earlier non-missing source forward unless include_current lets a present current source answer
- WINDOW-9. baseline_flag flags the last eligible row of each partition in date order, and a tie for last fails
- WINDOW-10. Window operations convert nothing: numbering returns int and selections keep their type
Text¶
Pad, take pieces by position, count scalars, write numbers with fixed decimals, change case, interpolate templates, and extract and replace with portable regular expressions.
String verbs¶
- TEXT-1. Text verbs take string sources and fail rather than convert another type
- TEXT-2. str_pad left-pads a value's canonical text with ASCII spaces to a minimum width
- TEXT-13. str_substr takes the scalars of a text from a position counted from 1, and gives missing past its end
- TEXT-16. str_substr with piece breaks a text between words into pieces of at most length scalars and takes one
- TEXT-14. str_length counts the scalar values of a text as an int
- TEXT-15. str_decimal writes a number with exactly
decimalsdigits by the one rounding, left-padded with spaces to a minimum width
String templates¶
- TEXT-3. A string template is literal text, braced placeholders and doubled braces, nothing else
- TEXT-4. str_template replaces each placeholder with its string value, or answers a missing one
Case¶
- TEXT-5. str_case changes the case of ASCII letters only, one scalar for one
Regular expressions¶
- TEXT-6. Every pattern is a portable ECMA-262 subset without lookaround or backreferences
- TEXT-7. A pattern carries the Unicode flag only: case-sensitive, anchored to the whole subject, stateless
- TEXT-8. Character classes are fixed ASCII and ECMA-262 sets, and a non-ASCII scalar is an escape
- TEXT-9. A schema pattern is a full match, while matches and str_extract search the subject
- TEXT-10. Capture groups are numbered by opening parenthesis, and str_extract returns one group
- TEXT-11. str_replace replaces every non-overlapping match, left to right, with literal text
- TEXT-12. A pattern too deep or too large to compile is refused at its path; matching is never refused
Dates and times¶
Compute differences, study days and times of day, read declared date forms, assemble and complete collected dates and times, report collected precision and imputation flags, and apply civil arithmetic.
Operations¶
- TIME-1. Each temporal operation has fixed input types, and a type-dispatched one declares its type
- TIME-2. to_date returns the calendar date of a datetime or of text carrying a complete date, and partial text gives missing
- TIME-3. to_epoch_day converts a date to its signed day count from 1970-01-01
- TIME-20. time_of_day returns a datetime's time of day as whole seconds since midnight
- TIME-23. to_time returns a datetime's time of day as a time
Differences¶
- TIME-4. diff returns end minus start in whole calendar units for dates, or in an elapsed unit for datetimes
- TIME-5.
closedsets which endpoints a day count between two dates includes, and only that count takes it - TIME-6. study_day counts from the reference date as day 1, with no day zero
Collected dates and times¶
- TIME-7. Collected date text is ISO 8601 read up to its first unknown field, and precision reports how much of the declared type a source carries
- TIME-22. date_text reads text in one of its declared date forms into the collected date text it denotes
- TIME-19. dtc writes collected date parts as collected date text that stops before the first missing part
- TIME-8. impute completes collected text into a value of its declared type from declared month, day and time rules
- TIME-9. Imputation bounds move only supplied fields, a bound outside the collected interval is ignored, and crossed bounds give not_after
- TIME-10. impute's month and day rules must fit each other and the calendar
- TIME-13. A missing source gives missing unless impute declares a fallback, and invalid text fails unless invalid answers it
Civil arithmetic¶
- TIME-14. shift moves a date by whole days, or a datetime by a signed elapsed amount rounded to a whole second
- TIME-17. duration_value reads ISO 8601 fixed-length duration text as a number in a declared unit
- TIME-21. duration_text writes a number in a declared unit as canonical ISO 8601 fixed-length duration text
- TIME-24. calendar_duration writes the whole months from one date to another, then the remaining days, as ISO 8601 duration text
Imputation flags¶
- TIME-18. imputation_flag returns the ADaM date or time imputation flag from an imputed value's collected precision
Verification¶
Apply assertions, severity, and grouped counts to completed values, and record what each run read, counted and checked in one run report.
Running verifications¶
- CHECK-1. Column checks run after their column converts; dataset checks run after all column work
- CHECK-2. A failed error verification fails the run; a violated warning fails nothing and changes no row
- CHECK-3. A verification may declare a nonempty id, unique within its verification list
- CHECK-4. A verification declares known fields, ordered bounds and existing columns of a compatible type
Column verifications¶
- CHECK-5. Only
not_missingrejects a missing value, on the rows its when selects and beyond any share its max_fraction allows, and declaring it on a key column is redundant - CHECK-6.
allowed_valuesrequires every present value to equal one listed value - CHECK-7.
rangerequires every present numeric value to lie within its inclusive bounds - CHECK-8.
max_lengthbounds a string column's values by their count of Unicode scalar values - CHECK-9.
matchesrequires every present string to match its regular expression
Dataset verifications¶
- CHECK-10.
uniquerequires the combined values of a column set other than the keys to be unique, missing values included - CHECK-11.
all_or_nonerequires the listed values of each row to be all missing or all present - CHECK-12.
assertrequires its predicate to be TRUE on every output row its when does not exempt - CHECK-13.
row_countbounds how many output rows its filter admits, as a count and as a share - CHECK-14. Row count bounds apply to every group of the artifact's rows that its when does not exempt
Assertions a verification cannot state¶
- CHECK-15. An ordered-series assertion is a derivation followed by a row-wise assertion
- CHECK-16. A cross-dataset link is asserted by the derivation that produces it, not by a verification
The run report¶
- CHECK-22. Every run builds one report, which a warning requires a file for and a failed run still writes
- CHECK-23. The report has one row per run, input dataset, row template, handler path, output column and evaluated check, in that order
- CHECK-24. The report has fourteen fixed columns, and a kind leaves missing each column it has no value for
- CHECK-25. KEYS and DETAILS are compact ASCII JSON with names in text order
- CHECK-26. The report is verified before it is written or returned, and a malformed report is an execution defect
Output¶
Select artifact columns, keys, profiles, and row order, and publish complete files atomically.
Columns and keys¶
- OUTPUT-1. The artifact's columns are exactly
output.columns, in that order - OUTPUT-2.
keyslists one or more output columns, each once - OUTPUT-3. Every artifact row's combined key values are non-missing and unique
Profiles¶
- OUTPUT-4.
output.pathis required and names the primary file - OUTPUT-5. Each output path's extension selects the
csvorparquetprofile from a closed mapping - OUTPUT-6. A profile carries every value the language admits without changing it
Publication¶
- OUTPUT-7. A run publishes once, after the whole artifact is complete
- OUTPUT-8. Each file replaces its target atomically, and a failed run leaves the target unchanged
The report file¶
- OUTPUT-9. The primary file and the report file have distinct paths, each selecting its own profile
- OUTPUT-10. The report file publishes before the primary file, and a failed run publishes only its report
Row order¶
- OUTPUT-11.
output.order_byorders the artifact's rows once, after every verification - OUTPUT-12. Each
output.order_byterm names a different declared column
Resource limits¶
Bound each file, table, declaration, pattern and built text by one fixed policy, refuse past it with one identity, and bound each partition of a partitioned run.
Refusals¶
- LIMIT-1. A size past a fixed limit refuses its operation as engine_rejected, naming the boundary, its limit and the observed size
- LIMIT-2. One fixed policy bounds each file, table, declaration, pattern and built text
Partitioned runs¶
- LIMIT-3. A build run over key-bounded partitions gives the whole-table run's result, and its row and cell limits bound each partition
File resolution¶
Resolve declared local paths from their base, reach one regular file, and read one immutable snapshot per physical file.
Resolution base¶
- FILE-1. A document's relative paths resolve from the file that declares them, never from a discovered root
- FILE-2.
relative_toselects the declaring file's or the entry file's directory as a relative path's base - FILE-3. A schema-linked artifact is an ordinary input at its own path, and its producer is never run
Written form¶
- FILE-4. A path is relative or rooted, decided from its text before the filesystem is consulted
- FILE-5. A path has no URI scheme, backslash, empty segment or trailing separator
- FILE-6.
.and..segments resolve textually from the base and may leave it
Reaching a file¶
- FILE-7. Resolution walks each component from a directory anchor and must reach one regular file
- FILE-8. No component below the anchor is a symbolic link
One snapshot per file¶
- FILE-9. A run reads one immutable byte snapshot of each physical file, whatever spelling reaches it
- FILE-10. Content that changes between validation and ingestion fails the run
Path failures¶
- FILE-11. A path failure names the written path and declaring field and reports exactly one condition
CSV profile¶
Read admitted CSV spellings and write canonical CSV bytes and display precision.
Writing¶
- CSV-1. A csv artifact is UTF-8 without a byte-order mark, and every record ends in a line feed
- CSV-2. The header names
output.columnsin order, and each row follows as one record - CSV-3. A field is quoted exactly when it is empty or contains a quote, comma,
U+000DorU+000A - CSV-4. Missing is written as an empty bare field and the empty string as two quote characters
- CSV-5. Each value is written as the canonical text of its column type
Display precision¶
- CSV-6.
output.decimalsis an integer from 0 to 18 for every float column of a csv artifact - CSV-7. With
output.decimalsof n, every float is written in fixed point with exactly n decimal digits - CSV-8. Display rounding happens once, when a field is written, and no other stage sees it
- CSV-9. Display rounding applies the one rounding to the exact binary64 value
Reading¶
- CSV-10. A csv source is UTF-8, with a byte-order mark only where its input declares one
- CSV-11. A record ends in
U+000A, optionally preceded byU+000D, the last may end the file, and blank lines that end the file are no record - CSV-12. Fields are separated by commas and are either bare or quoted, with nothing trimmed
- CSV-13. The header names each field once, and every later record has exactly that many fields
- CSV-14. A field reaches ingestion as its text, or as missing when it has no characters
- CSV-15. No reader option changes what the csv profile fixes, and a reader repairs nothing
- CSV-16. A csv reading failure names the dataset, the written path, and the record and field
Parquet profile¶
Read and write the closed Parquet field and value mapping.
Writing¶
- PARQUET-1. Each column type maps to exactly one Parquet physical and logical type
- PARQUET-2. A date counts days from 1970-01-01, and a datetime and a time whole-second microseconds from 1970-01-01T00:00:00 and from midnight, with no zone
- PARQUET-3. A float is stored as the binary64 value its derivation produced, never rounded
- PARQUET-4. Parquet artifacts of one completed dataset read back identically, without identical bytes
Reading¶
- PARQUET-5. A parquet source is one Parquet file, read in its stored field and record order
- PARQUET-6. Every Parquet field has a non-empty unique name and a scalar type
- PARQUET-7. The embedded Parquet type supplies the field type through a closed mapping that inverts the write mapping and admits signed integers, single-precision floats and other timestamp and time units
- PARQUET-8. A Parquet null is the missing value, and present values arrive unchanged
- PARQUET-9. A stored date, timestamp or time names an in-range civil value on a whole second
- PARQUET-10. File metadata and layout never change the fields, records, types or values delivered
SAS source profiles¶
Read SAS datasets and Transport v5/v8 through declared encoding and explicit numeric narrowing.
Containers and text¶
- SAS-1.
.sas7bdatand.xptselect the read-only SAS dataset and Transport profiles - SAS-2. A SAS input uses its stored encoding, and a Transport input declares its encoding
Field types¶
- SAS-3. Character storage supplies
strand numeric storagefloat, andtypesmay only narrow a numeric field - SAS-4. Numeric narrowing accepts only an exact integral value, and SAS dates count from 1960
Values and order¶
- SAS-5. SAS missing values become missing, and character values lose only trailing padding
- SAS-6. A SAS reader decodes only the captured snapshot, in stored field and record order
- SAS-7. A SAS or Transport file that cannot be decoded fails ingestion with one closed cause
- SAS-8. A SAS dataset yields only its live records, in stored order
ODM source profile¶
Read an ODM 1.3 or 2.0 snapshot into the item table, refusing transactional content and documents without clinical data, and skip audit records.
Reading¶
- ODM-1. An
.xmlinput is read as an ODM snapshot, refusing transactional content and skipping audit records
Dataset-JSON source profiles¶
Read a Dataset-JSON 1.1 file in either representation, typing each field by its column's dataType and narrowing only by declaration.
Reading¶
- DSJSON-1.
.jsonand.ndjsonselect the read-only Dataset-JSON 1.1 profiles, and the file alone is the source
Field types¶
- DSJSON-2. Each column's
dataTypesupplies its field's type through a closed table, andtypesmay only narrow it
Values and order¶
- DSJSON-3. Each value is spelled as its column's
dataTypewrites it and parses into its field's type, or fails ingestion - DSJSON-4. Fields are the
columnsin order and records the rows in stored order, andrecordscounts them - DSJSON-5. A Dataset-JSON file that cannot be read fails ingestion with one closed cause
Schema language¶
Define schema notation, registries, constraints, canonical shorthand expansion, and the canonical spelling of a written value.
Bundles and documents¶
- SCHEMA-1. A schema bundle is one entry point and every document it includes, loaded whole
- SCHEMA-2. A yamaa file declares its type and the oldest language version it needs, and an older engine refuses it
- SCHEMA-3. Documents reject duplicate keys, aliases, merge keys, explicit tags and unknown constructs
- SCHEMA-4. Scalars resolve under the YAML 1.2 core schema, where only true and false spellings are Boolean
Named types and registries¶
- SCHEMA-5. A named type is a class, a value descriptor or a registry-backed type
- SCHEMA-6. Class fields are closed, and
fields_fromcopies another class's fields unchanged - SCHEMA-7. A registry maps keywords to payload shapes, and a registry value names exactly one keyword
- SCHEMA-8. Two things in one naming list never share a name
Type expressions¶
- SCHEMA-9. A type expression is a type name, a list or dict of type expressions, or a union
- SCHEMA-10. One union shape is shorthand, expanded to its canonical class while validating
- SCHEMA-15. A written long form that holds only what its shorthand fills means the shorthand, and the lint reports it
Descriptors¶
- SCHEMA-11. A descriptor uses only the closed descriptor keywords, each where it applies
- SCHEMA-12. A value satisfies its type and every constraint its descriptor declares
- SCHEMA-13. A class value carries every required field and no undeclared field
- SCHEMA-14. A descriptor written in flow form and in block form is the same descriptor
Submission metadata¶
Govern dataset and column metadata, origin, methods, and document references.
Declaring submission metadata¶
- SUB-1. Submission metadata is optional and is declared only for columns the artifact carries
- SUB-2. The free-form
metadatamap is never read and never carries a governed field name
Models¶
- SUB-3. A specification declares its model, and the implementation guide a document binds it to must belong to that model
Dataset metadata¶
- SUB-4. Dataset metadata states its label, observation class, record structure and whether it repeats
- SUB-5. A dataset's domain defaults to the specification's domain and is declared only for SDTM and SEND
Column metadata¶
- SUB-6. A column's submission data type defaults from its column type and model, within the closed set that type admits
- SUB-7.
lengthandsignificant_digitsare declared exactly where the submission data type needs them - SUB-8. A
strcolumn's length is a bound its completed values must meet, stated once - SUB-26. A
strcolumn's date or time data type is an ISO 8601 form its completed values must have - SUB-9.
display_formatandroledescribe a column for a reader and never change a value - SUB-10.
coretakes its model's designations, andmandatorycomes from the keys, the declaration, or the class andcore - SUB-11. A mandatory column is checked for missing values, and a
not_missingbeside it is redundant
Value-level metadata¶
- SUB-12. A column's
value_levelentries give the rows their where clause selects their own metadata - SUB-13. Each row matches at most one entry of a column, an entry that matches no row warns, and an entry's origin is refuted on the rows it selects
Origin¶
- SUB-14. Every column with submission metadata declares an origin from closed type and source vocabularies
- SUB-15. Each model admits its own origin type and source pairs
- SUB-16. A Predecessor, Other or Not Available origin carries a description
- SUB-17. A value collected from a person references the annotated case report form, with a page under
Submission - SUB-18. A Derived origin declares its method
What the derivation refutes¶
- SUB-19. A declared origin the column's derivation contradicts is rejected, and an origin is never inferred
- SUB-20. A Predecessor column is a bare copy of the column its description names
Methods, comments and documents¶
- SUB-21. A method states its algorithm in prose and may add a name, a kind, code and documents
- SUB-22. Comments and document references are declared where they are used and name declared documents
When the profile is checked¶
- SUB-23. Rules needing no project file are checked on the specification alone, and the rest when a document composes it
Transport measurements and dates¶
- SUB-24. With a transport, a character column is as long as the longest value the section's datasets carry
- SUB-28. With a transport, a column or value-level definition that holds no value in its dataset has no data
- SUB-25. Under
ADaMa date, datetime or time is submitted as a SAS numeric date with a fixed display format and length - SUB-27. An
SDTMorSENDdataset carries its dates and times as text, never in adatetimeortimecolumn
Controlled terminology¶
Declare codelists, compose them by id across their sources, and enforce the items each binding lists.
Declaring codelists¶
- CT-1. A project's codelists compose by
idacross its sources, and a column binds one byid - CT-2. A codelist source's
standardnames its published terminology, and a source without one is sponsor-defined - CT-12. A codelist's
format_namebegins with$exactly when the codelist istext
Values¶
- CT-3. A codelist lists its items or defers to an external dictionary, never both and never neither
- CT-4. Coded values are unique within a codelist, of its data type, and keep their declared order
- CT-5.
decodeandrankare declared for every item of a codelist or for none - CT-6. Only an extensible published codelist may carry sponsor-extended items, and an extended item declares no alias
Bindings¶
- CT-13. A project binding needs a project file, and a specification checked or run without one fails validation
- CT-7. A bound codelist that lists items is the column's value set, and an external dictionary enforces nothing
- CT-8. A bound column's declared type admits its codelist's data type
- CT-9. An
allowed_valuesverification beside a column's codelist of items is redundant
Documents and inventories¶
- CT-10. A generated document carries exactly the codelists its output columns bind
- CT-11. An inventory-vocabulary column holds only names of datasets any submission section of the project declares
Define-XML¶
Compose study metadata into deterministic Define-XML 2.1 documents.
The study document¶
- DEFINE-1. A Define-XML document is composed from one selected submission section of the project file
- DEFINE-2. The section's
definetarget names the document's file, ends in.xml, and isdefine.xmlbeside a transport - DEFINE-3. Two generations with the same captured inputs and creation time produce the same bytes
- DEFINE-4. A
Submissioncontext adds the requirements a regulator imposes, andOtherrelaxes nothing else
Composition¶
- DEFINE-5. Each
specsentry contributes one dataset, identified by its domain and placed in entry order - DEFINE-6. The section's implementation guides belong to its model, and each dataset is bound to the one it selects
- DEFINE-7. Every composed specification declares dataset and column submission metadata and column labels
- DEFINE-8. Composition resolves the codelist, standard and document names a specification leaves unresolved
Identifiers¶
- DEFINE-9. Every generated identifier is a fixed prefix and the declared identifiers of the object's position
- DEFINE-10. Declared identifiers are unique in their space, so generated identifiers cannot collide
Document structure¶
- DEFINE-11. The document has one fixed element structure in a fixed order, and omits an element without content
Element mapping¶
- DEFINE-12.
ODM,StudyandMetaDataVersioncarry fixed attributes from the study and the selected section - DEFINE-13. Each standard and supporting document produces its definition and its leaf
- DEFINE-14. At most one annotated case report form is declared, and a value collected from a person requires one
- DEFINE-15. Each dataset produces one
ItemGroupDef, whosePurposefollows from its model - DEFINE-16. A dataset's leaf names its transport file or its artifact, relative to the document and inside its directory
- DEFINE-17. A dataset declared to have no data carries a comment that says why
- DEFINE-18. Each output column produces one numbered
ItemRef, keyed by its position inkeys - DEFINE-19. Each column produces one base
ItemDefcarrying onedef:Originper declared origin - DEFINE-20. Each codelist produces one
CodeList, whose item elements follow from whether its items declare decodes - DEFINE-21. Methods and comments produce
MethodDefanddef:CommentDefelements, and all translated text carries one language - DEFINE-22. Transport names are written only when they match the SAS transport name patterns
Serialization¶
- DEFINE-23. The document's bytes are fixed: UTF-8, one element per line, two-space indentation and fixed escapes
- DEFINE-24. Generated text never carries a carriage return or tab, nor a line feed in an attribute value
- DEFINE-25. A complete document, valid against the selected Define-XML schema, is published atomically or not at all
Scope¶
- DEFINE-26. Constructs outside the profile cannot be declared and are never generated
- DEFINE-27. A column's value-level entries generate one value list, and a where clause and a definition per entry
- DEFINE-28. Define-XML requires the project's
studyand the section'sstandardsanddefine, which a run does not - DEFINE-29. A section selects its Define-XML release explicitly, retaining 2.1.11 when omitted
- DEFINE-30. Historical metadata is a literal record and makes no assertion about current derivations or data
Dataset-JSON¶
Write a dataset and its submission metadata as one deterministic Dataset-JSON 1.1 file.
Requesting a transport file¶
- JSON-1. A section's
transportrequests one transport file per composed dataset, named for the dataset beside the document - JSON-2. Every transport file has exactly one writer
- JSON-3. A dataset declared to have no data has no transport file, and a dataset without rows declares it
- JSON-4. The file is Dataset-JSON 1.1 in the representation
transportselects and valid against that standard's schema
Content¶
- JSON-5. The rows are the published artifact's rows, read the way a consumer reads a producer's artifact, and no display precision reaches them
- JSON-6. Every metadata member comes from the declarations the Define-XML document is generated from
- JSON-7. The file carries the standard's members in a fixed order, omitting absent ones: one object, or a first line and one row per line
- JSON-8.
metaDataRefnames the Define-XML document beside the file - JSON-9. Each output column produces one column object carrying that column's Define-XML metadata
- JSON-10.
dataTypemaps the resolved submission data type through a closed table, and an ADaM date, datetime or time targets an integer - JSON-11. Each row is an array of its values written by column type, with missing as
null
Serialization and publication¶
- JSON-12. When Dataset-JSON is requested, each dataset's leaf names its Dataset-JSON file
- JSON-13. The file's bytes are fixed: UTF-8, one layout per representation, one spelling per string and number
- JSON-14. Transport files are published before the document, and only after every file renders and validates
Reading¶
- JSON-15. A file this profile writes reads back through the Dataset-JSON source profiles as its published table
SAS Transport¶
Write a dataset as one deterministic SAS Transport version 5 file in the public record layout.
Requesting a transport file¶
- XPT-1. A section's
transport: xptwrites each composed dataset as one SAS Transport version 5 file
Records¶
- XPT-2. The file is a fixed sequence of 80-byte records in the transport layout
- XPT-3. The header records carry fixed text, the dataset's name and label, and the creation time
- XPT-4. Each output column produces one NAMESTR, in
output.columnsorder
Names, types and values¶
- XPT-5. Names are names DEFINE-22 admits, and labels are at most 40 printable ASCII characters
- XPT-6. A
strcolumn is a character variable, a number a numeric one, and a date travels as its model submits it - XPT-7. A character value is printable ASCII of at most 200 bytes without a trailing blank, and missing is blanks
- XPT-8. A numeric value is an IBM System/360 double converted exactly from binary64, and missing is a period
- XPT-9. A numeric variable carries a display format only when its declared one parses as a SAS format
- XPT-10. A file above 5,000,000,000 bytes, or one ending in an all-blank observation, is refused before writing
Project functions¶
Define each project function once in a function file, resolve immutable runtimes, and validate function inputs, results, and activation conformance.
Function files¶
- FUNC-1. Project functions come only from the function files the caller's project lists, through the running host's implementation
- FUNC-2. A function file is admitted on its own against the function schema before any activation or study read
- FUNC-3. One host language applies to every function, and a declared lock pins the called packages
Definitions and calls¶
- FUNC-4. Each logical function has one closed definition, and a call names only the function and its arguments
- FUNC-5. A signature is closed and named, and every argument and default matches its declared type exactly
- FUNC-6. A call argument is one leaf of the expression grammar, never a composed expression
- FUNC-7. An omitted optional argument takes its default, and a missing argument short-circuits unless its parameter accepts missing
Binding and invocation¶
- FUNC-8. A binding is a statically named installed callable, invoked once for each logical row
- FUNC-9. A binding returns one scalar of its declared type, and missing only when its definition permits it
- FUNC-10. An invocation failure identifies the logical function, its callable and its authored source
Activation conformance¶
- FUNC-11. Each definition's inline tests cover every obligation its contract implies
- FUNC-12. Every build runs every case of every called function before any study data is read
- FUNC-13. A numeric result is compared at
comparison_decimalswith the one rounding, and is never changed
Project file¶
List a study's function files and host locks, declare its terminology and submission sections once, compose a project file on one parent, and check, run and package the specifications its sections list.
The project file¶
- PROJECT-1. A project file is passed explicitly and names one study's functions, host locks, terminology and submission sections
- PROJECT-16. A project file names at most one
parent, and composes on it section by section - PROJECT-2.
environmentsholds each host language's lock, and each host reads only its own - PROJECT-3. A section needs only
specs, and the study metadata a run does not read is required only by Define-XML - PROJECT-4. A project file's relative paths resolve from the project file that writes them
Specification names¶
- PROJECT-5. A listed specification's name is its
domain, unique across the project - PROJECT-6. Selecting a project specification by name accepts only a name the project defines
Selecting a section¶
- PROJECT-14. Selecting a project section accepts only a section the project declares
Checking a project¶
- PROJECT-7. Checking a project checks every listed specification in section and listing order, with the project findings
Project runs¶
- PROJECT-8. A project run builds each specification of its run scope once, a linked producer before its consumers
- PROJECT-9. A producer outside the run scope is not built, and its consumer reads the saved file
- PROJECT-10. An input that reads a run-scope artifact without a
schemalink fails - PROJECT-11. A failed run-scope specification stops only the specifications that depend on it
Saving a project run¶
- PROJECT-12. Saving a project run validates every target first, then publishes specification by specification in run order
Project submissions¶
- PROJECT-13. A project submission composes each selected section's Define-XML document in section order
- PROJECT-15. A project submission composes a specification that declares a run report only with the artifact and inputs that report records