@case-framework/survey-assistant 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -3
- package/dist/{attachments-B0hg3vpT.mjs → attachments-BuNni5vB.mjs} +1 -1
- package/dist/{attachments-B0hg3vpT.mjs.map → attachments-BuNni5vB.mjs.map} +1 -1
- package/dist/{authoring-references-BJQ_1nMX.mjs → authoring-references-CmwLc_C8.mjs} +49 -32
- package/dist/authoring-references-CmwLc_C8.mjs.map +1 -0
- package/dist/capabilities-D55dq-fO.mjs +582 -0
- package/dist/capabilities-D55dq-fO.mjs.map +1 -0
- package/dist/capabilities-default.d.mts +5 -12
- package/dist/capabilities-default.d.mts.map +1 -1
- package/dist/capabilities-default.mjs +2 -411
- package/dist/capabilities-z95e1mti.d.mts +117 -0
- package/dist/capabilities-z95e1mti.d.mts.map +1 -0
- package/dist/{constants-0UHGFcRJ.mjs → constants-Ct-vv9cu.mjs} +1 -1
- package/dist/{constants-0UHGFcRJ.mjs.map → constants-Ct-vv9cu.mjs.map} +1 -1
- package/dist/{constants-Be91Gay9.d.mts → constants-HL_klgJl.d.mts} +7 -28
- package/dist/constants-HL_klgJl.d.mts.map +1 -0
- package/dist/{controller-proxy-BH05e-C2.mjs → controller-proxy-BQ1YsVxJ.mjs} +12 -21
- package/dist/controller-proxy-BQ1YsVxJ.mjs.map +1 -0
- package/dist/controller-proxy-Cmzdr9tV.d.mts +65 -0
- package/dist/controller-proxy-Cmzdr9tV.d.mts.map +1 -0
- package/dist/default-D22AKTqE.mjs +233 -0
- package/dist/default-D22AKTqE.mjs.map +1 -0
- package/dist/{digest-SJmoYVaK.d.mts → digest-FnTTDBq2.d.mts} +2 -3
- package/dist/digest-FnTTDBq2.d.mts.map +1 -0
- package/dist/digest.d.mts +1 -1
- package/dist/digest.mjs.map +1 -1
- package/dist/engine-D950TfvC.mjs +3098 -0
- package/dist/engine-D950TfvC.mjs.map +1 -0
- package/dist/engine.d.mts +4 -3
- package/dist/engine.mjs +3 -3
- package/dist/{fair-guidance-CRYCRxQm.mjs → fair-guidance-BmO4PswW.mjs} +1 -1
- package/dist/{fair-guidance-CRYCRxQm.mjs.map → fair-guidance-BmO4PswW.mjs.map} +1 -1
- package/dist/{index-l_EK4yK7.d.mts → index-B8TLBd1G.d.mts} +18 -72
- package/dist/index-B8TLBd1G.d.mts.map +1 -0
- package/dist/index-CaX3hZmr.d.mts +23813 -0
- package/dist/index-CaX3hZmr.d.mts.map +1 -0
- package/dist/{index-x0qprHgK.d.mts → index-CeUlGkoU.d.mts} +58 -28
- package/dist/index-CeUlGkoU.d.mts.map +1 -0
- package/dist/{index-nhrgbgO5.d.mts → index-DYHdvSE8.d.mts} +347 -88
- package/dist/index-DYHdvSE8.d.mts.map +1 -0
- package/dist/lifecycle-DFzxVxpq.d.mts +54346 -0
- package/dist/lifecycle-DFzxVxpq.d.mts.map +1 -0
- package/dist/{memory-thread-repository-KWHQWFEW.mjs → memory-thread-repository-DmLadygY.mjs} +60 -30
- package/dist/memory-thread-repository-DmLadygY.mjs.map +1 -0
- package/dist/protocol-BQ7uIDYT.mjs +569 -0
- package/dist/protocol-BQ7uIDYT.mjs.map +1 -0
- package/dist/protocol.d.mts +4 -4
- package/dist/protocol.mjs +4 -3
- package/dist/{react-B3ybjJ-X.mjs → react-DybJ5pWw.mjs} +159 -46
- package/dist/react-DybJ5pWw.mjs.map +1 -0
- package/dist/react-integration.d.mts +2 -2
- package/dist/react-integration.mjs +2 -2
- package/dist/react.d.mts +3 -3
- package/dist/react.mjs +3 -3
- package/dist/references/assistant-operations.md +224 -180
- package/dist/references/core-rules.md +6 -3
- package/dist/references/element-types.md +189 -0
- package/dist/references/expressions.md +307 -168
- package/dist/references/fair-by-design.md +9 -9
- package/dist/references/follow-ups.md +151 -0
- package/dist/references/localization.md +26 -12
- package/dist/references/response-variables.md +38 -0
- package/dist/references/rich-text-content.md +22 -43
- package/dist/references/source-material-surveys.md +20 -24
- package/dist/references/survey-data-model.md +36 -102
- package/dist/{request-context-CG4SWijt.mjs → request-context-KVh8VjgH.mjs} +4 -10
- package/dist/request-context-KVh8VjgH.mjs.map +1 -0
- package/dist/{request-guardrails-TmgQtqp4.mjs → request-guardrails-C0ugBOp0.mjs} +6 -5
- package/dist/request-guardrails-C0ugBOp0.mjs.map +1 -0
- package/dist/server-agent.d.mts +62 -43
- package/dist/server-agent.d.mts.map +1 -1
- package/dist/server-agent.mjs +73 -40
- package/dist/server-agent.mjs.map +1 -1
- package/dist/server-runtime.d.mts +24 -42
- package/dist/server-runtime.d.mts.map +1 -1
- package/dist/server-runtime.mjs +12 -12
- package/dist/server-runtime.mjs.map +1 -1
- package/dist/server-tasks.d.mts +2 -2
- package/dist/server-tasks.mjs +2 -313
- package/dist/server-tools.d.mts +1 -1
- package/dist/server-tools.mjs +1 -1
- package/dist/server.d.mts +14 -36
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +5 -5
- package/dist/server.mjs.map +1 -1
- package/dist/storage-postgres.d.mts +9 -25
- package/dist/storage-postgres.d.mts.map +1 -1
- package/dist/storage-postgres.mjs +5 -4
- package/dist/storage-postgres.mjs.map +1 -1
- package/dist/tasks-Coh5N027.mjs +397 -0
- package/dist/tasks-Coh5N027.mjs.map +1 -0
- package/dist/{tasks-CYqrcaRO.d.mts → tasks-wb9M-bak.d.mts} +25 -41
- package/dist/tasks-wb9M-bak.d.mts.map +1 -0
- package/dist/thread-documents-DrHbaXqP.d.mts +119 -0
- package/dist/thread-documents-DrHbaXqP.d.mts.map +1 -0
- package/dist/{thread-handlers-DBAaU7BA.d.mts → thread-handlers-C3Iya92v.d.mts} +9 -40
- package/dist/thread-handlers-C3Iya92v.d.mts.map +1 -0
- package/dist/{tools-BvSovehT.mjs → tools-D0KBDolR.mjs} +677 -459
- package/dist/tools-D0KBDolR.mjs.map +1 -0
- package/dist/turn-survey-draft-B34lggSG.d.mts +185 -0
- package/dist/turn-survey-draft-B34lggSG.d.mts.map +1 -0
- package/dist/ui.css +1 -1
- package/dist/ui.d.mts +15 -54
- package/dist/ui.d.mts.map +1 -1
- package/dist/ui.mjs +203 -156
- package/dist/ui.mjs.map +1 -1
- package/docs/integration.md +11 -1
- package/package.json +41 -36
- package/dist/authoring-references-BJQ_1nMX.mjs.map +0 -1
- package/dist/capabilities-1KNnNO1_.mjs +0 -73
- package/dist/capabilities-1KNnNO1_.mjs.map +0 -1
- package/dist/capabilities-DVTfogjv.d.mts +0 -193
- package/dist/capabilities-DVTfogjv.d.mts.map +0 -1
- package/dist/capabilities-default.mjs.map +0 -1
- package/dist/constants-Be91Gay9.d.mts.map +0 -1
- package/dist/controller-proxy-BH05e-C2.mjs.map +0 -1
- package/dist/controller-proxy-Bd0ZHBPF.d.mts +0 -85
- package/dist/controller-proxy-Bd0ZHBPF.d.mts.map +0 -1
- package/dist/digest-SJmoYVaK.d.mts.map +0 -1
- package/dist/engine-Bo85Oyj0.mjs +0 -6723
- package/dist/engine-Bo85Oyj0.mjs.map +0 -1
- package/dist/index-Tnqv-yKW.d.mts +0 -777
- package/dist/index-Tnqv-yKW.d.mts.map +0 -1
- package/dist/index-l_EK4yK7.d.mts.map +0 -1
- package/dist/index-nhrgbgO5.d.mts.map +0 -1
- package/dist/index-x0qprHgK.d.mts.map +0 -1
- package/dist/lifecycle-Bx0aq_4S.d.mts +0 -529
- package/dist/lifecycle-Bx0aq_4S.d.mts.map +0 -1
- package/dist/memory-thread-repository-KWHQWFEW.mjs.map +0 -1
- package/dist/protocol-BhzQbx81.mjs +0 -1173
- package/dist/protocol-BhzQbx81.mjs.map +0 -1
- package/dist/react-B3ybjJ-X.mjs.map +0 -1
- package/dist/references/embedded-forms.md +0 -126
- package/dist/references/item-types.md +0 -407
- package/dist/request-context-CG4SWijt.mjs.map +0 -1
- package/dist/request-guardrails-TmgQtqp4.mjs.map +0 -1
- package/dist/server-tasks.mjs.map +0 -1
- package/dist/tasks-CYqrcaRO.d.mts.map +0 -1
- package/dist/thread-documents-rmd6nyX9.d.mts +0 -107
- package/dist/thread-documents-rmd6nyX9.d.mts.map +0 -1
- package/dist/thread-handlers-DBAaU7BA.d.mts.map +0 -1
- package/dist/tools-BvSovehT.mjs.map +0 -1
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
# Element authoring
|
|
2
|
+
|
|
3
|
+
Use the live registry capability and generated schema as the configuration authority. These notes explain behavior; they are not a second schema. A content item containing one element is the default way to author an ordinary question. Use `insert-preset` for a configured starting point, then inspect allocated IDs before editing or referencing it. Multiple elements, layouts and sections are available when the content actually requires them.
|
|
4
|
+
|
|
5
|
+
## group
|
|
6
|
+
|
|
7
|
+
A flow group is a hierarchy/container with `config: {items: [], shuffleItems: false}`. Only the existing root has `isRoot: true`. Create a non-root group empty, then add children in parent-before-child order. Groups have no respondent-facing content roles; use their editor label for author organization. For a visible heading, add a content item with a title or an information element. Use groups for meaningful nested survey structure, information elements for standalone explanation and page breaks for page boundaries. Within a single content item, use semantic sections rather than flow groups.
|
|
8
|
+
|
|
9
|
+
## Editor Presentation
|
|
10
|
+
|
|
11
|
+
Every item has three distinct naming/presentation surfaces:
|
|
12
|
+
|
|
13
|
+
- `editorName`: resolved display name returned by inspection; use the persistent item ID for edits. Response coding belongs to slots, not item names; change it with `update-response-settings`.
|
|
14
|
+
- `metadata.itemLabel`: internal editor label, not shown to respondents. Change it with `update-item-label`.
|
|
15
|
+
- `metadata.editorItemColor`: editor-only color swatch, not shown to respondents. Change it with `update-item-color`.
|
|
16
|
+
|
|
17
|
+
Across editor views, an unqualified request for labels on one or more items/questions means `metadata.itemLabel`, including the visible "Add label..." editor control. It does not mean respondent-facing question titles, option labels, or input labels unless the user says so. Do not ask for clarification when the requested item set is clear; inspect/search to resolve that set when needed. Clarify only if the request explicitly spans multiple label surfaces.
|
|
18
|
+
|
|
19
|
+
`update-item-color.color` must be one of the editor palette values provided in the `survey_change` tool contract. Use it only when the user asks for editor organization or color; it must not be used to imply respondent-facing meaning.
|
|
20
|
+
|
|
21
|
+
## page-break
|
|
22
|
+
|
|
23
|
+
Page-break/structural item. It has no response slots or respondent-facing content roles. Use an editor label to identify it while authoring. If a visible page heading is needed, place it on a content item following the break.
|
|
24
|
+
|
|
25
|
+
## information
|
|
26
|
+
|
|
27
|
+
Display-only rich content in owner role `body`, with no response slot. It occupies a full row. Use for standalone explanation or instructions within a composed item. Keep actual respondent prompts as inputs; blanks in source documents are not decorative text. Item title/subtitle/footer remain separate optional surfaces.
|
|
28
|
+
|
|
29
|
+
## text
|
|
30
|
+
|
|
31
|
+
A string input with `presentation: "short"` or `"long"`, persistent `slotId` and coding `variableName`. Optional purpose is text/email/tel/url/password; multiline rows and browser autocomplete are independent settings. Roles include label, help, placeholder and validation message. A placeholder never replaces an accessible label. Port source instructions as help or item subtitle, preserving existing constraints. Use required and the supported validation rules rather than a prose-only requirement.
|
|
32
|
+
|
|
33
|
+
## number
|
|
34
|
+
|
|
35
|
+
A numeric input or slider with a persistent slot and variable name. Preserve step, minimum, maximum, value display and localized unit. Slider presentation does not change response identity or type. Pick bounds and units from the user or source; do not invent constraints. Put domain limits in `min`/`max` (a number or `{expression, fallback?}`) and use the `integer` validation for whole numbers.
|
|
36
|
+
|
|
37
|
+
## date
|
|
38
|
+
|
|
39
|
+
Reuse the calendar input with `precision` of `year`, `year-month` or `year-month-day`. Answers are calendar strings `YYYY`, `YYYY-MM`, `YYYY-MM-DD`, never timestamps. Precision, regional display format and survey language are separate. Preserve configured precision, localized parser messages and inclusive bounds. Config `min`/`max` bounds are a calendar string or `{expression, fallback?}` relative to another answer; use calendar arithmetic, not timestamp conversion.
|
|
40
|
+
|
|
41
|
+
## boolean
|
|
42
|
+
|
|
43
|
+
A boolean response with switch or radio presentation. False is an answer, not missing; use explicit comparisons when a condition means Yes. Localized yes/no labels are element roles. A standalone boolean and a matrix boolean share response semantics, but their context-specific UI and validation presentation differ.
|
|
44
|
+
|
|
45
|
+
## choice
|
|
46
|
+
|
|
47
|
+
Use `presentation: "radio"`, `"checkbox"` or `"dropdown"`. If the user says “multiple choice”, “multiple answer”, “select all that apply”, “choose all”, or “checkboxes”, use checkbox with `maxSelection: null` unless they give a cap. “Choose up to N” uses checkbox with `maxSelection: N`, even for N=1. “Single choice” or “choose one” uses radio; an explicit dropdown request uses dropdown. Radio and dropdown answers are `reference`; checkboxes return `reference[]`. Options have stable IDs, optional export codes and localized label/description owner roles. Checkboxes require `maxSelection` (null for unlimited or a positive cap). Radio/dropdown configuration has no maxSelection field.
|
|
48
|
+
|
|
49
|
+
Radio and checkbox lists take a full row and may own option-inline follow-ups. Dropdowns may share a layout row and cannot own follow-ups. Every option needs visible localized wording; codes and IDs are not fallback labels. Preserve ordered scales, endpoints, shuffling and coding conventions. Use matrix elements for repeated common scales when appropriate.
|
|
50
|
+
|
|
51
|
+
Create the requested presentation directly. When explicitly changing an existing radio/dropdown to checkbox or the reverse, the answer type changes: assign a fresh `slotId` and inspect and repair dependencies; existing responses are not converted. Radio/dropdown changes retain the slot ID. Keep option IDs and translations, remove dropdown-only placement when changing to a full-width list, and never drop follow-ups to force a dropdown conversion. Radio lists permit clearing; preserve that behavior with `allowClear: true` when converting one to a dropdown.
|
|
52
|
+
|
|
53
|
+
Use visibility for options that become inapplicable: hidden selections are retained locally but excluded from active answers and submission. Disabled visible options retain active selections. Disabled checkboxes are locked both ways; enabled options can still change if the cap permits. A disabled radio/dropdown selection may be replaced by an enabled destination, but cannot be directly cleared while locked. Disabling the element or ancestors locks the whole choice.
|
|
54
|
+
|
|
55
|
+
Exclusivity is authored through expressions, with no special exclusive-option feature. In valid states the selected side must remain enabled so it can be deselected. For “None of these”, disable it when any ordinary option is selected and disable ordinary options when None is selected. Conflicting prefills or changing earlier answers can lock a checked option. Audit checkbox disabling that reads outside its own selection and prefer visibility when the real intent is inapplicability. Do not silently clear answers to fix a conflict.
|
|
56
|
+
|
|
57
|
+
`isDisabled` state reads can support selected-and-enabled conditions, but do not automatically add them to mutual disabling rules: that can create a real cycle. Inherited disabled states count, so a deliberately read-only prefilled answer is still selected but will fail a selected-and-enabled test. Ordinary answer comparisons usually fit such read-only cases.
|
|
58
|
+
|
|
59
|
+
## consent
|
|
60
|
+
|
|
61
|
+
Use one consent element for each independent permission. A containing item or section supplies a title and optional supporting introduction; the consent element owns its full `body` translation and records an explicit agreement or refusal. Both title and body are needed in each participant language, with an explicit element label or unambiguous enclosing title. Use an information element for information that does not ask for a decision.
|
|
62
|
+
|
|
63
|
+
Organize the participant-facing content in the owner-role content surfaces:
|
|
64
|
+
|
|
65
|
+
- `title` on the containing item/section: the main heading identifying the agreement or permission. Prefer the supplied document's main heading when available. This field stays visible on the question card and names the dialog unless `label` overrides it; do not put the only title inside the body.
|
|
66
|
+
- `subtitle` on the containing item, or `description` on the containing section: an optional brief introduction or reading instruction directly below the title. Leave it out when no separate introduction is needed.
|
|
67
|
+
- `label`: optional rich consent-specific heading. Empty inherits the nearest appropriate section/item title in the same locale. Supply only when a distinct local heading is useful; it appears above the inline document or in the dialog summary and dialog heading.
|
|
68
|
+
- `subtitle` on the consent element: optional rich consent-specific introduction, used only with `config.subtitleMode="custom"`.
|
|
69
|
+
- `body`: the actual content the participant needs to read before deciding, including the agreement, terms, or explanation of the permission. It is the document itself, not a description, summary, or instruction to read an absent document. Avoid repeating the question title as an opening body heading; retain meaningful section headings, paragraphs, lists, and links within the document. Follow an explicit request to preserve the source verbatim.
|
|
70
|
+
|
|
71
|
+
Follow supplied content: preserve its terms and meaning instead of replacing it with generic wording, silently changing its meaning, or adding unrequested provisions. When helping create new wording, be proactive: write useful, concrete draft terms and make reasonable creative choices from the available context. Do the useful work first, then identify the result as a draft and explain material assumptions or missing details in your reply. Do not present invented wording as facts or as a document supplied by the user. Use placeholders sparingly for details the user must supply, while still drafting the substantive content. Do not fill `body` with only a description of a document or a statement agreeing to unspecified terms elsewhere. Ask a focused question before acting only when useful progress is blocked, such as when exact reproduction requires unavailable source text. Missing optional details are a reason to note gaps afterward, not to delay a useful draft.
|
|
72
|
+
|
|
73
|
+
Config supports `presentation`: `"inline"` (preset default) or `"dialog"`, and `subtitleMode`: `"inherit"` (preset default), `"custom"`, or `"none"`. Subtitle mode applies to all languages. Inherit uses the semantic context subtitle; custom uses `subtitle` on the consent element for the current locale (empty stays absent); none omits the consent subtitle. The question subtitle remains visible in every mode. Inherited title/subtitle are not repeated inline or in the dialog summary, but are shown inside the dialog. Custom titles also identify the inline consent and dialog summary. Custom subtitles appear above the inline document or inside the dialog, never in the dialog summary.
|
|
74
|
+
|
|
75
|
+
Optional plain `acceptLabel` and `declineLabel` translations override choice wording. `unansweredLabel`, `acceptedLabel`, and `declinedLabel` override dialog status; `reviewLabel` and `changeLabel` override dialog actions. Empty values use the host UI defaults. Close, missing-title and unavailable-information messages belong to host player localization; do not create item translations for them. Languages without host translations require host localization for those generic messages. There is no separate decision heading. Without existing response data there is no automatic selection. Consent supports the ordinary initial-response and element-owned prefill paths using the boolean slot identified by `config.slotId`. There is no `required` setting or config effects list. Closing the dialog leaves the answer unchanged.
|
|
76
|
+
|
|
77
|
+
The element has a persistent `id`; config has an independent persistent `slotId`, plus an editable `variableName` (for example `research_consent`). Presets allocate IDs; complete authored nodes supply explicit IDs. Inspect preset results before referencing them. Boolean true means agreement, false means refusal, and absence means unanswered. Compare `{ "slotId": "<config.slotId>", "method": "get" }` with a boolean constant. `isDefined` tests either recorded decision. Never use the literal `accepted` as a universal slot ID.
|
|
78
|
+
|
|
79
|
+
To show a section only after agreement, place the agreement expression on the dependent item's, group's or section's `visibility` expression. Hiding retains previously entered answers in the session but omits hidden items from submission and subsequent exports; showing the section again restores them. Navigation rules target explicit slots on their content item and must not require a particular consent decision unless the user requested that rule.
|
|
80
|
+
|
|
81
|
+
## choiceMatrix
|
|
82
|
+
|
|
83
|
+
Toolbox presets have exact server-supported IDs on `insert-preset.presetId`:
|
|
84
|
+
|
|
85
|
+
| User wording | presetId | Actual toolbox defaults |
|
|
86
|
+
| ---------------------- | -------------------------- | ---------------------------------------------------- |
|
|
87
|
+
| Yes / No matrix | `choiceMatrix.yesNo` | Yes, No; scores 1, 2 |
|
|
88
|
+
| 5-point scale / Likert | `choiceMatrix.fivePoint` | Strongly disagree through Strongly agree; scores 1–5 |
|
|
89
|
+
| 7-point scale / Likert | `choiceMatrix.sevenPoint` | Seven agreement options; scores 1–7 |
|
|
90
|
+
| 5-point bipolar scale | `choiceMatrix.bipolarFive` | Five numbered options, scores 1–5, `bipolar: true` |
|
|
91
|
+
|
|
92
|
+
These are editable starting configurations, not fixed measurement instruments. Use `insert-preset` with `elementType: "choiceMatrix"`, the advertised preset ID, locale and flow/layout target. The bipolar preset does NOT imply scores −2…2: request those scores explicitly when wanted. Labels come from the shared toolbox factory (English, Dutch, German). Inspect the result before editing generated IDs. If custom anchors and rows are already known, author the complete element directly with explicit IDs and translations in one create/insert operation. Existing toolbox elements are ordinary matrices and remain editable.
|
|
93
|
+
|
|
94
|
+
Match the response wording to the question's construct: agreement labels answer statements, while liking, satisfaction, frequency and intensity need corresponding anchors. Preserve exact toolbox wording when the user explicitly requests those defaults. When custom anchors are already known, include the complete ordered `element.config.options` with explicit stable IDs, scores and matching `label` translations on each option owner in the creation operation; these define the custom scale. This creates the intended scale directly without a second pass over generated IDs. For later edits, copy the existing IDs exactly and preserve them.
|
|
95
|
+
|
|
96
|
+
Use a choice matrix for several row statements sharing the same categorical scale. Persistent IDs identify the element, rows, options, per-row computed scores and total. `variableNamePrefix` and each `rowName` derive survey-wide unique names: `<variableNamePrefix>_<rowName>`, `<variableNamePrefix>_<rowName>_score` and `<variableNamePrefix>_sum`. Inspect declared slots; do not synthesize IDs from those names.
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"id": "wellbeing_matrix",
|
|
101
|
+
"kind": "element",
|
|
102
|
+
"elementType": "choiceMatrix",
|
|
103
|
+
"config": {
|
|
104
|
+
"variableNamePrefix": "wellbeing",
|
|
105
|
+
"sumSlotId": "wellbeing_total",
|
|
106
|
+
"rows": [{ "id": "sleep_answer", "scoreSlotId": "sleep_score", "rowName": "sleep" }],
|
|
107
|
+
"options": [
|
|
108
|
+
{ "id": "never", "code": "never", "score": 0 },
|
|
109
|
+
{ "id": "always", "code": "always", "score": 4 }
|
|
110
|
+
],
|
|
111
|
+
"layout": "automatic"
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Create with a containing item `title`, and `label` roles on `sleep_answer`, `never` and `always`. Option scores are numeric scoring semantics; codes are export strings and labels are translated wording. Supply all scores or leave them all absent. Optional `leadingNonScoring`/`trailingNonScoring` each hold ONE `{id, code?}` object (never an array and never a score). Each participates in answers but not scoring. There is at most one leading and one trailing non-scoring choice; a second at the same end requires an explicit product decision, not silently overwriting the first. Optional bipolar endpoints use `startLabel`/`endLabel` on the matrix element. Layout accepts `automatic`, `stacked` or `matrix`; `rowLabelPosition` accepts `beside` or `above`.
|
|
117
|
+
|
|
118
|
+
Stored row answers are `reference` values containing exact option IDs. Computed score and sum slots are read-only and excluded from default exports unless explicitly included. A non-scoring or unanswered row has no score; a numeric score of zero is a defined score. The sum is absent when no visible rows have scored answers. Required rows use `required: true`. Use config patches for structural row/option/layout edits, translations for visible text, and `update-response-settings` for naming components, export codes and formats. Preserve surviving IDs. Reinspect expression diagnostics after removing slots/options.
|
|
119
|
+
|
|
120
|
+
### Editing a choice matrix
|
|
121
|
+
|
|
122
|
+
Inspect the current config before choosing array indices. Put all related patches and new translations in one `patch-element-config` operation. Example adding a final “Don't know” answer:
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"kind": "patch-element-config",
|
|
127
|
+
"elementId": "<inspected element ID>",
|
|
128
|
+
"patches": [
|
|
129
|
+
{ "op": "add", "path": "/trailingNonScoring", "value": { "id": "dont_know", "code": "DK" } }
|
|
130
|
+
],
|
|
131
|
+
"translations": [
|
|
132
|
+
{ "locale": "en", "ownerId": "dont_know", "role": "label", "plainText": "Don't know" }
|
|
133
|
+
]
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- Add a row at `/rows/-` with fresh `id`, `scoreSlotId`, unique `rowName` and its `label` role translation. Duplicate by copying the row settings and all relevant locales into NEW IDs. Keep surviving IDs unchanged.
|
|
138
|
+
- Remove rows/options with `remove` at the inspected index; reorder with `move` or replace the complete inspected array without changing IDs. `copy` alone duplicates IDs and is invalid. Remove or repair dependent expressions in the same turn.
|
|
139
|
+
- Add scale options at `/options/-` with `id`, optional `code`, and a score if the existing scale is scored. Include the option owner's `label` role. To disable scoring, remove every scale score in one operation. To reverse scoring, reverse score VALUES in the existing options; do not reorder options or labels. For zero-based/one-based/bipolar scoring, assign 0…n−1 / 1…n / −(n−1)/2…(n−1)/2 to all scale options in one patch. Non-scoring choices stay outside this array.
|
|
140
|
+
- Add or remove `/leadingNonScoring` or `/trailingNonScoring` as object properties. To move a non-scoring option from one end to the other, preserve its ID and label. To switch an option between scale and non-scoring roles, move the same ID atomically and add/remove its score appropriately.
|
|
141
|
+
- Set `/bipolar` true and translate `startLabel` and `endLabel` on the matrix element for endpoints. Set `/rowLabelPosition` to `beside` or `above`. Layout and positive `stackingBreakpoint` affect presentation, not responses.
|
|
142
|
+
- Row display conditions use `survey_expression` mutation `set-condition` with `ownerId` equal to the row ID and `property: "visibility"`; required-row messages use the row owner's `message` role. Whole-question visibility uses `set-condition` on the item/element owner. Use only targets declared by the installed matrix schema; never infer support from an arbitrary property in raw JSON.
|
|
143
|
+
|
|
144
|
+
## formMatrix
|
|
145
|
+
|
|
146
|
+
Use a form matrix for independent row/column cells, with a column-level field type and optional cell `fieldOverride`s. Names derive from `<variableNamePrefix>_<rowName>_<columnName>`; IDs and existing answers survive naming, ordering and layout edits. Every row/column intersection needs a persistent cell object, including static or empty cells, although only interactive cells declare response slots.
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{
|
|
150
|
+
"id": "visits_matrix",
|
|
151
|
+
"kind": "element",
|
|
152
|
+
"elementType": "formMatrix",
|
|
153
|
+
"config": {
|
|
154
|
+
"variableNamePrefix": "visits",
|
|
155
|
+
"rows": [{ "id": "visit_row", "rowName": "baseline" }],
|
|
156
|
+
"columns": [
|
|
157
|
+
{
|
|
158
|
+
"id": "weight_column",
|
|
159
|
+
"columnName": "weight_kg",
|
|
160
|
+
"field": { "type": "number", "unit": "kg", "validations": [] }
|
|
161
|
+
}
|
|
162
|
+
],
|
|
163
|
+
"cells": [{ "id": "baseline_weight", "rowId": "visit_row", "columnId": "weight_column" }],
|
|
164
|
+
"layout": "automatic"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
Translate the containing item `title`, row `label`, column `label`, and cell-specific `label`/`description` when needed. Field types are `text` (optional multiline), `number` (step/unit), `date` (`precision` `year`, `year-month`, `year-month-day`), `dropdown` (options `[{id,code}]`), `boolean`, `static`, `empty`. Interactive field definitions carry `validations: []` and optional `required`. Dropdown answers contain option IDs; visible option labels use the option owner's `label` role. Cell `fieldOverride`s use the same field schema. Static cells use the cell owner's `content` role. Use the capability's declared content surfaces for localization.
|
|
170
|
+
|
|
171
|
+
### Editing a form matrix
|
|
172
|
+
|
|
173
|
+
Config patches handle structural cells, overrides, columns and rows. Every structural edit must produce a complete rectangle in ONE `patch-element-config` operation.
|
|
174
|
+
|
|
175
|
+
A field-type change that changes a cell's answer value type needs a fresh cell ID. Replace only affected input cells, including inherited column defaults; preserve cells with unchanged effective types or independent overrides. Moving an input to an empty/static cell also retires its answer ID. Preserve owner content in every locale and explicitly repair references, prefills and export settings. Inspect before patching; do not reuse an old ID for a different answer type.
|
|
176
|
+
|
|
177
|
+
- For multi-row/column duplication, inspect the current arrays first, then construct the complete desired rows, columns and cells while retaining all surviving objects and IDs. Replacing these arrays together can be clearer than a long chain of index-sensitive patches. A duplicate is an addition; never rename or repurpose its source. Keep existing coding unchanged; choose short coding components for new units.
|
|
178
|
+
Before constructing the patch, map EVERY new cell to its source cell by row and column. Copy the complete source object, including its override and conditions, then remap identities and coordinates; apply explicitly requested differences last. Do not start duplicates from bare `{id,rowId,columnId}` cells: those are appropriate only for genuinely new, default-inheriting cells.
|
|
179
|
+
For example, when copying row A to B AND column X to Y, three cells copy A/X: A/Y, B/X and B/Y. If A/X has an independent dropdown override, all three copies need that override, each with fresh option/rule IDs and the source translations. B/Y must not fall back to Y's default field just because both coordinates are new. Unchanged existing cells keep their original IDs and settings.
|
|
180
|
+
After applying the patch, compare each mapped cell's effective field and owner content with its source, including the new row/new column intersection. Schema validation proves the rectangle is legal, not that its content was faithfully copied.
|
|
181
|
+
- Adding a row also adds one fresh `{id,rowId,columnId}` cell per existing column; adding a column adds a cell for every row. Removing a row/column removes its associated cells in the same patch. The executor automatically cleans translations owned by removed components in every locale; inspect the result before attempting any extra raw translation removals. Reordering rows/columns changes only array order; preserve cell IDs and coordinates.
|
|
182
|
+
- A column's `field` defines inherited settings. A cell `fieldOverride` is a COMPLETE field definition, not a partial patch; use `add` at `/cells/<index>/fieldOverride` when absent, or replace it when already present. Its content belongs to the cell ID. Reset it with `remove` to inherit the column again. Static and empty cells remain in `cells`, but have no response slot. Changes that preserve the answer value type retain cell IDs; retyping follows the fresh-ID rule above, including when resetting an override changes the effective type.
|
|
183
|
+
- Shared field content belongs to the column owner's role; overridden content belongs to the cell owner's role. Column headers always use the column owner's `label` role. Roles are `label`, `description`, `placeholder`, `message`, `content`, `yesLabel`, `noLabel`. Static text belongs to the column owner's `content` role when inherited or the cell owner's `content` role when overridden. Number `unit` is a config string, not a content key.
|
|
184
|
+
- Dropdown fields use `options: [{id,code}]`, with globally distinct component IDs and the option owner's `label` role translations. For an independent cell override copied from a shared dropdown, allocate new option and validation IDs and copy their translations in all existing locales. Reusing column-owned option/rule IDs in an override is invalid. Duplicate rows/columns the same way: new unit and cell IDs; deep-copy every existing override with new option/rule IDs and translated content. An override on the source must remain an override on the duplicate; omitting it silently changes that cell to the column default. After duplication, compare source and destination effective field types, settings, option codes and translated content, allowing only explicitly requested differences.
|
|
185
|
+
- Interactive fields can provide `validations: []` when no constraints are needed. Required is the field's boolean `required` property. Text validations: `minLength`, `maxLength`, `pattern`; number: `integer`; boolean: `mustBeTrue`; date and dropdown have no additional rules. Each rule has a fresh `id`, `type`, and a `value` where needed. Number and date fields take range bounds as field properties `min`/`max`, each a literal (number, or calendar string matching precision such as `2026-09`) or `{expression, fallback?}`. A bound whose expression has no value is ignored unless it has a `fallback`. Rule messages are the rule owner's `message` role; required and bound messages are the field owner's `message` role. Fixed minimum cannot exceed maximum.
|
|
186
|
+
- Column `width` and `rowLabelWidth` accept `{mode:"default"}`, `{mode:"fixed",pixels:160}`, or `{mode:"fit",minPixels:120}` (numeric minima 48). Layout is `automatic`, `stacked`, or `matrix`; `stackingBreakpoint` is a positive pixel width. Boolean arrangement is `horizontal` or `vertical`; text uses `multiline`; dates use `precision`; numbers use `step` and `unit`.
|
|
187
|
+
- Put new visible translations inside the patch operation; blank or incorrect namespaces are rejected. For row visibility, use `survey_expression` mutation `set-condition` with the row `ownerId` and `property: "visibility"`. Whole-question visibility uses `set-condition` on the item/element owner. Inspect the declared condition targets before adding other component conditions. Hidden-row answers are retained in the session and restored when shown, but excluded from expressions, validation, scoring and submission while hidden.
|
|
188
|
+
|
|
189
|
+
Coding uses one matrix naming edit with `elementId`, `prefix` (written to `variableNamePrefix`), `rows` and/or `columns`; never set arbitrary names or headers on derived cells. A shared dropdown code change affects all cells using that option set. Keep numeric scores, identities and translated wording separate from coding changes.
|