Skip to main content

Example corpus

Five forms that are meant to be run, not just read. Every one of them is validated on every CI run — by validateFormDefinition (packages/core/test/corpus.test.ts) and, separately, against the published JSON Schema in Ajv strict mode (tools/validate-schema.mjs). A form that stops validating fails the build.

rasd validate docs/examples/*.form.json

The forms

FileWhat it isWhat it is here to cover
pdm-food-distribution.form.jsonpdm-gfd-2026 — post-distribution monitoring for a general food distribution, ar/enThe reference tool. matrix, rank, rating, barcode, consent, a custom x: type, field-level encryption, a household roster
facility-monitoring-visit.form.jsonA health-facility monitoring visit, ar/engeotrace, choice filters, three datasets, a deep relevance tree, signature
wash-water-point-survey.form.jsonQuarterly water point inspection, en/frgeoshape, datetime, audio, a custom validator, navigation: "scroll", a non-Arabic second locale
nutrition-screening-referral.form.jsonMUAC screening and referral at a mobile clinic, ar/envideo, file, Arabic as the default locale, numbering: "native", calendar: "islamic-umalqura", encryption.mode: "submission", requires.features
pdm-300.form.jsonThe NFR-002 benchmark: 302 questions, 14 pages, 175 kBPerformance only. Generated — see below

Between them they exercise every built-in element type, every validator type and every settings option the spec defines. That is not decoration: it is why adding a type without touching this directory shows up as a gap rather than as nothing.

theme-agency-blue.json is the example theme, checked by tools/validate-theme.mjs for WCAG 2.2 AA contrast.

The benchmark form

pdm-300.form.json is generated by tools/build-pdm-300.mjs and checked in. Do not edit it by hand — CI regenerates it and fails on any difference.

It is deliberately hard rather than merely large: every module is gated on a select, forty calculations form a single dependency chain, aggregates fan in across pages, and one choice list has 400 options. Three hundred independent text inputs would measure almost nothing.

node tools/build-pdm-300.mjs # regenerate
node tools/build-pdm-300.mjs --check # what CI runs

The negative corpus

invalid/ holds one fixture per error code validateFormDefinition can raise — fifty of them, each named for its code and each carrying exactly one violation.

rasd validate docs/examples/invalid/E_CALC_CYCLE.form.json
# E_CALC_CYCLE /pages/0/elements/1 Calculation cycle: a → b → a

Some need an option, given in invalid/manifest.json:

rasd validate docs/examples/invalid/E_TOO_MANY_PAGES.form.json --limit pages=1
rasd validate docs/examples/invalid/E_VERSION_REUSED.form.json \
--previous docs/examples/invalid/E_VERSION_REUSED.previous.json

The fixtures that test a limit tighten it rather than shipping a form that genuinely exceeds the default — a 2001-element document would add megabytes to the repository to exercise one comparison. The default values themselves are pinned against docs/04 §16 in corpus.test.ts.

These files are generated by tools/build-invalid-corpus.mjs from a table of one-line mutations, so the only thing that differs between two of them is the violation each one carries.

The test that matters runs in the other direction: every error code found in validate.ts must have a fixture, so a new rule without a fixture fails CI. That is the half that keeps this from rotting — a corpus only ever proves things about the rules someone remembered to write a file for, and the rules nobody remembered are exactly the ones that quietly stop working. When it was first switched on it found fourteen limit guards that no test had ever fired, and a class of malformed expression that rasd validate had been calling clean.