Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
4a31fc2
fix: describe and exec keep a flow argument that is a widget's selection
claude Oct 23, 2026
2f60987
fix: check judges a list widget's own row click in its row
claude Oct 23, 2026
2879e66
fix: refuse a pluggable replace that would carry hidden content onto …
claude Oct 23, 2026
2ff03b1
fix: describe names a combo box's custom content
claude Oct 23, 2026
06ccd13
Merge remote-tracking branch 'origin/main' into claude/describe-round…
claude Oct 23, 2026
e7797c5
fix: alter entity add event handler adds a second handler for the sam…
claude Oct 23, 2026
339e6a8
style: gofmt mdl/backend/mfmutator/splice_handler_test.go
claude Oct 23, 2026
982387d
fix: write a pluggable text-template parameter's association steps
claude Oct 23, 2026
c4e0d77
fix: describe a pluggable text-template parameter across an association
claude Oct 23, 2026
31b049c
test: pin an expression in a pluggable text-template parameter
claude Oct 23, 2026
dd7d14f
test(bug-tests): pluggable text-template parameters across an associa…
claude Oct 23, 2026
7e04f07
fix: show page describes and writes "Number of pages to close" (mendi…
claude Oct 23, 2026
40a65b0
fix: type a view CASE column from its first branch, and widen numeric…
claude Oct 23, 2026
7e5793e
fix: a selection written by its widget key is stored as the selection…
claude Oct 23, 2026
db2c9b9
fix: refuse a routine header without parentheses with one error, at t…
claude Oct 23, 2026
20cdeea
docs(wiki): silent-property-drop — two names for one property, and a …
claude Oct 23, 2026
92c8438
fix(editorconfig): lift the else-if branches of a chained ternary
claude Oct 23, 2026
3468f21
fix(widgets): reset a hidden property that only another mode maps
claude Oct 23, 2026
b5400c8
fix(widgets): write, check and describe a combo box in database mode …
claude Oct 23, 2026
615e999
fix(pages): an ALTER-built data grid column keeps its filter's proper…
claude Oct 23, 2026
507e6c2
docs: a Data grid 2 column's Size is a relative weight, not pixels (m…
claude Oct 23, 2026
6cb9f03
test: regression case for an empty-caption custom-content column (men…
claude Oct 23, 2026
c31cbce
fix: log ... with stacktrace sets 'Include latest stack trace' (mendi…
claude Oct 23, 2026
0ffd3db
fix: warn when @excluded lands on a decision, loop or event (mendixla…
claude Oct 23, 2026
59162ba
docs(changelog): pluggable text-template parameters across an associa…
claude Oct 23, 2026
f8bc62c
Merge pull request #1656 from ako/claude/keen-heisenberg-q092ut
ako Oct 23, 2026
a741953
Revert "style: gofmt mdl/backend/mfmutator/splice_handler_test.go"
claude Oct 23, 2026
9284498
Merge remote-tracking branch 'origin/main' into claude/wizardly-ptole…
claude Oct 23, 2026
542081b
Merge branch 'mendixlabs:main' into main
ako Oct 23, 2026
cfcbf04
Merge remote-tracking branch 'origin/main' into claude/lucid-mendel-g…
claude Oct 23, 2026
c9890c7
Merge pull request #1658 from ako/claude/microflow-activity-flags-iss…
ako Oct 23, 2026
a4d16c3
fix: write and describe a combo box's database mode
claude Oct 23, 2026
1db98ff
fix: refuse a rewrite that would delete a changed combo box's custom …
claude Oct 23, 2026
0d5f162
Merge origin/main into claude/inspiring-feynman-hrnypb
claude Oct 23, 2026
48f3b8d
Merge origin/main into claude/determined-bohr-mh3q3t
claude Oct 23, 2026
f20ca93
Merge pull request #1661 from ako/claude/wizardly-ptolemy-9l7uoj
ako Oct 23, 2026
47d286a
Merge remote-tracking branch 'origin/main' into claude/lucid-mendel-g…
claude Oct 23, 2026
4ab5c9a
Merge pull request #1659 from ako/claude/inspiring-feynman-hrnypb
ako Oct 23, 2026
71ad1c3
Merge remote-tracking branch 'origin/main' into claude/describe-round…
claude Oct 23, 2026
a7e199e
Merge origin/main into claude/determined-bohr-mh3q3t
claude Oct 23, 2026
0878d61
Merge pull request #1660 from ako/claude/determined-bohr-mh3q3t
ako Oct 23, 2026
490726a
Merge pull request #1657 from ako/claude/lucid-mendel-g2nnrm
ako Oct 23, 2026
50323d6
Merge pull request #1655 from ako/claude/describe-round-trip-gaps-ibgvit
ako Oct 24, 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": "mdl/backend", "date": "2026-10-23", "symptom": "A pluggable widget's text-template parameter bound across an association — `fieldset fs (legend: '{1}', legendParams: ({1} = Repro.Parent_Child/Label))` — passed check and exec and failed the build: [CE1365] \"Attribute 'Repro.Child.Label' is not an attribute of entity 'Repro.Parent'.\" The stored AttributeRef had the right Attribute and EntityRef null. describe then printed the parameter as the bare `{1} = Label`, which re-executes into CE1613 \"The selected attribute 'Repro.Parent.Label' no longer exists.\" (#1494). The companion report #1495 (an expression parameter stored in AttributeRef.Attribute, spaces stripped) was already fixed in v0.25.0 by #823 and only needed a pin.", "cause": "The executor resolved the hops all along (buildClientTemplateParams -> resolveTemplateAssociationPath fills ClientTemplateParameter.AttributeRefSteps); widgetobj.SerializeColumnClientTemplateParameter hard-coded `EntityRef: nil` and never read the field, although attributeEntityRefBSON, which builds exactly that IndirectEntityRef, sat in the same file for column attributes. On the read side the pluggable describer's extractTextTemplateParameters was a copy of the core extractClientTemplateParameters loop that never learned associationTemplateParamPath.", "fix": "SerializeColumnClientTemplateParameter writes attributeEntityRefBSON(param.AttributeRefSteps); extractClientTemplateParameters now delegates to extractTextTemplateParameters, which gained the association path and the trimmed expression — one reader instead of two.", "file": "mdl/backend/widgetobj/builder.go (SerializeColumnClientTemplateParameter), mdl/executor/cmd_pages_describe_pluggable.go (extractTextTemplateParameters), mdl/executor/cmd_pages_describe_output.go (extractClientTemplateParameters)", "insight": "The reported statement was one of three victims: the same serializer writes widget-level templates, object-list item templates (Accordion group headerText) and Data grid 2 column templates, and the pre-fix binary on a blank 11.12.4 app gives CE1365 on all three — so enumerate the serializer's callers (grep BuildClientTemplateWithTextAndParams) before writing the repro, not after. Dump the stored ClientTemplateParameter before theorising: Attribute correct + EntityRef null says the resolver is fine and the encoder dropped a field it was handed, which rules out the whole entity-context investigation binding-context.md would otherwise send you on. For the expression half, do not trust the report's version: it was filed against v0.24.0 and CHANGELOG 0.25.0 already describes the fix; reproduce on main first, then pin it by stubbing each guard separately — the visitor's expressionSourceText (stub: `if1=1then'A'else'B'`) and isTemplateExpression (stub: `M.Job.if 1 = 1 …`) each reproduce one half of the reported message. The describe twin is the #977 drift a second time: #977 shared the source-variable sub-resolver and left the loop duplicated, so the next feature (association paths) landed in one copy only — share the loop, not a helper.", "refs": ["mendixlabs/mxcli#1494", "mendixlabs/mxcli#1495", "ako/mxcli#1348", "ako/mxcli#1349", "ako/mxcli#823"], "ce": ["CE1365", "CE1613"], "test": "mdl/backend/widgetobj/template_param_association_test.go (fails with EntityRef <nil> when builder.go is reverted); mdl/executor/cmd_pages_describe_sourcevariable_test.go TestBothDescribers_RenderAnAssociationPath (pluggable renders [Label]); mdl/executor/cmd_pages_template_expression_1495_test.go"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"date": "2026-10-23", "area": "mdl/backend", "symptom": "ako/mxcli#1563 (mendixlabs/mxcli#1631): `alter page … replace cbBooking with { combobox cbSale (… DataSource: database from M.Sale …) }` kept cbBooking's custom content (txtOptionName, bound to Booking.Name) inside cbSale. check -p and exec passed; with the content type 'yes', mx check: CE1365 \"Attribute 'M.Booking.Name' is not an attribute of entity 'M.Sale'\" at a widget the author never wrote and describe never printed. On current main describe prints the type, so the replace turns it 'no' and mx check passes on 11.13.0 — with txtOptionName still stored in cbSale, hidden and bound to Booking", "cause": "The #1247 same-kind REPLACE merge keeps every stored property on which the replacement and a baseline built from describe agree. describe never prints a combo box's custom content, so baseline and replacement are both empty there and the stored widgets are always kept — right while the content's data source keeps its entity, wrong once the statement moves it. The stored Type says which data source the content is built for (ValueType.DataSourceProperty: optionsSourceAssociationCustomContent → optionsSourceAssociationDataSource); the merge never read it", "file": "mdl/backend/pagemutator/pluggable_replace.go (staleLinkedContent, dataSourceEntity, mergePluggableReplace, CheckPluggableReplace), mdl/backend/stale_widget_content.go (StaleWidgetContentError), mdl/executor/cmd_alter_page.go (pluggableReplaceBaseline, refuseStaleContentReplace), mdl/executor/validate_alter_page_refs.go (check-time call, droppedFirst)", "fix": "A merge that would keep a Widgets property's stored widgets while the data source it is linked to now names another entity is refused (ADR-0012: carry or refuse, never drop), by exec and by check -p, naming the widgets and the remedy — `drop <names>;` first in the same statement, or drop + insert. check counts drops earlier in the script, since it reads the stored document where exec has already applied them. Same entity (a label, a sort, an XPath) keeps the content as before", "test": "TestStaleLinkedContent (2 shapes + 4 controls), TestReplacePluggableRefusesStaleContent (refused, nothing written; the check-time question; control after the content is gone), TestDroppedFirstDiscountsTheRecommendedDrop; mdl-examples/bug-tests/1563-replace-combobox-keeps-hidden-custom-content.mdl", "insight": "**Re-run the repro on main before fixing the reported symptom**: the CE1365 no longer reproduced (describe had since learned to print the content TYPE, so the merge now flipped it to 'no'), but the stored page still held the stale widget — the defect had moved from a build error to an invisible one, which no mx check catches. Dump the stored widget names, not just the error count. **The schema already said which content belongs to which data source** (ValueType.DataSourceProperty in the stored Type); entity comparison, not 'did the data source change', is what separates the refusal from #1247's own case (adding a sort to the same source). **A check-time twin of a refusal must model what exec applies first**: the recommended `drop X; replace …` was refused by check until it counted earlier drops — and a stub of that discount reproduced the false refusal, which is the control that shows it is load-bearing. Found on the way, not fixed here: `create or modify` of a page whose combo box the statement CHANGES silently drops the same custom content (Replaced page, then CE0642 'Custom content is required'); an unchanged combo box survives through the pluggable passthrough", "ce": ["CE1365", "CE0642"], "rules": [], "refs": ["ako/mxcli#1563", "mendixlabs/mxcli#1631", "mendixlabs/mxcli#1247", "mendixlabs/mxcli#1622"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-23", "symptom": "`alter page … { insert after dg column(Name) { column (Attribute: Kind, Caption: 'Kind') { dropdownfilter ddf (attributes: [Status]) } } }` stored attrChoice \"auto\" with an empty `attr`; check passed and describe printed a bare `dropdownfilter ddf` — #1519 item 2's symptom on the ALTER path, which #1422 named as not done (mendixlabs/mxcli#1519)", "cause": "buildColumnSpecFromAST (the INSERT/REPLACE column path) built a column's filter with backend.BuildFilterWidget from the widget id and name alone, so no filter property was ever read; CREATE routes the same child through buildWidgetV3 and the filter's .def.json. Routing it through buildWidgetV3 then exposed a second gap: a column REPLACE excluded only the target from the name scope, and ContainedWidgetNames read a column reference only as a data view footer, so a replacement reusing its filter's name was refused as a duplicate", "file": "`mdl/executor/cmd_pages_builder_v3_widgets.go` (buildColumnSpecFromAST builds filters via buildWidgetV3), `mdl/executor/cmd_alter_page.go` (column REPLACE excludes what the column contains), `mdl/backend/pagemutator/footerregion.go` (ContainedWidgetNames falls back to findBsonColumn)", "insight": "When a fix lands in one builder, grep for the OTHER builders of the same node: CREATE and ALTER build Data grid 2 columns through different functions, and the #1422 fix covered one. A path that never registered names cannot collide, so switching it onto the shared builder surfaces the name-scope gap the old path hid — run a REPLACE that reuses the inner widget's name as the control, not just an INSERT.", "refs": ["mendixlabs/mxcli#1519", "ako/mxcli#1401", "ako/mxcli#1422"], "test": "mdl/executor/widget_dropdownfilter_attr_test.go TestAlterColumn1519_FilterKeepsItsProperties; mdl/backend/pagemutator/mutator_column_addressing_test.go TestContainedWidgetNames_GridColumnReportsItsWidgets; mdl-examples/bug-tests/1519-alter-column-filter-attribute.mdl"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-23", "symptom": "`alter entity M.E add event handler on before commit call M.Second($currentObject)` failed with \"event handler already exists for Before Commit\" when the entity already had a Before Commit handler, while `create or modify entity` with two `on before commit` clauses stored both. The same key hid two quieter defects: `add event handler if not exists … call M.New` printed \"already exists, skipping\" for a microflow never wired, and `drop event handler on before commit` removed whichever handler was stored first", "cause": "ALTER ENTITY keyed a handler on (Moment, Event) alone, in both arms. A handler's identity is (Moment, Event, Microflow): Mendix allows several per event, and the DROP grammar had no way to name the microflow at all", "file": "`mdl/executor/cmd_entities.go` (`matchEventHandlers`, `storedHandlerMicroflow`, both event-handler arms of execAlterEntity), `mdl/grammar/domains/MDLDomainModel.g4` (`(CALL qualifiedName)?` on DROP EVENT HANDLER), `mdl/visitor/visitor_entity.go`; tests `mdl/executor/alter_entity_event_handlers_test.go`, `mdl/visitor/drop_event_handler_call_test.go`; repro `mdl-examples/bug-tests/alter-entity-1540-second-event-handler.mdl`", "insight": "When ADD's duplicate key is too coarse, look at DROP and the IF [NOT] EXISTS guards on the same key: all three were wrong, and two of them silently (a skip notice for a handler never added; the first-stored handler dropped). Once ADD can create two, a bare DROP is ambiguous, so it is refused and names the candidates rather than taking the first (the mutator-addressing rule). The validity claim was measured, not assumed, on 11.12.4 with three projects: two Before Commit handlers via ALTER = 0 errors; the same via the OLD binary's create or modify = 0 errors; a void-returning Before Commit handler = CE7247 (the control that shows mx check looks at handlers at all). The same microflow twice on one event is ALSO 0 errors, so ADD's remaining refusal of an exact duplicate is mxcli's re-run guard (it would run twice per commit), not a Mendix rule; say that in the comment rather than letting it read as one. Wrong turn to skip: renaming a copied project's .mpr breaks mx with StorageMprNameDiscrepancyException, which looks like a model failure", "refs": ["mendixlabs/mxcli#1540", "ako/mxcli#1438", "#18"], "ce": ["CE7247"], "rules": []}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-23", "symptom": "`combobox cbCode (source: 'database', optionsSourceDatabaseDataSource: microflow Mod.GET_Parents, optionsSourceDatabaseItemSelection: 'Single', optionsSourceDatabaseCaptionAttribute: Name, optionsSourceDatabaseValueAttribute: Name, databaseAttributeString: Code)` — check \"3 issues: 0 errors, 3 warnings\" (MDL-WIDGET06 'recognized but not yet persisted' for the datasource and the item selection), exec \"Created page\", mx check \"[CE0463] The definition of this widget has changed\" at Combo box 'cbCode' (CE1613 on Mod.Child.Name when the data view's entity has no Name) (mendixlabs/mxcli#1583)", "cause": "Two layers. (1) combobox.def.json had no database mode: the datasource had no write path, the explicit-key pass wrote the Selection-typed item selection as a PrimitiveValue, and the caption/value attributes, linked to the unwritten datasource, bound to the data view's entity. (2) Once those were written CE0463 stayed: the editorConfig lifter skipped every hide after `\"context\"===t.source ? (…) :` — the database and static branches of an else-if chain, whose guard's boundary is the outer `:` — and unmappedHiddenResets counted a property mapped in ANY mode as written, while the mapping loop only visits the selected mode; so the hidden `optionsSourceType` kept the template's 'enumeration' and `selectAllButtonCaption` its populated template", "file": "`sdk/widgets/definitions/combobox.def.json` (database mode on `hasDataSource:optionsSourceDatabaseDataSource`), `mdl/executor/widget_engine.go` (explicit pass routes Selection via SetSelection; Selection mapping reads its key; unmappedHiddenResets takes the selected mappings), `mdl/executor/editorconfig_extract.go` (elseChainTerms, groupElseChain, parseGuard `:` boundary, else-branch hides inherit enclosing group terms), `cmd_pages_describe_bykey.go` + `cmd_pages_describe_parse.go` (describeComboBoxDatabaseMode), `validate_widgets.go` (comboBoxMode via the engine's selectMode; validateComboBoxDatabase = MDL-WIDGET16), `validate_widget_attribute_type.go` (comboBoxDatabaseRule = MDL-WIDGET39), `widget_describe.go` (definitionDefaults reads the unconditioned mode)", "insight": "**Diff against `mx update-widgets` on a copy, not against a hypothesis.** After the first fix the widget still failed; flattening mxcli's widget and the update-widgets output (keyed by PropertyKey, $ID dropped) gave exactly two differences, both properties the editorConfig hides in database mode — which pointed straight at the lifter rather than the writer. The lifter's gap was invisible to every test because no widget before the combo box hid anything in an else-if branch; dump the lifted rules for every installed .mpk before and after (only Combo box and TreeNode changed) to bound the blast radius. Mode-scoped reads keep biting: widgetValueMap (#1519), unmappedHiddenResets and the example generator's definitionDefaults each read every mode's mappings and each was wrong once a second conditioned mode existed — grep `def.Modes` when adding a mode. A new mode needs its check rules measured too: database mode makes `Attribute:` a String/Integer/Long/Enum target (MDL-WIDGET39 had assumed enumeration) and makes the value attribute required when a target is set (CE0642 'Value') — one throwaway page per row on mxbuild settled both. Describe must spell the mode by the datasource's KEY: the generic `DataSource:` selects the association mode. Measured on 11.12.5 and 11.15.0, Combo box 2.5.0 (the reporter's 2.6.2 was not available here).", "refs": ["mendixlabs/mxcli#1583", "ako/mxcli#1488"], "ce": ["CE0463", "CE0642", "CE7247", "CE1613"], "rules": ["MDL-WIDGET06", "MDL-WIDGET16", "MDL-WIDGET39", "MDL-WIDGET10"], "test": "mdl/executor/widget_combobox_database_test.go; editorconfig_else_if_test.go; widget_hidden_reset_unmapped_test.go TestHiddenResets_AMappingOfAnotherModeIsReset; validate_combobox_caption_test.go TestMDLWIDGET16_ComboBoxDatabaseModeRequired; validate_widget_attribute_type_test.go TestCheck_ComboBoxDatabaseModeAttributeTypes; mdl-examples/bug-tests/1583-combobox-database-mode.mdl"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"date": "2026-10-23", "area": "mdl/executor", "symptom": "ako/mxcli#1647: describe → exec of TestApp's WorkflowCommons.User_WorkflowGroup_Select and WorkflowGroup_User_Select (Studio Pro-authored, 11.14.0) rebuilt each database-source, multi-selection comboBox1 as source 'context', selection Single — mx check CE0642 'Property Caption/Entity is required' ×4 and CE0115 on the button passing $comboBox1 to a list parameter ×2; describe had printed the database source as the association mode's `DataSource:` with a NOT re-executable note for the caption", "cause": "The same gap as ako/mxcli#1488 seen from the read side: combobox.def.json had no database mode, so describe could not spell one and exec could not build one", "file": "none of its own — fixed by mendixlabs/mxcli#1583 (database mode on hasDataSource:optionsSourceDatabaseDataSource, describeComboBoxDatabaseMode), see 2026-10-23-combobox-database-mode-not-written.json", "fix": "Verified on the merged branch: the same drop + create rebuild of the two TestApp pages stores both combo boxes exactly as Studio Pro does (optionsSourceType 'association' leftover included) and mx check 11.14.0 is 0 errors; describe → check over all 68 TestApp pages loses its two MDL-WIDGET16 false errors", "test": "covered by widget_combobox_database_test.go (from #1583); mdl-examples/bug-tests/1647-combobox-database-mode.mdl reproduces the TestApp shape (multi-selection passed to a list parameter) on a fresh project", "insight": "**Two sessions fixed the same gap from opposite ends the same day** — this one from describe → exec of a Studio Pro project, #1583 from a hand-written script — and converged on the same mode switch (hasDataSource:<key>, which the engine had documented for exactly this and no definition used). Merging main surfaced it as conflicts in five files and a definition that auto-merged into TWO database modes with no conflict marker: re-read every file both sides touched, not only the conflicted ones. The better half won: #1583 also fixed the editorConfig else-chain lift and the hidden-property reset that kept CE0463 after the write was right, which this session's version never reached because its repro (TestApp) does not set the properties those hide. **The measurement that tells a describe gap from a write gap is the rebuild, not the in-place round trip**: in place the pluggable passthrough kept the stored combo box and the run was 'Unchanged'", "ce": ["CE0642", "CE0115"], "rules": ["MDL-WIDGET16"], "refs": ["ako/mxcli#1647", "ako/mxcli#1488", "mendixlabs/mxcli#1583"]}
Loading
Loading