Skip to content

rehost: mendix-mpr pipeline (split from #293, 3/6) - #342

Merged
MendixMau merged 5 commits into
masterfrom
split-293/rehost
Oct 15, 2026
Merged

MendixMau merged 5 commits into
masterfrom
split-293/rehost

Conversation

@MendixMau

@MendixMau MendixMau commented Oct 14, 2026 •

Copy link
Copy Markdown
Owner

Split from #293 (part 3 of 6). #293's review said HOLD, so it is being split. This PR holds only the pipeline code.

Direct lane

What changed and why (one paragraph):
This adds pipelines/mendix-mpr/, the Rehost extractor for an existing Mendix app. rehost-extract.sh describes each own module with mxcli, reorders statements so callees come first (lib/topo-order-mdl.py), and replays them into a fresh target .mpr of the same Mendix version. When check or exec refuses something, the loop defers it and retries it (lib/quarantine-mdl.py, lib/exec-resume.py, lib/exec-each.py), so no module is dropped. It then writes a fidelity ledger: one row per source document, with the denominator in the header (lib/compare-mdl.py).

export-module-mpk.py writes a module package from an MPR v1 app, for Mendix 9 sources whose mx has no export. By default it empties these in the project documents:

  • demo users, user roles, admin password
  • per-configuration constant values, database credentials, certificates
  • navigation profiles

The module's own units, constant default values included, are copied byte for byte unless --scrub-constant-defaults is passed. Unknown options are refused. The exporter belongs here because the README documents it as this pipeline's "MPK route" and it reads a source .mpr.

Changes from #293:

  • No samples. The README states the results inline. The only captures are the small golden inputs of the new fixture.
  • Names replaced by app type.
  • Inbox, process and sample citations removed.
  • bash 3.2: rehost-extract.sh no longer uses mapfile or declare -A.
  • CLAUDE.md: one row added to the Pipelines table.

Generic-first check: none of these files read a BRD. All of them read a .mpr, mxcli output or MDL. So nothing moves to bin/.

Field evidence (from #293's runs, public apps, Linux container, mxcli v0.26.0 unless noted):

  • Banking sample app (Mendix 11.13, 155 documents):

    • 154 of 155 identical on describe
    • mx check 0, BUILD SUCCEEDED
  • GenAI showcase app (Mendix 11.12, 2776 documents), on an mxcli nightly:

    • 36 of 36 modules landed
    • Not build-green: 42 × CE1613
  • Field-service template (Mendix 9.24):

    • three modules exported on the default path (constant defaults copied) and installed into 10.24 and 11.13
    • one of them reached mx check 0 and BUILD SUCCEEDED on 11.13 after 3 Java edits
  • Not verified:

    • macOS: no bash-3.2 run
    • the two-tree layout (.mpr under app/)
  • No client data anywhere in the diff (leak guard clean; whole-word denylist grep clean)

  • Size cap: over the cap. One pipeline, about 1,370 lines excluding CHANGELOG and fixtures. export-module-mpk.py could be split off if wanted.

  • Test tier reached: T1 for the parse, the refusals and the option check (fixture below). The other checks:

    • py_compile and bash -n
    • a stub-mxcli smoke run of the whole script
    • all guard checks clean, render-routing --check in sync
  • Golden input is captured, not hand-written: tests/wave2/fixtures/rehost-list-modules/. Both layouts and both platforms: unverified, as stated above.

  • For a new skill: n/a (the skills are in skills: decompose-app, rehost-app + mendix-service-seam (split from #293, 4/6) #346)

  • CHANGELOG.md line appended, credited

  • No bug entries

Review

First review (MERGE-AFTER-FIX), addressed in 300cd35, constant handling revised in aa7d7fc

  1. MEDIUM: the secrets claim was false. Module constants' DefaultValue was copied byte for byte.
    • Now: the default is unchanged from the field-proven path, so constant defaults are copied byte for byte. The opt-in flag --scrub-constant-defaults empties every Constants$Constant DefaultValue in the module, recomputes the ContentsHash and prints constant defaults emptied: N (names), on stderr under --json.

    • --keep-constant-defaults, added in 300cd35, is dropped. It never reached master. Since a70afd9 it is refused like any unknown option (exit 2).

    • The README states plainly that module constant defaults travel in the MPK unless the flag is passed, and marks the flag "unverified in Studio Pro: not yet installed and checked". The what-is/isn't-scrubbed table is adjusted.

    • Checked headlessly, on a copy of mxcli's public v1 test project (Mendix 9.24) with two constants added by mxcli:

      • default run: values copied, units byte-identical to the source
      • with the flag: both values empty, hash recomputed, count printed
    • Field run still owed for --scrub-constant-defaults:

      1. export a module that has String and non-String constants with the flag
      2. mxcli marketplace install --file <out.mpk> into a Mendix 10.24 app
      3. mx check on 10.24, with the result captured: does the package install, and how is an empty Integer/Boolean default reported?
      4. then the same on 11.13

      Until that run, the flag stays opt-in and marked unverified.

  2. LOW: same-path misuse.
    • export-module-mpk.py refuses out == src by realpath, exit 2, before any os.remove or write. Checked directly and through a symlink.
    • rehost-extract.sh refuses source == target by realpath, exit 2, before creating the out-dir.
  3. LOW: bash 3.2, empty module list. The script exits 2 with a message before the first "${MODULES[@]}".
  4. Field proof for the list modules parse.

Confirmation review (MERGE-AFTER-FIX), addressed in aa7d7fc

Flipped the constant default and documented it, as described under item 1. After the flip, the fixture gave 5 ok, 0 FAIL, and all checks were clean.

Last fix, addressed in a70afd9

  • Unknown options are refused. export-module-mpk.py main() refuses any -- option outside --no-widgets, --scrub-constant-defaults and --json. It prints the unknown option, the known ones and the usage, exits 2, and writes nothing. Before this, a typo such as --scrub-constants was silently ignored and the package shipped every constant default in plain text. The README notes the refusal.
  • CHANGELOG wording. "with secrets scrubbed" now lists what the default path actually empties: demo users, user roles, admin password, per-configuration constant values, database credentials, certificates and navigation profiles. It also says that the module's own units, constant defaults included, are copied byte for byte.
  • Fixture case T6 in test-rehost-list-modules.sh:
    • --scrub-constants gets exit 2, the message names it, and no .mpk is written
    • all three known flags together pass the option check, and the run then stops at the missing source with exit 3
    • The fixture gets Python via bin/lib/portable.sh require_py (check-portability clean).
  • Results:
    • 6 ok, 0 FAIL. The previous exporter fails T6 (exit 3 instead of 2).
    • By hand on the test project: --scrub-constants gives exit 2 and no file; --scrub-constant-defaults empties 2 constants.
    • check-scripts, check-portability, check-no-client-data, check-no-private-citations and check-pr-discipline are all clean, render-routing --check is in sync, and the denylist grep is clean.

Baseline word count: 75,038 before, 75,038 after (budget 80,000).

Impact

Row Effect Evidence
Process None. New pipeline pipelines/mendix-mpr/, run by hand; no gate, nothing blocks. diff
Dependencies Shared file: CLAUDE.md (Pipelines table row). Merges clean onto master 868b3cb (git merge-tree). Conflicts with #346 (add/add in pipelines/mendix-mpr/README.md, export-module-mpk.py, rehost-extract.sh): #346 is stacked on an older head of this PR, so this lands first and #346 is rebased. #345 consumes this exporter's --json. Platform: bash 3.2 (no mapfile/declare -A) + Python; macOS and two-tree unverified. Reads a source .mpr through mxcli describe / list modules output (producer: mxcli) and MPR v1 files (exporter). Writes a separate target .mpr / .mpk, never the project model. git merge-tree vs 868b3cb and pairwise
Context cost Unchanged: baseline 73,522 → 73,522 words (budget 80,000); Stage 5 mdl 30,185 → 30,185, lead 25,820 → 25,820 bin/render-routing.sh --check on master 868b3cb vs this head (a70afd9) merged onto 868b3cb via git merge-tree in a temporary worktree
Behaviour n/a (scripts + pipeline README; the CLAUDE.md row is authoring guidance, not shipped). diff
Runtime None for exec, gates or checks. diff

🤖 Generated with Claude Code

https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw

pipelines/mendix-mpr/ code only: rehost-extract.sh, lib/ (statement split,
topo order, quarantine, exec-resume, exec-each, describe fix, compare),
export-module-mpk.py, README. No samples. Company/app names replaced by
app type; inbox and process-doc citations removed; rehost-extract.sh no
longer needs bash 4 (mapfile, associative arrays). CLAUDE.md Pipelines
table gains the row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
…, list-modules fixture

- export-module-mpk.py empties the module's Constants$Constant DefaultValue by
  default and prints the count; --keep-constant-defaults keeps them. README
  states exactly what is and is not scrubbed.
- export-module-mpk.py refuses out == src (exit 2) before any remove/write;
  rehost-extract.sh refuses source == target (exit 2) before writing.
- rehost-extract.sh exits 2 with a message on an empty module list (bash 3.2
  set -u on an empty array).
- Own-module parse moved to lib/own-modules.awk, rows taken after the |---
  separator instead of NR>3; fixture test-rehost-list-modules.sh over verbatim
  list-modules captures (mxcli v0.25.0/v0.26.0 on mxcli's public test project,
  and the field-service template capture from #293): 5 ok; the previous
  script fails T4 and T5.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
…s opt-in

The constant scrub had not been installed into Studio Pro or checked with
mx check, so it no longer changes the field-proven default path. Module
constant DefaultValues are copied byte for byte as before;
--scrub-constant-defaults empties them, recomputes ContentsHash and prints
the count (unverified in Studio Pro). --keep-constant-defaults is dropped.
README states that constant defaults travel in the MPK unless the flag is
passed; CHANGELOG ties "installed into 10.24 and 11.13" to the default path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
…bbed

export-module-mpk.py main() refuses any `--` option outside --no-widgets,
--scrub-constant-defaults and --json: prints usage, exits 2, writes nothing.
Before, a typo such as --scrub-constants was ignored and the package shipped
every constant default in plain text. Fixture test-rehost-list-modules.sh
gains T6 (6 ok; the previous exporter fails T6). CHANGELOG replaces "with
secrets scrubbed" by the list of what is emptied by default; README notes
the refusal.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
@MendixMau
MendixMau marked this pull request as ready for review October 15, 2026 09:01
@MendixMau
MendixMau merged commit f3a80fe into master Oct 15, 2026
2 checks passed
MendixMau pushed a commit that referenced this pull request Oct 15, 2026
Conflicts were #342 first-draft files carried by the stack: take master's reviewed
export-module-mpk.py, rehost-extract.sh and README; re-apply this PR's two-line skills
pointer in the README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
MendixMau added a commit that referenced this pull request Oct 15, 2026
, 4/6) (#346)

## Review (MERGE-AFTER-FIX), addressed in 3c472fe

1. **MEDIUM: wrong increment number.** The cut-score blind spots in `decompose-app.md` Stage 1 step 4 were measured in **increment 2**, the first cut scoring on the field-service template. They were wrongly cited as increment 5. The Evidence header now also covers the first two increments:
   - increment 1: `bin/cut-score.sh` built on a synthetic 4-module app (Mendix 10.24)
   - increment 2: read probe and first cut scoring on the template
2. **LOW: level amendment dropped.** Stage 6 now says the three levels were CONFIRMED with the user 2026-10-12. It also records that level 3 was amended **2026-10-13** from field evidence: "one journey per crossing edge" became **one journey per crossing kind**, because per edge was undefined for 536 in-edge rows (increment 7). The level 3 row carries the amended criterion.

Checks re-run after the fix: `render-routing --check` in sync, the three routing fixtures 5/0, 12/0 and 16/0, and all guards clean.

**Baseline word count:** 75,038 before, 75,038 after (budget 80,000).


Merge of master after #342: took master's reviewed pipeline files, re-applied the README skills pointer. Added-line client-name scan: clean.
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