Skip to content

Motivation

Two AI agents use the same specification to derive ADaM data. Both report completion, but their outputs differ. The specification leaves decisions for the agents to make during implementation. A human reviewer must find the gap, settle the rule, and rerun the derivation.

Review takes longer, and confidence in the result falls.

Introduction

yamaa is a domain-specific language (DSL) for clinical trial data standardization. A yamaa specification transforms ODM XML data, extracted from an EDC system, into SDTM and ADaM datasets following CDISC standards, and on to define.xml. yamaa's rules fix what every item means, so the same specification with the same inputs always produces the same dataset, in the R engine and in the Python engine alike.

The language is designed for AI-agent and human collaboration: people and agents build the specification together at the planning stage, so nothing is left for the coding stage to guess.

Why specifications disagree

An Excel specification has three layers, but only two of them are written down:

Layer What it answers Where an Excel spec keeps it
Structure What exists -- which datasets, which variables, which types Dataset sheet, Variable sheet
Algorithm What to compute The free-text derivation column
Semantics What that computation means when the data does not cooperate Nowhere. It lives in each programmer's experience

yamaa writes each layer into a different kind of file:

Layer of yamaa File
Structure yaml/schema*.yaml -- what a specification may contain
Algorithm your spec.yaml -- one specification produces one dataset
Semantics rules/ -- normative contracts for every written item
Worked proof benchmarks/ -- runnable specifications with byte-exact expected outputs

In one sentence: an Excel spec is written to be understood; a yamaa spec is written to be executed the same way twice.

One execution

A yamaa specification has exactly one execution. Where it would have two, yamaa fails instead of choosing.

Think of execution as a function:

output_dataset = derive(input_datasets, spec)

The contract covers two things: spec, the closed vocabulary saying what you can write and nothing more, and derive, the semantics saying what each written item means. See Principles for why this moves agreement to the planning stage.

The four components

Component Purpose Start here
Schema Declares what a specification may contain; anything it does not declare is rejected before execution. Schema introduction
Rules Fix the meaning of every written item, so the R and Python engines cannot read the same spec in two ways. Rules
Engine Runs specifications in Python and R; the same specification with the same inputs produces the same output dataset. Python and R engines under Engine in the nav
Benchmark Runnable specifications with input data and byte-exact expected outputs. Benchmark

What a specification looks like

One specification produces one dataset. yamaa first constructs the output rows, then derives columns onto those rows. Column derivation never changes the row count. See Derivation for the full keys / rows / columns walkthrough.

Derivations use only registered verbs -- no free-text derivation column. Every verb declares what happens when the data does not cooperate:

derivation:
  mapping:
    source: DM.SEX
    dict: {M: M, F: F}
    missing: U      # "if not collected, set to U"
    unmapped: U     # "if not in codelist, set to U"

Omit a handler and its condition stops the run. "Not collected" and "collected but unrecognised" are two conditions, answered by missing and unmapped. Write null as the answer to leave the value missing instead.

Where to go next