Skip to content

Commit c506ab3

Browse files
committed
fix(executor): CE0166 notifyTarget for 11.7.0+, visitor keyword arg parsing
Three fixes for Mendix 11.10.0 compatibility regression (11→10 mx check errors): **CE0166 — notifyTarget (11.7.0+)** - `addNotifyWorkflowActionGen` now detects project version ≥ 11.7.0 and constructs `NotifyWaitForNotificationActivityTarget` via `SetNotifyTarget()`, replacing the deprecated `activity` ByNameRef (version-gated out in 11.7.0). - `version` field added to `flowBuilderGen`; set from `backend.ProjectVersion()` at construction time in both microflow and nanoflow create paths. **visitor keyword arg names** - `buildMicroflowArgV3` now handles keyword-typed parameter names (e.g. `Search` is the `SEARCH` MDL token) via `argCtx.Keyword().GetText()`, preventing empty `arg.Name` when a nanoflow/microflow parameter shares a MDL keyword. **resolveNanoflowByName cache check** - `resolveNanoflowByName` now checks `execCache.createdNanoflows` first, enabling session-local nanoflow resolution in the page builder without a backend round-trip (mirrors the existing microflow cache pattern). **testdata reorganization** - Renamed `helpdesk-golden-clean/` → `helpdesk-golden-11.6.6/` (11.6.6, app, 0 errors) - Added `helpdesk-clean-11.6.6/` (blank 11.6.6 base) - Added `helpdesk-clean-11.10.0/` (blank 11.10.0 base, via mx convert) - Added `helpdesk-golden-11.10.0/` (11.10.0 with app, 10 errors: CE0166 fixed; CE0463×2 + CE0553 + CE1571 + 6 column errors remain as pre-existing known issues) - Removed `helpdesk-golden/` (broken permissions, superseded) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
1 parent 41d1f60 commit c506ab3

1,999 files changed

Lines changed: 14080 additions & 1122 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

cmd/mxcli/examples/helpdesk-app.mdl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
-- Design : docs/superpowers/specs/2026-05-22-helpdesk-app-design.md
99
-- Facts : docs/mendix-platform-reference.md
1010
-- Note : Golden rebuilt after mongo-driver v1→v2 migration (nav_compat bsonD fix)
11+
-- Note : codec.Encoder.Version field added for property-level version gating (new elements only)
12+
-- Note : gen init() VersionRegistry removed; PropertyVersioner interface dispatch replaces global map
1113
--
1214
-- Edge cases covered:
1315
-- Domain : self-ref association, cross-module association,
@@ -1624,3 +1626,5 @@ move microflow HD.ACT_Workflow_ShowAdminPage to folder 'Escalation/WorkflowA
16241626
move microflow HD.ACT_Workflow_Lock to folder 'Escalation/WorkflowAdmin';
16251627
move microflow HD.ACT_Workflow_Unlock to folder 'Escalation/WorkflowAdmin';
16261628
move microflow HD.ACT_Workflow_Notify to folder 'Escalation/WorkflowAdmin';
1629+
1630+
-- Note: golden rebuilt after SortItemList.InitFromRaw BSON key fix (Items→Sortings)

coverage/bench-baseline.txt

Lines changed: 53 additions & 53 deletions
Large diffs are not rendered by default.

mdl-examples/use-cases/helpdesk/helpdesk-app.mdl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
-- Note : Golden rebuilt after mongo-driver v1→v2 migration (nav_compat bsonD fix)
1111
-- Note : codec.Encoder.Version field added for property-level version gating (new elements only)
1212
-- Note : gen init() VersionRegistry removed; PropertyVersioner interface dispatch replaces global map
13+
-- Note : notifyTarget (11.7.0+) replaces activity ByNameRef in notify workflow action
14+
-- Note : visitor keyword arg parsing fixed (Search keyword → arg.Name now captured)
15+
-- Note : testdata reorganised: helpdesk-{clean,golden}-{11.6.6,11.10.0}/ naming scheme
1316
--
1417
-- Edge cases covered:
1518
-- Domain : self-ref association, cross-module association,

mdl/executor/cmd_microflows_create_gen.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import (
4646
"github.com/mendixlabs/mxcli/model"
4747
"github.com/mendixlabs/mxcli/modelsdk/element"
4848
genMf "github.com/mendixlabs/mxcli/modelsdk/gen/microflows"
49+
"github.com/mendixlabs/mxcli/modelsdk/version"
4950
)
5051

5152
// execCreateMicroflowGen handles CREATE MICROFLOW via the gen-typed
@@ -168,6 +169,10 @@ func execCreateMicroflowGen(ctx *ExecContext, s *ast.CreateMicroflowStmt) error
168169
hierarchy, _ := getHierarchy(ctx)
169170
restServices, _ := loadRestServices(ctx)
170171

172+
var mendixVer version.Version
173+
if rpv := ctx.Backend.ProjectVersion(); rpv != nil {
174+
mendixVer = version.Parse(rpv.ProductVersion)
175+
}
171176
fb := &flowBuilderGen{
172177
posX: 200,
173178
posY: 200,
@@ -181,6 +186,7 @@ func execCreateMicroflowGen(ctx *ExecContext, s *ast.CreateMicroflowStmt) error
181186
nanoflowsRepo: ctx.Nanoflows,
182187
hierarchy: hierarchy,
183188
restServices: restServices,
189+
version: mendixVer,
184190
}
185191

186192
// Initialise variable types from parameters so body statements

mdl/executor/cmd_nanoflows_create_gen.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import (
3535
"github.com/mendixlabs/mxcli/model"
3636
"github.com/mendixlabs/mxcli/modelsdk/element"
3737
genMf "github.com/mendixlabs/mxcli/modelsdk/gen/microflows"
38+
"github.com/mendixlabs/mxcli/modelsdk/version"
3839
)
3940

4041
// execCreateNanoflowGen handles CREATE NANOFLOW statements via the
@@ -202,6 +203,10 @@ func execCreateNanoflowGen(ctx *ExecContext, s *ast.CreateNanoflowStmt) error {
202203
hierarchy, _ := getHierarchy(ctx)
203204
restServices, _ := loadRestServices(ctx)
204205

206+
var mendixVer version.Version
207+
if rpv := ctx.Backend.ProjectVersion(); rpv != nil {
208+
mendixVer = version.Parse(rpv.ProductVersion)
209+
}
205210
fb := &flowBuilderGen{
206211
posX: 200,
207212
posY: 200,
@@ -216,6 +221,7 @@ func execCreateNanoflowGen(ctx *ExecContext, s *ast.CreateNanoflowStmt) error {
216221
hierarchy: hierarchy,
217222
restServices: restServices,
218223
isNanoflow: true, // EH defaults to "Abort" instead of "Rollback"
224+
version: mendixVer,
219225
}
220226

221227
// Initialise variable types from parameters so body statements

mdl/executor/cmd_pages_builder_v3.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -639,6 +639,10 @@ func (pb *pageBuilder) buildDataSourceV3(ds *ast.DataSourceV3) (element.Element,
639639
ns := genPg.NewNanoflowSource()
640640
assignFreshID(ns)
641641
ns.SetNanoflowQualifiedName(ds.Reference)
642+
// NOTE: ParameterMappings intentionally left empty. Nanoflow datasource
643+
// parameter mappings require a specific ByNameRef QN format that varies
644+
// by Mendix version; incorrect QNs cause load errors in 11.10.0.
645+
// CE0553/CE1571 remain as pre-existing known issues in the MDL baseline.
642646
return ns, entityName, nil
643647

644648
case "association":
@@ -1157,6 +1161,12 @@ func pageParamBSONType(dt ast.DataType) string {
11571161

11581162
// resolveNanoflowByName resolves a nanoflow qualified name to its ID.
11591163
func (pb *pageBuilder) resolveNanoflowByName(nfName string) (model.ID, error) {
1164+
if pb.execCache != nil && pb.execCache.createdNanoflows != nil {
1165+
if info, ok := pb.execCache.createdNanoflows[nfName]; ok {
1166+
return info.ID, nil
1167+
}
1168+
}
1169+
11601170
parts := strings.Split(nfName, ".")
11611171
var moduleName, name string
11621172
if len(parts) >= 2 {
@@ -2037,6 +2047,11 @@ func (pb *pageBuilder) buildDataGridDataSourceBSON(ds *ast.DataSourceV3) (bson.D
20372047
// Write Nanoflow QN directly at top level, matching the gen NanoflowSource
20382048
// ByNameRef field "Nanoflow". No NanoflowSettings wrapper needed (not in
20392049
// reflection data or gen type schema).
2050+
// NOTE: ParameterMappings intentionally left empty (version-prefixed array
2051+
// with no entries) for now. Nanoflow datasource parameter mapping requires
2052+
// a specific ByNameRef QN format for the parameter that differs between
2053+
// Mendix versions; using an incorrect QN causes a load error in 11.10.0.
2054+
// CE0553/CE1571 are tracked as pre-existing known issues in the MDL baseline.
20402055
doc := bson.D{
20412056
{Key: "$ID", Value: bsonutil.NewIDBsonBinary()},
20422057
{Key: "$Type", Value: "Forms$NanoflowSource"},

mdl/executor/cmd_pages_builder_v3_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,30 @@ import (
1616
"go.mongodb.org/mongo-driver/v2/bson"
1717
)
1818

19+
// newPageBuilderWithNanoflowStub returns a pageBuilder primed with a
20+
// createdNanoflows entry so buildDataSourceV3 can resolve the nanoflow
21+
// without hitting the backend.
22+
func newPageBuilderWithNanoflowStub(qualifiedName string) *pageBuilder {
23+
mb := &mock.MockBackend{}
24+
mb.SerializeGenElemToOpaqueFunc = func(elem element.Element) backend.OpaqueWidget {
25+
enc := codec.Encoder{}
26+
raw, err := enc.Encode(elem)
27+
if err != nil {
28+
return nil
29+
}
30+
return bson.Raw(raw)
31+
}
32+
return &pageBuilder{
33+
execCache: &executorCache{
34+
createdNanoflows: map[string]*createdNanoflowInfo{
35+
qualifiedName: {ID: model.ID("00000000-0000-0000-0000-000000000003"), Name: "NF_Search", ModuleName: "HD"},
36+
},
37+
},
38+
paramEntityNames: map[string]string{"$Search": "HD.TicketSearch"},
39+
widgetBackend: mb,
40+
}
41+
}
42+
1943
// buildTestWidgetV3WithDesignProp creates a WidgetV3 with a single design property.
2044
func buildTestWidgetV3WithDesignProp(key, value string) *ast.WidgetV3 {
2145
w := &ast.WidgetV3{Properties: map[string]interface{}{}}
@@ -279,3 +303,30 @@ func TestDataViewSelectionDatasource_StoresListenTargetSource(t *testing.T) {
279303
t.Errorf("ListenTarget = %q, want artGallery", gotTarget)
280304
}
281305
}
306+
307+
// TestNanoflowDatasourceResolvesViaCache verifies that buildDataSourceV3
308+
// resolves a nanoflow datasource reference using execCache.createdNanoflows,
309+
// enabling session-local resolution without a backend round-trip.
310+
func TestNanoflowDatasourceResolvesViaCache(t *testing.T) {
311+
pb := newPageBuilderWithNanoflowStub("HD.NF_TicketSearch_Apply")
312+
pb.widgetScope = map[string]model.ID{}
313+
314+
ds := &ast.DataSourceV3{
315+
Type: "nanoflow",
316+
Reference: "HD.NF_TicketSearch_Apply",
317+
Args: []ast.FlowArgV3{{Name: "Search", Value: "$Search"}},
318+
}
319+
320+
elem, _, err := pb.buildDataSourceV3(ds)
321+
if err != nil {
322+
t.Fatalf("buildDataSourceV3 nanoflow: %v", err)
323+
}
324+
325+
ns, ok := elem.(*genPg.NanoflowSource)
326+
if !ok {
327+
t.Fatalf("buildDataSourceV3 nanoflow: got %T, want *NanoflowSource", elem)
328+
}
329+
if ns.NanoflowQualifiedName() != "HD.NF_TicketSearch_Apply" {
330+
t.Errorf("NanoflowQualifiedName = %q", ns.NanoflowQualifiedName())
331+
}
332+
}

mdl/executor/flowbuilder_gen.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ import (
5353
"github.com/mendixlabs/mxcli/model"
5454
"github.com/mendixlabs/mxcli/modelsdk/element"
5555
genMf "github.com/mendixlabs/mxcli/modelsdk/gen/microflows"
56+
"github.com/mendixlabs/mxcli/modelsdk/version"
5657
)
5758

5859
// flowBuilderGen builds the flow graph from AST statements using
@@ -155,6 +156,11 @@ type flowBuilderGen struct {
155156
// nonPersistentEntities is lazily loaded on first isNonPersistentEntity call.
156157
// nil means not yet loaded; empty map means loaded but all entities are persistent.
157158
nonPersistentEntities map[string]bool
159+
160+
// version is the Mendix project version, used for version-gated BSON
161+
// property selection (e.g. notifyTarget introduced in 11.7.0).
162+
// Zero value means treat as oldest supported version.
163+
version version.Version
158164
}
159165

160166
// pendingErrorHandlerStateGen is the gen-typed equivalent of

mdl/executor/flowbuilder_workflow_gen.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import (
3636
"github.com/mendixlabs/mxcli/modelsdk/element"
3737
genMf "github.com/mendixlabs/mxcli/modelsdk/gen/microflows"
3838
genWf "github.com/mendixlabs/mxcli/modelsdk/gen/workflows"
39+
"github.com/mendixlabs/mxcli/modelsdk/version"
3940
)
4041

4142
// wrapActionGen wraps a gen action element in an ActionActivity at the
@@ -196,14 +197,23 @@ func (fb *flowBuilderGen) addOpenUserTaskActionGen(s *ast.OpenUserTaskStmt) elem
196197
}
197198

198199
// addNotifyWorkflowActionGen emits `notify workflow ...`.
200+
// In Mendix 11.7.0+ the deprecated `activity` ByNameRef was replaced by the
201+
// `notifyTarget` Part element (Workflows$NotifyWaitForNotificationActivityTarget).
199202
func (fb *flowBuilderGen) addNotifyWorkflowActionGen(s *ast.NotifyWorkflowStmt) element.ID {
200203
action := genMf.NewNotifyWorkflowAction()
201204
assignFreshID(action)
202205
action.SetErrorHandlingType(convertErrorHandlingTypeGen(s.ErrorHandling))
203206
action.SetOutputVariableName(s.OutputVariable)
204207
action.SetWorkflowVariable(s.WorkflowVariable)
205208
if s.ActivityQualifiedName != "" {
206-
action.SetActivityQualifiedName(s.ActivityQualifiedName)
209+
if fb.version.Compare(version.Parse("11.7.0")) >= 0 {
210+
target := genWf.NewNotifyWaitForNotificationActivityTarget()
211+
assignFreshID(target)
212+
target.SetActivityQualifiedName(s.ActivityQualifiedName)
213+
action.SetNotifyTarget(target)
214+
} else {
215+
action.SetActivityQualifiedName(s.ActivityQualifiedName)
216+
}
207217
}
208218
return fb.wrapActionGen(action, s.ErrorHandling)
209219
}

mdl/executor/flowbuilder_workflow_gen_test.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/mendixlabs/mxcli/mdl/ast"
1515
genMf "github.com/mendixlabs/mxcli/modelsdk/gen/microflows"
1616
genWf "github.com/mendixlabs/mxcli/modelsdk/gen/workflows"
17+
"github.com/mendixlabs/mxcli/modelsdk/version"
1718
)
1819

1920
func newTestFlowBuilderGen() *flowBuilderGen {
@@ -22,6 +23,12 @@ func newTestFlowBuilderGen() *flowBuilderGen {
2223
}
2324
}
2425

26+
func newTestFlowBuilderGenWithVersion(v string) *flowBuilderGen {
27+
fb := newTestFlowBuilderGen()
28+
fb.version = version.Parse(v)
29+
return fb
30+
}
31+
2532
func TestWrapActionGenAdvancesPosAndAssignsActivity(t *testing.T) {
2633
fb := newTestFlowBuilderGen()
2734
startX := fb.posX
@@ -251,6 +258,32 @@ func TestAddNotifyWorkflowActionGenSetsActivityQN(t *testing.T) {
251258
}
252259
}
253260

261+
// TestAddNotifyWorkflowActionGenUsesNotifyTargetOnV11_7 verifies that on
262+
// Mendix 11.7.0+ the executor sets the notifyTarget Part instead of the
263+
// deprecated activity ByNameRef (which is version-gated out in 11.7+).
264+
func TestAddNotifyWorkflowActionGenUsesNotifyTargetOnV11_7(t *testing.T) {
265+
fb := newTestFlowBuilderGenWithVersion("11.7.0")
266+
stmt := &ast.NotifyWorkflowStmt{
267+
WorkflowVariable: "WF",
268+
OutputVariable: "IsReceived",
269+
ActivityQualifiedName: "HD.WF_TicketEscalation.WaitForManagerAvailable",
270+
}
271+
fb.addNotifyWorkflowActionGen(stmt)
272+
act := fb.objects[0].(*genMf.ActionActivity).Action().(*genMf.NotifyWorkflowAction)
273+
274+
target := act.NotifyTarget()
275+
if target == nil {
276+
t.Fatal("notifyTarget must be set for Mendix 11.7.0+")
277+
}
278+
nt, ok := target.(*genWf.NotifyWaitForNotificationActivityTarget)
279+
if !ok {
280+
t.Fatalf("notifyTarget type = %T, want *NotifyWaitForNotificationActivityTarget", target)
281+
}
282+
if nt.ActivityQualifiedName() != "HD.WF_TicketEscalation.WaitForManagerAvailable" {
283+
t.Fatalf("notifyTarget activity QN = %q", nt.ActivityQualifiedName())
284+
}
285+
}
286+
254287
func TestAddOpenWorkflowActionGenSetsField(t *testing.T) {
255288
fb := newTestFlowBuilderGen()
256289
stmt := &ast.OpenWorkflowStmt{WorkflowVariable: "WF"}

0 commit comments

Comments
 (0)