diff --git a/CHANGELOG.md b/CHANGELOG.md index 30ebae9..30dc689 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ three commits past it), and a bug report can name a release instead of a sha nob Sections dated before 2026-09-19 predate the cycle and stay as they are. ## Unreleased +- learn(skills/learned-microflow-patterns.md): **expression functions take positional arguments only — `toString(from: $X)` is not a syntax error, it's a silent misparse.** MDL's expression grammar has no named-argument form for function calls; `label: value` parses as `label` (a bare unresolved identifier) COLON-divided by `value` — COLON being the OQL division operator. Verified on mxcli v0.24.0 / Mendix 11.12.1, scratch copy of a PoC model: `toString(from: $Temperature)` and `formatDateTime($D, pattern: 'yyyy-MM-dd')` both pass `mxcli check --references` silently (exit 0) because the collapsed argument count still matches the function's arity; `substring(from: $S, index: 0, length: 3)` fails, but with a misleading `E006` ("expects 2 to 3 argument(s), got 1") that never names labelled arguments as the cause. The likely source: labelled-colon syntax is genuine MDL elsewhere (page `Attribute:`/`Action: MICROFLOW Name(Param: val)`, `@anchor(from: bottom, to: top)`) — just never inside an expression — workshop feedback, Sep 2026 - learn(skills/learned-file-upload-widget.md): **a file upload mxcli can author, with proof that it uploads.** The Mendix File Uploader 2.5.0 bound to a `System.FileDocument` specialisation: the MDL shape (entities, grants, create/delete microflows, advanced formats), which upload widgets mxcli cannot author (classic FileManager, PDS uploader), the two traps with workarounds (a simple-mode `allowedfileformat` passes exec and fails `mx check` with CE0463; an uploader DESCRIBE will not re-exec, `exposes 2 datasources`), and the six-step upload instrument. Field run on stock v0.24.0: the section-4 MDL taken verbatim from the skill gave `mx check` 0 errors, 2/2 files stored, 2/2 downloads sha256-equal, `.csv` rejected with 0 rows; both traps reproduce unchanged on v0.24.0 — a Mendix app-rebuild project - new(skills/mendix-best-practices-index.md): **one row per Mendix best-practice area: the Mendix docs page, the bundled `assess-quality` section, the toolkit skill that applies it before the write, and the `mxcli lint` rule that catches it after exec.** An index, not a copy — the practice text stays on the Mendix pages (17 URLs verified HTTP 200 on 2026-09-25) and in the mxcli-bundled skill; Mendix's own Best Practice Recommender rules (MXP001–016) anchor the performance rows, and four rows say out loud that no lint rule exists and the preflight checklist is the only check. Routed `all` agents, stages 3/5/6, group reference — Maurits Visser - learn(skills/microflow-preflight.md, agents/mdl-agent.md): **a microflow now gets a tier before any MDL — Simple, Guided or Split-first — and Split-first means a posted split plan (thin orchestrator + one `SUB_` per responsibility, with signatures) that the user confirms first.** Prompted by a colleague's session refusing a long microflow as "too difficult" while the same task went through on a stronger model: the piece was too big, not the task. mdl-agent gains two rules — never hand back "too difficult", hand back the split plan; escalate one failing `SUB_` by name after one retry, never the whole script. Also records the mxcli team's answer on positioning: a standalone `mxcli layout` command — which on v0.24.0 and upstream main (2026-09-25) arranges domain models only (`--dry-run` on a scratch copy of a PoC model: 10 entity moves, no microflow), so the no-`@position` rule and the if-branch workaround stand until a microflow mode ships; noted in the bug ledger and `learned-microflow-patterns.md` — Maurits Visser diff --git a/skills/learned-microflow-patterns.md b/skills/learned-microflow-patterns.md index 8d42d6f..a28b132 100644 --- a/skills/learned-microflow-patterns.md +++ b/skills/learned-microflow-patterns.md @@ -459,6 +459,36 @@ This applies anywhere an enum value flows into a String context: concatenation, --- +## Expression Functions Take Positional Arguments Only — Never `name: value` + +**Bug (verbatim, from field feedback):** + +```mdl +set $JSON = $JSON + ',"temperature":' + toString(from: $Temperature); +``` + +**Rule:** every built-in Mendix expression function — `toString($X)`, `formatDateTime($D, 'yyyy-MM-dd')`, `substring($S, 0, 3)`, `length()`, `contains()`, etc. — takes **positional arguments only**. There is no `name: value` form inside an expression. That labelled-colon shape is real MDL syntax elsewhere — page properties (`Attribute: Name`), page actions (`Action: MICROFLOW Mod.Flow(Param: val)`), and annotations (`@anchor(from: bottom, to: top)`) all use it — which is almost certainly where the habit leaks in from. Inside an *expression*, a bare `name:` is not a label at all: `mxcli`'s expression grammar has no named-argument production for function calls (`argumentList: expression (COMMA expression)*`), so it parses `label: value` as `label` (an unresolved bare identifier) **`:`-divided by** `value` — COLON is the OQL division operator — one silently wrong expression, not an error. + +**This is not reliably caught by `mxcli check`, including `--references`.** Verified on mxcli v0.24.0 / Mendix 11.12.1: + +| Written | `mxcli check --references` | +|---|---| +| `toString(from: $Temperature)` | **Passes silently** (exit 0, "✓ All references valid" / "Check passed!") — parsed as `toString(from : $Temperature)`, one bogus division argument, argument count still matches `toString`'s arity of 1 | +| `formatDateTime($D, pattern: 'yyyy-MM-dd')` | **Passes silently** — same mechanism, second argument's label/value pair still counts as one argument, matching `formatDateTime`'s arity of 2 | +| `substring(from: $S, index: 0, length: 3)` (or any label, e.g. `src:` — not keyword-specific) | **Fails**, but with a misleading message that never names the real cause: `substring() expects 2 to 3 argument(s), got 1. [E006]` | + +A labelled call that happens to land on the function's normal arity round-trips through `mxcli check`/`describe microflow` clean and reaches real `mx check`/Studio Pro/mxbuild before anyone notices — where the bare identifier (`from`, `pattern`, …) fails as an undefined rule/constant reference. Only a call whose label count doesn't match the arity gets a (misleadingly worded) error from `mxcli check` itself. Treat any `name:` inside a function call's parentheses as a STOP regardless of whether `mxcli check` complained — grep the expression for `[A-Za-z]\w*:\s` before trusting a clean check. + +```mdl +-- WRONG — silently misparsed, not a syntax error: +set $JSON = $JSON + ',"temperature":' + toString(from: $Temperature); + +-- CORRECT: +set $JSON = $JSON + ',"temperature":' + toString($Temperature); +``` + +--- + ## CHANGE activity: clear a String attribute — use `empty` not `''` Setting a String attribute to empty string via `''` in a CHANGE activity causes CE0117: