Skip to content

Sync ako/mxcli: microflow splice refusals, legacy table cells, System.owner references, describe round trips, settings, marketplace - #1638

Merged
ako merged 72 commits into
mendixlabs:mainfrom
ako:main
Oct 23, 2026
Merged

ako merged 72 commits into
mendixlabs:mainfrom
ako:main

Conversation

@ako

@ako ako commented Oct 23, 2026

Copy link
Copy Markdown
Collaborator

Syncs ako/mxcli:main into upstream: 50 commits from fork PRs ako#1617, ako#1619, ako#1621, ako#1623–ako#1628, ako#1630 and ako#1633–ako#1635, plus ako#1638 (fork tooling).

Most of these work through the clusters on the fork's triage board, one commit per defect. Each has a test that fails with the reported symptom when its fix is reverted.

Fixes #131, #1486, #1487, #1489, #1490, #1549, #1610, #1623, #1627 and #1629. Addresses #610, #1358 and #1612. Refs #1453, #1517 and #1592.

Microflow splices (#1489, #1610, #1517)

Under mdl 1, create or modify / alter microflow refused several changes that touch only one node.

ALTER PAGE (#1453, #1592)

System module references (#610, #1358, #1612)

  • [id = $obj/System.owner] is refused when the entity stores no owner. MDL-RETRIEVE02's own rewrite used to fail the build with CE0161.
  • create / change of System.owner is refused, with advice that applies.
  • find/filter by System.owner builds. Describe keeps System associations qualified, so a specialization of System.User no longer re-executes by User_Language as an attribute.
  • A test runs an association to a System entity end to end.

describe → exec round trips (#1623, #1627)

  • A module's own description replays as a no-op. Describe no longer prints a view entity's association as a statement (CE6771), and no longer re-indents a view entity's stored OQL.
  • An XML-schema mapping's description no longer drops its root. Replaying it used to print Modified import mapping and empty the root element and every XmlPath. Any other rewrite of such a mapping is refused, naming what it would delete.
  • A view query keeps comments before its first and after its last token. OQL comments are gated on Mendix 11.7.
  • The SOAP-mapping guard reads the imported web service under its storage key. Before, it never fired on a Studio Pro mapping.

Settings and run --local (#131, #1549)

  • alter settings configuration accepts ExtraJvmParameters and sets MaxJavaHeapSize. run --local passes the configuration's JVM options to the runtime.
  • create configuration works on 11.12+. It used to be refused for duplicate ids in the copied OpenTelemetry part, and now mints fresh ones.
  • alter settings webui sets OptimizedClient, and describe emits it.
  • check refuses an unknown alter settings section or key, as exec does.
  • describe settings takes no category, only CONFIGURATION 'name'.

Marketplace (#1486, #1487)

  • marketplace install / update no longer writes package metadata into the app root. It installs only the files package.xml lists. Before, License.txt and manifest.json landed in the project.
  • marketplace diff / update no longer fail with "path too long" under %TEMP% on Windows.

CLI contract (#1490, #1629)

  • git note --write no longer loses notes when the reader of stdout exits early. All notes are written before anything is printed.
  • docker check no longer says widgets were normalised after update-widgets failed.
  • Docs:
    • The 11.6.1 floor applies to docker build only, and check works on Mendix 10.
    • docker check neither downloads MxBuild nor uses Docker. Seven texts said otherwise, and the error a reader of the old docs hits now names mxcli setup mxbuild.

Docs and fork tooling

  • Proposal: a 1,771-call build resizes the loop-efficiency estimate. Tool output is 21% of context, not 68%.
  • Wiki: syncs of describe-round-trip-gaps, mutator-addressing and package-operations-damage.
  • Changelog entries for the splice fixes.
  • Refactors in their own commits:
    • MDL-SET01's variable typing moves to flowObjectTypes.
    • The catalog reads click-action keys from types.WidgetClickActionKeys.
  • Fork-only tooling: the fork's issue-mirroring script no longer duplicates mirrors on a short listing

claude added 30 commits October 22, 2026 14:53
…th change (mendixlabs#1610)

Under mdl 1, create or modify with only an @caption added to or reworded on
an existing if was refused with 'changes where its paths end or meet'. The
caption is a property of the decision, like its condition: it is now set in
place through SetCondition, and the decision keeps its $ID and both paths.

Refs #1538, #1399.

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

Under mdl 1, create or modify and alter both refused any change to an
activity with an on-error handler, and each advised the other. The activity
replaced by one handling errors the same way is now swapped in place, keeping
the stored handler, its error flow and the merge it rejoins at; create or
modify diffs the handler body like an if branch, and alter recognises a
restated handler. Remaining refusals name drop-and-create, not the other mode.

Refs #1345, #1399.

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

An @annotation before a statement's @position is a free note, which is where
describe prints one. Restating an activity's note in that order was refused
with 'note "…" is not in the stored flow', which was false. The refusal now
names the order, the activity the stored note is attached to, and the
spelling that keeps it attached; the write-microflows skill states the rule.

Refs #1399.

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

The in-place replace of an activity with a custom error handler kept only the
activity from the fragment, so a note added to it was silently not written,
and a reworded note was refused. The activity's own notes now come with it,
drawn relative to the stored position, and stored notes are replaced.

Refs #1399, #1345.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7x31pk37iZUX9desbsBdf
`mxcli git note -p App.mpr --write | head -1` wrote no note and said
nothing (mendixlabs#1490, #1346). annotateCommits printed
each note before writing it, and a Go program writing to a stdout whose
reader has gone is ended by SIGPIPE, so the first print to the closed
pipe stopped the write for that commit and every later one.

With --write, every note is now written before anything is printed; the
report is held and flushed afterwards. A preview has no side effect and
still streams.

Writing each note just before its own print (the issue's first
suggestion) is not enough: with two commits the second print still
kills the process before the second write. The test covers two commits
for that reason.

Controls, TestGitNote_WriteSurvivesAClosedStdout (child runs the real
main() with stdout a pipe whose read end is closed; the child ending on
SIGPIPE is asserted in every arm):
  original order:            HEAD~1 lost, HEAD lost
  write-then-print per commit: HEAD~1 written, HEAD lost
  this fix:                  both written

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

Under mdl 1, a note-only change before an if was refused as a change of where
its paths end, and one before the final return as an annotation change. A
decision and an end event are changed in place, never replaced, and the
mutator had no way to attach a note to a node that stays. A new AddNotes op
does, and the diff sets their notes in place like their condition or value.

Refs #1399.

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

With an mx of the project's minor but another patch, `mx update-widgets`
refuses the project ("Project is in different Mendix version", exit
status 4) while `mx check` accepts it (mendixlabs#1629, ako/mxcli
#1561). docker check carried on, as it should, then closed with "Note:
widget definitions were normalised on a temporary copy" a few lines
after "Warning: update-widgets failed (continuing): exit status 4". The
note was keyed on update-widgets being requested, not on it succeeding.

It now keys on the outcome. After a failure it says the check ran
without normalisation, so a CE0463 may be one normalisation clears, and
how to get an mx of the project's exact version.

Measured on real Mendix 10.24.18 tooling (mx 10.24.18 against a v1
project relabelled 10.24.13): update-widgets exit 4, mx check 0 errors;
the same project unrelabelled exits 0 on both. Before the fix the
output contradicted itself; after it, the not-normalised note appears,
and a matched project still gets the normalised note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYmgi2rk8ZbVZ9uEGxR3Nq
`mxcli docker --help` listed "Mendix 11.6.1 or later" as a requirement
of the whole command group (mendixlabs#1629, #1561). The
floor is docker build's: a Portable App Distribution needs 11.6.1, and
Build refuses anything older; run and reload go through Build. docker
check has no gate and works on Mendix 10 (measured on 10.24.18: "The app
contains: 0 errors.").

The group help now scopes the floor to build, run and reload. docker
check --help says it has no floor, and that a failing update-widgets
(exit status 4 on a version mismatch, which mx check tolerates) does not
stop the check.

TestDockerHelp_VersionFloorIsBuildsNotChecks pins it: any line of the
group help naming 11.6.1 must name build. It failed on the old text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TYmgi2rk8ZbVZ9uEGxR3Nq
… is 21%, not 68%

A fourth project, a complete chess-game build measured with diag session-report,
is the largest session recorded and it corrects this document rather than
confirming it.

N x S now holds across three orders of magnitude: 59 calls x 108k = 6M against
6.2M measured, 523 x 435k = 228M against 228M, 1,771 x 372k = 659M against
653.5M. Nothing else here is as well established.

The unwelcome part is what that does to the levers. Tool output is 21% of this
build's bill against 35% in BENCH-001 run 3, and the remaining ~79% is the
conversation itself. The costliest single result is the same shape the benchmark
made item 3b out of — a bootstrap skill file read early and re-read ~260 times —
and it is 1.69M of 653.5M, 0.26%, where the benchmark put the same shape at
5.3%. A 59-call run is not a scale model of a 1,771-call build: it over-weights
every lever aimed at what a tool returns, because in a short session tool
results are most of what there is. The subsection that drew the original
conclusion now carries a banner saying to read it as benchmark-local, and
BENCH-002 at 2x the surface does not fix this.

What it promotes is item 3c, new: one session per phase, each resumed from
brain brief / brain plan. Splitting N calls across k near-empty phases is
N x S / 2k, a factor of k rather than a percentage; the chess session proposed
this itself and sized it at ~30%, which is the k = 2 case. Its price is one
re-orientation per boundary — so 3b, 4 and 4b are not competing with it, they
are what sets its price, and they are recorded as mis-sized token levers that
are better justified that way.

Two items resized downward: retries are 4.5% here against 13.6% in run 3, and
`check` is 9% of invocations, the fourth project in a row to put it nowhere near
the ledger's 83%. One shipped lever shows as adopted: `run wait` is the second
most frequent command at 95 calls, where the three earlier projects hand-rolled
nohup/poll/pkill loops.

The wall-time attribution and the licence-session-cap diagnosis for 150 app
restarts are the other session's estimates, not reproduced here, and are
recorded as a lead to verify rather than as findings.

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

MDL-SET01 tracked, statement by statement, which entity each object and
list variable holds. The next rule needs the same answer for an XPath
operand, so the walk moves into one type both can use instead of a second
copy. Behaviour is unchanged; the SET01 tests pass as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015XD4JpQem7z5pjk2WuYRqf
`set (Action: call microflow M.F) on card1` was refused for a container
CREATE had just written with an action (#1503,
mendixlabs#1592):

  widget "card1" (Forms$DivContainer) has no Action property — Action can
  only be set on a widget that performs an on-click action, such as a
  button or a clickable container

The setter looked only for an `Action` key. The metamodel spells the
click action per type: Action on the buttons and navigation list items,
OnClickAction on Forms$DivContainer, ClickAction on Forms$ListView and
both image viewers. SetWidgetAction now writes the key the stored widget
holds (types.WidgetClickActionKeys, in priority order; no type declares
two) and still refuses a widget with none.

The refusal test's fixture was a container without an OnClickAction, a
shape no stored model holds; it now uses a dynamic text.

Control: the new test fails on main with the reported message. Fixed, on
a blank 11.12.5 app the reporter's script applies, describe shows the new
microflow, re-executing the describe output reports `Unchanged page`,
and `docker check --no-update-widgets` reports 0 errors — for a container
that had an action and for one that had none.

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

The catalog's primary-action reader kept its own copy of the three keys a
widget stores its on-click action under; ALTER PAGE's setter now reads
the same list from mdl/types, so the two cannot drift again (the setter
had known only Action, #1503). The comment's 'layout grids'
was wrong: no LayoutGrid type declares OnClickAction.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PALuhnbBpSb16e2a9A44z9
The free-note ordering rule added in b9bedb2 took the skill body to 705
lines, which TestLargeSkillsWereSplit refuses. The notes section is
condensed; the rules it states are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7x31pk37iZUX9desbsBdf
…ame flow (mendixlabs#1517)

check -p (and exec's preflight) gave up on a statement about a flow an
earlier statement had changed, reporting it 'not predicted', and exec could
then refuse it after the earlier statements ran. The writer gains a simulated
mode: unit updates are held in memory and read back, never flushed, and any
other write is refused at guardWrite. check applies each change it predicts
as spliced to the simulation, so the next statement on that flow is
predicted against what exec would see.

Refs #1399.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7x31pk37iZUX9desbsBdf
…n reading of it

The full `diag session-report` supersedes the partial one recorded earlier
(1,784 calls and 655.7M against 1,771 and 653.5M; the shares are unchanged) and
shows the whole costliest-results list rather than its first entry. That entry
was a skill file, and the previous commit generalised from it the way BENCH-001
had. The list says otherwise.

Orientation at build scale is the agent re-reading its own work. Own MDL source
in small `sed` ranges is 28% of the ten costliest results and subagent artifacts
30%, against the skills' 22%; the lookup counts say the same at full scale, 559
file reads against 101 doc lookups, 154 of them repeats, and 984 of 1,653 Bash
calls are neither mxcli nor git nor build. One 17-line range of a generated file
was re-read by 504 later calls. That is a different problem from item 3b with a
different fix — not going back at all — so item 3d is added for it.

The cost is also a long tail, which inverts the method this document has used
throughout: the top ten are 12.2M of 134.6M, 9% of the tool re-read, against 75%
in BENCH-001 run 3. At build scale there is no whale to harpoon, so only the
structural levers (fewer calls, and not carrying the conversation between
phases) touch the bill.

Delegation is priced for the first time: 10 subagent calls produced 3 of the 10
costliest results, 3.6M, because a subagent saves its own context and not the
caller's unless the handback is small. Item 6 now carries that cost line.

Two defects named by the retry list are added to item 4c: `check` rejecting the
Live Sync "On tick" property on a widget mxcli itself writes, and `Failed to
fetch` on the first assertion after `run restart` — the worst chain in the
session at 5 retries, which says whatever `run restart` returns on is not
readiness.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MgcYSQrLLbUcnAMaCHpyqQ
`ALTER SETTINGS CONFIGURATION 'Default' ExtraJvmParameters = '…'` failed
with "unknown configuration setting: ExtraJvmParameters", and CREATE
CONFIGURATION with "unknown configuration property". The reader already
read the field and the settings overlay already wrote it back; only the
executor's key switches lacked the case, and DESCRIBE never printed it,
so a described project replayed without it.

Both statements now accept the key, and DESCRIBE emits it when set.
Every supported Mendix version stores the property (no versionInfo entry
in the Model SDK; a Studio Pro-authored 11.14 configuration carries it).

Fixes mendixlabs#131 (#1225).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014hU79xp8jYcDYXASt1GHHY
The last row of the #1326 (mendixlabs#1453) repro still
failed after the item address landed. CREATE accepts `group grp1 (…)`
and drops the name — an Accordion group stores none — so the next
statement is `insert into grp1 { … }`, and on a page that also holds a
data grid the miss pointed at the grid:

  widget "grp1" not found. DataGrid2 columns are addressed by a derived
  name (the bound attribute, or the caption), not the name written in
  MDL — available columns: Name (run DESCRIBE PAGE to confirm)

The miss now lists every item address on the page, spelled as typed,
before the column hint:

  widget "grp1" not found. An object-list item (an Accordion group, a
  pop-up menu item) stores no name, so a name written on one in CREATE
  is not kept — address it on its widget: acc1 item@1 = acc1
  item('One'). DataGrid2 columns are addressed by …

Listed are the widgets `item` resolves (exactly one object list), not a
list keyed `columns`, which the column hint covers by derived name.
check -p and exec share the message.

Control: the new test fails on main with the message above, for insert
into, set and drop. Fixed, on a blank 11.12.5 app the reporter's page
gives the new message at check and exec; the address it names applies
and `docker check --no-update-widgets` reports 0 errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PALuhnbBpSb16e2a9A44z9
…item-address miss

Two sentences in paragraphs that already held the class: a click action
is spelled per type (a setter knowing one key refused every container
while the catalog knew all three), and a miss's hint has to cover every
unnamed kind on the page, not the first one fixed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PALuhnbBpSb16e2a9A44z9
Under mdl 1, any change to a free note (one attached to nothing) was refused
as 'the free annotations change'. A new SetFreeNotes mutator op replaces the
flow's free notes and leaves every other element as stored; create or modify
applies it beside the moves and header and reports 'set: free notes'.

Refs #1399.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F7x31pk37iZUX9desbsBdf
…row, column)`

A legacy table cell stores no name and sits at a grid position, so an
alter target names it by that position, counted from 1 as describe will
print it. alterTarget gains `identifierOrKeyword CELL LPAREN row COMMA
column RPAREN`; CELL is a new keyword, listed among the words usable as
identifiers, so a widget named `cell` still parses. The visitor carries
the address as WidgetRef.Cell and spells it into Widget
(`table1 cell(1,2)`), the way a navigation list item's address travels,
so every operation receives it unchanged. A 0 row or column is refused.

The one-number @n read now takes NUMBER_LITERAL(0) and skips cell
addresses, whose two numbers are the position.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019httGxDh8UXt1Zoyh3Gh52
MDL-RETRIEVE02 rewrites `retrieve $u from $obj/System.owner` to
`retrieve $u from System.User where [id = $obj/System.owner] first;`.
That rewrite passed `check -p` and exec, then mx check failed with
[CE0161] "Error(s) in XPath constraint." whenever $obj's entity does not
store its owner (#1306, follow-up on mendixlabs#1358).

Measured with mx check on 11.12.5: $var/System.owner and
$var/System.changedBy are clean iff the root of the variable's
generalization chain stores the member (own entity, FileDocument
specialization, specialization of an owning root) and CE0161 otherwise
(plain entity, its specialization, a create-bound variable).

- validateRetrieveSystemMemberPaths types the variable (flowObjectTypes)
  and judges the root's flag, for microflows and nanoflows; it names the
  `alter entity <root> add attribute owner: AutoOwner` that fixes it.
- scriptSystemMemberRoot judges an entity the same script declares from
  its declaration, and treats an altered one as unknown (the alter is
  how a user applies the fix). #641's [System.owner = ...] check now uses
  it, so it no longer skips the one-script shape.
- MDL-RETRIEVE02's suggestion states the precondition.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015XD4JpQem7z5pjk2WuYRqf
`$S = create M.Entity (Name = 'x', System.owner = $User);` passed
`check -p`, and exec refused it with "member "System.owner" on entity
M.Entity is not a known association ... create the association first
(`create or modify association System.owner from ... to ...`)" — advice
no project can follow (mendixlabs#1612, #1540).

The issue expected the member to be written. Measured with mx check on
11.12.5, a MemberChange with Association "System.owner" (or
System.changedBy) is CE1050 "Unknown association 'System.owner'." for an
entity storing its owner and one that does not, a FileDocument
specialization, a specialization of an owning root, in a microflow and a
nanoflow. There is nothing to write, so this is a refusal:

- MDL-CHANGE01, project-free (plain check reports it) and exec-enforced,
  covering create, change and `set $o/System.owner`.
- The flow builder refuses at the create/change call sites with the same
  message, for paths that skip the rule (--no-check, alter).
- The suggestion is an association to System.User the project models,
  verified clean with mx check.

Kept out of resolveMemberChange on purpose: list operations share it, and
`find $l by System.owner = $u` builds clean.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015XD4JpQem7z5pjk2WuYRqf
`create association ... to System.User` wrote the association and then
exited 1: "failed to reconcile access rules of module System: load domain
model 00000000-0000-0000-0000-000000000002: ... no such file or
directory". reconcileModuleAccess already skips the virtual System module
and has a unit test; the issue asked for an exec test.

This runs the statement through exec on PedApp, with an access rule in
the FROM module so the reconcile has work to do, for System.User and
System.Language, and asserts check and exec agree and describe
round-trips. Control: with the skip removed it fails with the reported
"no such file or directory". On 11.12.5 the result is mx check clean.

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

# Conflicts:
#	mdl/executor/cmd_flow_modify.go
…tion

A legacy table cell stores no name, so an EMPTY one could not be
reached at all; the widgets already inside cells became addressable by
name in #1463 (#1326, mendixlabs#1453). Now:

  insert into table1 cell(1,2) { … }   -- append to the cell
  replace table1 cell(1,1) with { … }  -- swap its content
  drop table1 cell(1,2)                -- empty it (the cell stays: the
                                          table's grid needs it)

INSERT BEFORE/AFTER a cell is refused with the form that works. A
position under a spanning cell names that cell, and a miss lists the
table's cells. A cell is not a data container: widgets inserted into it
bind in the context of the table's surroundings, as a navigation item
sees its list's.

The stored shape was taken from the modeler, not from gen: a table
injected into a blank 11.13.0 app and run through `mx convert -p`
(0 errors) came back as Forms$Table { Cells [2] of Forms$DbTableCell
{ TopRowIndex, LeftColumnIndex, Width, Height, IsHeader, Widgets [2] },
ColumnWidths [2], Rows [2], WidthUnit "Weight" }. gen's Forms$TableCell
and Columns are not what Mendix 11 stores; the fixture is the converted
shape.

Control: the new tests fail before the change with `widget "table1
cell(1,2)" not found`; the data-context test fails without the
table-cell mapping with an empty entity. On the converted table inside
a data view, inserting an attribute-bound text box into the empty cell
binds T.Item.Name, replace and drop act on their cells, and
`docker check --no-update-widgets` reports 0 errors; main does not parse
the address. The regenerated LSP completion list gains the CELL keyword.

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

`marketplace update` (and `install`) left the package's own metadata —
manifest.json, License.txt, the READMEOSS report, Mendix EULA.docx — in the
app root as untracked files (mendixlabs#1487, #1344).

InstallPackageFiles copied every archive entry but project.mpr and
package.xml. It now installs what package.xml lists under <files>, which is
what `mx module-import` installs: measured on 11.12.1 with
ExternalDatabaseConnector 6.3.0 and BusinessEvents 3.12.1, mx wrote exactly
the listed files and passed over a listed one the archive lacks. Entries left
out are reported on one line. A package with no <files> list falls back to
leaving out root-level entries only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDwYCiqWmrM3iXhnz2YeJT
MDL cannot create a legacy table, so describe prints it as one
NOT re-executable line — which left the new `table1 cell(row, col)`
address undiscoverable and hid which cell held which widget. The cells
are now listed under that line, 1-based as ALTER PAGE takes them:

  -- Forms$Table (table1)  -- NOT re-executable: …
  --   cell(1,1): tInCell
  --   cell(1,2): (empty)

Control: without the output change the test misses all three cell
lines. On the converted 11.13.0 table after replace/drop, describe
prints cell(1,1): tRep and cell(1,2): (empty), matching the stored
cells.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019httGxDh8UXt1Zoyh3Gh52
On Windows, `marketplace diff` and `update` failed building the reference
project (mendixlabs#1486, #1343):

  Extracting module files into C:\Users\<user>\AppData\Local\Temp\mxdiff1185592798\target-ref
  The specified file name or path is too long, or a component of the specified path is too long.

mx refuses to write any file whose path is 260 characters or longer, and it
does so itself, so the limit holds on Linux too: measured with mx 11.12.1,
259 is written and 260 refused with the reported message. Bundled
node_modules trees reach 181 characters (11.12.1 blank app) to about 202
(NanoflowCommons 7.x), and %TEMP%\mxdiff<digits>\target-ref left room for
no user name at all.

NewWorkDir builds references under the shortest root the user owns —
%USERPROFILE%\.mxcli\t on Windows, /tmp on POSIX, or TMP/TMPDIR when
shorter — with one-letter names beneath it. A drive-root folder is not a
candidate: children of C:\ inherit Modify for every authenticated user. A
remaining refusal names the directory, its length and the budget left.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDwYCiqWmrM3iXhnz2YeJT
claude and others added 29 commits October 23, 2026 06:25
…ndings

Re-synthesized from the 21 package-operation records in
findings/cmd-mxcli/ (2026-07-31 to 2026-10-22), update.go, workdir.go,
scratch.go and the marketplace guide. New beats: package.xml's <files>
list is the payload contract; replacing a module is a delete that
cascades into other modules' associations, and a transplant arrives
unreconciled; order steps so a failure is not half an install; mx's
260-character path limit makes the scratch directory mxcli's choice.
Drops the quoted finding count; covers: adds cmd/mxcli/marketplace.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UDwYCiqWmrM3iXhnz2YeJT
The TestApp round-trip ratchet ("the allowlist may only shrink") failed
on this branch because 17 listed documents now round-trip:

- the 16 view-entity associations, whose describe printed a plain
  `create or modify association` that exec refuses (CE6771); describe now
  gives them no statement, the view's OQL column declares them;
- WorkflowCommons.ConflictedWorkflowDefinitionView, a Studio Pro-authored
  view entity whose only loss was the stored OQL text that describe → exec
  re-indented.

gofmt realigned the map once its longest keys were gone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017jEcJZDio1jrTrWtVzagjY
…sing-issues-pve1cy

Conflict in widgetNotFoundError: main added the legacy table-cell address
check (#1621) where this branch added the object-list item hint. Both are
kept, the cell check first, since it only fires for a cell(r, c) address.

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

fix: System.owner / System.changedBy references that pass check and fail the build (CE0161, CE1050)
…ler_test

TestSpliceRerun_FreeNoteLineEndings (integration, parity suite) used a
reworded free note as its control for 'still refused'. Free notes now change
in place (mendixlabs#1517), so the control asserts the reword is
written while a line-ending-only difference still writes nothing.

splice_handler_test.go was formatted with a Go 1.24 gofmt; reformatted with
the 1.27.3 toolchain's, as CI's fmt-check runs it.

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

`$m = find $l by System.owner = $User;` was refused at exec with advice
to create a System association, though mxbuild builds it; describe
printed a stored one as `by owner`, and an inherited System association
over Administration.Account as `by User_Language`, which re-executed as
the attribute Administration.Account.User_Language (CE1613)
(#1629).

Measured with mx check on 11.12.5: find/filter by System.owner or
System.changedBy is clean when the generalization root stores the member
(own entity, FileDocument specialization, specialization of an owning
root), CE0091 "No member selected." when it does not, and System.Owner
is CE1613.

- resolveMemberChange resolves System.owner / System.changedBy to the
  System association and refuses another case with the CE1613 spelling.
  Create/change still refuse them first (MDL-CHANGE01, CE1050).
- validateListOperationSystemMembers (reference tier: check -p and
  exec's pre-flight) refuses the CE0091 shape and names the alter.
- extractFieldName keeps a System association qualified, and the member
  speller spells a find's member with the same function, so a declared
  find and the stored one's description compare alike.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015XD4JpQem7z5pjk2WuYRqf
Resolves a CHANGELOG.md conflict at the head of Unreleased › Fixed: main
added the System.owner / System.changedBy entries, this branch the two
marketplace entries. All four kept.

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

fix: alter settings sets ExtraJvmParameters and the Web UI client; check refuses unknown sections
…enTelemetry part

`create configuration 'Staging'` on a Mendix 11.14 project was refused
with "3 element id(s) are used more than once". A new configuration copies
an existing one as its shape template, and from 11.12 a configuration
Studio Pro has saved carries a nested OpenTelemetry part whose elements
(the part and its Logs / Traces children) have $IDs of their own. The
shallow copy kept them, and the duplicate-id guard refused the write.

The template is now deep-copied with a fresh $ID for every nested storage
object; the values are still inherited, and the sibling no longer shares
sub-documents with the copy.

A blank `mxcli new` 11.14 app stores OpenTelemetry = null and does not
reproduce it; on testdata/testapp-views the fixed build creates the
configuration and `mx check` reports the same errors as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014hU79xp8jYcDYXASt1GHHY
Studio Pro's Configuration ▸ Server ▸ Java heap ▸ Maximum size (in MB)
sits beside Extra JVM parameters (mendixlabs#131). It was read and
written back, but `alter settings configuration` and `create
configuration` refused the key and DESCRIBE omitted it.

Both statements now accept it (Integer, MDL-SET01 at check time), and
DESCRIBE emits it when it is not 0 — the stored configuration has no
Default/Custom flag, so 0 is Studio Pro's "Default". No version gate: the
Model SDK has no versionInfo entry for maxJavaHeapSize.

Measured on a blank 11.14.0 app: `mx check` reports 0 errors after
setting it to 2048.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014hU79xp8jYcDYXASt1GHHY
A configuration's Extra JVM parameters — the proxy mendixlabs#131
was filed for — and its Java heap maximum are what Studio Pro passes to
the runtime JVM. `mxcli run --local` and `test --local` started the JVM
with a fixed argument list, so both were silently absent from every
local run.

The run now takes them from the same configuration it takes the constant
values from (chooseConfiguration, extracted from resolveConstantOverrides,
and carried on the same constantChain, so the project is read once):
`-Xmx<n>m` for a non-zero MaxJavaHeapSize, then the parameters split like
a shell would (a quoted run stays one argument), after mxcli's own -D
flags and before -jar. It prints what it passes, without -D values, and
refuses an unbalanced quote before booting.

Verified on the process: booted a blank 11.14.0 app with heap 768 and
`-Dmxcli.probe="from the configuration" -Dhttps.proxyPort=29758`; the
runtime JVM's /proc/<pid>/cmdline held -Xmx768m, the probe as one
argument and the port, all before -jar. The previous build's JVM held
none of them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014hU79xp8jYcDYXASt1GHHY
The LIST / DESCRIBE SETTINGS page documented `DESCRIBE SETTINGS
[category]` with examples `DESCRIBE SETTINGS MODEL`, `… CONFIGURATION`
and `… WORKFLOWS`; none of them parse. The forms that do are `DESCRIBE
SETTINGS` and `DESCRIBE SETTINGS CONFIGURATION 'name'`. The section
table now says what DESCRIBE emits for each section, in the order it
emits it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014hU79xp8jYcDYXASt1GHHY
fix: describe round-trip gaps — view entity associations and XML-schema mappings
The guard that refuses rewriting a mapping sourced from an imported web
service (#365) never fired on a Studio Pro mapping: gen read the source
under its SDK name `ImportedWebService`, but Mendix stores it as
`WsdlFile` (and an export mapping's header flag as `IsHeaderParameter`,
not `IsHeader`). mxbuild's own metadata pairs each storage name with
those SDK names; both pairs sat in keyaudit's known-wrong list. So
describe → exec of a SOAP mapping rewrote it and dropped the binding
(CE6896), and describe printed no SOURCE NOT REPRESENTABLE marker
(#1631).

- gen: storage-name overrides for both keys, in init and in the by-name
  lookup of InitFromRaw; struck from keyaudit.
- roundtrip: the #365 refusal joins the harness's deliberate refusals
  (ADR-0012), and the three TestApp Clients.Soap* mappings, allowlisted
  as breaking GetPut since #743, are struck — they are now refused with
  nothing written.

Control on those Studio Pro-authored mappings: with the gen fix reverted
the harness reports "executing the describe output wrote 1 unit(s)";
with it, "refused, nothing written: … service OrdersWS, operation
GetOrder".

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017jEcJZDio1jrTrWtVzagjY
A comment before a view entity query's first token or after its last
was dropped: the stored query was the token span, and the lexer skips
comments. Every describe → exec into another project lost it
(#1632).

The query now widens over comments between `as (` and the first token
and between the last token and `)`; whitespace handling is unchanged.

Measuring that on a real build showed the comment is only legal from
Mendix 11.7.0. 10.24.25 and 11.6.6 report CE0174 for a comment anywhere
in the query (UseOQLVersion2 on), while 11.7.0 and 11.13.0 report 0
errors. So a query that contains a comment is now refused by `check -p`
and `exec` below 11.7 (MDL-VERSION01, oql_functions.comments). That also
catches the comment between clauses mxcli always stored, which check
passed and mxbuild then rejected. `--` inside a string is not a comment.

Measured: on 10.24.25 the script is refused and nothing is written. On
11.7.0 all four comments are stored, describe → exec into a fresh
project keeps 4 of 4 (pre-fix binary 0), mx check 0 errors.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017jEcJZDio1jrTrWtVzagjY
fix: cli-contract-defects — git note loses notes to a closed stdout; docker check's help and output misstate what it does
…e1cy

fix(alter page): set Action on a container; a miss names item addresses
fix: marketplace package metadata in the app root; 'path too long' under %TEMP% (mendixlabs#1487, #1486)
…references-issues-bkrdmk

# Conflicts:
#	CHANGELOG.md
…s-cxgna9

fix: create configuration on 11.12+, run --local JVM options, MaxJavaHeapSize
fix: SOAP mapping source read under its storage key; view query comments kept and gated on 11.7
…ues-bkrdmk

fix: find/filter by System.owner builds, and describe keeps System associations qualified
On 2026-10-22 a transient empty page cut the listing of existing mirrors
short, and mirror.py re-created the 40 oldest upstream issues as new
mirrors. When duplicates exist, it also tracked the newest mirror (the
listing is newest first), so a closed duplicate shadowed the open
original and upstream closures were applied to the wrong issue.

- paged() asks again before treating an empty page after a full one as
  the end of the listing
- with duplicates, track the open mirror, and the oldest of those
- refuse to create mirrors (exit 1) when the listing is empty but the
  fork has mirrors, or more than 5 upstream issues older than the newest
  mirrored one are unmirrored; --allow-backfill overrides
- test_mirror.py runs the scenarios against a fake API; the previous
  script fails the four that cover the incident

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTDRrgJhKKmSUnBFaDUw62
fix: microflow-splice refusals — error handlers, captions, notes, chained check (mendixlabs#1489, #1610, #1517)
Stop mirror.py from duplicating mirrors on a short listing
@ako
ako merged commit 1c80196 into mendixlabs:main Oct 23, 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 SETTINGS CONFIGURATION does not support ExtraJvmParameters

2 participants