Repository navigation
fix: create or modify does not move a node the script places (#1508 case 6) - #1546
Merged
ako merged 3 commits intoOct 22, 2026
Merged
Conversation
`create or modify` pairing a new `if` and a restated one against the same
stored decision weighed "the same if but for its condition" exactly like
"the same if with a change in a branch", and lcsStatements breaks a tie
toward the earlier pair. So in
if $Out then …; end if; -- new, no @position
@position(-299, 200)
if $Flag then …; end if; -- restated, branch edited
the new `if $Out` took over the stored decision (its condition set in
place) and the restated `if $Flag` was inserted as a new node at its stated
position, on top of it: two decisions at (-299, 200), both merges at
(186, 200).
The weights are doubled and a changed condition now weighs 1, below every
other partial match, so the restated if pairs with its stored decision and
the new one is an insert. Every other ratio is unchanged.
Part of #1508 case 6 (mendixlabs#1598).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A `create or modify` that inserts statements without @position into a flow whose later statements state theirs made room by moving everything past the gap along. The stored flow then said something other than the script: in #1508 case 6 `if $Flag` went -299 -> 40, its merge 186 -> 525 and the return 530 -> 869, while the calls replaced in its branch — placed at their own stated positions, never shifted — stayed at (-124, 100) and (60, 100), left of their decision. Re-running the script was refused (the @merge no longer matched), and shifting "consistently" cannot fix that: the next run must move the nodes back. Under mdl 1 every point the script states a node at — @position, @merge, @start, a note's position:, a parameter's @position; loop bodies skipped, their coordinates are relative — is pinned on the mutator (MicroflowMutator.Pin), and a make-room shift (an insert, or a replace longer than what it replaces) that would move a pinned node is refused, naming the room it needs and the node in the way, with the two ways out: state @position on the new statements, or leave the positions after them unstated so they can move along. Pinning is by point, so a node a placed fragment puts at its stated position is pinned too. mdl 0 is unchanged (ADR-0011): there the refusal would fall back to the whole-flow rebuild, losing the merges, curves and $IDs the shift keeps — TestFlowModify_InsertIsSpliced, ADR-0012's headerless describe+insert acceptance test, caught exactly that. Fixes #1508 case 6 (mendixlabs#1598). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
versions.md enumerates what `create or modify` refuses under mdl 1 where mdl 0 rebuilds; add the insert that needs room past a node the script places. The review command gains the pattern that #1508 case 6 hit: a new splice refusal changes mdl 0 into a rebuild unless it is gated on the language version. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes case 6 of #1508 (mirror of mendixlabs#1598). Stacked on #1528 (
fix/flow-graph-geometry, cases 1–5; this builds on itsPinnedhandling). Base is that branch; retarget tomainonce #1528 merges.The bug
create or modifyof a nanoflow drawn with@positionon every statement, adding anif/elseafter the declare without@positionand editing the calls in the nextif's branch:Re-running the same script was refused (
the connectors of the If at (40, 200) are redrawn). With a plainif(no else) the newiftook over the stored decision and the restatedif $Flagwas drawn on top of it, both merges at (186, 200).Cause, confirmed from source and reproduced on PedApp:
makeRoomshifts every top-level node past the cut by the deficit (339);@position, so it isPlacedand never shifted;movedNodeonly records a move when stated ≠ stored, so the shifted nodes were never moved back (the merge is not a move candidate at all);lcsStatementsweighedifConditionChangedthe same assameIfShell; the tie went to the earlier pair.The decision (option a, chosen by the maintainer)
Shifting consistently cannot make the re-run report Unchanged while the script still states the old positions — measured even for a plain one-activity insert into a described flow (+104, then the re-run is refused on
@merge). So:Under mdl 1, a node at a stated position is pinned. The executor collects every point the script states a node at —
@position,@merge,@start, noteposition:, parameter@position; loop bodies skipped (relative coordinates) — and the mutator pins whatever is drawn there (MicroflowMutator.Pin). A make-room shift (insert or longer replace) that would move a pinned node is refused, naming the room and the node:Pinning is by point, not
$ID, so a node a laterPlacedfragment puts at its stated position is pinned too.mdl 0 is unchanged (ADR-0011). The option as proposed let mdl 0 fall back to the whole-flow rebuild, like every splice refusal.
TestFlowModify_InsertIsSpliced(ADR-0012's describe → insert → exec acceptance test, headerless) caught what that means: a headerless describe+insert that used to splice became a rebuild that deletes the Studio Pro merges and$IDs. ADR-0011 says a new refusal applies only under the version that introduces it, so the pins are gated onflowRebuildRefused.Applies; a headerless script makes room exactly as before.LCS weights split: exact 4, position-only / same
ifshell / editable loop 2, condition changed 1 (all existing ratios kept; only the condition-changed pair drops). The restatedif $Flagnow pairs with the stored one; the newifis an insert, refused like the else variant instead of stacking.alter microflowis unaffected (it states no kept positions, so nothing is pinned).Evidence
TestSplice_MakingRoomRefusesToMoveAPinnedNode(mfmutator): insert / longer replace / earlier placed fragment refused; controls (nothing pinned → b moves 420→570; pins only before the gap → accepted).TestLCSStatements_TheSameConditionWinsOverAChangedOne.TestCreateOrModify_InsertDoesNotMoveStatedNodes1508(PedApp, modelsdk backend): both reported variants refused and nothing written; control = the same change with positions after the insert left unstated → spliced, both calls betweenif $Flagand its merge, re-runUnchanged nanoflow.Control runs (fix stubbed, tests run):
Real binary on a PedApp copy (mdl 1): both variants refused with the message above; the free variant →
Modified … (spliced: 1 inserted, 1 replaced, 1 dropped), describe shows decision 40 / calls 215.. / merge 685 / return 1029, re-run →Unchanged nanoflow: MyFirstModule.NF_Do.mxcli docker checkon the result: no error on NF_Do / JS_Do / SUB_Check (the 1078 errors are PedApp's baseline: CE6083/CE0462/CE0535 from its stripped theme and widgets). Headerless: spliced as before (test case "mdl 0 splices as before").Gates
make build,make test,make lint,make check-mdl,make check-findings: pass. (A firstmake testfailed only onno space left on device:/tmpis a 12 GB tmpfs shared with other sessions; re-run withTMPDIRon the overlay disk, green.)-tags integration ./mdl/roundtrip):TestFlowRerunProperty(+ controls),TestPedAppFlowSpliceParity,TestPedAppSpliceParity_*, everyTestFlowModify_*(incl.TestFlowModify_InsertIsSpliced),TestSpliceRerun_*,TestFlowVerdictAgreement_*: pass. Skipped here (no TestApp fixture in this checkout):TestTestAppFlowSpliceParity,TestFlowModify_TestAppHeaderAndPositions.Review notes (
/mxcli-dev:review)No blockers. Two moderate points left open on purpose:
check -p/fmt --upgrade -pundermdl 1do report it, through the samedecideFlowModify. A warning on plain mdl 0 exec would need a "spliced, but warn" verdict that exec, diff and check do not have yet.statedPointsnames the position-bearing annotation fields by hand (Position,Merge,Start, note positions, parameters). A new one would have to be added there.Also
mdl-examples/bug-tests/flow-geometry-1508-splice-keeps-stated-positions.mdl.claude/skills/fix-issue/findings/mdl-backend/2026-10-21-splice-shift-leaves-placed-fragment-behind.jsondocs-wiki/bug-patterns/flow-graph-geometry.md: "making room is a move the script did not ask for"Not touched, noticed: the make-room shift also moves the parameters (y 53) along with the row (
$Flag200 → 539/699 here), so describe starts printing a parameter@positionafter any insert. Pre-existing; separate follow-up.🤖 Generated with Claude Code