Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
3ebd76f
ci: add non-gating Mendix 9.24 nightly job and gate 10.x-only doctype…
claude Oct 13, 2026
c2c9a23
fix: escape a business event service's ServiceName in describe
claude Oct 13, 2026
03fe8b5
fix: write pluggable widget Types in the project's Mendix version shape
claude Oct 13, 2026
fe6a4ee
Merge pull request #1160 from ako/ci/nightly-mendix-9-24
ako Oct 13, 2026
d0a1df0
Merge pull request #1161 from ako/claude/nice-einstein-a74lz4
ako Oct 13, 2026
b9b5038
Merge pull request #1162 from ako/fix/pluggable-widget-defaulttype-me…
ako Oct 13, 2026
39c286c
fix: keep action sources in the marketplace reference cache (mendixla…
claude Oct 13, 2026
26d5c38
fix(sync-java-deps): check the Gradle-resolved version, not every dec…
claude Oct 13, 2026
f9dab0f
fix: keep a JavaScript action's imports and EXTRA CODE on regeneratio…
claude Oct 13, 2026
32a3946
test: use testutil.SetHome in the #1441 cache tests (mendixlabs/mxcli…
claude Oct 13, 2026
f8226bc
fix: refuse change and member paths over a list retrieve (mendixlabs/…
claude Oct 13, 2026
db53e85
Merge remote-tracking branch 'origin/main' into claude/practical-john…
claude Oct 13, 2026
7a35260
fix: describe module with all emits every document type (mendixlabs/m…
claude Oct 13, 2026
8370996
Merge pull request #1165 from ako/fix/1429-js-action-keep-extra-code
ako Oct 13, 2026
afc9237
Merge pull request #1166 from ako/fix/1441-refcache-keeps-action-sources
ako Oct 13, 2026
f570854
Merge branch 'mendixlabs:main' into main
ako Oct 13, 2026
8f8c755
test,docs: keep list-of-one coverage valid under MDL-RETRIEVE03 (mend…
claude Oct 13, 2026
c1c595a
docs: keep the write-microflows skill within the 700-line body limit
claude Oct 13, 2026
f296b3c
fix: describe javascript action with type parameters emits MDL that p…
claude Oct 13, 2026
38e930b
Merge pull request #1168 from ako/claude/practical-johnson-5cb291
ako Oct 13, 2026
2582672
Merge pull request #1167 from ako/fix/1422-list-used-as-object
ako Oct 13, 2026
743ed84
fix(test): @throws catches errors from CALL JAVA ACTION and other cal…
claude Oct 13, 2026
d37aa0c
Merge pull request #1170 from ako/fix/js-action-describe-type-params
ako Oct 13, 2026
d701905
Merge origin/main into fix/1421-describe-module-all-doctypes
claude Oct 13, 2026
7c04367
test: check that FeedbackModule's with-all dump parses
claude Oct 13, 2026
3fd323a
Merge pull request #1171 from ako/claude/vibrant-cray-cqlr3a
ako Oct 13, 2026
876d15f
Merge pull request #1169 from ako/fix/1421-describe-module-all-doctypes
ako Oct 13, 2026
0b558a5
fix: name the auto-detected project and refuse an ambiguous one (mend…
claude Oct 13, 2026
a731629
fix: revoke resolves association members and refuses unknown ones (me…
claude Oct 13, 2026
f53041b
fix: roll back exec when a statement fails after the pre-check (mendi…
claude Oct 13, 2026
489bead
Merge pull request #1173 from ako/fix/1444-stray-mpr-autodiscovery
ako Oct 13, 2026
41b76b9
Merge pull request #1174 from ako/fix/1225-revoke-association-member
ako Oct 13, 2026
8d1e3b1
Merge pull request #1175 from ako/fix/1408-exec-atomic
ako Oct 13, 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-12","symptom":"`mxcli exec`: a statement that fails at write time (after the pre-check passed) leaves every earlier statement written — a created module and entity stay, and a `drop` ahead of the failing `create` is not undone","cause":"exec applied statements one at a time, each landing on disk as it ran, with no way back; the only all-or-nothing gate was the pre-check, which cannot predict write-time failures (a property the project's Mendix version cannot store, a widget that does not build)","file":"`modelsdk/mpr/journal.go` (`BeginJournal`, `journalDB` via `guardWrite`, `journalFile` at the four mprcontents write/delete sites in `writer_core.go`); `cmd/mxcli/cmd_exec.go` (`runScriptAtomically`)","insight":"A before-image journal, not a write buffer: buffering would have to make inserts and deletes visible to later reads in the run (deferral only holds updates, writer_deferred.go), while journaling leaves the write path — reconcile, elision, identity carry — exactly as it was and only copies each file before the run first touches it. `guardWrite` is already the choke point every write passes before it changes anything, so the .mpr copy is taken there. Rollback must run after the executor is closed: a deferred access-rule write lands at Close, and the .mpr is replaced under SQLite. Test hashes the whole project tree INCLUDING directories (a created unit's XX/YY dirs must go too) on both a v1 and a v2 fixture; control: the same script minus the failing statement must change the tree","refs":["mendixlabs/mxcli#1408"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "cmd/mxcli", "date": "2026-10-12", "symptom": "`marketplace update 109515 --to 5.2.1` refused an untouched NanoflowCommons with \"refusing to update: 44 element(s) have been changed locally and the update would discard them: JAVASCRIPT_ACTION Base64Decode ...\"; `marketplace diff` showed \"Locally modified (44 of 50 elements)\", every one a JavaScript action (mendixlabs/mxcli#1441). Only on a repeat run of a version - the first diff, a cache miss, was clean.", "cause": "The finished-reference cache stored the model only: isModelFile dropped javascriptsource/ and javasource/ as 'never read'. DESCRIBE JAVASCRIPT/JAVA ACTION reads <dir>/<Module>/actions/<Name>.{js,java} beside the .mpr and prints a 'source not available' placeholder when absent, so a cache MISS compared real code against real code and a cache HIT compared the placeholder against the project's code - every action Modified. The filter's own comment warned of exactly this ('anything that starts reading a sibling directory ... will see it on a cache miss and not on a hit').", "file": "cmd/mxcli/marketplace/refcache.go (isModelFile keeps javascriptsource/ + javasource/; refEntryFormat 'f2' prefix in refCacheDir so pre-fix model-only entries are never served), cmd/mxcli/marketplace/snapshot.go (Conclusive: omitted-source placeholder -> Unknown, never Modified); tests cmd/mxcli/marketplace/refcache_sources_test.go, refcache_test.go, inconclusive_test.go", "insight": "**A cache bug that only shows on the second run needs a miss-then-hit test, not a hit test.** The decisive test snapshots the same untouched module against the fresh reference and then against the cache-restored one; the miss half passing proves the fixture is sound, the hit half failing locates the cache. Assert Unchanged, not 'not Modified': with the placeholder gate in place the old filter yields Unknown, which still blocks `update` without --force - the control showed exactly that. **A cache-content change needs a key change**: an old entry is complete by its own marker and would keep serving the stripped tree for ever, so the fix versions the entry name (refEntryFormat) instead of trusting a filter change to reach existing caches. **A placeholder is not content**: DESCRIBE output that substitutes a 'not available' body for data must be inconclusive in the diff, else a missing file reads as an edit. Controls: old filter -> hit reports 'unknown' (gate kept) / 'modified' (gate off); unprefixed key -> legacy entry served.", "refs": ["mendixlabs/mxcli#1441", "#731", "#637"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area":"cmd/mxcli","date":"2026-10-12","symptom":"A command run without `-p` (e.g. `mxcli describe module M`) silently works against a stray `.mpr` in the working directory; the only sign is `Using project: App.mpr`, which reads the same for the intended project and a stray copy. With several `.mpr` files nothing is picked and the command just says `--project (-p) is required`","cause":"`rootCmd.PersistentPreRun` auto-discovery (`discoverProjectPath`) printed only the bare file name it set `-p` to, and returned nothing at all when the directory was ambiguous","file":"`cmd/mxcli/main.go` (`discoverProject`, called from `rootCmd.PersistentPreRun`)","insight":"Auto-detecting the sole `.mpr` is the CLI's documented resolution (init, new, theme and the LSP all do it), so refusing a single match would break `cd app && mxcli ...`; the defect was that the guess was indistinguishable from an explicit choice. Name the absolute path, say it was auto-detected and how to override, and list the candidates when ambiguous. The `-p` value stays the bare file name so nothing downstream sees a different path. Unit-test the helper on a temp dir (no chdir); control: a body returning the old bare notice fails all three content assertions","refs":["mendixlabs/mxcli#1444"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "cmd/mxcli", "date": "2026-10-13", "symptom": "Two modules declare the same artifact at different versions (ExcelImporter commons-lang3 3.18.0, CommunityCommons 3.20.0): `sync-java-deps --check` fails with `missing org.apache.commons:commons-lang3:3.18.0`, the sync deletes that jar and errors `sync finished but 1 dependency/dependencies are still missing from vendorlib/`, and `run --local` stops at `Resolving 1 managed Java dependency` on every start (#1450)", "cause": "`UnvendoredJarDependencies` checked every declaration for `<artifact>-<version>.jar`, but `mx sync-java-dependencies` runs Gradle over all modules at once and its conflict resolution vendors only the newest version per group:artifact — the older coordinate can never appear, so the postcondition was unsatisfiable", "file": "`cmd/mxcli/docker/javadeps.go` (`resolveJarDependencies`, `compareJarVersions`, `SupersededJarDependencies`), `cmd/mxcli/cmd_sync_java_deps.go`", "insight": "A gate that checks the sync's postcondition must check what the sync PRODUCES, not what the model declares — and the two differ exactly where Gradle resolves a conflict. The tell in the report was a sync that 'succeeded' and deleted the jar it then called missing: an unsatisfiable postcondition, not a failed download. Measured on 11.12.1 with `mxcli new` + two modules: vendorlib/ gets commons-lang3-3.20.0.jar only; pre-fix binary prints the reported error verbatim, fixed one passes. Versions must compare Gradle's way (numeric parts numerically, 1.0-beta < 1.0): a string compare picks 3.9.0 over 3.20.0. To run mx sync here, Gradle needs the proxy as JVM props (JAVA_TOOL_OPTIONS -Dhttps.proxyHost/Port) — otherwise mx says 'Failed to find some hosts', which is not a Maven outage. The per-module Note in `alter module … add jar dependency` (executor `warnUnvendoredJarDependencies`) still checks one module's declarations and can name a superseded coordinate", "refs": ["mendixlabs/mxcli#1450"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area":"cmd/mxcli","date":"2026-10-13","symptom":"`mxcli test`: a test whose body does `call java action` cannot use `@throws` — the expected Java exception is reported as `ERROR <message>`, not PASS; without `@throws` it is also ERROR rather than the usual `FAIL exception during execution: …`","cause":"The runner attaches its `ON ERROR` handler only to statements matched by `containsCallMicroflow`, which recognised `CALL MICROFLOW` / `CALL NANOFLOW` only; every other call-shaped activity was emitted without a handler and its error escaped the generated test microflow to the endpoint's outer handler","file":"`cmd/mxcli/testrunner/generator.go` (`startsErrorRaisingCall`, used by `attachOnError`, `rewriteWithErrorHandling`, `rewriteForThrowsTest`)","insight":"The set of statements the runner wraps must be the set the grammar gives `onErrorClause` to (MDLMicroflow.g4) — enumerate it from there, not from the statements the first tests used. Unit test each kind through BOTH generators and `visitor.Build` the output, since an `ON ERROR` on a statement that cannot take one would be a parse error. The cheap workaround (wrap the call in a microflow) hides the gap, so it went unreported until a module's own Java actions were tested. Proven live on 11.12.1 `--local --db-type hsqldb`: unfixed binary ERROR/ERROR, fixed PASS/FAIL on the same project. Also anchored the match at the statement start — the old `strings.Contains` treated a LOG whose text mentioned `call microflow` as a call","refs":["#1164"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/backend", "date": "2026-10-12", "refs": ["mendixlabs/mxcli#1429", "ako/mxcli#731", "ako/mxcli#705"], "symptom": "describe javascript action shows the EXTRA CODE only as a comment; re-running `create or modify` with an edited body overwrote a hand-restored .js, deleting the EXTRA CODE helpers and the import list the user code calls", "cause": "WriteJavaScriptSourceFile regenerated the file from the statement alone: GenerateJavaScriptSource had no slot for imports or extra code, unlike the Java twin (RetainSections, #705). The #731 fix only left the file alone when the body was unchanged", "file": "`mdl/backend/modelsdk/javascript_write.go` (WriteJavaScriptSourceFile), `sdk/javaactions/jsretain.go` (JavaScriptRetainedSections)", "insight": "When one doctype's file writer gains retention, grep for its twin: the Java fix (#705) landed long before the JS one with the same shape. Retain in the backend writer, next to the file read, so no interface change is needed and every caller is covered. JS imports can span lines and omit semicolons, and marketplace bundles put them above the banner, so scan statements up to the EXTRA CODE marker rather than matching single `import ...;` lines. The control is reverting only the writer: the test then loses every import and the helper.", "test": "TestWriteJavaScriptSourceFile_EditedBodyKeepsImportsAndExtraCode"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/backend", "date": "2026-10-13", "refs": [], "symptom": "Found running the doctype suite on Mendix 9.24.30 (no issue filed): every create page / alter page / snippet with a pluggable widget failed to write: \"failed to create page: CreatePage: insert: unit …: this Mendix 9.24.30 project cannot store CustomWidgets$WidgetValueType.DefaultType (Mendix 10.15.0+)\" (\"failed to save modified page\" for alter page), while `mxcli check` passed the script", "cause": "The pluggable widget Type is copied from the embedded 11.6 templates (sdk/widgets/templates/mendix-11.6, augmented from the project's .mpk) and written verbatim whatever the project version. Every CustomWidgets$WidgetValueType in it carries six keys Mendix introduced after 9.24 (mendixmodelsdk 4.116.0 WidgetValueType.versionInfo): SetLabel 10.5, IsLinked and IsMetaData 10.14, DefaultType 10.15, ActionVariables 10.21, AllowUpload 11.8. The property floor drops the empty ones and refuses a value: DefaultType is \"None\" on all 604 template value types, and IsLinked / IsMetaData / SetLabel are true on the combo box, dropdown sort and data grid filters, ActionVariables non-empty on some, so those were refused next", "file": "`mdl/backend/modelsdk/widget_pluggable_write.go` (templateFullBSONIDs, widgetTypeForVersion — used by LoadWidgetTemplate and BuildFilterWidget), `modelsdk/canon/propertyfloor.go` (PropertyDeclared)", "insight": "The Type is the widget package's schema, not anything the statement said, so a newer-version key in it is dropped whatever it holds — at template load, where the version is known — while the floor keeps refusing values in the Object. Studio Pro 9.24.30's WidgetValueType key set (Atlas_Core.LanguageSelectorWidget in a Studio Pro-authored 9.24 app, `mxcli bson dump --type snippet --format ndsl`) is exactly the template's minus those six, so the Model SDK versionInfo is complete for this type and the gate can use the floor's own data (canon.PropertyDeclared) instead of a hand list. codec.Encoder.OmitKeys does not reach it: the Type is decoded from raw bytes, its elements are clean, and the encoder passes clean fields through without consulting OmitKeys. Fixing DefaultType alone would have moved the refusal to IsLinked/SetLabel/ActionVariables; stubbing the gate in the unit test shows all of them at once. Not covered: 9.24 also stores CustomWidgetType.WidgetPhoneGapEnabled (deleted 10.0) that the template lacks (a property-set gap, not a refusal), and the data grid template's sample-column Object holds a 10.2+ Forms$DesignPropertyValue.Value"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"date": "2026-10-12", "area": "mdl/executor", "symptom": "mendixlabs/mxcli#1422: under `mdl 1;` `retrieve $E from M.Ent limit 1; change $E (Attr = 'x');` passed check and exec, then mx check reported CE1613 \"The selected attribute 'List of M.Ent.Attr' no longer exists\"; switching to `first` and re-running `create or modify` spliced the retrieve and kept the broken change.", "cause": "addChangeObjectAction qualified the member with fb.varTypes[var] verbatim, including the \"List of \" prefix; MDL-RETRIEVE01 only covered object-used-as-list; describe strips a member to its last dot segment, so the corrupt stored member printed as the clean statement and declaredMatches kept its bytes.", "file": "mdl/executor/cmd_microflows_builder_actions.go", "fix": "Builder refuses change over a list variable (naming CE1613 and `first`); new check rule MDL-RETRIEVE03 (database retrieve without the object range, then `change` or a `$E/Attr` path in any later expression, CE0117), promoted to exec; planFlowModify treats a stored list-qualified member as not spliceable (storedListQualifiedMember, same as #1418's storedImportWithoutEntity); describe appends a -- WARNING for it.", "test": "TestChangeOverListRetrieveRefused1422, TestChangeOverListStoredMemberIsNotKept1422, TestRetrieveListUsedAsObject1422; mdl-examples/bug-tests/1422-change-over-list-retrieve.mdl", "insight": "**describe normalising a stored value to its clean spelling makes corruption invisible to diff-then-patch** — the second instance after #1418, so any member/entity describe prints by trimming (last-dot split, prefix strip) is a candidate. The cheap repair is a stored-shape guard in planFlowModify that returns cannotSplice; corrupting one field of a correctly written unit via UpdateRawUnit reproduces the 'kept over a broken project' case without the old binary. Measured on mx 11.6.6: `set $E = empty` over the list (Change list Replace) builds at 0 errors; `return $E/Name` is CE0117 but mx check hid it behind the CE1613 in the same run — check each shape in its own project copy before deciding what to refuse."}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"date": "2026-10-12", "area": "mdl/executor", "symptom": "mendixlabs/mxcli#1421: `describe module ... with all` omits whole document types (nanoflows, snippets, JS actions, JSON structures, import/export mappings, task queues, image collections) with no error; on PedApp it emitted 0 of FeedbackModule's 11 nanoflows and 20 of its 49 documents.", "cause": "describeModule's WITH ALL branch was a hand-written section per document type covering 13 types while describe handlers exist for 30-odd; every section was `if err == nil { ... }`, so a failing list or describe was skipped too.", "file": "mdl/executor/cmd_modules.go; mdl/executor/describe_module_all.go; mdl/executor/executor_query.go", "fix": "One ordered registry (moduleDocKindsBefore/AfterDomainModel) of describable document kinds, each rendered through describeByKind (the dispatch extracted from execDescribe); a type-blind ListDocumentUnits pass prints `-- not describable: <kind> M.N` for any module unit no entry emitted; read-only reports (building block, icon collection) are emitted commented out; a describe or list failure prints `-- describe failed: ...` and fails the statement after the rest is written (as #1425 does).", "test": "TestDescribeModuleWithAll_AccountsForEveryDocument (each unit's own describe must appear in the dump; reverted: FeedbackModule 20 of 49, Atlas_Web_Content 0 of 88), TestModuleDocKindsCoverDescribableTypes, TestDescribeModuleWithAll_ReportsDescribeFailure", "insight": "**A per-type list next to a type-blind enumeration is the drift signal** — this was the fourth hand-kept copy of 'which document types exist' (catalog view, describe_auto, cmd/mxcli dispatch, scriptdiff). Count against ListDocumentUnits, which cannot miss a kind because it never asks for one, and compare each document's own describe output rather than counting `create` lines: a count passes when a document is dumped under the wrong name."}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"date": "2026-10-12", "area": "mdl/executor", "symptom": "`revoke write (Tag_GuestGroup) on entity ModA.Tag from ModA.User` (or the older `revoke ModA.User on ModA.Tag (write (Tag_GuestGroup))`) answered \"No access rules found matching …\" (later \"Unchanged … nothing to revoke\"), exited 0, and the association stayed ReadWrite; `write (Label)` on the same rule worked (mendixlabs/mxcli#1225).", "cause": "execRevokeEntityAccess resolved member names through EntityMembers, which yields attributes only, and fell back to `Module.Entity.Member` for anything else. An association's MemberAccess is stored as `Module.Association` (AssociationQualifiedName), so the ref matched nothing and the backend reported 0 rules modified — indistinguishable from an already-revoked right. GRANT had its own association enumeration (FROM side via ParentID, both ends for OWNER Both, cross-module Both, inherited) that REVOKE never reused.", "file": "mdl/executor/cmd_security_write.go (accessRuleAssociations shared by grant and revoke; revoke refuses an unmatched member like grant's unmatchedGrantMembers)", "insight": "Two writers keyed on the same stored reference must share the code that builds it — the grant's association loop and the revoke's attribute-only map had drifted since #758 fixed inherited attributes in both. The idempotent 'nothing to revoke' notice hid it: a count of 0 cannot tell 'already revoked' from 'named something the rule cannot hold'. Separate those before calling the backend — resolve the name, refuse if unknown, and only then let 0 mean unchanged. Measured on a fresh 11.6.6 app: pre-fix binary prints the Unchanged notice and describe still shows write (Tag_GuestGroup); fixed binary revokes it and `mxcli docker check` reports 0 errors.", "refs": ["mdl/executor/revoke_association_member_test.go", "mdl-examples/bug-tests/1225-revoke-association-member.mdl"]}
Loading
Loading