Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ three commits past it), and a bug report can name a release instead of a sha nob
Sections dated before 2026-09-19 predate the cycle and stay as they are.

## Unreleased
- learn(bug-logs): **`BUG-DRAFT-layout-merge-in-if-branch`** — the v0.24.0 layout engine (upstream #1154) puts the merge node on top of the activity that follows a loop inside an `if` branch, so `mxcli lint` reports MPR008 on a correct script that carries no `@position`; plain if/else and a branch holding only the loop lay out clean. Paste-ready draft in `bug-logs/pending-github-issues/`, NOT YET FILED. Matters to the lint ratchet (#134): an MPR008 whose two elements are a merge and the activity after a loop in an `if` branch is this bug, fixed by the workaround, never by `--update-baseline`. Measured on mxcli v0.24.0, Mendix 11.12.1, scratch copy of a PoC model — Maurits Visser
- new(skills/microflow-preflight.md): **a microflow with a loop, a list built from a list, or more than 20 activities now gets a posted checklist before its first MDL line.** Lint runs only after exec. CONV009/QUAL003 count top-level activities only, so 20 activities inside one loop count as 3. Retrieve, REST and Java calls inside a loop have no lint rule at all. The skill maps each Mendix microflow best practice to the rule that catches it afterwards, or marks it "preflight is the only check". It sets the layout rule to "omit `@position`", which upstream now states too, and adds STOP row 25, a baseline routing row and an mdl-agent bullet. It corrects the stale `reset layout` advice (BUG-28), the commit-in-loop cookbook recipe and the 30–50-activity guideline. Field evidence: measured on mxcli v0.24.0 on a scratch copy of a real model — CONV011 on a commit in a loop, MPR008 on partial and 100 px hand placement, MPR011 on negative loop-body coordinates, and a v0.24.0 auto-layout defect where a loop followed by an activity in an `if` branch puts the merge on that activity (MPR008 on a correct script) — Maurits Visser
- fix(project-bin/exec.sh): **the lint ratchet now runs after every clean mxbuild, and its verdict lands in the same BUILD-LOG row.** mxbuild proves the model compiles, not how it is built: on a field project a migration microflow shipped three commits inside loops (`mxcli lint` CONV011) under "✅ applied · mxbuild clean", because lint lived only in the gate-agent definition as an optional step and that agent had been spawned 0 times against 21 `exec.sh` runs. `exec.sh` now calls `bin/lint-gate.sh` after a clean build; a rise vs the committed baseline writes `⚠️ applied, LINT ROSE: <rules>` and exits 1 while keeping the write (shape, not corruption), `SKIP_LINT=<reason>` is the only override and is recorded in the row, and a project without `lint-gate.sh` gets `lint not installed` rather than a blank cell. `agents/gate-agent.md` and `agents/agent-roles.md` now read the row instead of treating lint as optional; `learned-detection-gaps.md` gains the register row. Field run: a marketplace guest-group migration, 2026-09-24, ~13 s per run on a 10k-finding project — Maurits Visser
- learn(ui-loop, learned-detection-gaps): **the screenshot harness is an instrument, and nobody
Expand Down
74 changes: 74 additions & 0 deletions bug-logs/mxcli-bugs.md
Original file line number Diff line number Diff line change
Expand Up @@ -5682,3 +5682,77 @@ Probe: `mxcli init --tool claude` (v0.22.0) into an empty directory. The generat
- `bin/sync-project.sh` now warns, report-only, when the `DECLARE $<var> <Module>.<Entity>;` row is present in a project's `CLAUDE.md` (stale `mxcli init` row — re-run init or strip it), alongside its existing stale-ledger-row warning.
- `skills/bootstrap-project.md`: the audit pass strips the row when merging into an init-generated `CLAUDE.md`.
- Still open: until a stamp exists upstream, record `mxcli --version` in `PROJECT.md` at init time so the drift is at least dated.

---

## BUG-DRAFT-layout-merge-in-if-branch: v0.24.0 auto-layout puts the merge on top of an activity that follows a loop inside an `if` branch — lint MPR008 on a correct script with no `@position` (2026-09-25)

> **NOT YET FILED** — paste-ready draft in `bug-logs/pending-github-issues/layout-merge-in-if-branch.md`.

**Discovered:** 2026-09-25, measuring the rewritten v0.24.0 layout engine (upstream #1154) for
`skills/microflow-preflight.md`, on a scratch copy of a small Mendix 11.12.1 PoC model.
**Reproducible:** yes, minimal A/B with two controls that lay out clean, on the same copy.
**mxcli version:** `v0.24.0` (built from the `v0.24.0` tag). **Mendix:** 11.12.1.

**What happens.** A microflow whose `if` branch contains a loop *and then another activity*
gets its merge node laid out on top of that activity. The script carries no `@position` at all,
so this is the auto-layout the `syntax microflow.layout` help tells you to prefer. `describe
microflow` shows the merge 20 px from the commit; `mxcli lint` reports **MPR008** (overlapping
elements) on a script that is correct.

```
-- no @position anywhere; default layout
create or modify microflow Probe.SUB_LoopInIf ()
begin
retrieve $Items from Probe.Item;
if $Items != empty then
loop $Row in $Items
begin
change $Row (Name = 'x');
change $Row (Name = 'y');
end loop;
commit $Items on error rollback;
else
log info node 'Probe' 'empty';
end if;
end;
```

Coordinates from `describe microflow Probe.SUB_LoopInIf` after `exec` on v0.24.0:

| element | x, y |
|---|---|
| if | 520, 200 |
| loop (true branch) | 870, 200 |
| commit (true branch, after the loop) | 1210, 200 |
| **merge** | **1230, 200** |
| log (else branch) | 690, 350 |
| end | 1430, 200 |

**Controls, same binary, same copy — both clean:**

| Shape | merge | lint |
|---|---|---|
| plain if/else, no loop (two activities in the true branch at 690 and 850) | 970, 200 | clean |
| `if` branch containing **only** the loop, nothing after it | after the loop | clean |

So the loop's own width is accounted for when the merge is placed, but an activity that follows
the loop inside the same branch is not. The pattern is common — "if there is anything to
process, loop over it, then commit the list" — and it is the shape the `microflow-preflight.md`
collect-then-commit recipe produces when the whole thing sits under a guard.

**Expected:** the merge sits after the last activity of the longest branch, as it does for
branches without a loop.

**Workaround (in `microflow-preflight.md` → "Known v0.24.0 defect"):** move the loop into a
`SUB_` microflow, or place the trailing activity after `end if`. Do not hand-place the merge
with `@merge` — partial hand placement is what MPR008/MPR011 flag first (measured in the same
session: one hand-placed statement among auto-placed ones → MPR008; a negative loop-body
coordinate → MPR011).

**Why it matters for the toolkit.** `project-bin/exec.sh` now runs the lint ratchet after every
clean mxbuild (#134) and a rise over the baseline writes `LINT ROSE` into the BUILD-LOG row. A
correct script that trips MPR008 through this defect looks identical to a real overlap, so the
gate-agent's "do not accept the rise with `--update-baseline`" rule needs this entry to tell the
two apart: an MPR008 whose two elements are a merge and the activity after a loop in an `if`
branch is this bug, and the fix is the workaround above, not a baseline bump.
71 changes: 71 additions & 0 deletions bug-logs/pending-github-issues/layout-merge-in-if-branch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
**Repo:** `mendixlabs/mxcli`
**Source:** `bug-logs/mxcli-bugs.md`, `## BUG-DRAFT-layout-merge-in-if-branch` — found 2026-09-25
**Status:** NOT YET FILED
**Suggested labels:** bug, layout, lint
**Duplicate check:** not yet searched (GitHub API unreachable from the session that drafted this) — search `MPR008 merge` and `#1154` before filing.

---

**Title:** v0.24.0 auto-layout places the merge on top of the activity that follows a loop inside an `if` branch (MPR008 on a script with no `@position`)

**Body:**

## Summary

With the rewritten layout engine (#1154), a microflow whose `if` branch contains a loop *followed by another activity* gets its merge node laid out on top of that activity. The script has no `@position` at all. `describe microflow` shows the merge 20 px from the trailing activity, and `mxcli lint` reports **MPR008** (overlapping elements) on a correct script.

**Version:** mxcli v0.24.0 (built from the `v0.24.0` tag), Mendix 11.12.1, Linux.

## Repro

```
-- no @position anywhere; default layout
create or modify microflow Probe.SUB_LoopInIf ()
begin
retrieve $Items from Probe.Item;
if $Items != empty then
loop $Row in $Items
begin
change $Row (Name = 'x');
change $Row (Name = 'y');
end loop;
commit $Items on error rollback;
else
log info node 'Probe' 'empty';
end if;
end;
```

```
mxcli exec repro.mdl -p App.mpr
mxcli -p App.mpr -c "describe microflow Probe.SUB_LoopInIf"
mxcli lint -p App.mpr
```

## Measured

| element | x, y |
|---|---|
| if | 520, 200 |
| loop (true branch) | 870, 200 |
| commit (true branch, after the loop) | 1210, 200 |
| **merge** | **1230, 200** |
| log (else branch) | 690, 350 |
| end | 1430, 200 |

Lint: `MPR008` on `Probe.SUB_LoopInIf`.

## Controls (same binary, same model) — both lay out clean

- Plain if/else without a loop: merge at 970, 200; true-branch activities at 690 and 850; lint clean.
- An `if` branch that contains **only** the loop and nothing after it: lint clean.

So the loop's width is accounted for when the merge is placed, but an activity after the loop inside the same branch is not.

## Expected

The merge sits after the last activity of the longest branch, as it does for branches without a loop.

## Workaround

Move the loop into a sub-microflow, or place the trailing activity after `end if`. Hand-placing only the merge with `@merge` is worse: partial hand placement trips MPR008/MPR011 itself, and the `syntax microflow.layout` help rightly says to prefer no `@position` at all.
Loading