pict-section-form 1.0.196 → 1.0.197

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.
Files changed (38) hide show
  1. package/docs/Comprehensions.md +181 -0
  2. package/docs/Comprehensions_Advanced.md +295 -0
  3. package/docs/Pict_Section_Form_Architecture.md +2 -2
  4. package/docs/Solvers.md +32 -8
  5. package/docs/_brand.json +18 -0
  6. package/docs/_cover.md +1 -1
  7. package/docs/_sidebar.md +2 -0
  8. package/docs/_version.json +7 -0
  9. package/docs/examples/README.md +14 -14
  10. package/docs/index.html +6 -7
  11. package/docs/input_providers/005-precise-number.md +5 -5
  12. package/docs/input_providers/009-chart.md +1 -1
  13. package/docs/input_providers/011-autofill-trigger-group.md +4 -4
  14. package/docs/input_providers/013-tab-section-selector.md +1 -1
  15. package/docs/input_providers/README.md +2 -2
  16. package/docs/retold-catalog.json +71 -1
  17. package/docs/retold-keyword-index.json +1998 -1984
  18. package/example_applications/authortopia/html/index.html +5 -5
  19. package/example_applications/change_tracking/html/index.html +4 -4
  20. package/example_applications/complex_table/.claude/launch.json +11 -0
  21. package/example_applications/complex_table/Complex-Tabular-Application.js +31 -0
  22. package/example_applications/complex_table/html/index.html +5 -5
  23. package/example_applications/complex_tuigrid/html/index.html +4 -4
  24. package/example_applications/dynamic_analysis/html/index.html +7 -7
  25. package/example_applications/ndt_field_test/html/index.html +9 -9
  26. package/example_applications/postcard_example/css/postcard.css +12 -12
  27. package/example_applications/postcard_example/css/pure.min.css +1 -1
  28. package/example_applications/scope_mathematics/Scope-Mathematics_Manifest.json +1 -1
  29. package/example_applications/scope_mathematics/html/index.html +4 -4
  30. package/example_applications/simple_distill/html/index.html +4 -4
  31. package/example_applications/simple_form/html/index.html +4 -4
  32. package/example_applications/simple_table/html/index.html +4 -4
  33. package/package.json +7 -6
  34. package/source/providers/Pict-Provider-DynamicFormSolverBehaviors.js +126 -0
  35. package/source/views/Pict-View-Form-Metacontroller.js +8 -0
  36. package/source/views/support/Pict-Provider-PSF-Support.js +12 -12
  37. package/test/PictSectionForm-Basic_tests.js +138 -0
  38. package/docs/css/docuserve.css +0 -73
@@ -0,0 +1,181 @@
1
+ # Comprehensions
2
+
3
+ The `addComprehensionEntity` solver function builds **multi-context, multi-entity
4
+ comprehensions** from form data — a JSON shape that can be inspected, diffed,
5
+ and pushed to a Meadow REST API via
6
+ [`meadow-integration load_comprehension`](https://github.com/stevenvelozo/meadow-integration).
7
+
8
+ Think of it as the "save side" of a form: a single function call lays down one
9
+ property of one record under one workflow context, and many calls compose into a
10
+ single nested tree that a downstream pipeline can read in one go.
11
+
12
+ ## Signature
13
+
14
+ ```
15
+ addComprehensionEntity(Context, Entity, GUID, Property, Value)
16
+ ```
17
+
18
+ | Parameter | Type | Meaning |
19
+ |---|---|---|
20
+ | `Context` | string (manyfest address) | Workflow bucket — `"OnSave"`, `"OnApprovalAction.Approve"`, etc. Dots create nested branches. |
21
+ | `Entity` | string | The entity name — `"Book"`, `"Recipe"`, `"Fruit"`. Opaque key (not parsed). |
22
+ | `GUID` | string | External GUID for the record. Opaque key (dots are NOT interpreted). |
23
+ | `Property` | string | The field to set on the record. Opaque key. |
24
+ | `Value` | any | The value to write. Strings, numbers, booleans, objects, arrays. |
25
+
26
+ Successive calls to the same `(Context, Entity, GUID)` **accumulate properties**
27
+ on the same record. Successive calls to the same
28
+ `(Context, Entity, GUID, Property)` **overwrite**.
29
+
30
+ ## The shape it builds
31
+
32
+ Given these solvers on a Book form:
33
+
34
+ ```js
35
+ "Solvers":
36
+ [
37
+ `addComprehensionEntity("OnSave", "Book", BookGUID, "Title", BookTitle)`,
38
+ `addComprehensionEntity("OnSave", "Book", BookGUID, "Author", BookAuthor)`,
39
+ `addComprehensionEntity("OnSave", "Book", BookGUID, "ISBN", BookISBN)`,
40
+ `addComprehensionEntity("OnApprovalAction.Submit", "Book", BookGUID, "Status", "Submitted")`,
41
+ `addComprehensionEntity("OnApprovalAction.Approve", "Book", BookGUID, "Status", "Approved")`
42
+ ]
43
+ ```
44
+
45
+ …the destination ends up looking like:
46
+
47
+ ```json
48
+ {
49
+ "OnSave": {
50
+ "Book": {
51
+ "0x73278432987": {
52
+ "Title": "The Giving Tree",
53
+ "Author": "Shel Silverstein",
54
+ "ISBN": "8675309"
55
+ }
56
+ }
57
+ },
58
+ "OnApprovalAction": {
59
+ "Submit": {
60
+ "Book": {
61
+ "0x73278432987": { "Status": "Submitted" }
62
+ }
63
+ },
64
+ "Approve": {
65
+ "Book": {
66
+ "0x73278432987": { "Status": "Approved" }
67
+ }
68
+ }
69
+ }
70
+ }
71
+ ```
72
+
73
+ Every leaf in this tree is a Meadow-shaped record keyed by external GUID — the
74
+ exact format [`load_comprehension`](https://github.com/stevenvelozo/meadow-integration)
75
+ expects.
76
+
77
+ ## Where the result lands
78
+
79
+ By default the tree is written to `AppData.FormEntityComprehensions`.
80
+
81
+ The destination is **a manyfest address** resolved against the pict instance, so
82
+ addresses like `AppData.X.Y`, `Bundle.X`, etc. all work. Change it on the
83
+ metacontroller:
84
+
85
+ ```js
86
+ // At any point after the metacontroller is registered (i.e. inside the
87
+ // application's constructor, after super() has run):
88
+ this.pict.views.PictFormMetacontroller.comprehensionDestinationAddress = 'AppData.MyWorkflowComprehensions';
89
+ ```
90
+
91
+ …or pass it in the metacontroller view options if you're constructing the
92
+ metacontroller manually:
93
+
94
+ ```js
95
+ pict.addView('PictFormMetacontroller', { ComprehensionDestinationAddress: 'AppData.MyWorkflowComprehensions' },
96
+ libPictSectionForm.PictFormMetacontroller);
97
+ ```
98
+
99
+ If the address resolves to nothing, the function materializes an object there on
100
+ the first write. If it resolves to a non-object scalar, the call logs a warning
101
+ and bails (it won't overwrite a number with an object).
102
+
103
+ ## Basic example — flat OnSave context
104
+
105
+ ```js
106
+ "Sections":
107
+ [
108
+ {
109
+ "Hash": "BookEditor",
110
+ "Solvers":
111
+ [
112
+ `addComprehensionEntity("OnSave", "Book", BookGUID, "Title", BookTitle)`,
113
+ `addComprehensionEntity("OnSave", "Book", BookGUID, "Author", BookAuthor)`,
114
+ `addComprehensionEntity("OnSave", "Book", BookGUID, "Status", "New")`
115
+ ]
116
+ }
117
+ ]
118
+ ```
119
+
120
+ After a solve, `AppData.FormEntityComprehensions.OnSave.Book[<BookGUID>]` holds
121
+ the three properties.
122
+
123
+ ## Quick gotchas
124
+
125
+ 1. **Empty GUIDs bail.** If any of `Context`, `Entity`, `GUID`, or `Property`
126
+ resolves to `null`, `undefined`, or the empty string, the call logs a warning
127
+ and returns `undefined`. Recipes with an empty `RecipeName` will not silently
128
+ create a `""` bucket — they just no-op until the user fills the name in.
129
+ 2. **Solver ordinals.** Solvers run in ascending ordinal order. Put your
130
+ `addComprehensionEntity` calls *after* any solvers they depend on (e.g. after
131
+ the `TotalCalories = SUM(...)` aggregate they read from). The complex_table
132
+ example uses ordinals 200–220 to keep them after the default-ordinal compute
133
+ solvers.
134
+ 3. **Re-solves overwrite.** Each solve re-runs every solver, so each
135
+ `addComprehensionEntity` call overwrites the property it wrote last time
136
+ with the current value. This is what you want — the comprehension always
137
+ reflects the current form state.
138
+ 4. **The destination is *not* cleared between solves.** If your form removes a
139
+ record (e.g. deletes a row from a grid), the previous comprehension for that
140
+ record stays behind. If that matters for your workflow, reset the destination
141
+ at the start of the solve cycle (`AppData.FormEntityComprehensions = {}`) or
142
+ in `marshalFromView` before the comprehension solvers fire.
143
+
144
+ ## Pushing the result
145
+
146
+ Once the comprehension is built, push it via meadow-integration:
147
+
148
+ ```js
149
+ // Browser-side -- POST the AppData blob directly to the Comprehension/Push REST endpoint.
150
+ fetch('/1.0/Comprehension/Push',
151
+ {
152
+ method: 'POST',
153
+ headers: { 'Content-Type': 'application/json' },
154
+ body: JSON.stringify(
155
+ {
156
+ Comprehension: pict.AppData.FormEntityComprehensions.OnSave,
157
+ GUIDPrefix: 'MYAPP'
158
+ })
159
+ });
160
+ ```
161
+
162
+ Or write to a file and push from a CLI:
163
+
164
+ ```bash
165
+ npx meadow-integration load_comprehension out.json --prefix MYAPP
166
+ ```
167
+
168
+ See [meadow-integration: Comprehensions](https://github.com/stevenvelozo/meadow-integration/blob/main/docs/comprehensions.md)
169
+ for the full push semantics — GUID marshaling, foreign-key resolution, batch
170
+ upserts, idempotency.
171
+
172
+ ## See also
173
+
174
+ - [Advanced patterns](Comprehensions_Advanced.md) — mixing hashes and direct
175
+ addresses, computed contexts, per-row `MAP VAR` generation, customized
176
+ destinations.
177
+ - [Solvers](Solvers.md) — full solver function reference.
178
+ - The [Complex Table example](../example_applications/complex_table/Complex-Tabular-Application.js)
179
+ builds a complete `RecipeWorkflowComprehensions` tree with `OnSave` and
180
+ `OnApprovalAction.{Submit,Approve}` contexts off the Recipe section and the
181
+ FruitGrid recordset.
@@ -0,0 +1,295 @@
1
+ # Comprehensions — Advanced patterns
2
+
3
+ This document goes deeper than [Comprehensions](Comprehensions.md):
4
+
5
+ - **Hash vs. address arguments** — when to write `BookGUID` (bare symbol),
6
+ `"AppData.Bundle.BookGUID"` (string address), `getvalue("...")` (explicit
7
+ lookup), and when to mix them.
8
+ - **Computed contexts** — `IF`/ternary results as the `Context` argument so a
9
+ single solver routes between `OnApprovalAction.Submit` and
10
+ `OnApprovalAction.Approve`.
11
+ - **Per-row generation** with `MAP VAR` over a recordset.
12
+ - **Customized destinations** at the metacontroller level.
13
+ - **Resetting between solves**.
14
+
15
+ The complete worked example for everything here lives at
16
+ [`example_applications/complex_table/Complex-Tabular-Application.js`](../example_applications/complex_table/Complex-Tabular-Application.js)
17
+ — if you only read one thing, read that file. This page explains the *why* behind
18
+ the patterns it uses.
19
+
20
+ ## Argument resolution — hashes, addresses, and quoted strings
21
+
22
+ The solver expression parser treats each argument to `addComprehensionEntity`
23
+ the same way it would treat any other function argument:
24
+
25
+ | Argument form | What happens |
26
+ |---|---|
27
+ | `BookGUID` | **Bare symbol** — resolved from the form's manifest. Looked up first by descriptor hash, then by address against the marshal destination. |
28
+ | `Record.GUID` / `AppData.Bundle.X` | **Dotted symbol** — resolved as an address (the parser does NOT need quotes around addresses). |
29
+ | `"OnSave"` / `"Book"` | **Quoted string** — taken literally, no resolution. |
30
+ | `getvalue("AppData.X.Y")` | **Explicit lookup** — useful when you want to force address-resolution semantics on a value built up from other solvers. |
31
+ | `IF(...)` / `CONCAT(...)` | **Nested function call** — the inner function's return value becomes the argument. |
32
+
33
+ In practice you mix freely:
34
+
35
+ ```js
36
+ "Solvers":
37
+ [
38
+ // Context and Property are literals; Entity is a literal; GUID and Value
39
+ // are resolved from form data.
40
+ `addComprehensionEntity("OnSave", "Book", BookGUID, "Title", BookTitle)`,
41
+
42
+ // Same shape, but the GUID and Value come from absolute addresses rather
43
+ // than descriptor hashes. Useful if the descriptor hashes haven't been
44
+ // wired up or the data lives outside the form.
45
+ `addComprehensionEntity("OnSave", "Book", AppData.SelectedBook.IDBook, "Status", AppData.SelectedBook.Status)`,
46
+
47
+ // Pull a value through a getvalue() call -- equivalent to the line above
48
+ // but with explicit resolution syntax. Use this form when an inner
49
+ // expression already produces an address string and you want to evaluate it.
50
+ `addComprehensionEntity("OnSave", "Book", getvalue("AppData.SelectedBook.IDBook"), "Status", getvalue("AppData.SelectedBook.Status"))`,
51
+
52
+ // The property name itself is computed. CONCAT returns a string, which
53
+ // becomes the Property argument.
54
+ `addComprehensionEntity("OnSave", "Book", BookGUID, CONCAT("Field_", FieldType), FieldValue)`
55
+ ]
56
+ ```
57
+
58
+ **Rule of thumb:** quote when you want a literal, leave unquoted when you want
59
+ the parser to look the symbol up. The first three arguments are almost always
60
+ literal strings (Context, Entity name) plus one resolved value (GUID); the
61
+ fourth is almost always a literal Property; the fifth is almost always resolved.
62
+
63
+ ## Computed contexts — routing with `IF`
64
+
65
+ The `Context` argument is a manyfest address. It's also just a string that the
66
+ function uses to walk a nested object — which means a *computed* string works
67
+ fine. The complex_table example routes between `OnApprovalAction.Submit` and
68
+ `OnApprovalAction.Approve` based on a `Proprietary` boolean:
69
+
70
+ ```js
71
+ { Ordinal: 220, Expression:
72
+ `addComprehensionEntity(
73
+ IF(Proprietary, "==", 1, "OnApprovalAction.Submit", "OnApprovalAction.Approve"),
74
+ "Recipe",
75
+ RecipeName,
76
+ "Status",
77
+ IF(Proprietary, "==", 1, "Submitted", "Approved")
78
+ )`
79
+ }
80
+ ```
81
+
82
+ Both `Submit` and `Approve` branches sit under `OnApprovalAction`, which lets
83
+ downstream code key off `Object.keys(comprehension.OnApprovalAction)` to discover
84
+ which actions fired this solve.
85
+
86
+ The same trick scales to richer routing — e.g. context-per-environment:
87
+
88
+ ```js
89
+ `addComprehensionEntity(
90
+ CONCAT("OnSave.", EnvironmentName),
91
+ "Recipe", RecipeName, "Status", "Saved"
92
+ )`
93
+ ```
94
+
95
+ This produces `OnSave.Production.Recipe.<name>.Status` or
96
+ `OnSave.Staging.Recipe.<name>.Status` depending on the value of
97
+ `EnvironmentName`.
98
+
99
+ ## Per-row generation with `MAP VAR`
100
+
101
+ `MAP VAR` iterates a recordset and fires the body expression once per row, with
102
+ the row bound to a name you choose (`row` is the convention). Combined with
103
+ `addComprehensionEntity`, this fans one solver across an entire grid:
104
+
105
+ ```js
106
+ // From complex_table -- the Recipe section's solvers reach into the FruitGrid
107
+ // recordset and emit one OnSave.Fruit.<name>.<property> entry per (fruit, property)
108
+ // pair. Three MAP VARs produce 3 * N comprehension writes in a single solve.
109
+ { Ordinal: 210, Expression: `MAP VAR row FROM FruitData.FruityVice : addComprehensionEntity("OnSave", "Fruit", row.name, "Family", row.family)` },
110
+ { Ordinal: 210, Expression: `MAP VAR row FROM FruitData.FruityVice : addComprehensionEntity("OnSave", "Fruit", row.name, "Order", row.order)` },
111
+ { Ordinal: 210, Expression: `MAP VAR row FROM FruitData.FruityVice : addComprehensionEntity("OnSave", "Fruit", row.name, "Calories", row.nutritions.calories)` }
112
+ ```
113
+
114
+ Inside the body, `row.X.Y` resolves against each row in turn — so you get
115
+ deep-property access without writing per-row solvers.
116
+
117
+ After the solve runs against the bundled FruityVice data, the comprehension at
118
+ `AppData.RecipeWorkflowComprehensions.OnSave.Fruit` looks like:
119
+
120
+ ```json
121
+ {
122
+ "Apple": { "Family": "Rosaceae", "Order": "Rosales", "Calories": "52" },
123
+ "Banana": { "Family": "Musaceae", "Order": "Zingiberales", "Calories": "96" },
124
+ "Mango": { "Family": "Anacardiaceae", "Order": "Sapindales", "Calories": "60" },
125
+ ...
126
+ }
127
+ ```
128
+
129
+ (49 fruits total in the complex_table dataset.)
130
+
131
+ If you need one comprehension write per row that touches *every* property of the
132
+ row, you have two reasonable options:
133
+
134
+ 1. Multiple `MAP VAR` solvers, one per property (as above). Clear and easy to
135
+ audit.
136
+ 2. A single helper solver function registered on
137
+ `DynamicFormSolverBehaviors` that takes a row + property list and calls
138
+ `addComprehensionEntity` internally. Worth the indirection only if you have
139
+ many entities with many properties; otherwise just write the explicit
140
+ `MAP VAR`s.
141
+
142
+ ## Customizing the destination
143
+
144
+ Each metacontroller has a `comprehensionDestinationAddress` property —
145
+ mirroring the existing `viewMarshalDestination` knob — that controls where
146
+ `addComprehensionEntity` writes. The default is `AppData.FormEntityComprehensions`.
147
+
148
+ ### Option 1: in the application constructor
149
+
150
+ This is what the [complex_table example](../example_applications/complex_table/Complex-Tabular-Application.js)
151
+ does. After `super()` (which registers the metacontroller view via
152
+ `PictFormApplication`), set the destination directly:
153
+
154
+ ```js
155
+ class MyWorkflowApplication extends libPictSectionForm.PictFormApplication
156
+ {
157
+ constructor(pFable, pOptions, pServiceHash)
158
+ {
159
+ super(pFable, pOptions, pServiceHash);
160
+ this.pict.views.PictFormMetacontroller.comprehensionDestinationAddress = 'AppData.WorkflowComprehensions';
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### Option 2: via metacontroller options
166
+
167
+ If you're registering the metacontroller view yourself (no `PictFormApplication`
168
+ parent), pass `ComprehensionDestinationAddress` in the options:
169
+
170
+ ```js
171
+ pict.addView(
172
+ 'PictFormMetacontroller',
173
+ { ComprehensionDestinationAddress: 'Bundle.PendingWrites' },
174
+ libPictSectionForm.PictFormMetacontroller
175
+ );
176
+ ```
177
+
178
+ ### Option 3: change it mid-flight
179
+
180
+ The property is a plain string -- reassign whenever you need different
181
+ destinations for different phases:
182
+
183
+ ```js
184
+ // Before fanning the form's solvers, redirect to a transient staging slot.
185
+ this.pict.views.PictFormMetacontroller.comprehensionDestinationAddress = 'TempData.PendingComprehension';
186
+ this.pict.PictApplication.solve();
187
+ const tmpPending = this.pict.TempData.PendingComprehension;
188
+
189
+ // Promote / discard / inspect tmpPending however you like.
190
+
191
+ // Switch back to the canonical destination for the next solve.
192
+ this.pict.views.PictFormMetacontroller.comprehensionDestinationAddress = 'AppData.WorkflowComprehensions';
193
+ ```
194
+
195
+ The destination address is resolved against the pict instance, so any subtree
196
+ works (`AppData.*`, `Bundle.*`, `TempData.*`, ...).
197
+
198
+ ## Resetting the tree between solves
199
+
200
+ `addComprehensionEntity` never deletes keys -- it only writes / overwrites. If
201
+ your form workflow expects "only emit comprehensions for *currently visible*
202
+ records," you need to clear the destination at the start of the solve cycle.
203
+ Two patterns:
204
+
205
+ ### Pattern A: low-ordinal reset solver
206
+
207
+ ```js
208
+ "Solvers":
209
+ [
210
+ // Runs before any addComprehensionEntity calls because of the explicit
211
+ // low ordinal. `getvalue` returns a reference to the live AppData branch,
212
+ // but assigning to `AppData.X` rebinds the address. In manyfest assignments
213
+ // we want to nuke the previous tree, so explicitly empty it.
214
+ { Ordinal: 1, Expression: `AppData.RecipeWorkflowComprehensions = "{}"` },
215
+ // ...then the addComprehensionEntity calls at higher ordinals
216
+ ]
217
+ ```
218
+
219
+ The string `"{}"` becomes `{}` after JSON round-trip on the assignment. If your
220
+ solver dialect doesn't coerce strings to JSON for you, do the reset in
221
+ JavaScript instead:
222
+
223
+ ### Pattern B: JS-side reset
224
+
225
+ Override `marshalFromView` or `onBeforeSolve` to zero the destination:
226
+
227
+ ```js
228
+ class MyWorkflowApplication extends libPictSectionForm.PictFormApplication
229
+ {
230
+ onBeforeSolve()
231
+ {
232
+ this.pict.AppData.RecipeWorkflowComprehensions = {};
233
+ return super.onBeforeSolve();
234
+ }
235
+ }
236
+ ```
237
+
238
+ This is the simplest version. The `addComprehensionEntity` resolver handles a
239
+ missing-or-emptied destination by re-materializing it on the next write.
240
+
241
+ ## Full reference: the complex_table sample config
242
+
243
+ The [complex_table example](../example_applications/complex_table/Complex-Tabular-Application.js)
244
+ exercises every pattern on this page in one application. The relevant pieces:
245
+
246
+ ```js
247
+ // Constructor sets a customized destination.
248
+ this.pict.views.PictFormMetacontroller.comprehensionDestinationAddress = 'AppData.RecipeWorkflowComprehensions';
249
+ ```
250
+
251
+ ```js
252
+ // Recipe section solvers -- mix of bare-symbol GUID (RecipeName) and address
253
+ // arguments, multiple OnSave properties, MAP VAR fanning over a recordset,
254
+ // and IF-routed OnApprovalAction.
255
+ Solvers:
256
+ [
257
+ // ...prior compute solvers...
258
+
259
+ // OnSave.Recipe.<RecipeName>.<Property> for the recipe-level facts.
260
+ { Ordinal: 200, Expression: `addComprehensionEntity("OnSave", "Recipe", RecipeName, "Name", RecipeName)` },
261
+ { Ordinal: 200, Expression: `addComprehensionEntity("OnSave", "Recipe", RecipeName, "Type", RecipeType)` },
262
+ { Ordinal: 200, Expression: `addComprehensionEntity("OnSave", "Recipe", RecipeName, "Description", RecipeDescription)` },
263
+ { Ordinal: 200, Expression: `addComprehensionEntity("OnSave", "Recipe", RecipeName, "Inventor", Inventor)` },
264
+ { Ordinal: 200, Expression: `addComprehensionEntity("OnSave", "Recipe", RecipeName, "TotalCalories", TotalFruitCalories)` },
265
+ { Ordinal: 200, Expression: `addComprehensionEntity("OnSave", "Recipe", RecipeName, "AverageFatPercent", AverageFatPercent)` },
266
+
267
+ // OnSave.Fruit.<fruit>.<Property> -- per-row via MAP VAR over the FruitGrid recordset.
268
+ { Ordinal: 210, Expression: `MAP VAR row FROM FruitData.FruityVice : addComprehensionEntity("OnSave", "Fruit", row.name, "Family", row.family)` },
269
+ { Ordinal: 210, Expression: `MAP VAR row FROM FruitData.FruityVice : addComprehensionEntity("OnSave", "Fruit", row.name, "Order", row.order)` },
270
+ { Ordinal: 210, Expression: `MAP VAR row FROM FruitData.FruityVice : addComprehensionEntity("OnSave", "Fruit", row.name, "Calories", row.nutritions.calories)` },
271
+
272
+ // OnApprovalAction.{Submit,Approve}.Recipe.<RecipeName> -- computed context.
273
+ { Ordinal: 220, Expression: `addComprehensionEntity(IF(Proprietary, "==", 1, "OnApprovalAction.Submit", "OnApprovalAction.Approve"), "Recipe", RecipeName, "Status", IF(Proprietary, "==", 1, "Submitted", "Approved"))` },
274
+ { Ordinal: 220, Expression: `addComprehensionEntity(IF(Proprietary, "==", 1, "OnApprovalAction.Submit", "OnApprovalAction.Approve"), "Recipe", RecipeName, "Reviewer", Inventor)` }
275
+ ]
276
+ ```
277
+
278
+ After loading the example, fill in the Recipe section and toggle the
279
+ Proprietary checkbox; inspect `_Pict.AppData.RecipeWorkflowComprehensions` in
280
+ the browser console to see the OnSave / OnApprovalAction subtrees update.
281
+
282
+ ## Where this stops being the right tool
283
+
284
+ `addComprehensionEntity` is for shaping comprehension trees inside the
285
+ solver. If you're operating outside the solver loop -- e.g. building a
286
+ comprehension from an HTTP response, transforming CSV, or merging two pre-built
287
+ comprehensions -- reach for the meadow-integration toolchain directly:
288
+
289
+ - `meadow-integration csvtransform` to map columns into entity records.
290
+ - `meadow-integration comprehensionintersect` to merge two comprehensions.
291
+ - The `Comprehension` object's `Object.assign` semantics for in-code merges.
292
+
293
+ See [meadow-integration: Comprehensions](https://github.com/stevenvelozo/meadow-integration/blob/main/docs/comprehensions.md)
294
+ for those tools. The solver helper is purpose-built for "as I edit this form,
295
+ build the comprehension that will save it."
@@ -121,8 +121,8 @@ for export and editing.
121
121
 
122
122
  ### Marshal Operations
123
123
 
124
- - **toView** (`onMarshalToView`): AppData Form inputs
125
- - **fromView** (`onMarshalFromView`): Form inputs AppData
124
+ - **toView** (`onMarshalToView`): AppData -> Form inputs
125
+ - **fromView** (`onMarshalFromView`): Form inputs -> AppData
126
126
 
127
127
  The Informary provider handles the actual DOM operations, using data attributes
128
128
  to map form elements to their corresponding data addresses.
package/docs/Solvers.md CHANGED
@@ -96,13 +96,13 @@ Standard mathematical operators are supported:
96
96
 
97
97
  | Function | Description | Example |
98
98
  |----------|-------------|---------|
99
- | `abs(x)` | Absolute value | `abs(-5)` 5 |
100
- | `round(x)` | Round to nearest integer | `round(3.7)` 4 |
101
- | `floor(x)` | Round down | `floor(3.7)` 3 |
102
- | `ceil(x)` | Round up | `ceil(3.2)` 4 |
103
- | `min(a, b)` | Minimum value | `min(5, 3)` 3 |
104
- | `max(a, b)` | Maximum value | `max(5, 3)` 5 |
105
- | `sqrt(x)` | Square root | `sqrt(16)` 4 |
99
+ | `abs(x)` | Absolute value | `abs(-5)` -> 5 |
100
+ | `round(x)` | Round to nearest integer | `round(3.7)` -> 4 |
101
+ | `floor(x)` | Round down | `floor(3.7)` -> 3 |
102
+ | `ceil(x)` | Round up | `ceil(3.2)` -> 4 |
103
+ | `min(a, b)` | Minimum value | `min(5, 3)` -> 3 |
104
+ | `max(a, b)` | Maximum value | `max(5, 3)` -> 5 |
105
+ | `sqrt(x)` | Square root | `sqrt(16)` -> 4 |
106
106
 
107
107
  ### String Functions
108
108
 
@@ -111,7 +111,7 @@ Standard mathematical operators are supported:
111
111
  | `concat(a, b, ...)` | Concatenate values into a string | `concat('Hello', ' World')` |
112
112
  | `join(separator, a, b, ...)` | Join values with a separator | `join(', ', 'a', 'b', 'c')` |
113
113
  | `stringgetsegments(s, delimiter)` | Split string into segments | `stringgetsegments('a,b,c', ',')` |
114
- | `stringcountsegments(s, delimiter)` | Count segments in string | `stringcountsegments('a,b,c', ',')` 3 |
114
+ | `stringcountsegments(s, delimiter)` | Count segments in string | `stringcountsegments('a,b,c', ',')` -> 3 |
115
115
  | `resolvehtmlentities(s)` | Resolve HTML entities in string | `resolvehtmlentities('&amp;')` |
116
116
 
117
117
  ### Array Aggregation
@@ -222,6 +222,28 @@ aggregate values from arrays:
222
222
  | `SetTabularRowLength(hash, length)` | Set the row count for a tabular data set |
223
223
  | `RefreshTabularSection(hash)` | Refresh a tabular section display |
224
224
 
225
+ ### Comprehension Generation
226
+
227
+ | Function | Description |
228
+ |----------|-------------|
229
+ | `addComprehensionEntity(Context, Entity, GUID, Property, Value)` | Writes a single Property/Value into a nested comprehension tree at `Context -> Entity -> GUID -> Property` in the configured destination (default `AppData.FormEntityComprehensions`). |
230
+
231
+ The `Context` argument is treated as a manyfest address, so dotted contexts
232
+ like `"OnApprovalAction.Approve"` produce nested context branches. Successive
233
+ calls accumulate properties on the same record. See [Comprehensions](Comprehensions.md)
234
+ for the basic walkthrough and [Comprehensions — Advanced](Comprehensions_Advanced.md)
235
+ for computed contexts, `MAP VAR` patterns, and customized destinations.
236
+
237
+ #### Comprehension Example
238
+
239
+ ```json
240
+ "Solvers": [
241
+ "addComprehensionEntity(\"OnSave\", \"Book\", BookGUID, \"Title\", BookTitle)",
242
+ "addComprehensionEntity(\"OnSave\", \"Book\", BookGUID, \"Author\", BookAuthor)",
243
+ "addComprehensionEntity(\"OnApprovalAction.Approve\", \"Book\", BookGUID, \"Status\", \"Approved\")"
244
+ ]
245
+ ```
246
+
225
247
  ### Logging
226
248
 
227
249
  | Function | Description |
@@ -365,3 +387,5 @@ Use in solvers:
365
387
  - [Configuration](Configuration.md) - Solver configuration options
366
388
  - [Architecture](Pict_Section_Form_Architecture.md) - Solver system internals
367
389
  - [Input Types](Input_Types.md) - Input visibility control
390
+ - [Comprehensions](Comprehensions.md) - `addComprehensionEntity` basics
391
+ - [Comprehensions — Advanced](Comprehensions_Advanced.md) - Computed contexts, `MAP VAR`, customized destinations
@@ -0,0 +1,18 @@
1
+ {
2
+ "Hash": "pict-section-form",
3
+ "Name": "Pict Section Form",
4
+ "Tagline": "Configuration-driven dynamic forms with 13+ input types, data marshaling, and mathematical solving",
5
+ "Palette": "mix",
6
+ "Icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-pict-section-form-filled-light\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\" fill=\"#ccb526\"/>\n\t\t<g clip-path=\"url(#frame-pict-section-form-filled-light)\"><defs><mask id=\"_cr_34122\"><rect x=\"0\" y=\"0\" width=\"96\" height=\"96\" fill=\"#fff\"/>\n\t\t\t\t\t\t<circle cx=\"64\" cy=\"48\" r=\"32\" fill=\"#000\"/></mask></defs>\n\t\t\t\t\t<circle cx=\"48\" cy=\"48\" r=\"32\" fill=\"rgba(255,255,255,0.18)\" mask=\"url(#_cr_34122)\"/>\n\t\t\t\t\t<circle cx=\"64\" cy=\"48\" r=\"26\" fill=\"#4bacbc\" opacity=\"0.7\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"28\" font-weight=\"700\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">PSF</text>\n\t</svg>",
7
+ "IconType": "svg",
8
+ "Favicon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-section-form-light\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\" fill=\"#ccb526\"/>\n\t\t<g clip-path=\"url(#fav-pict-section-form-light)\"><circle cx=\"48\" cy=\"48\" r=\"36\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">P</text>\n\t</svg>",
9
+ "FaviconDark": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-section-form-dark\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\" fill=\"#dece70\"/>\n\t\t<g clip-path=\"url(#fav-pict-section-form-dark)\"><circle cx=\"48\" cy=\"48\" r=\"36\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">P</text>\n\t</svg>",
10
+ "Colors": {
11
+ "Primary": "#ccb526",
12
+ "Secondary": "#4bacbc",
13
+ "PrimaryLight": "#ccb526",
14
+ "PrimaryDark": "#dece70",
15
+ "SecondaryLight": "#4bacbc",
16
+ "SecondaryDark": "#92c8d0"
17
+ }
18
+ }
package/docs/_cover.md CHANGED
@@ -1,4 +1,4 @@
1
- # Pict-Section-Form <small>1</small>
1
+ # Pict-Section-Form
2
2
 
3
3
  > A dynamic, configuration-driven forms framework built on the Pict application platform
4
4
 
package/docs/_sidebar.md CHANGED
@@ -14,6 +14,8 @@
14
14
  - Advanced
15
15
 
16
16
  - [Solvers](Solvers.md)
17
+ - [Comprehensions](Comprehensions.md)
18
+ - [Comprehensions — Advanced](Comprehensions_Advanced.md)
17
19
  - [Providers](Providers.md)
18
20
 
19
21
  - Input Providers
@@ -0,0 +1,7 @@
1
+ {
2
+ "Name": "pict-section-form",
3
+ "Version": "1.0.197",
4
+ "Description": "Pict dynamic form sections",
5
+ "GeneratedAt": "2026-05-21T02:52:57.836Z",
6
+ "GitCommit": "29398f7"
7
+ }
@@ -94,17 +94,17 @@ node ServeExamples.js
94
94
 
95
95
  | Feature | simple_form | simple_table | simple_distill | gradebook | postcard | complex_table | complex_tuigrid | manyfest_editor |
96
96
  |---------|:-----------:|:------------:|:--------------:|:---------:|:--------:|:-------------:|:---------------:|:---------------:|
97
- | Basic Inputs | | | | | | | | |
98
- | Tabular Layout | | | | | | | | |
99
- | TuiGrid | | | | | | | | |
100
- | Solvers | | | | | | | | |
101
- | Row Solvers | | | | | | | | |
102
- | Pick Lists | | | | | | | | |
103
- | Entity Bundles | | | | | | | | |
104
- | Trigger Groups | | | | | | | | |
105
- | localStorage | | | | | | | | |
106
- | Custom Themes | | | | | | | | |
107
- | Navigation | | | | | | | | |
108
- | Charts | | | | | | | | |
109
- | DateTime | | | | | | | | |
110
- | JSON Editor | | | | | | | | |
97
+ | Basic Inputs | [x] | [x] | [x] | [x] | [x] | [x] | [x] | [x] |
98
+ | Tabular Layout | | [x] | | [x] | | [x] | | [x] |
99
+ | TuiGrid | | | | | | | [x] | [x] |
100
+ | Solvers | [x] | | [x] | | | [x] | [x] | |
101
+ | Row Solvers | | | | | | [x] | [x] | |
102
+ | Pick Lists | | | [x] | | | [x] | [x] | |
103
+ | Entity Bundles | | | [x] | | | [x] | | |
104
+ | Trigger Groups | | | [x] | | | [x] | | |
105
+ | localStorage | | | | [x] | | | | [x] |
106
+ | Custom Themes | | | | | [x] | | | |
107
+ | Navigation | | | | | [x] | | | [x] |
108
+ | Charts | | | | | | [x] | | |
109
+ | DateTime | | | | | | [x] | [x] | |
110
+ | JSON Editor | | | | | | | | [x] |