Skip to content

Sync ako/mxcli: check catches CE1406/CE0114/CE6585 and version gates, revoke and OData fixes, run --listen-addr - #1508

Merged
ako merged 45 commits into
mendixlabs:mainfrom
ako:main
Oct 15, 2026
Merged

ako merged 45 commits into
mendixlabs:mainfrom
ako:main

Conversation

@ako

@ako ako commented Oct 15, 2026

Copy link
Copy Markdown
Collaborator

Syncs ako/mxcli:main into upstream: 23 commits from fork PRs ako#1373–ako#1389. Two of them port upstream contributor PRs onto current main: #1249 (--listen-addr, by Wengao Liu) and #1229 (dynamic-text RenderMode, by MendixMau). If this merges, those two PRs can be closed as superseded.

check catches more of what mxbuild refuses

Correct writes

run

Dependencies

These address the fork's Dependabot alerts.

  • vscode-mdl: in-range bun audit fix (brace-expansion, esbuild, qs, underscore), lockfile only. The audit goes from 12 advisories to 0.

  • vega-charts widget template:

    • in-range npm audit fix
    • sprintf-js is dropped by overriding js-yaml to v4 for load-nyc-config
    • postcss-selector-parser is pinned to 7.1.6 (GHSA-rj75-hqrm-r3gf), and the built widget is byte-identical

    The remaining advisories come in through @mendix/pluggable-widgets-tools and wait on an upstream tools release.

Docs

  • /mxcli-dev:review gets a recurring finding about upstream PRs cut from a stale base.
  • The manage-navigation skill's line index has been regenerated.
  • Each fix records its finding

jasonliu2017 and others added 30 commits October 1, 2026 20:07
…etwork

`run --local` binds the app to 127.0.0.1 and there is no way to widen it:
LocalRuntimeOptions.ListenAddr is the only field that reaches the runtime's
`runtime_listen_addresses`, and nothing sets it but the default at
applyDefaults. So the app cannot be opened from another machine on the LAN —
the use case being a phone or a second laptop pointing at a dev box, which is
not exotic enough to leave unsupported.

It cannot be fixed after boot either. appContainerParams is sent once, at
startup (StartLocalRuntime); re-sending update_appcontainer_configuration on a
running app fails, because the runtime already holds 127.0.0.1:<port> and
Linux rejects a second bind of the same port on 0.0.0.0:

    Runtime port '8095' is already in use
    No permission to open socket or another server is already running on
    Some(0.0.0.0):8095

So the address has to be right at startup, which means a flag.

The M2EE admin API is a privileged surface — it boots the app, rewrites
configuration and runs actions — so it must not be widened onto the network as
a side effect of widening the app bind. m2eeAdminListenAddr is a constant at
127.0.0.1, used for both the runtime's M2EE_ADMIN_LISTEN_ADDRESSES and mxcli's
own admin client. The client part is not tidiness: 0.0.0.0 is a bind address,
not a destination, so a client dialling it is not portable, and when the admin
bind was simply mirrored the readiness poll timed out with "runtime admin API
did not come up" on a runtime that was up and serving.

The default is unchanged at 127.0.0.1, so nothing behaves differently unless
asked.

Note for callers: the runtime derives ApplicationRootUrl from the bind address
when none is set, and 0.0.0.0 is not a host a browser can ask for. Pair this
with a reachable root URL — an ApplicationRootUrl naming a real host in the
model, or --runtime-setting ApplicationRootUrl=http://<host>:<port>/. The flag
help says so.

Closes #1248
…labs#1505)

Studio Pro stores a multi-line note with CRLF line breaks and describe
prints them raw. A script saved by an editor with LF no longer matched
the stored free annotations, so `create or modify` under mdl 1 refused:
"the free annotations change; the splice edits activities only". A note
on an activity re-spliced that activity for the same reason.

declaredMatches now compares note text with every line break spelled LF.
A matched note is left as stored, so its CRLF bytes are kept and the run
writes nothing. A real change to a free note is still refused, and the
refusal now names the note, quoted with escapes so an invisible-character
difference shows as one.

The bug-test holds raw CR bytes and is marked -text in .gitattributes,
since eol=lf on *.mdl would strip the case on commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012mdoMLzgHy7h8qbvVNkb92
…ir rules (mendixlabs#1501)

`revoke write (NewAttr) on entity M.E from M.RoleA, M.RoleB, M.RoleC`
printed "nothing to revoke", exit 0, and every rule kept NewAttr ReadWrite.
The rules were granted one role each; RevokeEntityMemberAccess only touched
a rule whose role set equalled the statement's, so none matched. It now
narrows every rule all of whose roles are named (as a full revoke already
did per role) and refuses, before writing, a rule shared with a role the
statement does not name.

Backend tests reproduce the 0-rules-modified symptom before the fix; the
single-role revoke on the same project was the control that ruled out the
reported default-member-access hypothesis.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VKmbj53BC2vuUWYmgWgfQ5
…ute (mendixlabs#1440)

Reported (mxcli v0.26.0):

  alter snippet M.S { replace <widget> with {
    combobox x (Attribute: $Asset.Asset_Customer, CaptionAttribute: CustomerManagement.Customer.CustomerName)
  } };

  check: "Check passed!"
  exec:  "property attributeEnumeration binds Asset_Customer, which is an
          association ... not an attribute"

exec is the correct side. With no DataSource the combo box is in
enumeration mode, and attributeEnumeration cannot hold a reference (#830).
The refusal existed only in the widget engine's Attribute mapping, and no
check pass called it.

check now asks the same question through the same function, and resolves
the name against the same entity exec uses:
- CREATE PAGE/SNIPPET: in the pluggable attribute-scope walk (checkWidget).
  `$Param.Name` resolves against the parameter's entity; a bare name
  resolves against the #647 binding scope.
- ALTER INSERT/REPLACE: in the insertion-point pass, against the stored
  document's ParamScope and alterEntityContext.

A combo box gets its own remedy, which names the association mode
(`Attribute: $Asset.M.Asset_Customer, DataSource: ..., CaptionAttribute:`).
On mx 11.6.6 that mode gives 0 errors, and describe -> exec reports
"Unchanged snippet".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
)

Reported: "File Uploader: an `allowedfileformat` in `configMode: 'simple'`
passes check and exec, then fails `mx check` with CE0463 ... hidden
TextTemplates inside object-list items are never nulled".

The File Uploader editorConfig hides an allowedFileFormats item's
`typeFormatDescription` (with mimeType/extensions) per item while that
item's configMode is "simple". The extractor already lifted the nested
rule, but ApplyVisibilityRules only walked top-level properties, so the
required item TextTemplate kept the populated ClientTemplate the item
builder gives it. `mx update-widgets` on a copy changes exactly that slot
to null.

ApplyVisibilityRules now applies nested rules per list item, resolving
each condition in its own scope (item vs widget), and skips nested rules
in the top-level pass so a colliding top-level key is never touched.

Measured on Mendix 11.6.6 with File Uploader 2.5.1: CE0463 before, 0
errors after; describe -> exec -> describe is identical. The same fix
clears the CE0463 on doctype-tests/32 Accordion `acc2` (custom-header
groups hide the required headerText); fixtures 30 and 31 are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
fix: a note's line endings are not a change to a spliced flow (mendixlabs#1505)
…r-access

fix(backend): a partial revoke from several roles narrows each of their rules (mendixlabs#1501)
…le KEY (mendixlabs#1426)

Reported: "Published OData with no KEY, or a KEY on an attribute without a
unique rule, passes check" -- `mxcli check` said "Check passed!", exec
wrote it, and mx check reported
  [CE6585] "Published entity 'ModA.EntA' must have a key defined."
  [CE6624] "Add a unique validation rule to attribute 'Name' of entity
           'ModA.EntA' to be able to use it as the key."

Measured on mx 11.6.6: no KEY is CE6585 for every entity kind (also
`expose (*)` and no expose clause). A single KEY on a persistable entity
needs a unique validation rule, on OData3 and OData4 alike; not null or
an index does not satisfy it. A composite key, or a key on a view or
non-persistent entity, needs no rule.

New check rules MDL-ODATA08 (CE6585) and MDL-ODATA09 (CE6624), both
errors, in ValidateProgram so exec's preflight refuses too. MDL-ODATA09
resolves the entity from the script, then the project, and stays silent
when it cannot (unknown entity, inherited attribute, entity altered by
the script). Two bug-test scripts that were themselves CE6585 are keyed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
Review follow-ups to mendixlabs#1249:

- AppURL is what mxcli dials (health check, screenshots, "App is
  running at"), but it was built from the bind address: 0.0.0.0 is not a
  destination and `::` produced the unparseable http://:::8080/. A
  wildcard now dials loopback of the same family, and IPv6 hosts are
  bracketed via net.JoinHostPort.
- --listen-addr must be an IP address, refused before --detach and the
  build instead of as a bind failure in the runtime log.
- A wildcard bind with no application root URL (model, hub or
  --runtime-setting) warns at boot, since the runtime derives one from
  the bind address. The network URLs the app is reachable at are printed
  after boot.
- Flag rows in the run-local skill and docs-site page, CHANGELOG entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UBgg5k5sdMTsURKiigb19C
mendixlabs#1420)

Reported (mxcli v0.26.0). A param-bound legacy reference selector in a
snippet was replaced with

  combobox x (Association: M.A, DataSource: database M.E, CaptionAttribute: Attr)   -- no data container

check and exec both passed, and the build then failed:

  [CE7007] "Selected value is not valid for entity 'Asset_Customer/Customer'.
  Please select the value again."

Reproduced on mx 11.6.6. The writer stores the association with no
SourceVariable, which means "the enclosing object", and outside every data
container there is no such object. Mendix can express the construct. Studio
Pro stores this binding with SourceVariable = the snippet or page parameter.
MDL already writes that from `Attribute: $Asset.M.Asset_Customer`, which
gives 0 errors on 11.6.6 and which describe -> exec reports as "Unchanged
snippet". The bare spelling is now refused, and the message names CE7007 and
the spelling that builds. mxcli does not guess which parameter was meant.

One decision (comboBoxAssociationNeedingObject) is used in three places:
- exec: in the widget engine's Association mapping, when Build started with
  no entity in scope;
- check without a project: new rule MDL-WIDGET46 at a document root;
- check with -p: for an ALTER INSERT/REPLACE at an insertion point with no
  entity (unscopedInsertion).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
Port of mendixlabs#1229 (closes mendixlabs#1228) onto current
main.

`alter page P { set (RenderMode: H2) on <dynamictext> }` was refused as "not
a property of this built-in widget", although CREATE PAGE and REPLACE accept
RenderMode on a dynamictext and the MCP backend's mutator already sets it.
setRawWidgetPropertyMut had no case for it, so it fell through to the
pluggable-property setter.

Add a RenderMode case dispatched on the stored $Type (Forms$DynamicText): the
value is validated case-insensitively against Text, Paragraph and H1-H6 and
written in its canonical spelling; anything else is refused with the accepted
list, leaving the document untouched. Other widgets keep the previous path.

Changes against the upstream PR:
- docs, syntax help and the bug-test script use `set (Key: value)` instead
  of the deprecated `set Key = value` (MDL-DEPR101); the bug-test script is
  upgraded to the `mdl 1;` form so the conformance gate accepts it
- the finding is its own file under findings/mdl-backend/ instead of an
  append to the merged-back mdl-backend.jsonl
- the quick reference no longer claims every other widget gets an error
  naming the allowed set; only a bad value on a dynamic text does

Tested: the new pagemutator tests fail on unmodified main and pass with the
change. Bug-test script against a copy of testdata/pedapp (Mendix 11.13.0):
exec applies it and describe shows H2, Paragraph, H4; the unfixed binary
refuses the first alter. H7 is refused by check and by --no-check exec, with
nothing written. make test, make lint and make check-findings pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NDLRXjMy1B18Cj3nX5RuCX
…1613)

Publishing a specialization and exposing a member its generalization
declares passed check and exec, then mx check reported
  [CE1613] "The selected attribute 'OdInh.Sub.Code' no longer exists."
for an inherited attribute and an inherited association alike.

lookupEntityMembers read only the published entity's own attributes and
the associations it is directly a side of, so an inherited member fell
to the bare-name attribute fallback and the writer prefixed the
published entity. Inherited attributes are now qualified by the entity
that declares them (any depth, keeping their EDM type), and inherited
associations publish as association ends with the specialization
standing in for the generalization's side.

Found by the mendixlabs#1426 fix, which could not measure an
inherited KEY while this error masked the others.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
…ixlabs#1424)

Reported: "Mxcli-written Data grid 2 fails CE0463 on a 10.x target until
`fix widgets`" — a blank 10.24.0 app plus one `create page` with a
DATAGRID gives CE0463 on the grid; `mxcli fix widgets` clears it.

10.24.0 ships Data Widgets 2.30.3 and the embedded template is 3.4-shaped,
so AugmentTemplate rebuilds the definition from the .mpk. Against
`mx update-widgets` output the Object was identical and the Type differed
in three places, all augmentation defects:

- PropertyDefs were indexed by bare key across nesting levels; 2.30.3
  declares `filter` twice (column: widgets, filterList item: attribute),
  so the column's filter got the item's definition. All reconcile passes
  now address properties by scoped key ("columns/filter").
- Exemplar indices were taken before stale properties were removed, so the
  new `filterList` object list was cloned from an Integer property and had
  no ObjectType. Indices are now taken after removal (top level and nested).
- <associationTypes> and selectableObjects were never parsed or
  reconciled (column filterAssociation / filterAssociationOptionLabelAttr).

Also drop template Translations where the package ships none (drop-down
filter emptyOptionCaption), which surfaced once the grids stopped failing.

Measured: the report's script on 10.24.0 1 -> 0 CE0463, describe -> exec
-> describe identical; doctype-tests/31 on 10.24.0 7 -> 0, on 10.24.24
2 -> 0, on 11.6.6 0 -> 0; doctype-tests/30 on 11.6.6 0 -> 0;
doctype-tests/32 on 11.6.6 3 -> 2.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
fix: refuse a published OData entity with no KEY or a non-unique single KEY (mendixlabs#1426)
…tion-check

fix: check refuses a combo box bound to an association through Attribute (mendixlabs#1440)
…et-param

fix: refuse an association-mode combo box with no object to start from (mendixlabs#1420)
…bute

fix: publish inherited OData members under their declaring entity (CE1613)
fix: null hidden TextTemplates inside object-list items (mendixlabs#1198)
fix: rebuild an older Data Widgets definition correctly on 10.x (mendixlabs#1424)
…5e8da

feat(run): add --listen-addr so a local app can be reached from the network
Measured on 11.12.1 with a blank app (HSQLDB) and an after-startup
microflow logging Core.getConfiguration().getApplicationRootUrl():

  default (127.0.0.1)                       -> null
  --listen-addr 0.0.0.0                     -> null
  0.0.0.0 + --runtime-setting ApplicationRootUrl=http://192.0.2.2:8080/
                                            -> http://192.0.2.2:8080/

So the claim, in #1249's help text and in two older comments, that the
runtime derives its root URL from the listen address is false: unset
stays unset. The wildcard warning, flag help, docs rows and CHANGELOG
now say that instead. Behaviour is unchanged.

Also verified live: under 0.0.0.0 the app answers 200 on the LAN
address and loopback, the admin API only on loopback; under a single
interface address mxcli dials that address (loopback refuses) and the
admin API stays on loopback. `::` could not be measured: this container
has no IPv6 (AF_INET6 unsupported), and Mendix reports the failed bind
as "Runtime port '8080' is already in use".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UBgg5k5sdMTsURKiigb19C
fix(pages): ALTER PAGE/SNIPPET SET RenderMode on a dynamic text (port of mendixlabs#1229)
…5e8da

docs(run): the runtime does not derive a root URL from the bind address
bun audit fix, lockfile only: brace-expansion 5.0.5 -> 5.0.12,
esbuild 0.28.0 -> 0.28.1, qs 6.14.1 -> 6.16.0, underscore 1.13.7 -> 1.13.8.
bun audit: 12 vulnerabilities -> 0. Extension still compiles.

Addresses Dependabot alert #23 (alert body not readable from the session;
this clears every advisory bun audit reports for vscode-mdl).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNquFqC4yEhzhY1LcCP5KE
npm audit fix --package-lock-only: 51 -> 49 advisories. The remaining roots
(braces, sprintf-js, postcss-selector-parser) arrive via
@mendix/pluggable-widgets-tools 11.12.1; npm's only offered fix is a
downgrade to 8.18.4, so they are left for an upstream tools release.
A placeholder-filled copy of the template still builds an .mpk.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNquFqC4yEhzhY1LcCP5KE
claude and others added 15 commits October 15, 2026 19:03
sprintf-js <= 1.1.3 has no patched release (unbounded precision specifiers
-> RangeError). Its only path was @istanbuljs/load-nyc-config -> js-yaml 3
-> argparse 1 -> sprintf-js, and js-yaml loads argparse only from its CLI,
so it was never reachable; but with no fix upstream the alert can only close
by leaving the tree.

Override js-yaml to ^4.1.0 for load-nyc-config alone: v4 uses argparse 2
(no sprintf-js), and load() keeps its signature. Verified a .nycrc.yaml
still loads through it and a placeholder-filled copy still builds an .mpk.
npm audit: 49 -> 29.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNquFqC4yEhzhY1LcCP5KE
…ot (mendixlabs#1433)

`mxcli new --version 10.24.0` created a project whose first build failed
with 4x CE6083 "Design property ... is not supported by your theme", then
printed "Project created" and exited 0.

The scaffold layout hardcoded Atlas 4's flex design properties on the
topbar container. Atlas is versioned with the project: 10.24's template
ships Atlas Core 3.17, which declares none of them. The topbar properties
are now written only where the project's themesource declares them
(executor.ThemeDeclaresDesignProperty). On Atlas 3 none are, and none are
needed: its .topbar-content rule is already a centred flex row.

A first build that mxbuild refuses for model errors is now a typed
docker.ModelErrorsError, and `new` finishes its steps and exits 1 with the
errors listed. Other first-build failures (no JDK, no mxbuild) stay
warnings, since they say nothing about the project.

Measured with mx check: 10.24.0 4 errors before, 0 after; 11.6.6 0 both,
flex properties kept.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
Dependabot alert #21 (GHSA-rj75-hqrm-r3gf): flat selectors such as
.a.a.a... parse in O(n^2). The widget lock held 7.1.5 (postcss-modules)
and 6.1.4 (cssnano 5 plugins); no 6.x release is patched and
`npm audit fix --force` proposes downgrading pluggable-widgets-tools to
8.18.4, so pin the patched version with an npm override.

7.0.0's only breaking change is safe insertion during iteration. The
built widget is byte-identical to the baseline, and cssnano output on a
selector corpus is identical under 6.1.4 and 7.1.6.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012EqHXncQcCt3C8WJHHN2xJ
`mxcli check -p` passed scripts that `mxcli exec` then refused for the
project's Mendix version (e.g. `create view entity` on a 9.24 project),
after running the statements before the refused one. Every version gate
lived inline in its handler as a checkFeature call, which neither check
nor exec's pre-flight ever reaches.

The gates now come from one statement-to-feature table,
statementVersionGates (mdl/executor/version_gates.go). The handlers
refuse through checkVersionGates(ctx, stmt); Executor.CheckVersionGates
reports the same refusals as MDL-VERSION01, run by `check -p` and by
exec's pre-flight, so exec refuses before anything is written. A test
fails on any new direct checkFeature call outside the table.

Still exec-only: gates that depend on stored state (drop/alter of a
message definition document that is not there) and the write-time
property floor. The issue's own StableId/CaseValues refusal was the
latter and is already cured by #1410; the flows now pass both check and
exec on 9.24.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
fix(new): scaffold layout builds on Mendix 10.24; fail when it does not (mendixlabs#1433)
… it, MDL-SEC22 (mendixlabs#1500)

No check modelled CE0114 "A microflow that does not apply entity access can
only call microflows that also do not apply entity access" - a consistency
rule between two documents, not a reference - so `check -p --references`
passed and mxbuild refused. CheckEntityAccessCalls simulates stored and
scripted microflows/rules (carriedApplyEntityAccess for absent annotations),
reports new off->on calls and off->rule-on decisions as errors, stays silent
on unresolved callees. Measured on mxbuild 11.13.0/11.14.0: reverse, on->on,
off->off, nanoflow and excluded callers build clean, at Off and Prototype.
Two variants on a fresh 11.14 project: issue script -> MDL-SEC22 exit 1, exec
-> 1x CE0114; caller fixed -> check passes, 0 errors. Revert-proof: gate
stubbed -> 6 tests fail "got 0"; callee test dropped -> off->off control fails.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VKmbj53BC2vuUWYmgWgfQ5
The index on main is stale (make check-skill-index fails on every branch);
regenerated here so this PR's CI is green. A no-op once main carries it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VKmbj53BC2vuUWYmgWgfQ5
…ixlabs#1498)

Nothing read Projects$ModuleSettings.ExportLevel and the entity read dropped
ExportLevel, so check passed what mxbuild refuses as CE1406 (a Hidden element
referenced from navigation / another module) and CE5400 (an API microflow
exposing a Hidden entity). New validateProtectedModuleRefs in the --references
pass; describe module/entity and show modules now say Protected / the level.
Rules measured on mxbuild 11.13.0 and 11.14.0 with controls; tests fail with
the validator stubbed and with the entity read reverted.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VKmbj53BC2vuUWYmgWgfQ5
The index on main is stale (make check-skill-index fails on every branch);
regenerated here so this PR's CI is green. A no-op once main carries it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VKmbj53BC2vuUWYmgWgfQ5
…parser

build(deps): force postcss-selector-parser 7.1.6 in vega-charts widget
fix(check): report a microflow without entity access calling one with it, MDL-SEC22 (mendixlabs#1500)
…vels

fix(executor): check references into Protected (add-on) modules (mendixlabs#1498)
Conflict in the vega-charts widget: main added a postcss-selector-parser
override. Kept both overrides and regenerated package-lock.json with npm
(main's lockfile + npm install + in-range npm audit fix), not by hand.
sprintf-js stays out of the tree; npm audit 19 advisories, all braces
(no patched release).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XNquFqC4yEhzhY1LcCP5KE
fix(deps): clear vscode-mdl npm advisories within existing ranges
@github-actions

Copy link
Copy Markdown

AI Code Review

Review Summary

This PR syncs 23 commits from ako/mxcli:main, bringing several important improvements to mxcli's checking and validation capabilities, write correctness, and runtime features.

What Looks Good

  • Comprehensive check enhancements: Now catches CE1406/CE5400 (Protected module references), CE0114 (entity access mismatch), CE6585/CE6624 (OData key validation), and combo box issues that previously only failed at build time
  • Version gate unification: Moved version gating logic to a central location so check and exec now agree on version restrictions (fixing Check is not version-aware: it passes scripts that exec then refuses for a version reason #1434)
  • Write correctness fixes:
  • New runtime feature: run --local --listen-addr enables network access to local apps
  • Thorough testing: All new features have corresponding test files and MDL examples
  • Evidence-based fixes: Each change includes a bug findings file following project conventions
  • Dependency maintenance: Addresses Dependabot alerts for vscode-mdl and vega-charts

Moderate Issues Requiring Verification

  1. LSP wiring: For new MDL features like ALTER PAGE/SNIPPET SET RenderMode, need to verify LSP diagnostics/formatting/navigation were updated in cmd/mxcli/lsp.go (not shown in diff but required by full-stack consistency checklist)
  2. User documentation: Should verify docs-site/ updates for new features like --listen-addr and altered validation behavior

Minor Observations

  • Some test files are large but appropriately comprehensive
  • All new executor commands appear properly wired through the full pipeline (grammar → AST → visitor → executor)
  • No obvious code duplication or violations of MDL syntax guidelines
  • Changes maintain proper scope (each commit in the fork likely did one thing)

Recommendation

Approve this PR. It delivers valuable improvements that close significant gaps between mxcli check and mxbuild behavior, enhances correctness of writes, and adds useful functionality. The changes follow architectural patterns, include proper testing, and maintain the project's evidence-based approach to fixes.

Verification needed before merge: Confirm LSP wiring for new MDL features and user documentation updates for --listen-addr and validation behavior changes. These are likely addressed in the complete diff or are minor enough that they don't block approval given the overall quality of the changes.


Automated review via OpenRouter (Nemotron Super 120B) — workflow source

@ako
ako merged commit 3d3bb3e into mendixlabs:main Oct 15, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ALTER PAGE / ALTER SNIPPET cannot SET RenderMode on a dynamic text ("not a property of this built-in widget")

4 participants