Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
9fe249a
Triage the fork's own issues alongside the mirrors
claude Oct 24, 2026
78b5e57
Merge pull request #1662 from ako/claude/funny-lovelace-wtudp7
ako Oct 24, 2026
88057f2
fix(pages): keep a stored DisabledDuringExecution false on rebuilt pl…
claude Oct 24, 2026
11df8f7
Merge pull request #1663 from ako/claude/cool-keller-jtch0r
ako Oct 24, 2026
2740511
refactor(sql): spell the object-sequence UPDATE aliases with AS
ako Oct 24, 2026
df82f53
fix(pages): patch a stored pluggable widget per property instead of r…
claude Oct 24, 2026
fb53f97
fix: a filter's Placeholder/Adjustable in create page are not written…
ako Oct 24, 2026
c7b0640
fix: rename attribute rewrites unrelated XPath constraints and drops …
ako Oct 24, 2026
76745d6
fix: IMPORT ... LINK reports success and links nothing (ako/mxcli#1454)
ako Oct 24, 2026
815a9b6
Merge pull request #1664 from ako/claude/cool-keller-jtch0r
ako Oct 24, 2026
63ad914
fix: rename of a document in a same-named folder renames the folder (…
ako Oct 24, 2026
2675f26
fix: call rest service sends an expression body or URL as its source …
ako Oct 24, 2026
27e533f
fix: a fall-through error handler inside a branch loops or ends the f…
ako Oct 24, 2026
8c39139
Merge pull request #1665 from ako/fix/1652-textfilter-placeholder-dro…
ako Oct 24, 2026
576a81e
Merge pull request #1666 from ako/fix/1506-rename-attribute-unrelated…
ako Oct 24, 2026
e3f3b4f
Merge pull request #1667 from ako/fix/1454-import-link-storage-format
ako Oct 24, 2026
3ab86b8
Merge pull request #1668 from ako/fix/1443-rename-same-named-folder
ako Oct 24, 2026
304fe50
Merge pull request #1669 from ako/fix/1444-rest-call-body-variable
ako Oct 24, 2026
f43ed84
Merge pull request #1670 from ako/fix/1459-error-handler-in-branch
ako Oct 24, 2026
2f6970c
docs(skills): regenerate demo-data's line index
ako Oct 24, 2026
a51a75e
fix: an if without else inside an error handler loses its false case …
ako Oct 24, 2026
ca068f4
fix: rename constant leaves @Module.Const in expressions naming the o…
ako Oct 24, 2026
b87765f
fix: move enumeration to another module leaves its references naming …
ako Oct 24, 2026
4e9551c
Merge pull request #1672 from ako/fix/1455-error-handler-if-false-case
ako Oct 24, 2026
6f9c157
Merge pull request #1673 from ako/fix/rename-constant-expression-refs
ako Oct 24, 2026
07577f0
Merge pull request #1675 from ako/fix/move-enumeration-reference-sweep
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-24", "symptom": "`rename constant M.C_Root to C_Base` printed \"Renamed constant\" with no reference count, and mx check then reported CE1613 \"The selected constant 'M.C_Root' no longer exists\" at every activity using it (create variable, log message, end event). A cross-module `move constant` the same. `rename enumeration` renamed a value that was the whole expression but not one inside a longer one (`$S = M.Status.Open and …` → CE0117). Found while fixing ako/mxcli#1443, which had hidden it (ako/mxcli#1671)", "cause": "The reference sweep's two primitives (RenameReferences → replaceQNInValueCounted, and UpdateQualifiedNameInAllUnits → replaceQualifiedNameRef, used by cross-module MOVE) rewrite a stored string only when it EQUALS the old qualified name or STARTS WITH it plus '.'. An expression always writes a constant as `@Module.Name`, so not even a constant that is the whole expression matched; an enumeration value matched only as the whole expression", "file": "`mdl/types/expression_rename.go` (RewriteExpressionReferences), `mdl/backend/modelsdk/infrastructure_write.go` (replaceQNInValueCounted, replaceQualifiedNameRef), `cmd/mxcli/syntax/features_misc.go` (rename topic)", "insight": "Expressions live under ordinary keys (InitialValue, Expression, ReturnValue, XpathConstraint, a split's Caption), so a key list would be a maintenance trap; instead apply a token-aware rewrite to every string the whole-string match leaves alone, which is safe because the tokens are unambiguous: `@` + qualified name + non-name byte is only ever a constant, and `QN.Member` not preceded by a name byte, '.', '/', '$' or '@' is only a member access (the '/' guard keeps association path steps out). Skip single-quoted literals with '' escapes, or a log message that quotes the name gets rewritten. Leave the module-prefix pair (\"Old.\" → \"New.\") alone — module rename is its own open problem. Use `mxcli bson dump --format ndsl | grep` to find which keys hold a name; it is faster than writing a BSON walker (no pymongo in the devcontainer). Neither MDL nor this fix can author `@M.C` inside an XPath — the grammar parses `@` as a one-word step — so cover the XPath form with the rewriter's unit tests. Revert each primitive separately: the cross-module move assertion fails only with replaceQualifiedNameRef reverted. Separate defect kept out: `move enumeration` returns before the cross-module sweep runs at all", "refs": ["ako/mxcli#1671", "ako/mxcli#1443"], "ce": ["CE1613", "CE0117"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-24", "symptom": "A custom error handler that falls through (`on error without rollback begin log …; end error;`, no RETURN/RAISE ERROR) on an activity inside an IF branch was wired to the wrong place. With a result variable (`$N = call microflow …`, `$Obj = create …`, `$R = call rest service … returns response`) the handler's last activity flowed into a merge spliced in FRONT of the enclosing split — an endless loop while the call kept failing (runtime: 3063 'failed' lines in ~5s, after-startup never returned); describe printed `merge rejoin1;` before the if and `join rejoin1;` in the handler. Without one it flowed into a new end event (describe: a `return;` in the handler the source never had) — nothing after the failure ran; with `returns Boolean as $Result` that end returned the non-existent $Result (CE0109, the only shape any check caught). Same in IF/ELSE (either arm), CASE and type-split arms, nanoflow loop/while bodies and `while true`; in a THEN that ends in RETURN the handler skipped to the code after the IF. check, exec and mx check passed (ako/mxcli#1459, mendixlabs/mxcli#1565)", "cause": "Pending fall-through rejoins live in one builder-wide slot (errorHandlerSource/TailFrom/SkipVar + queue) that only buildFlowGraph's top-level loop settled, on the flow LEAVING the failing activity. The branch body loops (addIfStatement ×3, addEnumSplit, addStructuredInheritanceSplit, the loop/while sub-builders, addManualWhileTrueStatement) settled only an EMPTY handler (`emptyErrorHandlerFrom == lastID`), so a non-empty one leaked out of the branch and the enclosing loop settled it on the next flow it drew: the skip-var path (taken whenever the activity has an output variable) ignores the origin and spliced it into `previous -> split`; without skipVar nothing matched and terminatePendingErrorHandlersAtEnd gave it an end event; inside a loop sub-builder it was simply dropped (no outgoing flow = iteration ends)", "file": "`mdl/executor/cmd_microflows_builder_flows.go` (enterBranch/leaveBranch/settleBranchFlow, pendingHandlers; mergeOnEdge keeps a branch-exit rejoin merge on the branch row), `cmd_microflows_builder_control.go` (addIfStatement: per-arm scope, settle every in-arm flow and the arm's exit into the merge, merge created lazily when a returning arm leaves a handler; loop/while/while-true bodies), `cmd_microflows_builder_actions.go` (addEnumSplit, addStructuredInheritanceSplit)", "insight": "Scope the pending-handler slot to each branch body (take it on entry, hand back only what the branch could not settle) instead of adding an origin guard to the skip-var path: the skip-var delay exists precisely so a rejoin can land on a flow whose origin is NOT the source, and the shared slot also let an in-branch flow settle the ENCLOSING path's handler. The 'third shape' (handler in a THEN ending in RETURN joining the IF's exit merge) was a30881bbb's deliberate shared continuation; it is kept only where it was earned — a skip-var handler whose next statement reads the failed output — and the merge is now created only when a returning arm actually leaves one (static bodyHasContinuingCustomErrorHandler over-predicted it). Assert on the graph (where does the handler's last activity go next, through merges) with a control that the failing activity's own next is the same node; describe text alone misleads because the broken loop-body shape describes as a clean fall-through. Runtime A/B on 11.12.2 (after-startup, parseInteger('x') callee): fixed = before/failed/after call/end once each. A custom handler inside a MICROFLOW loop is CE0644 regardless, so the loop part matters for nanoflows. Not the same root cause as ako/mxcli#1455 (handler-body loop drops the deferred false case on in-body flows)", "refs": ["ako/mxcli#1459", "mendixlabs/mxcli#1565", "ako/mxcli#1455"], "ce": ["CE0109", "CE0644"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-24", "symptom": "ako/mxcli#1652 (mendixlabs/mxcli#1643): `textfilter tfName (Attributes: [Name], Placeholder: 'Search name', Adjustable: false)` in `create page` passed check (no MDL-WIDGET06/07) and exec, and neither value was stored — describe printed a bare `textfilter tfName (Attributes: [Name])`, 'Search name' occurred 0 times in the page BSON. `alter page … set (placeholder: …, adjustable: …) on tfName` wrote both. Feeding describe's own `adjustable: false, placeholder: '…'` back into create stored adjustable and still dropped placeholder", "cause": "The filters' hand-written definitions map neither key, so both reach the widget engine's explicit-property pass (Build step 4.6), which looked the authored name up in the template's PropertyTypeIDs byte-for-byte. `Adjustable` != `adjustable`; and `Placeholder:` is a grammar keyword (PLACEHOLDER) that the visitor always stores as Properties[\"Placeholder\"], so no spelling could reach the template's `placeholder`. check's allow-list, its persistedByExplicitPass verdict, the mapping pass (lookupProperty) and ALTER's setter (#1069) all fold case — the create writer was the one reader that did not", "file": "mdl/executor/widget_engine.go (explicitPropertyKey, used by the explicit-property pass in Build)", "fix": "Resolve the authored name to the template's own key case-insensitively (exact match first; a case-only match must be unique and of a kind the pass writes correctly — the explicitPassWritableTypes set check already calls persisted), and write/scope by that key. Authored names are iterated sorted, since two spellings can now land on one key", "test": "mdl/executor/widget_explicit_key_case_test.go — real embedded text/number/date filter templates; asserts the stored placeholder TextTemplate text and adjustable/delay PrimitiveValue. Stashing the fix fails 5 subtests with `placeholder stored \"\", want \"Search name\"` / `adjustable stored \"true\", want \"false\"` / `delay stored \"500\", want \"250\"`. Repro mdl-examples/bug-tests/textfilter-1652-placeholder-adjustable.mdl", "insight": "Siblings came free: the number and date filters declare the same `placeholder`/`adjustable` pair and the text/number `delay`, and the fix is in the shared pass, so every unmapped key on every pluggable widget now behaves the same in any case. When the checker judges keys case-insensitively and calls a key 'persisted by the explicit pass', grep the WRITER's lookup for a bare map index (`propertyTypeIDs[name]`) — that one line was the whole disagreement, and it is the same bug #1069 fixed on the ALTER side a release earlier. A grammar keyword is a spelling the author cannot control: the visitor canonicalises `placeholder:` to `Placeholder`, so describe's lower-case output could never round-trip — test the describe spelling, not just the report's. Structural proof that is cheaper than a browser: the placeholder WidgetValue written by create is identical (ids stripped) to the one ALTER writes, which the reporter showed working; raw mx check 11.13.0 on the repro is 0 errors. Not fixed here, seen on the same repro: check -p warns MDL-WIDGET10 that a text filter's `attributes` 'is hidden when attrChoice is auto — the value will be ignored', but SetAttributeObjects flips attrChoice to 'linked' and the attributes ARE written (a false warning, the #1519 dropdownfilter shape on the text/number/date defs)", "refs": ["ako/mxcli#1652", "mendixlabs/mxcli#1643", "#1069"], "rules": ["MDL-WIDGET06", "MDL-WIDGET10"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-24", "symptom": "An `if` without `else` inside a custom error handler (`on error without rollback begin if $Flag then return 1; end if; return -1; end error;`), whose THEN ends in RETURN, passed check and exec, but the decision's second outgoing flow was stored with NoCase instead of `false`: mx check reported CE0079 \"The 'false' condition value should be configured…\" at the decision and CE0773 \"Value must be of type Boolean.\" at the flow. describe read the NoCase edge back as an `else`. The same `if` in the main flow, with an explicit else, or with a THEN that does not return was stored correctly (ako/mxcli#1455, mendixlabs/mxcli#1558)", "cause": "Such an `if` has no merge, so addIfStatement leaves its FALSE edge pending in nextConnectionPoint/nextFlowCase/nextFlowAnchor for the NEXT flow to carry. addErrorHandlerFlow's handler-body loop copied the case into lastErrCase but used it only for takePendingJoin and the handler's final rejoin; the edge to the next statement inside the handler was drawn with a plain newHorizontalFlow, dropping the case — and the deferred @anchor(false: …) with it. Every other body loop (top level, IF arms, CASE/type-split arms, loop/while bodies) takes both", "file": "`mdl/executor/cmd_microflows_builder_flows.go` (addErrorHandlerFlow, the in-handler edge)", "insight": "When one body loop misbehaves and the same construct is fine elsewhere, grep every `newHorizontalFlow(last…ID, actID)` and check each sits in the else of a pending-case test: here all seven siblings did and the handler loop alone did not, which localised it in one step. Carry the deferred anchor too (pendingFlowAnchors when the previous statement was compound) — a test reverting only the anchor half fails 1→3 vs bottom→top, so it is a separate, real omission. Assert on the edges' cases, not describe text: describe renders the NoCase edge as an `else`, which reads correct and even round-trips (re-exec of the describe output builds a valid if/else), hiding the defect. Distinct from ako/mxcli#1459 (fall-through handlers inside branches), same cluster", "refs": ["ako/mxcli#1455", "mendixlabs/mxcli#1558", "ako/mxcli#1459"], "ce": ["CE0079", "CE0773"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-24", "symptom": "`move enumeration Shop.Status to Other;` printed \"Updated enumeration references\" and \"Moved enumeration\", but every reference outside the domain models kept naming the old module: mx check reported CE1613 at a parameter of the enumeration type, a create-variable activity (type and value), an end event returning an enumeration value, and the microflow's return type. Entity attributes of the type were updated (ako/mxcli#1674, split out of ako/mxcli#1671)", "cause": "execMove's dispatch did `return moveEnumeration(…)` for an enumeration, returning before the shared `if isCrossModuleMove { updateQualifiedNameRefs(…) }` sweep that every other document's cross-module move falls through to. moveEnumeration itself only called UpdateEnumerationRefsInAllDomainModels", "file": "`mdl/executor/cmd_move.go` (execMove's enumeration case)", "insight": "When one kind of a shared operation misbehaves, look for an early `return` in the dispatch before the code every case relies on: here two cases returned early, and only one of them (moveEntity) ran its own sweep. The domain-model update the enumeration case did print made the move look complete, so the entity attribute is the right control in a test and not evidence of success. The sweep is whole-value only on its own; an enumeration value inside a longer expression also needs the expression-aware rewrite of ako/mxcli#1671 (measured: this fix alone leaves CE0117 on `$In = X.Open or …`, both together 0 errors)", "refs": ["ako/mxcli#1674", "ako/mxcli#1671"], "ce": ["CE1613", "CE0117"]}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-24", "symptom": "`rename page Shop.Order_Overview to Order_List` (CLI `mxcli rename page` and MDL alike) on a page in a folder named 'Order_Overview' renamed the FOLDER, left the page as it was, printed \"Renamed page: …\" and had already pointed every caller at the new name: mx check CE1613 \"The selected page 'Shop.Order_List' no longer exists\". Same for microflow, nanoflow, constant, enumeration, java action and workflow in a same-named folder; a document in a differently named folder renamed fine", "cause": "The handlers resolved the document among the requested kind (ListPages etc.) only to set a `found` flag, then called RenameDocumentByName(module, oldName, newName), which looked the name up AGAIN over every unit in the module's containers, whatever its $Type, and rewrote the first top-level Name that matched. A Projects$Folder is such a unit, and a FOLDER clause inserts the folder before the document it holds (Unit is a rowid table scanned in insertion order), so the folder won. The reference sweep ran before the document rename, so the damage was done whatever happened next", "file": "mdl/executor/cmd_rename.go (execRenameDocument, execRenameEnumeration, execRenameJavaAction); mdl/backend/modelsdk/infrastructure_write.go (RenameDocument, replacing RenameDocumentByName); mdl/backend/infrastructure.go", "fix": "Remove the second lookup: the handlers keep the ID of the document they found and call RenameDocument(id, oldName, newName), which refuses a Projects$Folder/ModuleImpl unit and a stored Name other than oldName. The document is renamed before the reference sweep, so a refused rename leaves every reference where it was", "insight": "Whether a name-only lookup hits the folder or the document is decided by unit insertion order, not by chance per run: a document created WITH a folder clause loses to its folder, one moved into an existing folder later wins — which is why the issue's enumeration/java action variants (created, then moved) looked fine on main while page/microflow/nanoflow/constant/workflow failed. A regression test must arm that order and assert it as a precondition, or it can pass against the bug. The executor had already answered the question (which document?) — passing that answer down, by ID, deletes the second resolver instead of teaching it about $Type; placement.go's FindDocumentUnit had the same lesson written down. Out of scope and still open on main: RENAME CONSTANT does not rewrite `@Module.Const` inside expressions (CE1613 at the End event, reproduced at module root with no folder) — it was masked here because the constant was never renamed", "refs": ["ako/mxcli#1443", "mendixlabs/mxcli#1545"], "ce": ["CE1613"], "test": "TestRenameDocument_InSameNamedFolder_RenamesTheDocument (mdl/executor/rename_same_named_folder_test.go), TestRename_Page_RefusedDocumentRenameSweepsNothing, TestRename_Page_DryRunRenamesNoDocument (mdl/executor/cmd_rename_mock_test.go), TestRenameDocument_RefusesContainersAndAStaleName (mdl/backend/modelsdk/rename_document_test.go); mdl-examples/bug-tests/rename-1443-same-named-folder.mdl"}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"area": "mdl/executor", "date": "2026-10-24", "symptom": "`call rest service post '…' (Body: $Payload)` sends the eight characters `$Payload` as the request body; `describe` prints `Body: template '$Payload'`. `check`, `exec` and `mx check` all pass — mx check only warns CW0094 \"Variable 'Payload' is never used\". The deprecated `body $Payload` clause, and a URL written as an expression (`@M.BaseUrl + '/rates'`, stored as that text so the request never reaches the server), behave the same", "cause": "`addRestCallAction` (mdl/executor/cmd_microflows_builder_calls.go) turned any non-string-literal URL or custom body into `fb.exprToString(...)` and stored that SOURCE TEXT as the Microflows$StringTemplate's Text, with no parameters. The grammar accepts `Body: <expression>` and `restCallUrl: expression`; the builder treated both as template text", "file": "`mdl/executor/rest_call_templates.go` (`restCallTemplate`, `checkRestCallTemplatesStmt` = MDL-REST05, `restCallAsTemplates`), called from `addRestCallAction`, `validate_microflow.go` (walkBody) and `flow_declared_match.go` (messageAsTemplate); tests `mdl/executor/cmd_microflows_rest_template_expression_test.go`; fixtures `mdl-examples/bug-tests/rest-call-1444-body-variable.mdl`, `rest-call-1444-expression-with-params.fail.mdl`", "insight": "Same rule `log`/`show message`/`validation feedback`/`send email` already applied (literal = template text, anything else = '{1}' with the expression as parameter) — the REST builder was the one template site that never got it, so grep for `exprToString(` assigned to a template's TEXT when auditing the class. The Studio Pro shape is measured, not assumed: ako/TestApp `Mappings.PostCustomRequestTemplate_2` (11.13.0) stores Text '{1}' + one TemplateParameter `$BodyPayload`, the shape the fix now writes (Text '{1}', Parameters marker 2 + one TemplateParameter). Fixing the builder alone is not enough: `create or modify` compares the declared AST with the AST parsed from describe, so `Body: $X` and the described `Body: template '{1}' with ({1} = $X)` must be normalized to one form there too, or every re-run sees a changed activity (the #905 rule). A string literal that spans lines arrives as a SourceExpr around the literal — unwrap it, or `Body: '<multi-line>' with (…)` is mistaken for an expression. Judge it at runtime with an echo server, not by the call's status: the baseline returned 200 with body `$Payload`; `on error continue` swallowed the failed URL request without a log line, so only the echo server's absent request showed it", "refs": ["ako/mxcli#1444", "mendixlabs/mxcli#1546", "ako/mxcli#905"], "rules": ["MDL-REST05"], "test": "TestRestCallBody_ExpressionIsTheTemplatesParameter, TestRestCallURL_ExpressionIsTheTemplatesParameter, TestRestCallTemplate_ExpressionWithParametersIsRefused, TestRestCallBody_ExpressionRoundTripsThroughDescribe, TestDeclaredMatches_RestCallExpressionIsItsTemplate"}
Loading
Loading