Skip to content

Commit f5004cb

Browse files
authored
Merge pull request #1298 from ako/main
Mendix 11.15: message definitions are documents (MessageDefinition2)
2 parents 0c21d62 + 5db4fe9 commit f5004cb

61 files changed

Lines changed: 1910 additions & 92 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.claude/skills/fix-issue/findings/mdl-backend.jsonl‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,3 +168,4 @@
168168
{"area": "mdl/backend", "date": "2026-10-02", "symptom": "getput: describe → exec of a combo box with `Editable: <expr>` rewrites ConditionalEditabilitySettings/Conditions[0]: 2 -> 3", "cause": "Forms$ConditionalEditabilitySettings registered Conditions as a plain mandatory list (default marker 3); Studio Pro writes [2], as for visibility", "file": "`mdl/backend/modelsdk/widget_write.go` (RegisterTypeDefaults)", "insight": "measured on both editability settings in TestApp; the ALTER path (pagemutator setWidgetConditionalSettingMut) still hand-writes [3] for both settings", "refs": ["#721"]}
169169
{"area": "mdl/backend", "date": "2026-10-04", "symptom": "ako/mxcli#980 (found adding navigation profiles to the TestApp round-trip harness): describe -> exec of an offline profile rewrote every multi-line sync constraint as the one-line text describe prints", "cause": "navOfflineConfigs wrote the spec's constraint verbatim; describe folds Studio Pro's multi-line layout (singleLine) and the visitor re-normalises it, so the text never matches the stored bytes", "file": "`mdl/backend/modelsdk/navigation_write.go` navOfflineConfigs / xpathWithoutLayout", "insight": "When describe deliberately changes layout, the writer must carry the stored layout for an unchanged value; compare with whitespace outside string literals removed (inside a literal it is part of the value — that is the control)", "refs": ["#980"]}
170170
{"area": "mdl/backend", "date": "2026-10-04", "symptom": "ako/mxcli#980: create or modify navigation on a native profile ignored its menu block, sync block, login/not-found page and on-sync-error while reporting 'updated'; describe printed a native nanoflow home as `home microflow` and bottom bar items without action or icon", "cause": "navPatchNativeProfile only patched home pages; nativeNavProfileFromGen read BottomBarItem.Page only; the grammar had no nanoflow home", "file": "`mdl/backend/modelsdk/navigation_write.go` navPatchNativeProfile, `navigation_read.go` nativeNavProfileFromGen, `mdl/executor/cmd_navigation.go` checkProfileClauses", "insight": "A profile-kind-specific writer must refuse every clause it does not apply (checked in the executor before anything is written, including profile creation), and describe must not print what exec would refuse — list it as comments. No native profile exists in any local fixture, so the reader is pinned with a hand-built gen document", "refs": ["#980"]}
171+
{"area": "mdl/backend", "date": "2026-10-05", "symptom": "On Mendix 11.15 `TestMappingFixtureRoundTrip` fails for the blank app's own FeedbackModule mappings: describe -> exec adds `\"MessageDefinition\": \"\"`; and a mapping `with message definition` built on 11.15 fails `mx check` with CE0270 \"No root element could be found in the schema\"", "cause": "Mendix 11.15 REMOVED the mapping's `MessageDefinition` key (message definitions became `MessageDefinitions$MessageDefinition2` documents; the source moved to `MessageDefinition2` as `Module.MessageName`, measured with `mx convert` 11.15.0). The writer added the key unconditionally and the executor put the source in it, which 11.15 no longer reads", "file": "`model.ImportMapping`/`ExportMapping` (`MessageDefinition *string`, `MessageDefinitionSource()`), `mdl/backend/modelsdk/mapping_read.go` (`optionalStringFromRaw`) + `mapping_write.go`, `mdl/executor/mapping_messagedefinition.go` (`mappingMessageDefinitionKeys`, `messageDefinitionsAreDocuments`), `sdk/versions/mendix-1{0,1}.yaml` (`integration.message_definition_collection` max 11.14.99, `message_definition_document` min 11.15.0)", "insight": "**A key can be REMOVED by a version, not only introduced** \u2014 the #279 carry rule applies in both directions, so `MessageDefinition` is now a pointer like `MessageDefinition2`. The source key follows the stored document's shape on an update (a pre-11.15 document transplanted into an 11.15 project keeps its source in `MessageDefinition`, which is what kept the fixture's AgentCore/Email_Connector mappings green) and the project version only on a create. Caught by the new 11.15 nightly job, not by any fixture: none of the pinned documents was 11.15-shaped until the blank 11.15 app's own FeedbackModule mappings appeared in the base project", "refs": ["ako/mxcli#987", "ako/mxcli#279"]}

‎.claude/skills/fix-issue/findings/mdl-executor.jsonl‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -865,3 +865,4 @@
865865
{"area": "mdl/executor", "date": "2026-10-04", "symptom": "ako/mxcli#980: describe navigation printed a menu item whose action was a nanoflow call / open link / create object with no OnClick, and exec of that description stored Forms$NoAction — TestApp's 'Item 4' (Forms$CallNanoflowClientAction) lost its action at exit 0", "cause": "create or modify navigation / menu is a full menu rebuild from the spec; the reader kept only page/microflow/sign-out, so the spec had no way to say 'keep what is stored' and the writer fell through to NoAction", "file": "`mdl/executor/cmd_navigation.go` convertMenuItemDefs (pairs items by caption path, KeepAction), `mdl/executor/cmd_menus.go` menuItemsFromAST, writers `navigation_write.go` navMenuAction / `menu_write.go` menuActionToGen", "insight": "A full-rebuild writer needs the stored element at hand to carry what the language cannot spell — the same carry offline CompatibilityMode already had. Pair by caption path (first unused sibling with that caption); carry only when the script states no action so an explicit action still wins. The reader must keep the raw action bytes (element.Raw()), not a projection of it", "refs": ["#980"]}
866866
{"area": "mdl/executor", "date": "2026-10-04", "symptom": "ako/mxcli#980: describe navigation printed call nanoflow / open link / create object items with no action and a call microflow without its progress bar, confirmation, async and form-validation settings; exec of the description stored NoAction / the defaults", "cause": "navigation had its own three-action model (Page/Microflow/SignOut) in reader, describe (printMenuMDL), grammar (navMenuAction) and writer (navMenuAction), parallel to the full widget client-action stack pages already had", "file": "`mdl/executor/cmd_navigation.go` printMenuMDL / menuItemActionMDL / menuActionBuilder, `mdl/backend/modelsdk/menu_action_write.go`, `MDLParser.g4` navMenuAction -> actionExprV3", "insight": "Same fix shape as #959 for navigation-list items: keep the raw action, describe it with renderClientActionMDL, parse actionExprV3, build with pageBuilder.buildClientActionV3, serialize with clientActionToGen. Then the round trip only needs the serializer to match Studio Pro's shape — measured gaps were Forms$CallNanoflowClientAction.OutputMappings, Forms$NoAction.DisabledDuringExecution and Menus$MenuItem AlternativeText/Items. For what the expression cannot spell (TitleOverride, LinkType, NumberOfPagesToClose2) keep the stored action when the built one equals it modulo $IDs and those keys. Prove it with a harness test that injects one Studio Pro-shaped item per kind and renames captions to force a build without carry", "refs": ["#980", "#959"]}
867867
{"area": "mdl/executor", "date": "2026-10-04", "symptom": "ako/mxcli#980: check --references refused describe navigation's own output on TestApp — `Icon: image System.Images.Save` gave \"unknown image collection System.Images\"", "cause": "validate_icon_refs resolves against the project's image collections; the System module (and its Images collection) is the platform's and is not stored in the project", "file": "`mdl/executor/validate_icon_refs.go` iconIndex.check / isSystemCollection", "insight": "A reference into the virtual System module can never be in a project listing; skip it rather than refuse (mxbuild resolves it). The member list is not in mxbuild's files in a readable form, so 'resolve' means 'do not judge'", "refs": ["#980"]}
868+
{"area": "mdl/executor", "date": "2026-10-05", "symptom": "On Mendix 11.15, `TestMxCheck_DoctypeScripts/40-message-definition-examples.mdl` fails with CE0270 \"No root element could be found in the schema\" at MsgTest.IMM_Order. On a converted or Studio Pro 11.15 project, `list message definition collections` finds nothing, and `describe import mapping` prints no source", "cause": "Mendix 11.15 replaced `MessageDefinitions$MessageDefinitionCollection` with one `MessageDefinitions$MessageDefinition2` document per definition. `mx convert` turns the collection into a `Projects$Folder` with the same unit ID and name, and the ExposedEntity tree is byte-identical apart from $IDs. mxcli read and wrote only collections, so on 11.15 there was nothing to resolve a mapping against", "file": "`mdl/backend/modelsdk/messagedefinition_document.go` (read/write, reusing the collection's exposedNodeFromGen/messageNodeToGen), `mdl/executor/cmd_messagedefinition_documents.go` (create/describe/drop/list + version refusals), `mdl/executor/mapping_messagedefinition.go` (`findMessageDefinition(ctx, ref)` returns the stored reference), `cmd_messagedefinitions.go` (alter target resolution, association-drop guard), grammar `createMessageDefinitionStatement` / `DROP|DESCRIBE MESSAGE DEFINITION` / `LIST MESSAGE DEFINITIONS`", "insight": "**`mx convert` is the oracle for a storage change.** Converting a known 11.14 project gives a Studio Pro-authored 11.15 reference for the new shape and for how references move, so no guessing is needed. **Under the revert, 11.15 fails earlier than CE0270.** A two-part name written into the old `MessageDefinition` key makes mxbuild refuse to load the project (`StorageLoadException: ... is not a valid OldMessageDefinitionIdentifier`). The old key is typed as a three-part identifier even though 11.15 no longer reads it. The doctype script uses `-- @version: ..11.14` / `11.15+` sections, and the 11.15 mapping needs a different name from the older section's, because a plain `check` sees both sections and reports MDL-DUPDEF", "refs": ["ako/mxcli#987"]}

‎.claude/skills/mendix/json-structures-and-mappings/SKILL.md‎

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,22 @@ target entity** — the stored cardinality follows the direction of traversal an
183183
the association's type, so a `Reference` gives a single object one way and a list
184184
the other, while a `ReferenceSet` is a list both ways.
185185

186+
**Mendix 11.15 removed collections.** Each definition is its own document, and
187+
a mapping names it in two parts. The collection form is refused on 11.15, and
188+
the document form below 11.15:
189+
190+
```sql
191+
mdl 1;
192+
create message definition Sales.OrderMessage for Sales.Order as 'Orders' {
193+
OrderId,
194+
Sales.Order_Customer/Sales.Customer { FirstName }
195+
};
196+
create import mapping Sales.IMM_Order with message definition Sales.OrderMessage
197+
{
198+
create Sales.Order { OrderId = OrderId }
199+
};
200+
```
201+
186202
The full vocabulary, the ALTER statements, inherited attributes and what mxcli
187203
deliberately does not guess:
188204
[reference/message-definitions.md](reference/message-definitions.md).

‎.claude/skills/mendix/json-structures-and-mappings/reference/message-definitions.md‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,36 @@ CE0295 (`Association '...' is not allowed`) on any mapping element bound to it.
5151
the entity that declares it, which is what Mendix stores; qualifying one against
5252
the entity that merely uses it is CE1613.
5353

54+
### Mendix 11.15: one document per definition
55+
56+
Mendix 11.15 removed the collection. Each definition is a separate document,
57+
and Studio Pro's converter turns a collection into a folder of the same name
58+
holding one document per definition. The statement is the collection's
59+
`definition` entry on its own:
60+
61+
```sql
62+
mdl 1;
63+
create message definition Sales.OrderMessage
64+
folder 'Messages/MD_Order'
65+
for Sales.Order as 'Orders' {
66+
OrderId,
67+
Sales.Order_Customer/Sales.Customer { FirstName }
68+
};
69+
alter message definition Sales.OrderMessage add member LastName in Customer;
70+
list message definitions in Sales;
71+
describe message definition Sales.OrderMessage;
72+
drop message definition Sales.OrderMessage;
73+
```
74+
75+
A mapping names it in **two** parts (`with message definition Sales.OrderMessage`).
76+
A three-part name from an older script (`Sales.MD_Order.OrderMessage`) still
77+
resolves on a converted project and is stored as the two-part one.
78+
79+
Which form applies depends on the project version. On 11.15 the collection
80+
statements are refused with a hint to use the document form. Below 11.15 the
81+
document form is refused with a hint to use the collection. Use `list message
82+
definitions` on 11.15 and `list message definition collections` before it.
83+
5484
### Editing one without restating it
5585

5686
Real definitions nest deeply, so a whole-document rewrite is a poor tool for

‎CHANGELOG.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
5656

5757
### Fixed
5858

59+
- **Import and export mappings on Mendix 11.15 keep the 11.15 shape** (ako/mxcli#987) — Mendix 11.15 removed a mapping's `MessageDefinition` key and moved a message-definition source to `MessageDefinition2` as `Module.MessageName`. mxcli wrote `MessageDefinition: ""` onto every mapping it created or rewrote, a property the 11.15 document does not have; it now carries the key's presence from the stored document, and a new mapping gets it only below 11.15. On 11.15 `with message definition` stores its source in `MessageDefinition2`, and `describe` / `list import mappings` / the catalog read the source from whichever key holds it, so an 11.15 mapping no longer describes without its source. The catalog schema version is bumped, so a cached catalog rebuilds.
5960
- **`mxcli oql -p` and `mxcli log` reach a `run --local` started with `--admin-port`** (ako/mxcli#982) — both read the admin port and password the loop records in `.mxcli/run-local.json` for any connection flag not given, so the `Query data: mxcli oql -p …` hint `run --local` prints works on a non-default port instead of failing "cannot connect … localhost:8090". `run --local` now also prints a `mxcli log list -p …` hint. Precedence: flags, then a live loop, then environment, `.docker/.env`, defaults; a handshake left by a stopped loop is ignored.
6061
- **The Vega charts skill pack writes JSON numbers with `toString(round(x, 2))`** (ako/mxcli#982) — it recommended `formatDecimal(x, '0.00')`, which follows the user's language: a Dutch user got `12,50` and "Data is not valid JSON". Measured on 11.13: `toString(round(…))` is locale-independent and has no exponent; `formatDecimal(x, '0.00', 'en-US')` also works, but an underscore tag (`'en_US'`) is silently ignored.
6162
- **`check` predicts the view-entity OQL that mxbuild or the database refuses** (ako/mxcli#981) — a comparison as a select column (`r.A = r.B as Same`, CE0174) is **MDL033**, with the `case when … then true else false end` form as the fix; an aggregate over a column the GROUP BY also uses (`count(r.Season)` by `r.Season`, `max(r.D)` by `datepart(YEAR, r.D)`, CE0174) is **MDL034**; a plain column that is neither aggregated nor grouped (CE0174, also next to `group by r.ID`) is **MDL035**; and a non-aggregated expression that is not a GROUP BY expression (`datepart(MONTH, r.D)` next to `group by datepart(YEAR, r.D)`), which builds and then fails when the view is read (PostgreSQL 42803, HSQLDB 42574), is **MDL036** — all errors, so exec refuses them too. A literal aggregated (`sum(1)`, `count(1)`, `count('x')`, `count(true)`, `sum(0.0)`) warns **MDL037**: HSQLDB, Studio Pro's default database, refuses it with 42567; and a bare integer or string literal column draws the **MDL038** note, because on HSQLDB a consumer's `v.One + 1` returns 11. String concatenation (`r.Name + ' x'`) is now inferred as String(200), so `string` / `string(100)` declarations are MDL031 (CE6770). A view attribute declared `autonumber` over an AutoNumber column (CE6770) is refused under `mdl 1;` and warns **MDL-V1-VIEWAUTONUMBER** without the header; declare it `long`.
@@ -154,6 +155,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
154155

155156
### Added
156157

158+
- **Message definitions on Mendix 11.15: `create message definition`** (ako/mxcli#987). Mendix 11.15 replaced the message definition collection with one document per definition, and Studio Pro's converter turns a collection into a folder of that name holding the documents. The new statements cover the document form: `create [or modify] message definition M.Name [folder '…'] for M.Entity [as '…'] { members }` (the collection's `definition` entry on its own), `describe message definition`, `drop message definition`, `list message definitions [in M]` and `alter message definition M.Name add|drop|set member …`. A mapping names the document as `with message definition M.Name`. A three-part `M.Collection.Definition` from an older script still resolves on a converted project and is stored as `M.Name`. **Version-dependent:** the document form is refused below 11.15 with a hint to use the collection, and on 11.15 the collection statements are refused with a hint to use the document form. `list message definition collections` on 11.15 points to `list message definitions`. `describe` prints the document form, so describe → exec round-trips. Before this, 11.15 projects showed no message definitions, and a mapping over one failed `mx check` with CE0270. This is an addition, so `mdl 1` scripts are unaffected.
157159
- **`check` notes a locale-less `formatDecimal` in hand-built JSON** (ako/mxcli#982) — **MDL-JSONNUM01** (info) for `formatDecimal(x, '0.00')` inside a `+` concatenation whose string literals contain `{` or `":`, which writes `12,50` for a Dutch user. Use `toString(round(x, 2))` or pass a hyphenated locale. A display string (`'Total: ' + formatDecimal(…)`) is not flagged.
158160
- **`mxcli fix hashes` verifies and repairs the MPR v2 ContentsHash index** (ako/mxcli#972) — every `Unit.ContentsHash` in the `.mpr` is compared with `base64(SHA-256)` of its `.mxunit`, and mismatches, missing files and orphan files are reported; the command exits 1 when any remain. `--repair` rewrites the mismatched hashes from the files in one transaction, under the same Studio Pro open-project guard as every write. Restoring a unit with `git checkout` leaves the index stale and `mx check` does not notice; measured on a TestApp copy, an entity added by `exec` and then reverted with a byte-level restore is reported as one `DomainModels$DomainModel` mismatch, and after `--repair` the verify is clean and `mx check` reports 0 errors. `exec` and `docker check` print a one-line warning when the index disagrees (about 0.2 s on 900 units). An MPR v1 project has no index, and the command says so.
159161
- **Warnings for git states that crash Studio Pro** (ako/mxcli#972) — Studio Pro 11.13 fails to open a project ("Unable to find 'system' property in 'system'") when its git branch has no upstream or git reports "detected dubious ownership". `docker check`, `run --local` and the new `mxcli diag -p app.mpr` project section warn with the remedy (`git push -u origin <branch>`; `git config --global --add safe.directory <path>` on the Studio Pro machine). Never fatal, and silent outside a git repository, on a detached HEAD, under `CI`, or with `MXCLI_NO_GIT_WARNINGS=1`. See the new "Working Outside Studio Pro" page.

‎cmd/mxcli/lsp_completions_gen.go‎

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎docs-site/src/SUMMARY.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,8 @@
272272
- [OData and Integration Statements](reference/odata/README.md)
273273
- [Integration Statements](reference/integration/README.md)
274274
- [CREATE JSON STRUCTURE](reference/integration/create-json-structure.md)
275+
- [CREATE MESSAGE DEFINITION COLLECTION](reference/integration/create-message-definition-collection.md)
276+
- [CREATE MESSAGE DEFINITION](reference/integration/create-message-definition.md)
275277
- [CREATE IMPORT MAPPING](reference/integration/create-import-mapping.md)
276278
- [CREATE EXPORT MAPPING](reference/integration/create-export-mapping.md)
277279
- [CREATE DATA TRANSFORMER](reference/integration/create-data-transformer.md)

0 commit comments

Comments
 (0)