Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
d1d6c95
meta: add the workflow sub-process members to the System module
claude Nov 11, 2026
443ef89
roundtrip: strike the sub-process documents that now execute
claude Nov 11, 2026
d74700a
fix(test): generated test callers apply entity access (#2100)
claude Nov 11, 2026
8b045c4
Merge remote-tracking branch 'origin/main' into fix/2100-test-callers…
claude Nov 11, 2026
b574989
Merge pull request #2147 from ako/claude/beautiful-thompson-96trn4
ako Nov 11, 2026
5027f47
fix(check): accept the container names Studio Pro stores in grid rows…
ako Nov 11, 2026
dc81d80
fix(pages): keep a binding read through an outer data view (#2107)
ako Nov 11, 2026
9156cf4
fix(run): keep mxbuild's client source so --watch builds incrementally
claude Nov 11, 2026
401ae57
fix(run): keep the client source out of mxbuild's way on Windows
claude Nov 11, 2026
354a04d
Merge remote-tracking branch 'origin/main' into fix/2109-2107-outer-c…
ako Nov 11, 2026
8cbe6d6
style: gofmt the #2107 test
ako Nov 11, 2026
c483827
Merge remote-tracking branch 'origin/main' into claude/fervent-einste…
claude Nov 11, 2026
de458bd
Merge pull request #2157 from ako/fix/2109-2107-outer-context-bindings
ako Nov 11, 2026
e5f222e
Merge remote-tracking branch 'origin/main' into claude/fervent-einste…
claude Nov 11, 2026
dab9acb
Merge branch 'main' into fix/2100-test-callers-entity-access
ako Nov 11, 2026
38b3d2f
Merge pull request #2152 from ako/claude/fervent-einstein-4d6q38
ako Nov 11, 2026
ef7ed33
Merge remote-tracking branch 'origin/main' into fix/2100-test-callers…
claude Nov 11, 2026
9c0bcdd
Merge pull request #2148 from ako/fix/2100-test-callers-entity-access
ako Nov 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "cmd/mxcli", "date": "2026-11-11", "symptom": "ako/mxcli#2100 (mendixlabs/mxcli#1805): a .test.mdl test calling a microflow with Apply entity access = Yes failed CE0114 at build ('A microflow that does not apply entity access can only call microflows that also do not apply entity access') and MDL-SEC22 at check; the same for an applying @setup. Making the generated test microflow apply entity access then failed CE0150 on the runner's own handlers ('attributes of System.Error … cannot be accessed in microflows that apply entity access').", "cause": "Three generators wrote callers without the setting: writeTestFlow (endpoint), GenerateTestRunner (legacy MxTest.TestRunner) and CheckSource (MxTest.Check_* wrappers). The runner's verdict and @throws handlers read $latestError/Message directly, which an applying flow may not.", "file": "cmd/mxcli/testrunner/caller_entity_access.go (callerAppliesEntityAccess, errorMessageFlow helper), generator_endpoint.go (attachOnError numbers its handlers), generator.go, check_source.go, runner.go (legacy cleanup), build_attribution.go", "insight": "CE0114 has one direction, so the safe constant is 'apply' (the same call RegisterEndpoint made for #1654) — but the setting has a second, opposite constraint (CE0150), and the fix has to be measured against both: mx check on 11.12.1 at Off and Production showed an applying flow reading an ordinary entity's attribute is 0 errors, so CE0150 is the only cost. Mendix's CE0150 text prescribes the helper. The runtime half needs no measurement because the endpoint runs tests under Core.createSystemContext. A test body that reads $latestError/ itself is the one case 'apply' would newly break, so it keeps the old setting; under the legacy runner that decision is per suite because all tests share one microflow. The reported fix named two generators; the legacy runner was a third.", "refs": ["ako/mxcli#2100", "mendixlabs/mxcli#1805", "ako/mxcli#1654"], "test": "cmd/mxcli/testrunner/caller_entity_access_test.go; mdl-examples/bug-tests/test-runner-2100-*"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "cmd/mxcli", "date": "2026-11-11", "symptom": "`run --local --watch` on Mendix 11.16.0 took 20-22 s to apply a microflow edit and 25-28 s, with a runtime restart that drops every browser session, to apply a page edit. Every change logged \"mxbuild --serve's incremental build left web/dist without dist/pages ... restarting mxbuild --serve for a full build\" or \"mxbuild --serve cannot build this change incrementally (it wants client source its first build does not leave behind)\".", "cause": "A build in an mxbuild --serve process writes the client source its bundler reads (web/pages, layouts, nanoflows, snippets, widgets, package.json) and deletes it when the build ends. The next build regenerates only the changed documents, so the bundler has almost no input: dist/ goes from 47 files to 4, or the build fails on a missing web/pages file. serveRecovery answered both with a fresh serve process and a cold build per change, and the cold build's restartRequired restarts the runtime.", "file": "cmd/mxcli/docker/client_source_keep.go (clientSourceKeep: watch, restore, missingPageSource), cmd/mxcli/docker/serve_recovery.go (buildKeeping, isBundleFailure), cmd/mxcli/docker/runlocal.go (the boot build is watched too)", "insight": "The earlier measurement that ruled this out (webclient_legacy_paths.go, 11.14) put back the bundler config and the empty directories, not the files in them, and concluded that nothing done to the deployment helps. What settled it was copying web/ every 50 ms during a cold build and diffing the copy against web/ afterwards: 75 files existed only mid-build. Putting them back before the next /build made it complete in 2.3 s with restartRequired false. Control: that bundle against a cold build of the same model on a fresh process has the same file set and differs only in the build timestamp on each import. Keep what a successful build deleted rather than a list of directory names, so a version that leaves its source in place keeps nothing; and check dist/pages against the kept source after every build, because a missed file is bundled this time and silently absent the next. A measurement taken through a project's own ./mxcli tests the binary that link points at: `make build` replaces bin/mxcli with a new inode and leaves the hardlink on the old one, which produced one full run of 'the fix does nothing'.", "refs": ["ako/mxcli#2150"], "test": "cmd/mxcli/docker/client_source_keep_test.go"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-11-11", "refs": ["ako/mxcli#2107", "ako/mxcli#826", "ako/mxcli#833", "mendixlabs/mxcli#1591"], "ce": ["CE7247"], "symptom": "describe page -> exec of six FactoryManagement pages (Mendix 11.16) failed: a markdown viewer in an inner data view was refused \"`GenAICommons.Span.Output` is an attribute of GenAICommons.Span, not of ConversationalUI.CopyHelper … CE7247\" (and Span_TextGeneration_SlideIn's markdownViewer3 failed \"failed to resolve mapping for stringAttribute\"); an attribute-based visibility condition failed \"ConversationalUI.TraceView has no attribute HasError\".", "file": "mdl/executor/cmd_pages_parameter_binding.go (namedObjectSourceName, isNamedObjectAttributeText), cmd_pages_describe_pluggable.go and cmd_pages_describe_parse.go (print $dv.Attr / $dv/Assoc/Attr), cmd_pages_builder_v3.go (namedObjectVariable, used by resolveRootedAssociationPath), widget_engine.go (parameterBinding takes a data view; rootedAttributeBinding; BuildContext.AttributeSteps), widget_expression_value.go and validate_widget_expression_value.go (rooted data-source form on an attribute property), cmd_pages_builder_visible_when.go, cmd_pages_input_binding_context.go (MDL-WIDGET34 accepts an enclosing data view), mdl/backend (WidgetObjectBuilder.SetAttributeWithSteps in widgetobj and mcp). Tests: cmd_pages_outer_dataview_binding_2107_test.go", "cause": "Studio Pro stores both bindings with the data-view pair SourceVariable {Widget: <outer data view>, PageParameter: …} (markdownViewer3 also with association steps). parameterSourceName returns \"\" when Widget is set, so describe fell back to the qualified name and the rewrite resolved it against the nearest container. The `$dataView1.Attr` spelling existed for built-in inputs only (#826); the pluggable engine, Visible-by-attribute and MDL-WIDGET34 accepted a parameter only, and no pluggable attribute property could store association steps at all.", "insight": "**When a describe falls back to a qualified name, look for a SourceVariable the reader ignored.** Every one of these bindings carried the pair, and the existing spelling for it just had not been wired into every reader and writer: grep the parameter-only helpers (parameterSourceName, parameterVariable) for their callers, and widen them in ONE helper (namedObjectVariable, namedObjectSourceName) so check, describe and exec agree. Also note that `$x/Assoc/Attr` parses as an association data source, not an expression: a fix tested only through the expression form passes its unit test and still fails the real page (MDL-WIDGET42) - feed the engine the parsed shape. Controls: reverting each edit fails its test; the old binary refuses all six pages, the new one reports Unchanged page on all six; a fresh page with $dvOuter.Output, $dvOuter/Span_Trace/SystemPrompt and Visible: $dvOuter.Flag in (true) builds with mx check 0 errors on 11.16."}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-11-11", "refs": ["ako/mxcli#2109", "mendixlabs/mxcli#1324", "mendixlabs/mxcli#122", "ako/mxcli#2095"], "ce": ["CE0117", "CE0115"], "symptom": "describe page -> exec of four FactoryManagement pages (Mendix 11.16) was refused by check on its own output: \"`actionButton1` reads `$grid1` …, but `grid1` is the data container the widget sits in directly\" (MDL-BUTTON02) and \"$grid1 cannot be stored — … an explicit one is rejected as CE0115\" (MDL-PAGEARG01). The stored pages build (untouched app: 4 unrelated errors).", "file": "mdl/executor/validate_page_button_context.go (checkButtonContextTree: control bar nearest \"\", nearestSelectable; isObjectContextContainer + combobox; checkOwnContainerName skips a show page in a selectable grid's rows), mdl/executor/cmd_pages_showpage_args.go (pageArgContext.rowSelectionOf, namesRowSelection, selectableDataGrid, enteringDataWidgetOf shared by argContextForChildren and both engine sites), mdl/executor/widget_engine.go. Tests: validate_own_container_slots_2109_test.go; updated validate_page_own_container_name_test.go (btnCtlBar) and cmd_pages_showpage_selection_arg_122_test.go", "cause": "Three slots open or move an object context that the walks modelled wrong. A selectable data grid's name is its selection in its rows as well as its control bar (Studio Pro stores Variable {Widget: grid1} from column content). A control bar takes its object from above the grid but sits INSIDE it, so the container above is an outer one, not the nearest. A combo box's option content is its own item context. And the pluggable engine entered a data widget's argument context with its own constructor, so a fix in argContextForChildren alone left exec refusing what check accepted.", "insight": "**Dump the stored slot before deciding which side is wrong, and find the property path, not just the widget.** A small walker mapping each CustomWidget TypePointer to its PropertyKey showed `Datagrid:grid1 > [columns] > [content]`, `[filtersPlaceholder]` (printed as controlbar) and `Combobox > [optionsSourceAssociationCustomContent]` - three different reasons in one rule. Then **re-measure an old 'measured' verdict with today's writer before trusting it**: btnCtlBar's CE0117 on 11.14 was an error in an EXPRESSION `$dvP`; since #2095 the argument is written as the variable pair, and a probe on 11.16 builds it - and even a button DIRECTLY in dvP passing $dvP - with 0 errors (positive control in the same build: CE1365), so MDL-BUTTON02's premise for action arguments may be stale beyond this fix. Controls: reverting each of the five edits fails its test; old binary refuses all four pages, new one reports Unchanged page on the three that MDL-WIDGET03 (#2110) does not block."}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area":"modelsdk/meta","date":"2026-11-11","symptom":"describe -> exec of TestApp WorkflowCommons.Snip_WorkflowActivityRecord_Header (Mendix 11.14.0): mx check CE0117 'Error(s) in expression.' at Text 'text4', a parameter reading $WorkflowActivityRecord/System.WorkflowActivityRecord_WorkflowSubProcess/Caption","cause":"modelsdk/meta's System module (extracted from 11.6.4) had no System.WorkflowSubProcess, WorkflowSubProcessDefinition, their associations or System.WorkflowSubProcessState, so the association path could not resolve and the builder stored the parameter as an expression","file":"modelsdk/meta/system_module.go (SystemEntityDef.Introduced, ModelerSystemEntitiesIn, SystemEnumerationsIn), modelsdk/meta/system_enumerations.go, mdl/backend/modelsdk/system_module_read.go, mdl/backend/modelsdk/enumeration.go","insight":"Two measurements, two sources: attributes, types and String lengths from the model.mdp of a deploy build (mxcli docker build -o writes app/model/model.mdp; mx check does not), and the introducing version from the names in Mendix.Modeler.Core.dll per version (mxcli setup mxbuild --version X, grep, delete; ~1.6 GB each). Bisect with a control name that exists in every version (WorkflowActivityRecord_Actor), or 'absent' cannot be told from 'the model is stored elsewhere'. Result: absent 11.6.0/11.7.0, present 11.8.0 onward; 11.8.0 alone also has WorkflowActivityDetails_WorkflowSubProcess. Gate the ENTITY and derive its associations' presence from their ends (as RuntimeOnly already did), so new associations need no per-row version. A test whose count assumed every System enumeration exists for the 11.6.6 fixture is the gate working, not a regression: compare against the version-aware list.","refs":["#2141","mendixlabs/mxcli#1810"],"ce":["CE0117","CE1613"]}
11 changes: 7 additions & 4 deletions .claude/skills/mendix/system-module/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ description: "Reference for the built-in System module — User, FileDocument, I
| 275-332 | 3. HTTP / Web Services |
| 333-359 | 4. Error Handling |
| 360-383 | 7. Utility Entities |
| 384-448 | 8. Enumerations |
| 449-480 | 9. Inheritance Hierarchies |
| 481-536 | 10. Common Patterns |
| 537-539 | Source |
| 384-451 | 8. Enumerations |
| 452-483 | 9. Inheritance Hierarchies |
| 484-539 | 10. Common Patterns |
| 540-542 | Source |

<!-- /skill-index -->
# Mendix System Module Reference
Expand Down Expand Up @@ -440,6 +440,9 @@ refused. `describe` prints them as `--` comment lines for that reason.
### WorkflowState
`InProgress`, `Paused`, `Completed`, `Aborted`, `Incompatible`, `Failed`

### WorkflowSubProcessState
`InProgress`, `Aborted`, `Failed`, `Completed`, `Paused`

### WorkflowUserTaskCompletionType
`Single`, `Veto`, `Consensus`, `Majority`, `Threshold`, `Microflow`

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,48 @@ Detailed audit of each workflow activity execution.
| WorkflowActivityRecord_TaskTargetedUsers | System.User | Many-to-Many |
| WorkflowActivityRecord_TaskAssignedUsers | System.User | Many-to-Many |
| WorkflowActivityRecord_TaskTargetedGroups | System.WorkflowGroup | Many-to-Many |
| WorkflowActivityRecord_WorkflowSubProcess | System.WorkflowSubProcess | Many-to-One (11.8+) |
| WorkflowActivityRecord_WorkflowSubProcessDefinition | System.WorkflowSubProcessDefinition | Many-to-One (11.8+) |

### System.WorkflowSubProcess

A running or finished sub-process of a workflow. Mendix 11.8 and later
only: in an older project every name in this section is CE1613 "no longer exists".

| Attribute | Type | Description |
|-----------|------|-------------|
| Caption | String(200) | Sub-process caption |
| StartTime | DateTime | When it started |
| EndTime | DateTime | When it ended |
| State | Enum (WorkflowSubProcessState) | Execution state |
| Reason | String | State reason |

| Association | Target | Type |
|-------------|--------|------|
| WorkflowSubProcess_Workflow | System.Workflow | Many-to-One |
| WorkflowSubProcess_WorkflowSubProcessDefinition | System.WorkflowSubProcessDefinition | Many-to-One |

`WorkflowUserTask_WorkflowSubProcess`, `WorkflowEndedUserTask_WorkflowSubProcess`
and `WorkflowCurrentActivity_WorkflowSubProcess` point at it from a task or activity.
Read its caption from an activity record with
`$WorkflowActivityRecord/System.WorkflowActivityRecord_WorkflowSubProcess/Caption`.

### System.WorkflowSubProcessDefinition

The definition of a sub-process (Mendix 11.8 and later).

| Attribute | Type | Description |
|-----------|------|-------------|
| Caption | String(200) | Definition caption |
| IsObsolete | Boolean | Removed from the model |
| ModelGUID | String(36) | Sub-process GUID in the model |

| Association | Target | Type |
|-------------|--------|------|
| WorkflowSubProcessDefinition_WorkflowDefinition | System.WorkflowDefinition | Many-to-One |

`WorkflowUserTaskDefinition_WorkflowSubProcessDefinition` points at it from a user
task definition.

### System.WorkflowActivityDetails

Expand Down
27 changes: 14 additions & 13 deletions .claude/skills/mendix/test-microflows/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ description: "Write and run MDL-based microflow tests with `mxcli test` — anno
| 190-232 | Test File Formats |
| 233-248 | string Operations |
| 249-272 | Running Tests |
| 273-470 | How It Works |
| 471-509 | Check a test file before you run it |
| 510-631 | Writing Good Tests |
| 632-646 | Test File Organization |
| 647-659 | Interpreting Failures |
| 660-681 | CI Integration |
| 682-688 | Related Skills |
| 689-693 | Warm test loop (`mxcli test --local [--watch]`, `--attach`, `run --local --test-endpoint`) |
| 273-471 | How It Works |
| 472-510 | Check a test file before you run it |
| 511-632 | Writing Good Tests |
| 633-647 | Test File Organization |
| 648-660 | Interpreting Failures |
| 661-682 | CI Integration |
| 683-689 | Related Skills |
| 690-694 | Warm test loop (`mxcli test --local [--watch]`, `--attach`, `run --local --test-endpoint`) |

<!-- /skill-index -->
# Test Microflows Skill
Expand Down Expand Up @@ -325,11 +325,12 @@ chained, `--local` ran with the app's startup logic suppressed, and a suite that
depended on startup state passed under `--attach` and failed under `--local` for
reasons unrelated to the code.

`MxTest.RegisterEndpoint` applies entity access, so it can call a startup
microflow that does or does not (CE0114 only forbids a non-applying microflow
calling an applying one); yours still runs with its own setting. A build error
located in `MxTest.RegisterEndpoint` or `MxTest.RegisterTestEndpoint` is reported
as an mxcli defect, not as an error in your project.
`MxTest.RegisterEndpoint` and the generated test microflows apply entity
access, so they can call a microflow that does or does not (CE0114 only forbids
a non-applying microflow calling an applying one); yours still runs with its own
setting. Exception: a test whose own error handler reads `$latestError/…` gets a
flow that does not apply it, since an applying one may not (CE0150). A build
error in an `MxTest` document mxcli generated is reported as an mxcli defect.

One thing rollback does **not** cover: whatever the startup microflow writes
happens at boot, outside any test's transaction, so `@cleanup rollback` does not
Expand Down
Loading
Loading