docs(wiki): digest the mdl/grammar findings into three bug-pattern pages - #359
Merged
Merged
Conversation
`filter($L, Amount > 0)` was stored as `Microflows$FilterByExpression` with the authored text verbatim. Mendix evaluates that expression once per item with the item bound to `$currentObject`, where a bare attribute name is not valid — so mxbuild reported CE0117 while `mxcli check` passed. This is the unfinished half of bug #343. That fix rerouted `attr = value` to `Microflows$Filter` (filter BY ATTRIBUTE), which takes a member name rather than an expression and so accepts the bare form. Every other predicate still fell through to the expression shape, which made the split turn on the OPERATOR and be invisible to the author: `Status = 'x'` built and `Status != 'x'` did not. Not a Mendix version change, despite the report: the same 19-microflow probe produces the identical 7 errors on mxbuild 11.11.0 and 11.13.0. - A bare name that provably resolves to a member of the list's element entity is rewritten to `$currentObject/<member>` (an association keeps its module qualifier, an attribute does not). A name that does not resolve is refused rather than left to surface as CE0117. When the element entity cannot be determined nothing is proven either way, so the predicate is passed through. - The predicate can reach the builder as a frozen `SourceExpr`, so the rewrite patches the source text too, skipping single-quoted literals — the `'Amount'` in `filter($L, Qty > 0 and Status != 'Amount')` must survive untouched. - MDL-LISTOP01 refuses an iterator variable that is not in scope, pre-empting CE0109. It keys on scope rather than on the name, so `$item` stays valid as an enclosing loop's iterator — the shape of CLAUDE.md's O(N) `find` idiom. - The `syntax microflow.list-operations` example no longer teaches a form that only compiles through the `=` reroute, and notes that SORT is not an expression, so a bare attribute is the only spelling there. Control: stubbing the qualifier takes the repro from 0 to 7 × CE0117 with the two `=` cases staying green, which is also the #343 regression guard. Repros: mdl-examples/bug-tests/1002-filter-find-bare-attribute.mdl (0 errors on mxbuild 11.13.0) and 1002-filter-bad-iterator.fail.mdl. Closes mendixlabs#1002 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017s476QkXr9CFMvKspVzcvu
Follow-up to the mendixlabs#1002 fix, covering the surfaces a user actually hits the new messages from. - docs-site error-messages appendix: MDL-LISTOP01 under "mxcli Check Errors" (alongside the MDL-WIDGET rules), and the unresolvable-bare-name refusal under "mxcli Execution Errors". The MDL-LISTOP01 entry spells out that the rule keys on scope rather than on the name, so `$item` as an enclosing loop's iterator is not flagged. - `mxcli syntax errors.execution`: both errors with their cause and fix, and CE0117/CE0109/MDL-LISTOP01 as keywords on that topic and on microflow.list-operations — keywords are emitted in the `--json` index that agents cache, so a CE number now leads back to the right topic (the CE0133 precedent). - CLAUDE.md: the always-in-context O(N) `find` idiom uses `$item`, which reads like something MDL-LISTOP01 forbids. One clause records that the iterator there is in scope and stays valid, so the documented idiom is not "fixed" into something worse later. No list-operations page exists under docs-site/src/language/, and the check rules do not appear in `mxcli lint --list-rules` (verified), so neither needed a change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017s476QkXr9CFMvKspVzcvu
fix(mdl): a bare attribute in FILTER/FIND built an expression Mendix rejects (mendixlabs#1002)
49 of the 53 mdl/grammar findings (92%) now fall under a named class. Three pages are new; the rest reuse describe-round-trip-gaps and silent-property-drop. - capability-gap-as-parse-error (36 touched, ~20 primary). The distinctive one. Someone tries to express something Mendix supports, the parser says `no viable alternative`, and they conclude the FEATURE is impossible — a parse error is indistinguishable from a mistake they made. So the reports in this class are not feature requests, they are workarounds: an admin screen hand-rolled as five pages because a tab container was believed not to exist, "use a Java action" for a binary upload, "go to Studio Pro" as the standing answer to translation, a headless pipeline ending in a manual step. The gap is bidirectional — DESCRIBE of a document that HAS the construct must do something, and in the mapping findings it emitted MDL that parsed and rebuilt a different document, which is worse than a parse error. Also records that a narrow/wide statement pair (SET vs REPLACE) is a whitelist extended one bug report at a time, and that "not in the metamodel" is not a conclusion until the namespace is right. - keyword-collisions (22 touched, ~8 primary). The distinguishing question is how a collision fails, not whether one happens: a parse error is recoverable, a different valid parse is not — a widget conditional calling trim() was silently dropped. Records that a grammar alternative and its visitor case are ONE change (accepting -7 without the AST case serialized `[Amount > ]`), and the control-binary sweep for proving a relaxation causes no regressions. - scripts-that-cannot-rerun (5). Statement-level idempotence, kept deliberately apart from ADR-0008's write-level idempotence, which is what people usually mean when they say mxcli is idempotent. `exec` halting on the first error turns "90% already applied" into "none of the remaining 10% applied", and the silent variant — a duplicated index — is worse than the error. Coverage stated in CLAUDE.md was corrected to the measured 92% before committing; the first draft claimed 98% from memory. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stacked on #358 — and note that #356, #357 and #358 are all still open (
mainis at #352). This branch also merges currentmainin, so the chain stays current.49 of the 53
mdl/grammarfindings (92%) now fall under a named class. Three pages are new; the rest reusedescribe-round-trip-gapsandsilent-property-drop.no viable alternative— and the user concludes the feature is impossiblecapability-gap-as-parse-error
The distinctive class in this area, and the one with the clearest cost. A parse error is indistinguishable from a mistake the user made, so the reports are not feature requests — they are workarounds:
The gap is bidirectional. MDL not being able to write a construct is half of it —
DESCRIBEof a document that has one must do something, and dropping it silently is the common outcome. In the mapping findings it did worse: emitted MDL that parsed and rebuilt a different document, which looks like a successful round trip and is not.Two method points recorded: a narrow/wide statement pair is a whitelist that gets extended one bug report at a time (
SETvsREPLACE), so the fix is to reuse the wide rule rather than add another case to the narrow one; and "not in the metamodel" is not a conclusion until the namespace is right — a grep under one prefix ruled out a capability that lives under another, and one 4 KB Studio Pro unit settled in minutes what the grep had "disproved".keyword-collisions
A parse error is recoverable — the user quotes the name. The same collision resolving to a different valid parse is not: a widget conditional calling
trim()was silently dropped, so the page lost its visibility rule and built cleanly.A grammar alternative and its visitor case are one change. Accepting an unquoted
-7in XPath without the matching AST case made the constraint serialize as[Amount > ]— a dropped operand instead of a loud error, caught only because the visitor has a round-trip helper. And a relaxation is proven with a control binary (stash the.g4, regenerate, sweep every example with both), not by reading: 13 scripts failed with the change, the same 13, all pre-existing.One correction before committing
The coverage figure in
CLAUDE.mdsaid 98%. The measurement says 92%, and I'd written the first number from memory rather than from the script. Corrected in the same commit, and noted in the commit message.Where the digest stands
mdl/executorcmd/mxclimdl/backendmdl/grammarmdl/visitor🤖 Generated with Claude Code