Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
fe7bfea
docs(proposal): def-driven pluggable widget bodies (mendixlabs/mxcli#…
claude Sep 4, 2026
e95475e
docs(proposal): widgets as first-class MDL, not a second dialect
claude Sep 4, 2026
703a068
fix(widgets): name a remedy that can work, accept (), and emit slot n…
claude Sep 4, 2026
3411797
fix(widgets): drop the premise that mxcli should ship the four missin…
claude Sep 4, 2026
2289847
fix(message definitions): a ReferenceSet is a list in both directions
claude Sep 4, 2026
cf11e63
feat(widgets): DESCRIBE WIDGET, so a widget describes in-language too
claude Sep 4, 2026
2373f53
feat(widgets): DESCRIBE WIDGET reports body containers and what is au…
claude Sep 4, 2026
5faadc0
fix(domain model): refuse dropping an association a message definitio…
claude Sep 4, 2026
13614f5
fix(check): resolve an ALTER's target document, not just its module
claude Sep 4, 2026
45865d6
feat(widgets): DESCRIBE WIDGET emits an MDL example that parses as wr…
claude Sep 4, 2026
1848dd4
feat(mdl): ADD VALUE IF NOT EXISTS / DROP VALUE IF EXISTS on an enume…
claude Sep 4, 2026
2b5aa2f
feat(widgets): narrow the example's bindings by the widget's own rules
claude Sep 4, 2026
ba342de
docs(proposal): settle open question 1 — the validator needs a slice …
claude Sep 4, 2026
15c7149
feat(check): the validator knows what a widget is (slice 0)
claude Sep 4, 2026
83427b4
fix(check): MDL-WIDGET25 needs a project, and its repro is not a .fai…
claude Sep 5, 2026
cff5f01
feat(catalog): a widget is a reference target (slice 5)
claude Sep 5, 2026
18e0ee9
fix(search): match a reference target whose stored spelling differs i…
claude Sep 5, 2026
476cebc
docs(proposal): record what slice 5 actually did, and where it differs
claude Sep 5, 2026
b2f1160
chore(testdata): ignore the widget docs the fixture regenerates
claude Sep 5, 2026
4a95d3c
docs(proposal): close open questions 5 and 6
claude Sep 5, 2026
997e1d9
fix(check): widget property warnings must not depend on map iteration…
claude Sep 5, 2026
bca5466
feat(page): a widget and its body are named by the definition (slices…
claude Sep 5, 2026
bde10f8
fix(describe): emit the widget's own name, and stop losing its body s…
claude Sep 5, 2026
0e92325
fix(describe): reconstruct a pluggable widget's containers instead of…
claude Sep 5, 2026
a2463b8
fix(describe): emit a widget's property keys verbatim, not PascalCased
claude Sep 5, 2026
76776d0
fix(examples): use a valid interpolation value in the chart examples
claude Sep 5, 2026
0bf2642
fix(check): accept a widget property's documented alias, not only its…
claude Sep 5, 2026
8293b18
fix(check): route a chart series' friendly DataSource by its dataSet …
claude Sep 5, 2026
ae2b2b8
fix(check): stop guessing Decimal for sum() over an unresolvable argu…
claude Sep 5, 2026
5b2f808
fix(check): an object-list item is not a widget, so it cannot be a CE…
claude Sep 5, 2026
64055ca
docs(findings): record the four check false positives found under a p…
claude Sep 5, 2026
668ad9a
fix(check): read a widget's properties from its .mpk, not a hand-writ…
claude Sep 5, 2026
a3e561e
fix(describe): stop emitting properties the example's own configurati…
claude Sep 5, 2026
63d1614
fix(describe): give an object-list item a value the checker accepts
claude Sep 5, 2026
d8294e7
fix(catalog): index the widgets inside an object-list item
claude Sep 5, 2026
a3c3a50
docs(findings): record the four defects the external test projects found
claude Sep 5, 2026
81918e7
fix(test): make the item-literal guard hermetic instead of environmen…
claude Sep 5, 2026
d9c11cd
docs(findings): record the gitignored-fixture-cache test trap
claude Sep 5, 2026
c31e210
docs(site): a reference page for DESCRIBE WIDGET
claude Sep 5, 2026
8eb0553
docs(site): the widget list is not the boundary any more
claude Sep 5, 2026
5952e48
docs(skill): teach the short widget form, not only the id form
claude Sep 5, 2026
d371fab
docs: correct the widget describe command form, and say what it now p…
claude Sep 5, 2026
68546f3
Merge pull request #396 from ako/claude/banking-app-feedback-do04dy
ako Sep 5, 2026
ea1cbdd
Merge branch 'main' into claude/mxcli-unit-test-perf-n7ggx8
ako Sep 5, 2026
a69c87a
Merge pull request #397 from ako/claude/mxcli-unit-test-perf-n7ggx8
ako Sep 5, 2026
1ebebc3
feat(check): resolve member names, not just the entity they belong to
claude Sep 5, 2026
3aa2ee0
feat(check): resolve member names inside widgets — XPath steps and te…
claude Sep 5, 2026
7c6b906
fix(security): make UPDATE SECURITY run at all, and honour its scope
claude Sep 5, 2026
42fb308
feat(check): enforce expression kinds — bare words and log template p…
claude Sep 5, 2026
f34987e
fix(pages): resolve a page-level association datasource from its cont…
claude Sep 6, 2026
cbe698a
feat(check): refuse unqualified CREATEs and void-with-alias; give the…
claude Sep 6, 2026
3d5f152
docs(bug-test): drop an explanation the file itself disproves
claude Sep 6, 2026
b0bf951
Merge pull request #398 from ako/claude/mxcli-unit-test-perf-n7ggx8
ako Sep 6, 2026
b036efd
fix(widgets): evaluate a visibility rule against what will be written
claude Sep 6, 2026
f53dfc6
fix(lint): name the document type a finding is actually about
claude Sep 1, 2026
2cbb500
feat(demo): ship the capture-integrity machinery as code
claude Sep 6, 2026
a74938c
docs(demo): the capture lessons the intro-video films paid for
claude Sep 6, 2026
dff7143
Merge pull request #399 from ako/claude/mxcli-unit-test-perf-n7ggx8
ako Sep 6, 2026
ed3a9e5
feat(check): warn when a navigation menu item specifies no icon (MDL074)
claude Sep 6, 2026
bf31150
feat(navigation): author and round-trip all three menu icon kinds
claude Sep 6, 2026
28239e3
Merge pull request #400 from ako/claude/sudoku-test-issue-46-iyxn30
ako Sep 6, 2026
b202246
Merge pull request #401 from ako/claude/banking-app-feedback-do04dy
ako Sep 6, 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
32 changes: 32 additions & 0 deletions .claude/skills/fix-issue/findings/mdl-executor.jsonl

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions .claude/skills/fix-issue/findings/mdl-grammar.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,5 @@
{"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"]}
{"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"]}
{"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"]}
{"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"]}
{"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"}
Loading
Loading