Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
21011a0
fix: mxcli test finds test files in subfolders (closes #1363)
stagknee Oct 9, 2026
6383ce3
fix: mxcli test skips folders starting with _ and says why --list fou…
stagknee Oct 15, 2026
0d7e44a
fix: mxcli test keeps going past a subfolder it cannot read (#1363)
stagknee Oct 15, 2026
605d4fb
fix(javaactions): write a JavaScript action's parameters the way mxbu…
stagknee Oct 17, 2026
8a70726
fix: accept a bare enum name as a return type in exec, as check does
stagknee Oct 17, 2026
514a4be
fix(run): --detach on Windows no longer opens a console window per child
stagknee Oct 17, 2026
2bfb697
fix(executor): store a quoted Editable expression as a conditional ed…
stagknee Oct 17, 2026
f23390f
fix(executor): treat `editable: false` as Never in MDL-WIDGET31, cove…
stagknee Oct 17, 2026
f8513dc
fix(check): resolve the pages and flows a navigation or menu document…
stagknee Oct 17, 2026
640e914
fix(describe): name the entity an association data source reaches as …
stagknee Oct 17, 2026
fea2f53
fix(check): accept a Data grid 2's own settings without a project (me…
stagknee Oct 17, 2026
41db3b6
fix(describe): print a Data grid 2's and a Gallery's settings by thei…
stagknee Oct 17, 2026
d00edcd
Merge mendixlabs/mxcli#1574: fix(check): accept a Data grid 2's own s…
claude Oct 19, 2026
eff0919
Merge mendixlabs/mxcli#1575: fix(describe): print a Data grid 2's and…
claude Oct 19, 2026
470201d
Merge mendixlabs/mxcli#1572: fix(describe): name the entity an associ…
claude Oct 19, 2026
6a969e3
Merge mendixlabs/mxcli#1570: fix(check): resolve the pages and flows …
claude Oct 19, 2026
410258c
Merge mendixlabs/mxcli#1563: fix: accept a bare enum name as a return…
claude Oct 19, 2026
ddb417b
Merge mendixlabs/mxcli#1561: fix(javaactions): write a JavaScript act…
claude Oct 19, 2026
9cc0fcb
Merge mendixlabs/mxcli#1568: fix(executor): treat `editable: false` a…
claude Oct 19, 2026
13bd339
Merge mendixlabs/mxcli#1566: fix(run): --detach on Windows no longer …
claude Oct 19, 2026
e211549
Merge mendixlabs/mxcli#1368: fix: mxcli test keeps going past a subfo…
claude Oct 19, 2026
4a3b6ce
fix(check): read Data grid 2's embedded schema from modelsdk/widgets
claude Oct 19, 2026
bde20b2
docs(run): say why a detached Windows run still cannot be stopped gra…
claude Oct 19, 2026
be2c23a
docs(check): say why an empty stored set skips the navigation-target …
claude Oct 19, 2026
0b8242f
test(describe): build the by-key test grid from sdk/widgets again
claude Oct 19, 2026
b43f1d7
fix(examples): name the login page Administration.Login
claude Oct 19, 2026
2f9876b
fix(examples): give the navigation example a login page that exists
claude Oct 19, 2026
a1fb0d8
fix(check): do not resolve a navigation profile's login page
claude Oct 19, 2026
b44a473
Merge pull request #1490 from ako/integrate/wave1-upstream-prs
ako Oct 19, 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-10-09", "symptom": "`mxcli test tests --list` prints `Found 0 test(s)` when the suites live in `tests/<Module>/*.test.mdl`, while `mxcli test tests/Sales --list` finds them", "cause": "`testrunner.ParseTestDir` listed the directory with `os.ReadDir` and `continue`d on every sub-directory, so only test files directly inside the named folder were ever read", "file": "`cmd/mxcli/testrunner/parser.go` (`ParseTestDir`, `walkTestTree`), `cmd/mxcli/testrunner/runner.go` (`emptySuiteError`)", "insight": "**Discovery is a recursive walk now, and hidden folders below the root are skipped** (`.git`, `.mxcli`; the root itself is always read, so `mxcli test .` works). `emptySuiteError` must use the same walk or its `were not read` hint goes blind to exactly the nested layout the fix enables. `filepath.WalkDir` does not follow a root that is a symlink, so `walkTestTree` resolves it first (`os.ReadDir` used to follow it). Layout test: `parser_dir_test.go`; the `FilesRead` counter and the per-file `FileErrors` isolation are unchanged and the walk keeps going past a bad file. No other discovery rule (node_modules etc.) exists in the test runner, so none was added.", "refs": ["mendixlabs/mxcli#1363"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "cmd/mxcli", "date": "2026-10-15", "symptom": "`mxcli test tests/ --list` printed `Found 0 test(s)` and exited 0 over a tree whose only suites sat in a deliberate positive-control folder (`tests/unit/_control`) kept out of the default run, and that read as a green result", "cause": "The control was out of the default run only because discovery (before #1363) never entered sub-folders; once discovery recursed there was no opt-out, and `--list` treats an empty listing as success (a real run with 0 tests already exits 1 with `no tests found`) while saying nothing about why", "file": "`cmd/mxcli/testrunner/parser.go` (`walkTestTree`, `TestSuite.SkippedDirs`), `cmd/mxcli/testrunner/runner.go` (`ListTests`, `emptySuiteError`, `skippedDirsLine`)", "insight": "**Making discovery recursive needs an opt-out in the same change, and an opt-out must be reported.** Folders starting with `_` below the root are skipped, like dot-folders (the Go toolchain convention); the root named on the command line is always read, so `mxcli test tests/unit/_control` runs the control. `_` folders are collected into `SkippedDirs` and printed on the line after `Found N test(s)` by both the run and `--list`; dot-folders are not (`.git`/`.mxcli` noise). `ListTests` takes a second writer (`hints`, stderr from the command) and writes `emptySuiteError`'s explanation there when it found nothing, so stdout stays what scripts parse; its exit status is still 0, which is the contract of a listing, while a run with no tests exits 1. Do not fix a 'silent 0' by making `--list` fail: CI uses it to ask what exists. Tests: `parser_dir_test.go` (the `_control` cases, the root-is-read control, the hint writer).", "refs": ["mendixlabs/mxcli#1363"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "cmd/mxcli", "date": "2026-10-15", "symptom": "`mxcli test tests` fails with `reading test directory: open .../locked: permission denied` and runs nothing when one subfolder (a locked folder, a root-owned folder in a mounted volume) cannot be read, although `tests/Sales/*.test.mdl` next to it is fine", "cause": "`walkTestTree` returned the `filepath.WalkDir` callback's `err` for every entry, so an error below the root became the whole walk's error and `ParseTestDir` returned it as a hard failure", "file": "`cmd/mxcli/testrunner/parser.go` (`walkTestTree`, `ParseTestDir`), `cmd/mxcli/testrunner/runner.go` (`noTestsParsedError`, `reportFileErrors`, `suiteFileErrorResults`)", "insight": "**Moving from a one-level `ReadDir` to a recursive walk turns every subfolder's error into the whole run's error unless errors below the root are made per-entry.** Only an error on the root is fatal; below it `onErr` appends a `FileError{Dir: true}` and the callback returns nil (WalkDir already skips the unreadable folder), so the run still goes red through `FileErrors` and keeps every readable test. Every consumer of `FileErrors` then needs the folder case worded as `could not be read`, not `failed to parse`. **Tests that run as root (CI, devcontainers) cannot see `chmod 000`, and Windows ignores it**: the real chmod test skips there, so the logic is also pinned by injecting the error through the `walkFunc` seam (`walkTestTreeWith`), which runs everywhere. The same walk now serves `testFilesMTime` (`--watch`), so discovery rules cannot drift between the parser and the change detector.", "refs": ["mendixlabs/mxcli#1363", "mendixlabs/mxcli#1368"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "cmd/mxcli", "date": "2026-10-17", "symptom": "On Windows, `mxcli run --local --detach` opens a visible console window for every console program the detached run starts (java, mxbuild, gradle); several terminal windows pop up during a boot. The same run without `--detach`, as a background child of a shell, shows none", "cause": "`setDetachAttrs` started the run with `CREATE_NEW_PROCESS_GROUP | DETACHED_PROCESS`. DETACHED_PROCESS gives the run no console at all, so Windows allocates a new console, with its own window, for each console child the run starts", "file": "`cmd/mxcli/cmd_run_detach_windows.go` (`setDetachAttrs`); test `cmd/mxcli/cmd_run_detach_windows_test.go`", "insight": "A process with no console is not a quiet process: every console child it starts gets a NEW visible console. What silences a tree is one console that has no window, shared by all of it. CREATE_NO_WINDOW gives the run exactly that, and its children inherit it. Windows ignores CREATE_NO_WINDOW when it is combined with DETACHED_PROCESS, so the flag cannot simply be added to the old set. `HideWindow` does not help: it hides the run's own window only, not those of its children. Prove it by the mechanism, not the flag: a helper started through `setDetachAttrs` reports `GetConsoleCP` (0 = no console), `GetConsoleWindow` and `GetConsoleProcessList`; a console child of the helper must appear in the run's own process list and have no window. Before the fix the helper had no console and its child was alone on a visible window; after, the child shares the run's console, which has no window. Real run on Mendix 11.12.5 (Windows Terminal as the default terminal host): v0.26.0 showed 4 new visible windows during a boot, the fix 0, in two runs. A hidden console does not make a `conhost.exe` disappear (the run owns one), so count windows, not conhost processes. The run no longer shares the caller's console, so closing the launching terminal does not touch it, and `run stop` (`taskkill /T /F`) is unaffected", "refs": ["mendixlabs/mxcli#1484"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-16", "symptom": "`create microflow M.F () returns M.Enum as $V` (also nanoflow and rule) passed `check -p --references` and was then refused by exec with \"entity 'M.Enum' not found for return type\"; for a rule check refused it too, with a misleading \"a rule must return a Boolean or an enumeration, not Entity\". `returns enum M.Enum`, `Enumeration(M.Enum)` and a bare enum name as a PARAMETER type all worked", "cause": "the parser records a bare Module.Name as an entity reference; the create handlers retry it as an enumeration for parameters but their return-type block only looked for an entity, while declaredTypeResolver.check was written against the general rule (entity or enumeration) and validateRule saw the unretyped entity kind", "file": "`mdl/executor/cmd_microflows_build.go` (microflow and nanoflow build), `mdl/executor/cmd_rules_create.go`, `bareEnumerationType` in `cmd_microflows_helpers.go`, `declaredTypeResolver.bareEnumeration` and the rule case in `validate.go`", "insight": "A fallback added for one declaration site (parameters) but not its sibling (return types) is a check/exec disagreement, because the checker was written against the general rule, not the site. When a handler resolves a name in one place, grep for the same lookup at every sibling site before trusting a green `check -p`; and a check-time validator that reads the AST kind (validateRule: Boolean or enumeration) needs the same retyping exec applies, or it refuses what exec now accepts. Settled by a PedApp assertAgree test per kind plus a stored-BSON comparison against the `enum` spelling, and mx check 11.12.5 at 0 errors. The same ambiguity is still open for a Java action's bare enum parameter and return type, which stores an entity type (CE1613)", "refs": ["mendixlabs/mxcli#1562"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-17", "symptom": "`mxcli check pers.mdl` without `-p` warned `widget dgAttr (datagrid) property configurationAttribute is not recognized and will be silently dropped on write [MDL-WIDGET07]` (and the same for configurationStorageType, storeFiltersInPersonalization, refreshInterval, columnsHidable, showEmptyPlaceholder, a column's minWidth/minWidthLimit/allowEventPropagation/exportValue), although `exec -p` stores each of them and `check -p` accepts them (mendixlabs/mxcli#1573). An Expression-typed key (rowClass, a column's columnClass) was worse: MDL-WIDGET42 ERROR \"a plain-value property cannot hold the expression\", so a script `exec` takes failed `check` outright, and so did `describe` output carrying one.", "cause": "DATAGRID has no embedded definition (sdk/widgets/definitions holds combobox, gallery, the filters, image): its .def.json is generated from the project's own package, and an embedded one would take precedence over that package for every write because RefreshWidgetDefinitions skips an id the registry already holds. With no project the keyword therefore resolved to no definition, and validateWidgetTreeIn fell through to validateStaticWidgetUnknownProps, whose vocabulary is the union of what the built-in widgets' builders read and describe prints; validateWidgetExpressionValues, given no definition and no item mapping, called every key a plain-value property.", "fix": "validate_widget_embedded_schema.go: for a keyword widget the registry has no definition for (DATAGRID, and its `column`), read the property list of the template mxcli embeds for it (widgets.GetTemplate; the grid's own keys, the `columns` item type for a column). A key the template declares (or the `<key>Params` of a text template) is accepted by MDL-WIDGET07, and its declared type decides MDL-WIDGET42 (Expression takes an expression). A key it does not declare still draws MDL-WIDGET07 with a did-you-mean from the template's names, now worded as what is true: it cannot be verified without a project. Nothing changes with a project, or for a built-in widget.", "file": "mdl/executor/validate_widget_embedded_schema.go", "test": "mdl/executor/validate_widget_embedded_schema_test.go (every key the template declares, derived from it); mdl-examples/bug-tests/1573-datagrid-by-key-settings-check-no-project.mdl", "insight": "`make check-mdl` runs `check` with no project, so the symptom is invisible to the usual loop (`check -p`) and shows only when a script is checked in a repo or by a tool without a project; the reproduction needs the pair `check` vs `check -p` on one file. The embedded template is the 11.6 baseline, kept conservative on purpose (widget-engine.md), so it is evidence of what a key IS and never of what it is not: the Data grid 2 template carries the same 40 grid keys and 21 column keys as the 11.12.5 package (3.4.0), but a newer widget version can add more, which is why an undeclared key is reported as unverifiable rather than as dropped, and why the misspelled-key case keeps its warning. Adding an embedded datagrid.def.json looks like the obvious fix and is the wrong one: it would change every write, not just the check."}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-17", "symptom": "`describe page` prints `-- Context: $currentObject (Shop.Order_Customer)` — the ASSOCIATION — under a data view or list view bound over an association (`DataSource: $currentObject/Shop.Order_Customer`), where the entity it reaches (`Shop.Customer`) belongs; the page itself is correct (`mx check` clean) and only the comment, and consumers that qualify names against the context, were wrong (mendixlabs/mxcli#1571)", "cause": "`dataSourceEntityContext` returned `rawDataSource.Reference` for every kind but a flow. The Reference means a different thing per source kind: the entity for a database source, the flow for a microflow/nanoflow source (the 6e59e0e3e fix), the association for an association source, the page parameter's name for a parameter source. `associationSourcePath` read each step's DestinationEntity but kept only the association names, so a single-hop source carried nothing but the association", "file": "`mdl/executor/cmd_pages_describe_flowcontext.go` (`dataSourceEntityContext`), `mdl/executor/cmd_pages_describe.go` (`rawDataSource.Destination`, `associationSourceDestination`), `mdl/executor/cmd_pages_describe_datasource.go` (the two sites that build an association source)", "insight": "Deriving the context entity from a datasource reference needs a per-kind rule, and each kind with a non-entity reference is its own instance of this bug: ask what `Reference` holds before using it as an entity. For an association source the answer is stored, not inferred: Forms$AssociationSource, a DataViewSource and a pluggable XPath source all keep EntityRef.Steps[last].DestinationEntity, which is already right in both directions (owner to child and back), for a reference set, and for a destination that specializes the association's end — so read it rather than working out parent/child from the domain model (ALTER PAGE's `entityFromEntityRef` does the same, FINDINGS #55). A step with no stored destination keeps the old output. Not fixed here, same function: a `parameter` source's Reference is the page parameter's NAME, so a data view over `$Order` prints `(Order)`, not `(Shop.Order)`; the entity is stored in the same DataViewSource's EntityRef. The check-time `childContext` already treats an association source as unresolved on purpose"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-17", "symptom": "`describe page` printed a Data grid 2 as `datagrid dg (DataSource: database from Shop.Ord, PageSize: 25, Pagination: virtualScrolling)` although exec had stored `configurationStorageType: localStorage`, `itemSelectionMethod: rowClick`, `refreshInterval: 30`, `columnsHidable: false`, a column's `minWidth`, labels and the empty-state placeholder (mendixlabs/mxcli#1573). Executing the description wrote the widget's default over every one of them, with `check` and `mx check` at 0 errors; a Studio Pro-authored grid lost its `onClickTrigger: double` the same way. The Gallery had the same loss (pagination, pageSize, showEmptyPlaceholder, state storage).", "cause": "The write side takes any pluggable-widget setting by its own property key (the explicit-key pass), but the describer for the widgets it has dedicated extractors for (datagrid2, gallery, combobox, filters) read only the properties MDL has a keyword for. The generic pluggable path that does print by key (extractExplicitProperties) is skipped for those widget types (isKnownCustomWidgetType), and it has no notion of a default, so it could not simply be switched on: it would print the whole schema of every untouched widget.", "fix": "cmd_pages_describe_bykey.go: nonDefaultPropsByKey reads each property's declared type and default from the stored widget's own Type.ObjectType (and the item type of `columns`) and prints a setting only when it differs from what exec writes for it left out; wired into the datagrid2 and gallery describers, each column, and the emptyPlaceholder slot. Text templates compare against the text the widget ships (Translations), an Expression prints unquoted (quoted when it is only a string literal), an attribute prints bare only where exec resolves a bare name; a value with no MDL spelling (attribute over associations) is named in a `-- NOT re-executable` comment.", "file": "mdl/executor/cmd_pages_describe_bykey.go", "test": "mdl/executor/cmd_pages_describe_bykey_test.go (against the shipped Data grid 2 / Gallery templates); mdl-examples/bug-tests/1573-datagrid-by-key-settings-describe.mdl", "insight": "Three traps decided the design. (1) DefaultValue is not the default exec writes: four text templates have DefaultValue '' but store their shipped text from Translations, so comparing with DefaultValue printed four labels on every grid; the untouched-grid test is built from the shipped widget template for that reason. (2) `describe -> exec` printing 'Unchanged page' proves nothing about the writer: exec keeps the stored page when the statement equals its description, so a lossy describer is a fixed point of itself; the round trip only shows after `drop page` + exec of the description, compared as BSON with ids stripped (v0.27.0 differs on all six pages of the bug-test script, the fix is identical on all six). (3) A by-key `itemSelection: Single` is stored as PrimitiveValue with Selection 'None' (the explicit pass routes a Selection-typed key as a primitive: mappedKeys holds mapping Sources, not keys), i.e. no selection at all, so the bug-test uses `Selection:`; describe skips Selection-typed keys, which keeps a describe -> exec -> BSON comparison from hiding that write-side defect."}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-17", "symptom": "`create or modify navigation` (or `create or replace`, deprecated or `mdl 1` spelling) naming a home page, role home, login page, not-found page or a menu item's page/microflow/nanoflow that does not exist passed `check -p` (\"Check passed!\") and `exec` (\"Navigation profile 'Responsive' updated.\"); only `mx check` objected: CE1613 \"The selected page 'Shop.NoSuchHome' no longer exists.\" at Navigation profile, and one per bad menu item. A page's own show page / call microflow and an unknown icon were refused. Same for `create menu`.", "cause": "The reference-resolution passes were added one reference kind at a time (validateWidgetReferences for widget trees, validateIconRefs, validateNavigationRoles for the role only), so navigation targets were in none of them. The exec handler built each menu action with a pageBuilder whose tolerateDanglingRefs is true for menus (so a target stored by name never failed), and read home/login/not-found pages straight into the spec; CREATE OR REPLACE NAVIGATION rewrites the whole profile.", "file": "`mdl/executor/validate_navigation_targets.go` (`navigationTargets`, `unresolvedNavigationTargets`, `validateNavigationTargets` called from `validateProgramWithWarnings`; `validateNavigationTargetsForExec` called first in `execAlterNavigation` and `execCreateMenu`); forward references via `navigationDefRefs` in `eagerDefRefs` and `Executor.enterScriptFlows` (`scriptTargets`)", "insight": "A reference pass written per kind leaves every kind it does not list silently unchecked, and the escape is silent both ways (check passes, exec writes, the build reports it one build later) — when adding a statement that names documents, grep every place a page/microflow name is resolved and ask which statements are NOT in the list. Navigation targets are written by a statement that replaces the whole profile, so the refusal has to come before the write, in the handler as well as in the pre-flight (`exec --no-check` skips the pre-flight). Reuse the same lookups (buildPageQualifiedNames and friends). A target stored by name and created further down the script must follow the flow-call rule (forwardFlowCalls, #1405) rather than statement order: a first version that made it an MDL-ORDER01 error broke a working script shape (navigation written before its pages: upstream execs it and mx check reports 0 errors) — measure what upstream does with the other order before enforcing one. Measured on a Mendix 11.12.5 app: 4 CE1613 before for the reported script, 0 errors after a valid navigation; an empty listing from the backend is silence, not a finding (as in validateForwardDefRefs)", "refs": ["mendixlabs/mxcli#1569"]}
Loading
Loading