Expand description
Questionnaire answer sheets: render a prose questionnaire, collect
answers interactively or from a document, and decode them by stable
identity through one shared validation pipeline. Structs that derive
Questionnaire lower to this same runtime model and fill themselves from
validated Answers without a serde boundary.
standout-input owns the reusable machinery: definition validation,
deterministic rendering, parsing, collection adapters, shared field
decoding and validation, derive-support traits, and diagnostics. The
application owns its questionnaire definition, whole-form rules (a
closure passed to Questionnaire::decode_answers_with), interactive
flow, review, confirmation, and side effects.
§Rendered format
A rendered sheet is a preamble (format version, questionnaire ID,
fingerprint) followed by numbered questions, each ending in a stable
<id:...> tag. A line is a question line iff it ends with a tag as its
last non-whitespace content — any trailing content, even a period,
demotes it to prose. The answer is everything between a question line
and the next one (or EOF); everything before the tag (numbering,
wording, indentation, hint) is cosmetic and may be freely reworded.
Declared defaults render pre-filled. One limitation is accepted by
design: an answer that itself ends in a schema-valid tag reads as a
question line — there is no escaping, only a warning-level diagnostic
(RawAnswers::warnings) when answer text contains a stray <id:.
§Nested and repeatable groups
Alongside scalar fields, a questionnaire may declare Groups: nested
sections answered once, or repeatable sections answered once per
submitted item within Repeat bounds. Adding an item to a repeatable
group is copy-the-block editing — duplicate one rendered block below the
last and answer the copy; a group occurrence is counted as a line
ending with the group’s tag, never by numbering or prose. Definition
IDs never change (every input’s name field is command.inputs.name); a
submitted instance is addressed by its occurrence path, which
inserts a zero-based index per enclosing repeatable-group occurrence
(command.inputs[1].name). Answers and RawAnswers are keyed by
occurrence path and expose occurrence_count;
indexes belong to an answer instance, not the definition, so they never
enter the fingerprint.
§Decoding
One blank rule applies everywhere: a blank answer resolves to the
declared default first; without one, a blank optional field is an
omission and a blank required field is a missing-value error. A
conditional field (ScalarField::active_when) is asked and enforced
only while its controller holds the expected value; a populated
inactive field is an error rather than silently discarded. A default
may instead be dynamic (ScalarField::with_dynamic_default): a
closure over earlier decoded answers, paired with a mandatory revision
that enters the fingerprint in the static default’s place (closures
can’t be hashed). Interactive collection re-prompts only on a failed
entered answer, keeping earlier answers; batch collection (file/stdin)
accumulates every diagnostic from one pass instead.
§Compatibility
The preamble pins a format version, questionnaire ID, and a semantic fingerprint; parsing requires an exact match on all three; a stale sheet gets a diagnostic asking for a fresh one rather than a guessed mapping. The fingerprint covers every property that changes accepted answers — IDs, kinds, optionality, defaults, constraints, conditions, and validator/dynamic-default revisions — and ignores wording, numbering, and ordering. It is a compatibility checksum only, not an authentication or tamper-detection mechanism.
§Sensitive content
Answer sheets are plain text and may hold private or sensitive values: keep saved sheets out of version control and delete them when done. Diagnostics identify fields by ID and line number without echoing answer values; application validators and form messages should do the same.
Structs§
- Answers
- Condition
- Dynamic
Default - Earlier
Answers - Field
Validator - Form
Error - Group
- Questionnaire
- Questionnaire
Choice Parse Error - RawAnswers
- Repeat
- Scalar
Field
Enums§
- Answer
Sheet Diagnostic - Answer
Value - Constraint
- Item
- Questionnaire
Error - Questionnaire
Input Error - Scalar
Kind - Validation
Diagnostic