Skip to content

new(model-scope): find and put back units a write changed only in XPath whitespace - #535

Closed
saingge wants to merge 1 commit into
MendixMau:masterfrom
saingge:new/model-scope
Closed

saingge wants to merge 1 commit into
MendixMau:masterfrom
saingge:new/model-scope

Conversation

@saingge

@saingge saingge commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Branch new/model-scope, 1 commit (487c390) on origin/master 393d253. First of two stacked PRs; fix/exec-model-scope wires it in.

Direct lane

What changed and why (one paragraph):
On a Mendix 10.24.18 app (MPR v2), one mxcli v0.27.0 alter entity … rename attribute rewrote 135 units in 20 modules that never referenced the attribute. The only change in each unit was the line breaks between bracketed conditions in XPath constraint strings. mxcli diff-local showed nothing, because the MDL it renders is identical, so the reviewer met all 135 in the branch diff (mendixlabs/mxcli#1596). New project-bin/model-scope.py compares each changed unit file with a git ref (default HEAD). A unit is noise when every differing field is an XpathConstraint/XPathConstraint that is equal once whitespace outside string literals is removed; anything else is real. report [-v] prints the counts and the real changes per module. restore checks the noise units out of the ref and updates their ContentsHash rows through mxpatch.py; if the checkout stops part-way, it still re-indexes every listed file, so the index matches the files, and exits 2 asking for a re-run. check --staged exits 1 when staged unit files are noise and names the remedy; MODEL_SCOPE_OK=1 lets one commit through, out loud. Nothing calls it yet; the next PR adds it to exec.sh and the pre-commit hook.

Impact

Row Answer
Process none: a new on-demand command; nothing calls it in this PR, nothing new blocks
Dependencies bin/lib/install-manifest.sh (one name in MXTK_PROJECT_BIN plus a comment). Imports mxpatch.py and mxunit_bson.py from its own directory (both already installed). Python 3 and git only. Open draft #311 also edits install-manifest.sh; a trial merge (git merge-tree) gives the same conflicts with this branch as with origin/master alone, so this PR adds none. The canvas stack also adds a line to install-manifest.sh; whichever merges second keeps both.
Context cost none: no routed or always-loaded file touched
Behaviour n/a: scripts only
Runtime n/a in this PR (nothing calls it). Measured: report on the golden capture, 0.19 s wall (/usr/bin/time -p, macOS arm64)

Field evidence: the incident above (mxcli v0.27.0, Mendix 10.24.18, 135 units / 20 modules), found in branch review. Reproduced on a public model: tests/wave2/fixtures/model-scope/golden-v0.27.0/ is a real mxcli v0.27.0 rename on the toolkit's own mxpatch fixture model (Mendix 11.14.0). mxcli printed "Updated 2 XPath constraint(s) in 2 document(s)"; one of the two was in module Other, which the script never named. CAPTURE.md records every step, including how the two-line XPaths were written (through mxpatch.py, since mxcli stores XPaths on one line, mendixlabs/mxcli#1542). Field run (T2): on a copy of a Mendix 10.24 enterprise app, see Verification.

  • No client data anywhere in the diff (leak guard clean, plain and with LEAKGUARD_BASE=origin/master; new words are synthetic fixture names and code identifiers)
  • Size cap: over the line cap. 3 files, 593 lines excluding fixtures and CHANGELOG: model-scope.py 410, test-model-scope.sh 179, manifest 4. The instrument is one file that cannot be split without splitting its single rule, and it ships with its test. The wiring is already split off into the stacked PR.
  • Test tier reached: T2 field run (Verification) and T1 (tests/wave2/test-model-scope.sh, 39/39) plus T0 for the manifest (test-manifest-clean-checkout.sh, 1/1)
  • Golden input captured, not hand-written; both layouts (.mpr at the root and under app/, section C); macOS only, Git Bash/Windows not run (paths go through os.path, git through subprocess with argument lists)
  • New skill: n/a
  • CHANGELOG.md line, credited
  • Bug entries: n/a

Verification

Run in an isolated worktree on 393d253 + this commit, macOS arm64, Python 3.

  • bash tests/wave2/test-model-scope.sh → PASS: 39 FAIL: 0. Sections: G golden capture (report "3 unit file(s) changed, 1 real, 2 noise", "real changes by module: MyFirstModule 1"; restore makes both noise units byte-equal to before/, the real domain-model change stays, mxpatch verify shows no mismatch), A whitespace rule, B classification (whitespace inside a literal = real, XPath whitespace plus another field = real, key order = real, added/deleted = real, a page's XPathConstraint, a unit in a folder), C restore (second run writes nothing, .mpr byte-identical; --against; model under app/; clean tree; unknown ref exits 2; a checkout that stops part-way, forced by a read-only unit directory, exits 2 with the restored unit re-indexed and the index matching every file), D check --staged.
  • Mutation control: with the rule changed to strip whitespace inside literals too, the run reports FAIL literal not real (37/1).
  • Mutation control: the previous restore (no re-index after a failed checkout) fails the part-way case (FAIL partial restore, 38/1).
  • Field capture: after restore on the captured after/ state, real mxcli fix hashes -p TestApp.mpr (v0.27.0) exited 0 and reported the index matches every unit file (fix-hashes-after-restore-v0.27.0.out).
  • Field run: a Mendix 10.24 enterprise app, mxcli v0.27.0: one rename changed 149 units in 21 modules; restore put back 146 (XPath whitespace only, 21 modules), kept 3 real (the domain model and 2 documents that reference the attribute, all in the renamed entity's module) in 1.3 s; a second report shows 0 noise; mx check (mxbuild 10.24.18, Docker) on the restored model: exit 0, 0 errors.
  • bash tests/wave2/test-manifest-clean-checkout.sh → 1 passed, 0 failed ("project-bin/ is fully named by the manifest").
  • bin/check-portability.sh → clean, 306 files. bin/check-scripts.sh reports project-bin/script-owners.sh: line 295: syntax error under macOS bash; that file is unchanged from origin/master.
  • bin/check-no-client-data.sh → no client data, 1155 files; with LEAKGUARD_BASE=origin/master → no new capitalised words.
  • Not run: mx check on the restored 11.14 capture (11.14 mxbuild not available); the field run above covers it on 10.24.18. The full suite (CI).

…th whitespace

mxcli v0.27.0's `alter entity ... rename attribute` rewrote 135 units in 20 modules of a
Mendix 10.24.18 app that never referenced the attribute. The only change in each was the line
breaks between bracketed XPath conditions; `mxcli diff-local` showed nothing
(mendixlabs/mxcli#1596).

project-bin/model-scope.py: `report` sorts changed units into real and noise, `restore` checks
the noise out of HEAD and updates its ContentsHash rows through mxpatch.py, `check --staged`
exits 1 on staged noise (MODEL_SCOPE_OK=1 overrides once). Not wired into exec.sh or the hook
yet; that is the next PR.

Fixture tests/wave2/test-model-scope.sh, including a golden before/after capture of a real
v0.27.0 rename on a public model (fixtures/model-scope/golden-v0.27.0/, CAPTURE.md).
@MendixMau

Copy link
Copy Markdown
Owner

Thanks @saingge! Independent review: MERGE. We moved your commit unchanged, with your authorship, into #559, plus one docstring line: it said exec.sh runs restore, and nothing does yet. Moving it lets CI run without fork approval and lets us handle CHANGELOG conflicts. This PR closes when #559 merges; the merge commit carries a Co-authored-by line for you.


Generated by Claude Code

MendixMau added a commit that referenced this pull request Oct 22, 2026
…th whitespace (#559, from #535)

mxcli v0.27.0's `alter entity ... rename attribute` rewrote 135 units in 20 modules that never referenced the attribute; only XPath line breaks changed (mendixlabs/mxcli#1596). project-bin/model-scope.py: `report` sorts changed units into real and noise, `restore` checks the noise out of HEAD and rehashes its ContentsHash rows via mxpatch.py, `check --staged` exits 1 on staged noise (MODEL_SCOPE_OK=1 overrides once). Not wired into exec.sh or the hook yet; the docstring now says so. Golden input is a real v0.27.0 capture; field run restored 146 of 149 units, mx check 0 errors. Contributed by @saingge in #535.

Review: MERGE — field-proven, captured golden input, nothing calls it yet; docstring corrected. Security review: safe (git/sqlite3 via argument lists, no shell).

Co-authored-by: saingge <262679532+saingge@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
@MendixMau MendixMau closed this Oct 22, 2026
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.

2 participants