From e61a1339c8a02725695db8a151d9f1ff5b8a70c9 Mon Sep 17 00:00:00 2001 From: r Date: Fri, 25 Sep 2026 08:45:05 +0000 Subject: [PATCH] =?UTF-8?q?bug-logs:=20BUG-DRAFT-layout-merge-in-if-branch?= =?UTF-8?q?=20=E2=80=94=20v0.24.0=20auto-layout=20overlaps=20the=20merge?= =?UTF-8?q?=20with=20the=20activity=20after=20a=20loop=20in=20an=20if=20br?= =?UTF-8?q?anch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Parked as a paste-ready upstream draft (NOT YET FILED) plus the ledger entry, so the lint ratchet's MPR008 rise can be told apart from a real overlap. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw --- CHANGELOG.md | 1 + bug-logs/mxcli-bugs.md | 74 +++++++++++++++++++ .../layout-merge-in-if-branch.md | 71 ++++++++++++++++++ 3 files changed, 146 insertions(+) create mode 100644 bug-logs/pending-github-issues/layout-merge-in-if-branch.md diff --git a/CHANGELOG.md b/CHANGELOG.md index f1623157..480cc18b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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: ` and exits 1 while keeping the write (shape, not corruption), `SKIP_LINT=` 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 diff --git a/bug-logs/mxcli-bugs.md b/bug-logs/mxcli-bugs.md index c4268be7..9cce60b6 100644 --- a/bug-logs/mxcli-bugs.md +++ b/bug-logs/mxcli-bugs.md @@ -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 $ .;` 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. diff --git a/bug-logs/pending-github-issues/layout-merge-in-if-branch.md b/bug-logs/pending-github-issues/layout-merge-in-if-branch.md new file mode 100644 index 00000000..9256cbe4 --- /dev/null +++ b/bug-logs/pending-github-issues/layout-merge-in-if-branch.md @@ -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.