Skip to content

Sync ako/mxcli: optional page parameters, lint rules for every AI tool, CONV021, catalog reference fixes - #1693

Merged
ako merged 18 commits into
mendixlabs:mainfrom
ako:main
Oct 31, 2026
Merged

ako merged 18 commits into
mendixlabs:mainfrom
ako:main

Conversation

@ako

@ako ako commented Oct 31, 2026

Copy link
Copy Markdown
Collaborator

Syncs ako/mxcli:main into upstream: 9 commits from fork PRs ako#1823–ako#1827, ako#1830 and ako#1831.

Fixes #1242 and #1640.

Pages

Lint

  • The bundled lint rules are installed for every AI tool (Lint rules only load from .claude/lint-rules/, and init --tool cursor installs no Starlark rules at all #1242). mxcli lint reads .claude/lint-rules/ whichever tool a project uses, but init wrote that folder only for claude and opencode.
    • With init --tool cursor (or aider, continue, copilot, vibe or windsurf), lint ran only the built-in Go rules, silently and with exit 0.
    • Lint now also says when it runs without the bundled rules.
  • New rule CONV021 warns on a create or change directly followed by a commit of the same object. That is two activities doing what one does. The warning names the setting that keeps the behaviour, for example Commit Yes for a commit with events.

Catalog

  • Message definitions record their references. A message definition exposes an entity, its attributes and associations by qualified name. So show references to now lists them, and impact analysis no longer calls an exposed entity or attribute unused.
  • A project widget is described the same way on every source build. Parallel describes each loaded their own widget definitions, so a build sometimes fell back to the generic pluggablewidget '<id>' form. The incremental build then kept that row until a FORCE.
  • The first command that builds the unit index says so. After an upgrade or on a fresh clone, that command opens every unit file once, which was an unexplained stall on Windows. It now prints one line explaining the wait.

Tests

  • The nightly's 10.24 leg is green again. The REST client round-trip test now expects the check-time query-parameter gate below 11.0, which a recent commit added

claude and others added 18 commits October 30, 2026 22:21
… commit

A Create or Change object activity without commit, followed directly by a
Commit of the same object, is two activities doing what one does: the
create/change with its Commit option set. The rule warns and names the
setting that keeps the behaviour: a commit with events becomes Commit Yes,
one without events Yes without events, and Refresh in client is kept if
either had it, with the MDL form (`… commit [without events] [refresh]`).

It reports only a pair the merge cannot change the meaning of: in a
microflow, Commit = No on the create/change, the commit names its object,
the normal flow joins them directly, nothing else flows into the commit,
and neither has custom error handling. Loop bodies are searched too.

Measured on an 11.13.0 app: of five microflows it reports the two with the
pattern (create then commit; change then commit without events and
refresh) and not the preferred form, a log in between, or a commit with
custom error handling. Rewriting the two as the suggestion says clears the
rule, describes as `… commit`/`… commit without events refresh`, and mx
check reports 0 errors before and after. The three Studio Pro fixtures in
testdata report nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011oK82sUVQEB3K5W5vh85wM
Lint rule CONV021: a create/change directly followed by a commit of the same object
…ion only (#548)

A property the widget's editorConfig hides is reset to its declared
default, and both reset sites in PluggableWidgetEngine.Build used the
primitive setter whatever the property's value type. So every combo box
mxcli wrote stored its hidden customEditabilityExpression with
PrimitiveValue "false" as well as Expression "false", where Studio Pro
stores PrimitiveValue "". mx check accepts both; the cost was that
mxcli's widgets differed from Studio Pro's.

Measured by declared value type across ako/TestApp and PedApp (221
pages, snippets and layouts): 939 Expression-typed WidgetValues fill
PrimitiveValue 0 times, and no other type fills Expression. The reset
now writes an Expression property's default with SetExpression.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NUbjJ5DeS2vysn9hfKir4Y
…nting its argument (#1649)

Since Mendix 11.5 a page parameter can be optional
(Forms$PageParameter.IsRequired = false), and a menu item may then open
the page with no argument. mxcli could neither say nor see it: describe
page dropped the flag, describe navigation printed
`show page M.Sale_View(Sale = $currentObject)` for that menu item, and
executing describe's output was refused with MDL-PAGEARG01, so the
navigation profile could not be changed from MDL (mendixlabs#1640).

`Params: ( $Sale: M.Sale optional )` now writes IsRequired false through
create page and alter page add parameters, gated to 11.5+ (MDL-VERSION01)
and refused on a snippet parameter (MDL087). describe page prints it, and
the implicit `= $currentObject` mapping describe recovers is for required
parameters only. The reader treats an absent IsRequired (every parameter
below 11.5) as required: gen's accessor reads it as false.

On the 11.6.6 fixture a menu item opening the page with no argument
checks clean with `optional` and fails CE1571 without it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NUbjJ5DeS2vysn9hfKir4Y
fix(pages): pluggable expression defaults in Expression only (#548); optional page parameters (#1649)
…build (#1799)

A source catalog build sometimes described a pluggable widget in the generic
`pluggablewidget '<id>'` form instead of its keyword, and the incremental build
then kept that row until a FORCE.

Each parallel describe built its own context and so loaded its own widget
registry. With one definition that never counts as current (hand-made, or its
.mpk removed), every load called RefreshWidgetDefinitions(force), which
truncated and rewrote every .def.json while the other workers read them. A
describe that read a truncated file got a registry without the widget.

The describes now share the build's registry, loaded once before the fan-out,
and a definition is replaced by rename so no reader sees a half-written file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A message definition exposes an entity, its attributes and associations by
qualified name, but the member-ref walk visited only mappings, so `show
references to` never listed one and impact analysis called an exposed
entity or attribute unused.

Both storage shapes are walked now: the pre-11.15 collection
(MESSAGE_DEFINITION_COLLECTION) and the 11.15+ document (MESSAGE_DEFINITION).
Entity edges are `mapping`, attribute and association edges `member`, as for
an import or export mapping.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…y when lint runs without them (#1292)

`mxcli lint` reads .claude/lint-rules/ whichever AI tool a project uses, but
init wrote it only for claude and opencode: `init --tool cursor` (and aider,
continue, copilot, vibe, windsurf) left lint running the built-in Go rules
alone, silently and with exit 0.

init now writes the rules outside the per-tool branches, next to the lint
config, and lint/report print a warning when no rules directory is found.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(catalog): describe a project widget the same way on every source build (#1799)
fix(catalog): record the references a message definition makes (#1781)
The nightly's 10.24.24 leg went red in TestRoundtripRestClient_WithQueryParams:
"want the QueryParameters refusal, got: query: ( … ) on a REST operation
requires Mendix 11.0.0+". 9aa1df3 added a check-time gate for query
parameters on a REST operation (rest_client_query_params), so the statement
is now refused before the write is reached, and the write's
"Rest$RestOperation.QueryParameters (Mendix 11.0.0+)" never surfaces. Only a
pre-11.0 project takes this branch, and per-PR CI runs one newer version,
so the PR that added the gate never ran it.

The test now asserts the gate's own message and floor. Verified on a
10.24.24 project: the old assertion fails with the nightly's message, the
new one passes, and it fails again (with the write's refusal) when the
gate's applies is stubbed to false.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GeAhBjRBm5vN2ik3ddvVWW
…ite's refusal

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

test(rest client): expect the query-parameter version gate below 11.0
After an upgrade to the unit-index-2 format, or on a fresh clone, one command
opens every unit file to build the index: 641 opens where the previous build
opened 383 on a 541-unit project, an unexplained stall on Windows.

The reader now prints one line through mpr.ColdUnitIndexNotice before such a
build. It is nil by default, so library callers stay silent; the CLI sets it
to stderr together with the banner, so -q and MXCLI_QUIET suppress it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fix(init,lint): install the bundled lint rules for every tool, and say when lint runs without them (#1292)
feat(mpr): say when the first command builds the unit index (#1806)
@ako
ako merged commit 2413da5 into mendixlabs:main Oct 31, 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.

Lint rules only load from .claude/lint-rules/, and init --tool cursor installs no Starlark rules at all

2 participants