feat(forms): per-field description texts (Erläuterungssätze) #81

Open
laoc wants to merge 2 commits from feat/field-descriptions into feat/issue-77-form-preview
Owner

Adds an optional per-field description in the builder, stored in the field tag's open JSON settings bag, rendered under the label at fill time. Edit round-trip proven for ALL eight options-bag keys (the next silently dropped property fails by name), plus an e2e driving both fieldToState call sites including an XSS-inert check (FieldsRenderer interpolates, never {@html}).

TestOER-verified at 5c9ce139, no defects; output-wart scope measured (only field-output tags move, cycle converges with outputs pinned).

Stacked on #78 (base: feat/issue-77-form-preview). Buzz thread: #edufeed-app.

🤖 Generated with Claude Code

Adds an optional per-field description in the builder, stored in the field tag's open JSON settings bag, rendered under the label at fill time. Edit round-trip proven for ALL eight options-bag keys (the next silently dropped property fails by name), plus an e2e driving both fieldToState call sites including an XSS-inert check (FieldsRenderer interpolates, never {@html}). TestOER-verified at 5c9ce139, no defects; output-wart scope measured (only field-output tags move, cycle converges with outputs pinned). Stacked on #78 (base: feat/issue-77-form-preview). Buzz thread: #edufeed-app. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
A field tag's 6th element is an open JSON settings bag and
parseFormTemplate already spreads unknown keys into field.options, so
the wire format needed no change and old clients ignore the key. What
was missing: a producer and a consumer.

- builder: description textarea on every field row (all types)
- encoder: description travels in the field's settings bag
- renderer: shown under the label, whitespace-pre-line so authored
  bullet lists keep their line breaks (the Fragebogen Abschnitt-9 case)
- edit path: fieldToState moved from FormBuilder.svelte into
  builder-state.js unchanged (plus the description line) so the full
  parse -> state -> tags cycle is testable as a pure round trip; a
  property that survives publish but not re-edit is silently erased the
  first time an author reopens their form — same one-direction class as
  the checkbox options bug

Known pre-existing wart, deliberately untouched: parseFormTemplate
defaults a missing output to amb:<field-id>, so an output-less form
re-encodes with that default materialised as a field-output tag. The
idempotence test pins outputs explicitly to keep description the only
moving part.

Tests written first: publish direction red at 226302bc (description
dropped by the encoder), edit direction red on the missing fieldToState
export; both controls green pre-fix. Absent-description tag output is
asserted byte-identical to today's.
FORMS_EDIT_ROUNDTRIP_SWEEP generalises the edit-direction guarantee from
one property to the class: all eight options-bag keys driven through
builder state -> tags -> parse -> fieldToState -> tags, tag sets
asserted identical, so the NEXT dropped property fails too, not only
description. Mutation-proven per property in TestOER's run; the
displayIf row re-proven here against the files as landed (4 failed).

E2E_FIELD_DESCRIPTION_EDIT drives both fieldToState call sites in a
real browser — edit route and fork dialog — plus a hostile description
(<img onerror>/<script>) asserted rendered as inert text: FieldsRenderer
interpolates, never {@html}, measured not read.

Written by TestOER, adopted verbatim; both files svelte-check clean
(0 errors with them in), 3/3 e2e green on real Chrome here before
committing.
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin feat/field-descriptions:feat/field-descriptions
git switch feat/field-descriptions

Merge

Merge the changes and update on Forgejo.

Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.

git switch feat/issue-77-form-preview
git merge --no-ff feat/field-descriptions
git switch feat/field-descriptions
git rebase feat/issue-77-form-preview
git switch feat/issue-77-form-preview
git merge --ff-only feat/field-descriptions
git switch feat/field-descriptions
git rebase feat/issue-77-form-preview
git switch feat/issue-77-form-preview
git merge --no-ff feat/field-descriptions
git switch feat/issue-77-form-preview
git merge --squash feat/field-descriptions
git switch feat/issue-77-form-preview
git merge --ff-only feat/field-descriptions
git switch feat/issue-77-form-preview
git merge feat/field-descriptions
git push origin feat/issue-77-form-preview
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
edufeed/edufeed-app!81
No description provided.