| name | validate-form |
| description | Run schema + HL7 FHIR Validator + clinical-sanity validation on Questionnaire.json through Formtastic's host-managed validation endpoint. Use before publish, before a big propose-edit, or when the user asks "is this form valid?" |
Validate form
When to use this
- The user asks "is this form valid?" or "any issues?"
- Before a publish (
status: draft → active).
- After a heavy propose-edit, as a self-check before surfacing it.
What "valid" means here
Three layers, in priority order:
- Zod shape — our
QuestionnaireSchema (in
src/shared/fhir.ts). The host validation endpoint runs this first.
It catches missing required fields, wrong types, and malformed
extensions.
- HL7 FHIR Validator — the Bun host keeps the validator's built-in
HTTP server warm and proxies it through
FORMTASTIC_VALIDATOR_URL:
curl -sS -X POST "$FORMTASTIC_VALIDATOR_URL" \
-H 'content-type: application/fhir+json' \
--data-binary @Questionnaire.json
Prefer this endpoint over launching java -jar validator_cli.jar;
the point is to avoid JVM startup cost on every validation.
- Clinical heuristics (use the critique-form skill's
checklist as a guide). These are warnings, not errors.
If FORMTASTIC_VALIDATOR_URL is not set, fall back to schema/clinical
sanity review only; keep the visible reply product-facing rather than
describing harness internals. Do not invoke the
validator jar directly unless the user explicitly asks you to debug the
validator host.
Output
Write findings to $FORMTASTIC_RUN_DIR/output/issues.json. Use the same
shape as critique-form:
[
{ "severity": "error", "linkId": "q3", "message": "type=text but answerOption[] populated; answerOption applies to choice/open-choice only." },
{ "severity": "warning", "linkId": "rf-thunderclap", "message": "Required item without a text prompt." },
{ "severity": "info", "message": "Total runtime estimate ~6.5min at median path." }
]
In $FORMTASTIC_RUN_DIR/output/reply.md, summarize with counts without
mentioning host artifacts or filenames:
0 errors, 2 warnings, 1 info note. The issues are ready for review in
the validation panel.
Common errors caught by validator_cli
Questionnaire.url not absolute / not a valid URI.
- Extension on an item without a profile that allows it (rare for
R4 core extensions; common for SDC extensions if the SDC IG
isn't on the validator's IG path).
answerOption populated on boolean/integer items.
enableWhen.question references a linkId that doesn't exist.
- Duplicate linkIds.
Pitfalls
- Treating
validator_cli warnings as errors. Most warnings are
informational (e.g. "no profile referenced"); only fail the run
on actual errors.
- Running against the wrong FHIR version (
-version 4.0.1 for R4).
- Skipping the SDC IG flag — extension URLs we use will be flagged
as unknown without it.
- Letting clinical-sanity warnings block a publish; surface them,
let the user decide.