|
51 | 51 | {"area": "mdl/grammar", "date": "2026-08-27", "raw": "| After ako/mxcli#260, ten of the 327 demo-app mappings still describe into MDL that does not parse — an export root printed as `. {`, and a custom-handler parameter printed as `Suggestion: (Value)` | Two leftovers of the same families. (1) `group as` covers a nested entity-less node (#262) but a ROOT has no member name, so it had no spelling at all. (2) `customHandlerParamText` rendered the stored value path raw, so an array-of-primitives parameter leaked Mendix's `(Wrapper)`/`(Value)` markers | `mdl/grammar/domains/MDLDomainModel.g4` (`exportMappingRootElement`), `mdl/executor/cmd_export_mappings.go` (the entity-less-root branch, and the association-less handling), `mdl/executor/mapping_customhandler.go` (`customHandlerParamText`, `buildCustomHandler`) | **Printing the member is only half of it**: emitting `Value` while the builder concatenates it back as `…|(Wrapper)|Value` gives a path that resolves to nothing, so resolve the parameter path THROUGH the schema index (`resolvePathKind(..., true)`) the way a member reference is resolved. Two things only a real build caught, both invisible to `mxcli check`: an entity-less root fell through to the VALUE branch and produced a project mxbuild cannot LOAD (*\"Type ExportValueMappingElement does not contain a constructor with a parameter of type ExportMapping\"*), because the builder decides object-vs-value on `def.Entity != \"\"`; and an element with NO association cannot be `Find` — **CE0224 \"No association selected for obtaining objects.\"** — it is `Parameter`, which is what CapitalConnector.EM_AttachedDataRequest stores on both its elements. Took the corpus from 317/327 parsing to **327/327**. Repro `mdl-examples/bug-tests/mapping-260b-last-parse-failures.mdl` |", "refs": ["#262", "ako/mxcli#260"], "ce": ["CE0224"]} |
52 | 52 | {"area": "mdl/grammar", "date": "2026-08-28", "raw": "| A JSON structure's ARRAY ITEM element gets a derived name (`LinesItem`, `JsonObject`) that no MDL can change, and every mapping over the structure carries it — `describe` of a Studio Pro mapping then diffs on `ExposedName`. The obvious workaround, `custom name map ('lines\\|(Object)' as 'OrderLine')`, parses, executes and does **nothing** | An array's item is the anonymous `[…]` entry, so it has no JSON key; `customNameMap` is keyed on JSON keys, so the item was unreachable by construction. And an entry matching no key was applied to nothing and reported nothing, so the failed workaround was indistinguishable from success | grammar `mdl/grammar/domains/MDLDomainModel.g4` (`customNameMapping` gains `ITEM OF`), `mdl/ast/ast_jsonstructure.go` (`CustomItemNameMap`), `mdl/visitor/visitor_jsonstructure.go`, `mdl/types/json_utils.go` (`snippetBuilder.itemName`, `SnippetKeys`), `mdl/executor/cmd_jsonstructures.go` (`collectCustomItemNames`, DESCRIBE), `mdl/executor/validate_json_structure_names.go` (`MDL-JSON01`/`MDL-JSON02`) | **Do NOT infer Studio Pro's generation rule from stored documents — they are hand-edited.** Measured across 621 array elements in nine apps: 61% are the generator's `JsonObject`/`Wrapper`[+counter], 35% are a word someone chose, 4% are `<Name>Item`. The fingerprint that settles it is `JSON_AutoConfigResponse`, whose eight arrays read *in document order* `Scope, Wrapper_2..Wrapper_6, Claim, CodeChallengeMethods` — a counter with **gaps where a human renamed**; and `JSON_SensorData`'s `Array → SensorData`, a name with no relation to the array's. A version story fitted to a 9-structure sample (\"10.24 singularises, 11.4 does not\") evaporated at corpus scale. So the fix is **expressiveness, not default-matching**: no default can match a corpus that is a third hand-written, and changing the default would rewrite every stored structure's item names plus every mapping bound to one (ExposedName is a resolution key, #882). Design notes: `item of 'key' as 'Name'` rather than folding it into the existing entry, so naming an item does not require restating the array's name and adding one is a one-line diff; the same clause names a primitive array's **Wrapper**, because that wrapper IS the item; `item of 'Root'` for a root array, which has no key. DESCRIBE needs its own collector — an item's path segment is the marker `(Object)`/`(Wrapper)`, so the existing one skips it, and without it a named item was written on CREATE and silently renamed back by describe → exec. ako/mxcli#272 |", "refs": ["#882", "ako/mxcli#272"]} |
53 | 53 | {"area": "mdl/grammar", "date": "2026-08-31", "symptom": "`DESCRIBE MICROFLOW` emits `reduce($list, expr)` (or `all(...)` / `any(...)`) and mxcli's own checker then rejects its own output: \"set 'X' calls 'reduce()', which is not a Mendix expression function [MDL044]\". Note the word **set** — the parser did not reject the call, it read the line as a Change Variable whose value happened to be a function call, and MDL044 was right about the rest", "cause": "DESCRIBE rendered an aggregate as `strings.ToLower(storedEnumValue)`, assuming every value of Mendix's `AggregateFunction` was also an MDL keyword. Mendix has eight, the grammar had five. Underneath sat a quieter defect: Mendix stores a Reduce's seed and result type in `ReduceInitialValueExpression` / `ReduceReturnDataType` and the semantic model had no field for either, so a grammar-only fix would have round-tripped the syntax while deleting the fold", "file": "`mdl/grammar/MDLLexer.g4` (REDUCE/ANY/INITIAL + the `keyword` rule so they stay usable as identifiers), `mdl/grammar/domains/MDLMicroflow.g4` (`listAggregateOperation` + `reduceFoldOptions`), `mdl/ast/ast_microflow.go`, `mdl/visitor/visitor_microflow_actions.go`, `mdl/executor/cmd_microflows_builder_actions.go`, `mdl/executor/cmd_microflows_format_action.go` (`mdlAggregateKeyword`), plus all four read/write paths: `sdk/mpr/parser_microflow.go`, `sdk/mpr/writer_microflow_actions.go`, `mdl/backend/modelsdk/microflow_read_actions.go`, `mdl/backend/modelsdk/microflow_write.go`", "insight": "**A renderer that stringifies an enum outgrows its grammar silently** — the sibling `formatListOperation` switches on concrete types and cannot, which is the shape to prefer. The guard is a describe→parse loop over `microflows.AllAggregateFunctions` (`TestDescribedAggregateParsesBack`), so a ninth Mendix function fails a test rather than a user's script. **Get a reference document before believing the vendor docs**: Mendix's reference guide says a return type is \"not applicable\" to All/Any, but Studio Pro writes `ReduceReturnDataType` as Boolean on both, and `Attribute` as `\"\"` when unused — all three activities now re-serialize byte-identically to Studio Pro's. `mx check` is no help here (0 errors before and after); the controls are the origin/main parse (`reduce`/`all`/`any` → Change Variable, with `sum` → aggregate as the positive control) and reverting the write path (`TestReduceFoldReachesStorage` then reports the two keys missing). #1004", "refs": ["#1004"], "rules": ["MDL044"]} |
| 54 | +{"area": "mdl/grammar", "date": "2026-09-04", "symptom": "`container c ()` / `dynamictext t ()` / `pluggablewidget 'id' pw ()` are parse errors, reported at the `)` as though the widget were wrong, while bare `container c` and `container c (x: 'y')` both parse.", "cause": "widgetPropertiesV3 was `LPAREN widgetPropertyV3 (COMMA widgetPropertyV3)* RPAREN` — at least one property required.", "file": "mdl/grammar/domains/MDLPage.g4", "insight": "An empty property list is what an LLM writes for a widget that needs no properties, and the error points at the paren rather than the cause. One-character fix (wrap the list in `( … )?`). Found while measuring something else — the first run of a keyword-parse survey used `()` throughout and mis-scored every keyword as rejected, including ones that worked. If a whole measurement comes back uniformly negative, suspect the harness before the subject.", "refs": ["mendixlabs/mxcli#1036"]} |
| 55 | +{"area": "mdl/grammar", "date": "2026-09-05", "symptom": "After adding a generic (IDENTIFIER | keyword) alternative to widgetTypeV3, `slot body` parsed as a widget of type `slot` and `placeholder Main { ... }` as a widget named Main. Both still parsed, `mxcli check` still exited 0, and a diff of check output across all 515 mdl-examples scripts showed ZERO difference.", "cause": "pageBodyV3 listed widgetV3 FIRST, before useFragmentRef / placeholderBlockV3 / slotMarkerV3. SLOT, PLACEHOLDER and USE are all inside the `keyword` rule (655 tokens), so the generic widget alternative matched them before the specific alternative could.", "file": "mdl/grammar/domains/MDLPage.g4", "insight": "Put the specific alternatives BEFORE widgetV3 in pageBodyV3, the same ordering fix widgetV3 already applies internally for `template for`. The transferable lesson is about the MEASUREMENT, not the grammar: a corpus diff of `mxcli check` output compares DIAGNOSTICS, so it is blind to a construct that parses into the wrong AST shape. 515 scripts said nothing; two visitor unit tests caught it immediately. When a grammar change could reinterpret existing syntax rather than reject it, assert on the AST, not on the diagnostics. CONTROL: reorder pageBodyV3 back and TestSpecificPageBodyFormsWinOverTheGenericWidget / TestSlotMarkerWinsOverTheGenericWidget fail.", "issue": "mendixlabs/mxcli#1036"} |
0 commit comments