mxcli v0.27 exec is all or nothing; STOP #22, learned-detection-gaps, iterative-build-loop and exec.sh still say it is "not transactional", and the "non-idempotent statement last" pattern no longer works #539
Description
Files at 393d253: skills/learned-mdl-preflight.md line 59 (STOP #22); skills/learned-detection-gaps.md line 31; skills/iterative-build-loop.md line 287; project-bin/exec.sh lines 1615 and 1739-1741 ("PARTIAL APPLICATION LIKELY") · mxcli: v0.27.0 · Mendix: 11.14.0
Summary
The mxcli v0.27.0 release notes: "exec is all or nothing: when a statement fails at write time, the whole run is
rolled back, so a script never leaves a project half-changed" (mendixlabs/mxcli#1408). Reproduced:
-- r2.mdl (second run; the first run created both entities)
create or modify persistent entity M.E (A: String(50), C: Integer); -- edited: adds C
create persistent entity M.F (B: String(10)); -- bare create, already exists
$ mxcli exec r2.mdl -p <app>.mpr
Modified entity: M.E
Error: entity already exists: M.F — ...
Nothing was written: statement 1 was rolled back, and the project is as it was before exec
exit 1
$ mxcli -c 'describe entity M.E' -> A only; C is not there
The toolkit still teaches the old behaviour:
| Place | Text today | True on v0.27? |
|---|---|---|
learned-mdl-preflight.md STOP #22 |
"mxcli is not transactional across statements ... the earlier statements stay written" | No |
learned-detection-gaps.md:31 |
"the failing statement stops the script and every statement below it is silently skipped" | Half. Nothing below runs, but nothing above is kept either |
iterative-build-loop.md:287 |
"partial changes are already live" | No |
exec.sh:1739-1741 |
"PARTIAL APPLICATION LIKELY ... everything before the failing statement is already in the model" | No. It misleads the reader of a failed run |
A pattern this breaks. Projects that followed the old rule put the one statement with no idempotent form (an
alter page ... insert, a drop enumeration without if exists, a bare create) last. A re-run then "re-applies
everything above it, then is refused" and the model still gets the earlier edits. On v0.27, the refusal of that last
statement rolls back the whole run. Any edit made to an earlier statement is silently not applied, and the exit code
is 1 on every re-run. The "exec twice, the second run writes nothing" check becomes a failure instead of a no-op.
STOP #22's conclusion is still right: one owner per document, create or modify / if not exists everywhere,
and a from-empty replay. Only the reasoning and the consequences changed.
Suggested fix (ranked)
- Rewrite the four passages, version-gated: "Before v0.27.0, exec was not transactional (earlier statements stayed
written). From v0.27.0 it rolls back the whole run on any write-time failure ('Nothing was written: statement N was
rolled back')." Keep STOP Docs: "Where you run this" visual (guide §5, README, SVG) and the Docker-on-WSL2 / lanes-mix notes #22's rule. Add the new consequence: a non-idempotent statement anywhere, first or last,
makes the whole script fail on re-run and drops every edit in it. - Add a STOP row (or extend Docs: "Where you run this" visual (guide §5, README, SVG) and the Docker-on-WSL2 / lanes-mix notes #22): "never rely on placing a non-repeatable statement last". Give one-shot statements
their own script, or comment them out after the first exec with a dated note. exec.sh: on a failed exec, read mxcli's version (or grep the output forNothing was written) and print
"rolled back by mxcli, nothing applied" instead of "PARTIAL APPLICATION LIKELY". Keep the gate run either way.- The STOP-table pre-exec scan (Turn the learned-mdl-preflight STOP table into a static pre-exec scan #349) could warn on a script whose last statement has no idempotent form.
How to retest
The two-statement script above on a scratch app, run twice: on v0.27+ the second run exits 1 with "Nothing was
written", and the first entity keeps its old definition.
Activity
fix(doctor, exec): name the env file JAVA_HOME came from; failed-exec…
Bug sweep 2026-10-26: gates, runners, doctor, lint receipt, git hooks…
MendixMau commentedon Oct 26, 2026
Fixed in #578 (squash a088b4e). STOP #22, learned-detection-gaps, iterative-build-loop and exec.sh now say v0.27+ exec is all-or-nothing. exec's message is conditional on mxcli printing "Nothing was written", since a failed rollback can leave the project partly updated (checked against
cmd_exec.go).Generated by Claude Code