Skip to content

Commit 9defa89

Browse files
committed
Merge remote-tracking branch 'origin/main' into HEAD
2 parents 4bc8c00 + 3e384be commit 9defa89

31 files changed

Lines changed: 3236 additions & 466 deletions

.claude/skills/debug-bson.md

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Use when encountering:
99
- **Studio Pro crash on open** with `RevStatusCache.CreateDeleteStatusItem` in stack trace
1010
- **`mx diff` crash** with "Sequence contains no matching element"
1111
- **CE1613** "The selected attribute/enumeration no longer exists"
12+
- **CE0115** "The arguments that are passed to page X do not match the expected parameters"
1213
- **CE0463** "The definition of this widget has changed"
1314
- **CE0642** "Property X is required"
1415
- **CE0091** validation errors on widget properties
@@ -306,6 +307,51 @@ for t, props in crash_props.items():
306307

307308
**Fix**: Extract a fresh template from a project with `mx update-widgets` applied. The Type section must match the installed widget version exactly.
308309

310+
### CE0115: Arguments Passed to Page Do Not Match Expected Parameters
311+
312+
**Symptom**: `mx check` reports `[CE0115] "The arguments that are passed to page 'X' do not match the expected parameters."` on an action button that uses `show_page TargetPage (Param: $currentObject)`.
313+
314+
**Root cause**: The BSON array type indicator rule. Every Mendix BSON array must begin with an `int32` **type indicator** of `2` or `3`. This indicator is skipped by `extractBsonArray` and by Studio Pro's reader. Writing `int32(len(items))` as the first element instead produces an invalid indicator when `len ≠ 2` and `len ≠ 3` — Studio Pro cannot recognise the array and reads 0 parameter mappings.
315+
316+
**Type indicator values**:
317+
| First element | Meaning |
318+
|---------------|---------|
319+
| `int32(3)` | Initialized array — used for `Items`, `DesignProperties`, and most non-empty lists |
320+
| `int32(2)` | Initialized empty array — used for `ParameterMappings`, `PagesForSpecializations`, `Parameters` |
321+
| Any other value | **Invalid** — Studio Pro ignores the entire array |
322+
323+
**How Studio Pro stores page parameter mappings**: Studio Pro does **not** store explicit `Forms$PageParameterMapping` objects in BSON. It always writes `ParameterMappings: [2]` (type indicator only, no inline objects) and infers `$currentObject` at runtime from the enclosing widget context — DataGrid row, DataView datasource, etc. No matter what the MDL source specifies for `(Param: $currentObject)`, the correct serialization is always the empty `[2]` array.
324+
325+
**Correct writer pattern for `Forms$FormAction`**:
326+
```go
327+
formSettings := bson.D{
328+
{Key: "$ID", Value: idToBsonBinary(generateUUID())},
329+
{Key: "$Type", Value: "Forms$FormSettings"},
330+
{Key: "Form", Value: pageName}, // BY_NAME_REFERENCE
331+
{Key: "ParameterMappings", Value: bson.A{int32(2)}}, // always empty; runtime infers mapping
332+
{Key: "TitleOverride", Value: nil},
333+
}
334+
return bson.D{
335+
{Key: "$ID", Value: idToBsonBinary(id)},
336+
{Key: "$Type", Value: "Forms$FormAction"},
337+
{Key: "DisabledDuringExecution", Value: true},
338+
{Key: "FormSettings", Value: formSettings},
339+
{Key: "NumberOfPagesToClose2", Value: ""},
340+
{Key: "PagesForSpecializations", Value: bson.A{int32(2)}},
341+
}
342+
```
343+
344+
**What NOT to do**:
345+
```go
346+
// WRONG: produces [1, {mapping}] — invalid type indicator 1
347+
paramMappings := bson.A{int32(len(a.ParameterMappings))}
348+
for _, pm := range a.ParameterMappings {
349+
paramMappings = append(paramMappings, bson.D{...Forms$PageParameterMapping...})
350+
}
351+
```
352+
353+
**Diagnostic check**: Inspect the raw `ParameterMappings` array in a Python BSON dump. If it shows `[1, {...}]` instead of `[2]`, the type indicator is wrong. Studio Pro-generated pages always show `[2]`.
354+
309355
## Key Principles
310356

311357
1. **Template cloning > building from scratch**: Clone properties from a known-good template Object, then modify only specific values. Building from scratch produces subtly different structures.

mdl-examples/bug-tests/295-showpage-null-variable.mdl

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,45 @@
88
-- a non-null Forms$PageVariable embedded object in its Variable field.
99
--
1010
-- Run with: mxcli check 295-showpage-null-variable.mdl
11+
create module bug295;
1112

12-
CREATE SNIPPET AuditTrail.LogViewer (
13-
Folder: 'Snippets'
13+
create persistent entity bug295.Product (
14+
/** Auto-incrementing product ID */
15+
ProductId: autonumber default 1,
16+
/** Product name (required) */
17+
Name: string(200) not null error 'Product name is required'
18+
);
19+
20+
-- Target page that accepts an entity parameter.
21+
CREATE PAGE bug295.Product_Detail (
22+
Title: 'Product Detail',
23+
Url: 'Product_Detail',
24+
layout: Atlas_Core.Atlas_Default,
25+
Params: { $Product: bug295.Product }
26+
) {
27+
DATAVIEW dv1 (DataSource: $Product) {
28+
DYNAMICTEXT txt1 (Content: '$Product/Name')
29+
}
30+
};
31+
32+
-- Overview page with a DataGrid column button that opens the detail page
33+
-- and passes $currentObject as the page parameter. This is the scenario
34+
-- that previously produced a null PageParameterMapping.Variable in BSON.
35+
CREATE PAGE bug295.Product_Overview (
36+
Title: 'Products',
37+
Url: 'Product_Overview',
38+
layout: Atlas_Core.Atlas_Default
1439
) {
15-
DATAVIEW dv1 (DataSource: $Log, Editable: false) {
16-
ACTIONBUTTON btn_open (
17-
Caption: 'Open log detail',
18-
Action: SHOW_PAGE AuditTrail.Log_View(Log: $currentObject)
19-
)
40+
DATAGRID dg1 (
41+
DataSource: bug295.Product,
42+
Caption: 'Products'
43+
) {
44+
COLUMN colName (Attribute: Name, Caption: 'Name')
45+
COLUMN colActions (Caption: 'Actions') {
46+
ACTIONBUTTON btnDetail (
47+
Caption: 'Detail',
48+
Action: SHOW_PAGE bug295.Product_Detail (Product: $currentObject)
49+
)
50+
}
2051
}
2152
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
-- ============================================================================
2+
-- Bug #306: Annotations emitted before unsupported-activity comments
3+
-- ============================================================================
4+
--
5+
-- Symptom (before fix):
6+
-- Activities whose BSON type isn't yet implemented in mxcli's describer
7+
-- render as `-- unsupported: <Type>` comments. Before the fix, the
8+
-- describer still prefixed these comment lines with `@position`,
9+
-- `@anchor`, etc. The grammar only accepts annotations as prefixes of
10+
-- real microflow statements (not comments), so the resulting MDL failed
11+
-- to re-parse with errors like:
12+
-- line N:0 mismatched input '@' expecting {...}
13+
--
14+
-- After fix:
15+
-- When a formatted statement begins with `--`, `emitObjectAnnotations`
16+
-- is skipped — only the comment is emitted. Annotations on SUPPORTED
17+
-- activities continue to be emitted as before.
18+
--
19+
-- Reproducibility note:
20+
-- The unsupported-activity branch can only be triggered by an .mpr
21+
-- containing a BSON activity type that mxcli does not yet describe
22+
-- (typical examples are very new or rarely-used activity types). Pure
23+
-- MDL cannot create such an activity. The Go-side regression
24+
-- `TestTraverseFlow_UnsupportedActivitySkipsAnnotations` covers that
25+
-- path directly.
26+
--
27+
-- This script provides a POSITIVE CONTROL: a microflow whose every
28+
-- activity carries position / caption / anchor annotations. Its describe
29+
-- output must (a) parse with `mxcli check`, and (b) round-trip cleanly,
30+
-- confirming the annotation-emission codepath still works for the
31+
-- common case.
32+
--
33+
-- Usage:
34+
-- mxcli exec mdl-examples/bug-tests/306-describer-annotations-before-unsupported-comment.mdl -p app.mpr
35+
-- mxcli -p app.mpr -c "describe microflow BugTest306.MF_AnnotatedFlow"
36+
-- The output must re-execute cleanly against the same project.
37+
-- ============================================================================
38+
39+
create module BugTest306;
40+
41+
create microflow BugTest306.MF_AnnotatedFlow (
42+
$input: string
43+
)
44+
returns string as $result
45+
begin
46+
declare $result string = empty;
47+
48+
@caption 'log entry'
49+
log info node 'BugTest306' 'flow started';
50+
51+
@caption 'guard'
52+
if $input != empty then
53+
@caption 'happy path'
54+
set $result = 'value: ' + $input;
55+
else
56+
set $result = 'no value';
57+
end if;
58+
59+
return $result;
60+
end;
61+
/
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
-- ============================================================================
2+
-- Bug #320: DESCRIBE emitted default anchor fragments redundantly
3+
-- ============================================================================
4+
--
5+
-- Symptom (before fix):
6+
-- `describe microflow` printed `@anchor` lines for every activity, even
7+
-- when every from/to side matched the MDL default for that flow shape:
8+
-- - regular sequence flows default to `from: right, to: left`
9+
-- - true branches of IF default to `from: right, to: left`
10+
-- - false branches of IF default to `from: bottom, to: top`
11+
-- Output looked like
12+
-- log info node 'X' 'a';
13+
-- @anchor(from: right, to: left) -- noise: this is the default
14+
-- log info node 'X' 'b';
15+
-- producing verbose, non-author-friendly DESCRIBE output and noisy
16+
-- `mxcli diff-local` runs after a roundtrip.
17+
--
18+
-- After fix:
19+
-- `emitAnchorAnnotation` and `emitSplitAnchorAnnotation` (in
20+
-- cmd_microflows_show_helpers.go) suppress fragments that match the
21+
-- default and skip the entire annotation when all sides are defaults.
22+
-- Non-default sides (e.g. `to: top` on a return) are still emitted.
23+
--
24+
-- Usage:
25+
-- mxcli exec mdl-examples/bug-tests/320-describer-suppress-default-anchor-fragments.mdl -p app.mpr
26+
--
27+
-- mxcli -p app.mpr -c "describe microflow BugTest320.MF_LinearDefaults"
28+
-- The output must contain NO `@anchor` line — every flow uses defaults.
29+
--
30+
-- mxcli -p app.mpr -c "describe microflow BugTest320.MF_NonDefaultReturn"
31+
-- The output must keep `@anchor(to: top)` on the return statement.
32+
-- ============================================================================
33+
34+
create module BugTest320;
35+
36+
-- Linear flow, all defaults — describe must emit zero @anchor lines.
37+
create microflow BugTest320.MF_LinearDefaults ()
38+
begin
39+
log info node 'BugTest320' 'a';
40+
log info node 'BugTest320' 'b';
41+
log info node 'BugTest320' 'c';
42+
end;
43+
/
44+
45+
-- One non-default `to: top` on the return — describe must keep that fragment.
46+
create microflow BugTest320.MF_NonDefaultReturn (
47+
$value: integer
48+
)
49+
returns boolean as $ok
50+
begin
51+
log info node 'BugTest320' 'check';
52+
@anchor(to: top)
53+
return $value > 0;
54+
end;
55+
/
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
-- ============================================================================
2+
-- Bug #322: Multiline source expression whitespace lost on roundtrip
3+
-- ============================================================================
4+
--
5+
-- Symptom (before fix):
6+
-- The visitor rebuilt expression strings from parsed expression nodes,
7+
-- so original line breaks and whitespace inside DECLARE initial values
8+
-- and LOG template parameters were normalized away. A multiline
9+
-- `declare $X string = ...` statement that authors had carefully
10+
-- formatted across several lines came back as a single very long line
11+
-- after describe → exec → describe. Inter-parameter blank lines in
12+
-- `LOG ... WITH (...)` were similarly collapsed, making real-world
13+
-- microflows non-fixpoint and producing noisy `mxcli diff-local` output.
14+
--
15+
-- After fix:
16+
-- Added a `SourceExpr` AST node that wraps an expression with its
17+
-- original source text. The visitor uses `buildSourceExpression` for
18+
-- source-sensitive declare/log/while expressions, and the executor
19+
-- serializes `SourceExpr` through to MDL output so the original
20+
-- whitespace and line breaks survive every roundtrip.
21+
--
22+
-- Usage:
23+
-- mxcli exec mdl-examples/bug-tests/322-multiline-source-expression-whitespace.mdl -p app.mpr
24+
-- mxcli -p app.mpr -c "describe microflow BugTest322.MF_MultilineDeclare"
25+
-- mxcli -p app.mpr -c "describe microflow BugTest322.MF_MultilineLogTemplate"
26+
-- The describe outputs must keep the multiline shape and must be
27+
-- fixpoints under describe → exec → describe.
28+
-- ============================================================================
29+
30+
create module BugTest322;
31+
32+
-- DECLARE initial value spread across several lines with leading `+`. The
33+
-- describer must preserve the line breaks rather than collapse them onto
34+
-- one line.
35+
create microflow BugTest322.MF_MultilineDeclare (
36+
$Page: integer,
37+
$Token: string
38+
)
39+
returns string as $Endpoint
40+
begin
41+
declare $Endpoint string = '/api/v1'
42+
+ '/items?page=' + toString($Page)
43+
+ '&token=' + $Token;
44+
45+
return $Endpoint;
46+
end;
47+
/
48+
49+
-- LOG template parameters separated by a blank line. The newline-only
50+
-- whitespace between `{1} = toString($Count)` and the next parameter must
51+
-- survive the roundtrip.
52+
create microflow BugTest322.MF_MultilineLogTemplate (
53+
$Count: integer,
54+
$Endpoint: string
55+
)
56+
begin
57+
log info node 'BugTest322' 'Processed {1} items for {2}' with ({1} = toString($Count)
58+
59+
, {2} = $Endpoint);
60+
end;
61+
/
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
-- ============================================================================
2+
-- Bug #326: Describer paired splits with downstream merge instead of nearest
3+
-- ============================================================================
4+
--
5+
-- Symptom (before fix):
6+
-- When a microflow had two sequential `if ... end if;` blocks, the
7+
-- describer could pair the FIRST split with the SECOND merge, nesting
8+
-- the continuation between the two ifs (and even the second if) inside
9+
-- the first if's body. A describe → exec → describe cycle then mutated
10+
-- the structure even though the original graph was valid:
11+
-- -- before fix, after first describe:
12+
-- if $Logo != empty then
13+
-- log info node 'App' 'logo';
14+
-- log info node 'App' 'after logo'; -- wrong: was outside first if
15+
-- if $Cover != empty then -- wrong: was sibling, not nested
16+
-- log info node 'App' 'cover';
17+
-- end if;
18+
-- end if;
19+
--
20+
-- Root cause:
21+
-- Split/merge pairing picked any common downstream merge reachable from
22+
-- both branches, not the nearest one. Error-handler flows were included
23+
-- in the search, biasing it further.
24+
--
25+
-- After fix:
26+
-- `findMergeForSplit` now uses shortest-path distances per branch and
27+
-- selects the nearest common merge, ignoring error-handler flows for
28+
-- structural pairing.
29+
--
30+
-- Usage:
31+
-- mxcli exec mdl-examples/bug-tests/326-describer-pair-split-with-nearest-merge.mdl -p app.mpr
32+
-- mxcli -p app.mpr -c "describe microflow BugTest326.MF_SequentialIfs"
33+
-- The describe output must keep the two `if ... end if;` blocks as
34+
-- siblings (with the `log` between them at top level), and the
35+
-- describe → exec → describe cycle must be a fixpoint.
36+
-- ============================================================================
37+
38+
create module BugTest326;
39+
40+
create microflow BugTest326.MF_SequentialIfs (
41+
$Logo: string,
42+
$Cover: string
43+
)
44+
begin
45+
if $Logo != empty then
46+
log info node 'BugTest326' 'logo';
47+
end if;
48+
49+
log info node 'BugTest326' 'after logo';
50+
51+
if $Cover != empty then
52+
log info node 'BugTest326' 'cover';
53+
end if;
54+
end;
55+
/

0 commit comments

Comments
 (0)