Skip to content

Sync ako/mxcli: 18 reported-issue fixes (check/exec parity, describe round-trips, Mendix 9 JDK) - #1448

Merged
ako merged 43 commits into
mendixlabs:mainfrom
ako:main
Oct 13, 2026
Merged

ako merged 43 commits into
mendixlabs:mainfrom
ako:main

Conversation

@ako

@ako ako commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

Syncs ako/mxcli:main into mendixlabs/mxcli:main: 20 commits since #1447, landed in the fork through PRs ako#1140–ako#1157. Eighteen fix a reported issue; two are test follow-ups.

check / exec agree

describe round-trips

describe subcommand

Mendix 9 and settings

Marketplace

claude and others added 30 commits October 12, 2026 18:18
…s#1431)

Reported: "`mxcli check -p R/R.mpr bad.mdl good.mdl` ... the final line is
'Check passed!' even though the exit code is 1"; reversing the file order
flips the last line, so anything reading the log tail sees success.

runCheckFiles kept only the worst exit code; each file printed its own
verdict and nothing printed one for the set. It now closes with
"N of M files failed: a.mdl, b.mdl" or "All M files passed".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
Reported: "`mxcli marketplace download <id> --output <existing dir>` ...
fails with a rename error reading `rename ... file exists`".

The temp file was created in filepath.Dir(output) and renamed onto output
itself. An --output that is an existing directory, or ends in a separator,
now gets the temp file inside it and the package written as
<dir>/<CDN filename> (or the content-<id>-<ver>.mpk fallback). Flag help
says "file or directory".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
Reported: `mxcli describe rule PgVectorKnowledgeBase.Rule_...` answers
"Unknown type: rule", although `show rules` lists 14 and the MDL
statement `describe rule ...` is handled by the executor.

The describe subcommand keeps its own copy of the DESCRIBE type list
(describeMDLCommand) and two auto-detect maps; none of them knew rules,
so the explicit form was refused and the bare `describe Mod.Rule` form
found "no describable document". Add RULE -> DESCRIBE RULE, catalog
ObjectType RULE and unit type Microflows$Rule -> rule, and list rule in
the help and the Valid types line.

The "which is not a rule in this project" refusal from the same report
is a downstream effect and is left alone.

Test: TestDescribeMDLCommand_Rule (cmd/mxcli). Control: with the fix
reverted it fails with "describe rule M.R: Unknown type: rule".

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

Reported: `marketplace install` on a module already in the project says
updates are "NOT done automatically" and hands the user off to Studio Pro,
in a container that has none; `mxcli marketplace update` exists.

Install still refuses to update implicitly, but now prints the concrete
`mxcli marketplace diff <id> -p <mpr> --to <ver>` and
`mxcli marketplace update <id> -p <mpr> --to <ver>` commands (placeholders
for a --file install, which has no content id). Long help and the
marketplace guide / capabilities table say the same.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
Reported: "`describe module ... with all` truncates at 10 000 lines without
a warning" — "output stops in the middle of a statement", exit 0.

The per-statement output guard returns an error from Write once it passes
maxOutputLines and discards everything after, but describers ignore
Fprintf's error, so the handler returned nil and Execute never looked at
the guard. Execute now returns the limit error when the statement otherwise
succeeded but the guard was exceeded; the message says the output was
truncated and suggests describing per document.

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

Reported: describe java action prints
  `Name: String not null -- This sets the Name of the tool...,`
"the comma lands inside the comment, so the next parameter is a syntax
error" -- mxcli check of the output fails with
`line 255:4 mismatched input 'Name' expecting ')'`.

The parameter loop wrote ", " at the start of the next iteration, i.e.
after the previous parameter's trailing `-- doc` comment. The JavaScript
action describer carries the same loop and the same bug. Both now write
the separator at the end of each non-final parameter, before the comment.

Test: describe -> visitor.Build round trip for a Java and a JavaScript
action with documented parameters; both fail with the fix reverted
(`mismatched input 'Amount' expecting ')'`).

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

Reported: `alter settings runtime ( JavaVersion: '17' );` on a Mendix 9.24
model printed "Unchanged model settings" -- no hint that the property does
not exist in that version.

refuseIfNotStored exempted JavaVersion unconditionally because it is stored
under either JavaVersion or JavaMajorVersion. A 9.x document carries
neither, and settingsoverlay.SetJavaVersion writes nothing when
JavaVersionKey(raw) is empty, so the statement was a silent no-op. Exempt
only when one of the keys is present; otherwise refuse, saying the setting
does not exist on this Mendix version and the JDK is chosen by the platform.

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

Reported: `check` ends with `Check passed!`, but `exec` refuses

    $Sum = sum $List by Amount;
    set $Sum = $Sum + 1;

with "variable 'Sum' is not declared" (same for `$N = count $List`).

The validate pass declared an AggregateListStmt's output; addAggregateListAction,
which exec runs, never registered it, so the SET's declared-variable check
failed only at exec. It now declares the result: count Integer, average
Decimal, all/any Boolean, reduce its declared return type, and sum/min/max
Unknown (their type follows the attribute, which is not resolved here).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
Reported: `expose (Name as 'Name' (KEY), "Description")` passes check and
exec, then mx check fails with
  [CE1613] "The selected attribute 'ModA.EntA."Description"' no longer exists."
and describe prints `"Description" as '"Description"'`.

parseExposeMembers and the publish-microflow expose loop read
IdentifierOrKeyword().GetText(), which keeps a QUOTED_IDENTIFIER's quotes.
Use identifierOrKeywordText, as every other name slot in the file does.
After the fix the repro describes as `Description as 'Description'`.

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

Reported: `mxcli describe module Banking -p <banking>.mpr` prints only
`mdl 1; create or modify module Banking; create or modify module role ...`
although the help says "Describe a module (all contents)"; the full
emitter needs `-c "describe module Banking with all"`, which is
documented only in the changelog.

Choice: add an opt-in `--all` flag (DESCRIBE MODULE ... WITH ALL) and fix
the help, rather than appending WITH ALL to every describe module.
- A plain describe module matches what `-c "describe module X"` prints,
  so the subcommand and the MDL statement keep one meaning.
- Scripts that describe a module for its header and roles keep working.
- WITH ALL has open gaps: mendixlabs#1421 (omits document types) and mendixlabs#1425
  (truncates at 10k lines without saying so). Making it the default would
  swap a wrong help line for output that is silently incomplete.
`--all` on any other type is refused rather than ignored.

Test: TestDescribeModule_HelpMatchesOutput (cmd/mxcli). Control: with the
pre-fix help and a pass-through stub it fails with
`describe --help promises "all contents" for a plain describe module`
and `describe has no --all flag`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
`list java actions in System` listed System.VerifyPassword, but

    describe java action System.VerifyPassword
    Error: java action not found: System.VerifyPassword

and exec of a microflow calling it logged

    warning: could not look up Java action System.VerifyPassword: java
    action not found: System.VerifyPassword (entity type params will be empty)

ReadJavaActionByName only scanned stored units, and resolved the module
first, which fails for System (no stored module unit). The System built-ins
are virtual and were synthesized on the list paths only. Fall back to
meta.BuildSystemJavaActionsFull by name when the module is System and no
stored unit matches; stored units still win, unknown System.X stays
not found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
Reported: `mxcli run --local --db-type hsqldb` against a Mendix 9.24 app,
with JAVA_HOME pointing at JDK 17, fails in mxbuild's Gradle 7.6 with
"Unsupported class file major version 65" -- mxcli resolved JDK 21 even
though JAVA_HOME is 17, and a 9.x model has no JavaVersion setting to
steer the choice.

ProjectJavaMajor fell back to DefaultJavaMajor (21) whenever the model
stores no JavaVersion, which is always the case on 9.x, so resolveJDK
skipped the JDK 17 JAVA_HOME. Derive the fallback from the project's
Mendix version instead: 9.x -> 17 (9.x supports Java 11 and 17; 9.24 LTS
uses 17), 10.x/11.x -> 21 as before. Also stop the JDK-not-found error
suggesting `alter settings runtime ( JavaVersion: '21' )` below the
default: on 9.x that statement changes nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
Reported: "`describe user role` omits `CheckSecurity` when it is `false`",
so the replay re-creates the role with the default -- "Silent security
change on replay (round-trip drift)". Expected: the output carries
`CheckSecurity: false`, as `show user roles` reports it.

formatUserRoleMDL printed CheckSecurity only when true, but a new role is
written with true (Security$UserRole.CheckSecurity defaults to true), and
`create or modify` keeps an unstated stored value, so false was lost both
on recreate and on replay onto an existing role. It is now always printed.

The executor mock's AddUserRole built roles with Go's zero CheckSecurity,
which hid this from the #707 round-trip test; it now mirrors the real
writer's default.

Test: TestIssue1427_UserRoleCheckSecurityFalseSurvivesReplay fails before
the fix ("recreated role has CheckSecurity true, want false", "modified
role kept CheckSecurity true, want false").

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

Reported: describe emits `content { }` for native pluggable-widget child
slots (Repeater, SafeAreaView); check then fails with "`content` is not a
container of `repeater` — it declares: template [MDL-WIDGET26]" and exec
with "content needs a name".

The widget definition names a widgets-typed slot with
mdlContainerForWidgetSlot (content -> TEMPLATE); describe's
extractChildSlots used deriveObjectListKeyword, the object-list convention,
which leaves `content` unchanged. Describe now calls the same function as
the definition.

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

Reported: a script that creates image collection ModA.Icons and then a
page with `image img1 (Image: 'ModA.Icons.pix')` fails check with
  image collection not found: ModA.Icons (referenced as ModA.Icons.pix)
and exec with "Refusing to execute: 1 unresolved reference(s) above.
Nothing was written." Split into two scripts, it passes.

validateWidgetReferences resolved image references against the project
only, under a stale comment saying MDL cannot create an image collection.
scriptContext now records the collections and images that
CreateImageCollectionStmt declares, and they are merged into the project
sets (only when those could be read, so a failed read still reports
nothing). An undeclared image in a script-created collection is still
reported.

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

Reported: `$L = sort $BookChunkList by Similarity desc;`, where Similarity is
declared on the generalization, fails in mxbuild with

    CE1613 "The selected attribute 'Embeddings_SemanticSearch.BookChunk.Similarity' no longer exists."

The list-operation sort prefixed a bare attribute with the list's own entity.
The retrieve `sort by` path already resolves the declaring entity through
resolveAttributeInEntityHierarchy; the list sort now does the same, falling
back to the list entity when the model does not resolve the name. FIND/FILTER
already qualify through resolveMemberChange, which walks the hierarchy.

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

For

    create or modify microflow M.F () returns Boolean as $Closed
    begin
      $Closed = true;
      return $Closed;
    end;

`$Closed = true;` was refused with "a reassignment says `set` under mdl 1:
write `set $Closed = true;`", and `set $Closed = true;` then with
"variable 'Closed' is not declared" - each message sent the reporter to
the other.

The semantics are right and unchanged: `as $X` names the result for
callers and declares nothing. Messages only:
- the mdl 1 "use set" error also offers `declare $X <Type> = …;` for a
  variable that is new;
- the not-declared error on `set $X`, when $X is the flow's `returns … as`
  name, says the clause does not declare it and shows the declare with the
  return type. validateFlowBody now receives the return type for this.

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

Without it mx check fails CE6624 (an OData key attribute needs a unique
validation rule), which hid whether the CE1613 from the quoted name was gone.

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

The separator fix makes these JavaScript actions' describe output parse
again, so integration (roundtrip) failed with "no longer breaks parse —
strike it from knownFailures … The allowlist may only shrink" for each of
them, on both PedApp and TestApp. All 14 entries listed lawParse only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
fix: fail a statement whose output hit the line limit (mendixlabs#1425)
fix: declare an aggregate's output variable in the build pass (mendixlabs#1413)
fix: unquote quoted names in OData expose clauses (mendixlabs#1423)
…curity

fix: describe user role always states CheckSecurity (mendixlabs#1427)
fix: qualify a list sort's inherited attribute with its declaring entity (mendixlabs#1430)
)

Reported: "Exec writes an import-mapping microflow with a null entity and
the `.mpr` can no longer be loaded" — a microflow calling
`import from mapping X` above `create import mapping X` passed check and
exec, then mx check failed loading the project with "Value cannot be
null. (Parameter 'value')" in EntityType.set_EntityId.

The flow builder dropped the mapping lookup error and stored the activity
with VariableType.Entity = "". Fixed at three layers:

- builder: an unresolved mapping, or one without a root entity, is a
  statement error instead of an empty result entity;
- MDL-ORDER01 (no-project and project tiers) gains an "import mapping"
  kind, so check reports the forward reference before anything is written;
- writer: CreateMicroflow / UpdateMicroflow and the splice's
  SerializeObject refuse an import activity with no result entity (loop
  bodies included).

A project already written by the old bug was not repaired by re-running
the statement: describe prints the broken activity as exactly the
statement that would fix it, so create or modify reported "Unchanged
microflow". A stored import activity without a result entity is now not
spliceable: mdl 0 rebuilds the flow (healing it), mdl 1 refuses with the
drop-and-create advice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
fix: run --local picks JDK 17 for a Mendix 9 project (mendixlabs#1437)
fix: resolve image refs against collections the script creates (mendixlabs#1419)
…ndixlabs#1410)

Reported: microflows and nanoflows cannot be created or altered in a 9.x
project —

  Error: failed to create microflow: unit …: this Mendix 9.24.2 project cannot
  store Microflows$Microflow.StableId (Mendix 10.2.0+);
  Microflows$SequenceFlow.CaseValues (Mendix 10.15.0+)

(also CreateNanoflow and ALTER MICROFLOW; 10.0–10.14 for CaseValues alone).
Same root cause as mendixlabs#1434, whose repro is an empty microflow
on 9.24.2.

The flow writers emitted the newest shape whatever the version. The property
floor (e671bec) rightly refuses the two keys that hold a value; before it they
were written silently, and forcing that shape back onto 9.24 is 8 errors in
mx check (CE0079/CE0773: the decision's cases are not read).

Gated on major.minor (flowVersion), with the Model SDK's StructureVersionInfo
(mendixmodelsdk 4.116.0) as the floors and the shapes measured from a Studio
Pro 9.24.30 document and the same document after `mx convert` to 10.12.19:

- Microflow.StableId only from 10.2 (encoder OmitKeys, which now also applies
  to registered type defaults); on >= 10.2 it is emitted and carried as before
- the case as one NewCaseValue below 10.15, a CaseValues list from 10.15
  (gen bound the single case as "CaseValue"; overridden to its storage name)
- Origin/DestinationBezierVector below 10.16 (+ LineType "BezierCurve" from
  10.8), the BezierCurve Line from 10.16 — sequence and annotation flows;
  the reader takes the vectors from either shape
- ReturnVariableName from 10.12, parameter IsRequired/DefaultValue from 10.17
  (both were written on any 10.x; the floor cannot see them)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
fix: refuse alter settings JavaVersion on a model that stores none (mendixlabs#1438)
ako and others added 13 commits October 12, 2026 23:12
fix: end a multi-file check on a verdict for the whole set (mendixlabs#1431)
fix: describe child slots with the definition's keyword (mendixlabs#1400)
fix: wire rules into the describe subcommand (mendixlabs#1402)
…ule-all

# Conflicts:
#	cmd/mxcli/cmd_describe_test.go
…t-dir

fix: marketplace download --output accepts a directory (mendixlabs#1443)
fix: explain `returns … as $X` in the set/declare messages (mendixlabs#1436)
fix: describe code action writes param separator before its doc comment (mendixlabs#1412)
…ace-update

fix: install names `marketplace update` for a module already present (mendixlabs#1442)
fix: refuse import from mapping without a result entity (mendixlabs#1418)
fix: add describe --all and make the module help truthful (mendixlabs#1435)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01W3x8Fyvir8kLyPgJs1BDmF
fix: write flows in the shape each Mendix 9/10 version declares (mendixlabs#1410)
@github-actions

Copy link
Copy Markdown

AI Code Review

What Looks Good

This PR successfully syncs 18 reported-issue fixes and 2 test follow-ups from the ako/mxcli fork. The changes are well-scoped, each addressing a specific issue with corresponding test coverage. Key improvements include:

  • Check/Exec Parity: Fixed multi-file check summary reporting, aggregate variable declaration, return variable messaging, import mapping validation, image reference resolution, and output line limit handling.
  • Describe Roundtrips: Fixed user role CheckSecurity preservation, code action parameter separator placement, pluggable widget child slot keyword usage, OData quoted name handling, and inherited attribute qualification in list sorts.
  • Describe Subcommand: Added rule type support, fixed describe module --all help/output consistency, and enabled system Java action lookup by name.
  • Mendix 9/JDK: Corrected --local JDK selection for Mendix 9 projects and refused alter settings runtime (JavaVersion: ...) on models without JavaVersion storage.
  • Marketplace: Made --output accept directories and improved already-installed module messaging to suggest diff/update commands.

All fixes include:

  • Appropriate test additions (unit/integration tests)
  • Backend/executor layer modifications where needed
  • No new MDL syntax (so full-stack wiring check not applicable)
  • Clear commit-level focus (18 fixes + 2 test follow-ups as stated)
  • Adherence to MDL design guidelines (no syntax violations in changes)

Recommendation

Approve the PR. The changes are correct, well-tested, and maintain consistency with the project's architecture and guidelines. No issues were found during review against the checklist.


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

@ako
ako merged commit bd45c47 into mendixlabs:main Oct 13, 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.

2 participants