From b7eadda50876d0e8b81e18453018cd48bb500631 Mon Sep 17 00:00:00 2001 From: MendixMau Date: Thu, 15 Oct 2026 22:40:24 +0800 Subject: [PATCH] fix(verify-module): rung budgets for graph, coverage, journeys are variables (TK-008) Field report from a five-app lab project (Mendix 11.15, mxcli v0.26.0). Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + project-bin/verify-module.sh | 12 +++++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6e238acd..bf5f786c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m ## Unreleased +- fix(verify-module): the graph, coverage and journeys rung budgets are variables (`VM_TMO_GRAPH`, `VM_TMO_COVERAGE`, `VM_TMO_JOURNEYS`; defaults unchanged at 300/300/900, like the existing `VM_TMO_CONFORMANCE`), so a large build plan or a loaded machine can raise the 300 s that reported a clean coverage run as a timeout (TK-008) — five-app lab project (Mendix 11.15, mxcli v0.26.0) - new(mxpatch, exec): **`project-bin/mxpatch.py`, the shared patch core, and a `mxcli fix hashes` check around every `exec.sh --patch` run: the two shipped workflow patchers no longer leave a stale ContentsHash.** mxpatch finds a unit by type + name (+ module) with a byte pre-filter, finds an element by Name, gets/sets a value by key, and writes the unit and its `.mpr` ContentsHash (base64 SHA-256 of the file) in one step; dry run by default, `already applied` on a re-run, and a refusal (exit 3) when the current value is not the expected old one. `wf-set-call-captions.py` and `wf-add-path-terminators.py` now write through it, refuse drift (a caption is replaced only while it is still the stamped microflow name or the `--expect-caption` value; `--expect-paths N` for terminators), and also take the `exec.sh --patch` form (` Module.Workflow`). The index is committed before the file swap, so a kill mid-write leaves a MISMATCH that `fix hashes` reports and a re-run repairs. `mxunit_bson.py` reads BSON 0x09 (UTC datetime). `exec.sh --patch` runs `mxcli fix hashes` (v0.25.0+, probed via `fix --help`) before and after the script and restores the snapshot on any issue the baseline did not have, before mxbuild, which cannot see it. Field evidence: captured mxcli v0.25.0/v0.26.0 runs on a public model (`tests/wave2/fixtures/mxpatch/CAPTURE.txt`): master's patchers leave a MISMATCH, the ported ones verify clean; the hash routine agrees with mxcli on 67 of 67 mismatched and 302 matching units of a second model. Widget-shape copying and pluggable-widget properties wait on a captured page unit. Field run ([#390](https://github.com/MendixMau/mxcli-project-toolkit/issues/390), mxcli v0.26.0, macOS): PASS, and the patch repaired a ContentsHash MISMATCH an old-style `--patch` had left on the unit it rewrote. Fixes from it: the backup of a rewritten unit is kept outside `mprcontents/` (in `$MXPATCH_BACKUP_DIR`, which `exec.sh --patch` points into the snapshot it just took, else a 0700 `/mxpatch-bak-/`; refused when it resolves inside `mprcontents/`, through a symlink or another case spelling; named with pid and counter so two writes in one second keep both), no longer as an untracked `.mxunit.bak` that `git add mprcontents` would commit; the BUILD-LOG row carries the hash bracket (`hashes: baseline 1 mismatch (pre-existing), verify clean (1 pre-existing repaired by this patch's rewrite)`); and the baseline message says that a unit the patch rewrites gets a fresh hash, and to repair the others with `fix hashes --repair`. A baseline MISMATCH that is still reported on a unit the patch rewrote counts as new (restore, exit 1), not as pre-existing. — jopterhorst ([#294](https://github.com/MendixMau/mxcli-project-toolkit/issues/294), [#295](https://github.com/MendixMau/mxcli-project-toolkit/issues/295)) - learn(pipelines/mendix-mpr/samples): **three minimal mxcli repros from the native-module bug hunt, the files the upstream draft cites** (split from [#293](https://github.com/MendixMau/mxcli-project-toolkit/pull/293), 6/6). `fsm-template-9.24.2/native-bughunt/` holds CAPTURE.txt and D1–D3, which are written from scratch in a `Repro` module: `describe entity` printing `index ( desc);`, the native Repeater `content` slot, and no flow writable to a 9.24.2 project. They are the repros for U3, U2 and U14 in `bug-logs/pending-github-issues/2026-10-12-mxcli-0.26-round-trip-report.md`. The other 472 sample files of #293 had no citing reader, because the skills and Rehost splits state their field results inline, so none of them ships. — MendixMau, Decompose/Rehost lab runs 2026-10-12 - learn(inbox, pending-github-issues): **ten field-note drops from the Decompose/Rehost lab runs, and one not-filed draft of 53 mxcli 0.26 defects for mendixlabs/mxcli** (split from [#293](https://github.com/MendixMau/mxcli-project-toolkit/pull/293), 5/6). `contrib/inbox/2026-10-1{2,3}-*.md`: increments 1–8 of the split-a-monolith runs on a public Marketplace template (FSM 9.24.2), the native-module bug hunt, and the GenAI Showcase regeneration (0.26.0 and the 2026-10-13 nightly); each now has the template's front matter and is at most 600 words. `bug-logs/pending-github-issues/2026-10-12-mxcli-0.26-round-trip-report.md`: the U1–U53 table the inbox drops refer to, marked DRAFT — NOT FILED, to be split into one issue per defect and retested before anything is posted. No BUG numbers assigned; triage promotes. — MendixMau, Decompose/Rehost lab runs 2026-10-12/13 diff --git a/project-bin/verify-module.sh b/project-bin/verify-module.sh index fc4681aa..42a9126b 100755 --- a/project-bin/verify-module.sh +++ b/project-bin/verify-module.sh @@ -434,6 +434,8 @@ fi # These three share no state and touch no app, so they always run in parallel — unlike the # runtime instruments in §2 there is nothing here to race on and no login session to spend, so # this needs no opt-in flag. +# Rung budgets in seconds, overridable for big plans or loaded machines (TK-008): +# VM_TMO_CONFORMANCE (1200) VM_TMO_GRAPH (300) VM_TMO_COVERAGE (300) VM_TMO_JOURNEYS (900) if [ -x "$(_tool conformance-check.sh)" ]; then run_launch "conformance (ledger claims vs live model)" "$OUTDIR/10-conformance.log" gate "${VM_TMO_CONFORMANCE:-1200}" -- \ "$(_tool conformance-check.sh)" --module "$MODULE" @@ -442,7 +444,7 @@ else fi if [ -x "$(_tool graph-sweep.sh)" ]; then - run_launch "graph sweep (orphans + wiring shape)" "$OUTDIR/11-graph.log" gate 300 -- \ + run_launch "graph sweep (orphans + wiring shape)" "$OUTDIR/11-graph.log" gate "${VM_TMO_GRAPH:-300}" -- \ "$(_tool graph-sweep.sh)" --module "$MODULE" else fault "graph sweep (orphans + wiring shape)" "bin/graph-sweep.sh not installed" @@ -496,12 +498,12 @@ else # 3 and 4 are not passes and not faults; they are graded absences, and the rung says which. PREFLIGHT="$(_tool coverage-preflight.sh)" if [ -n "$PREFLIGHT" ] && [ -x "$PREFLIGHT" ]; then - run_launch "coverage (BRD leaves: UNCLAIMED/PHANTOM/DOUBLE)" "$OUTDIR/12-coverage.log" gate 300 -- \ + run_launch "coverage (BRD leaves: UNCLAIMED/PHANTOM/DOUBLE)" "$OUTDIR/12-coverage.log" gate "${VM_TMO_COVERAGE:-300}" -- \ "$PREFLIGHT" --summary ${MODULE:+--module "$MODULE"} elif [ -f "$LEDGER" ] && [ -n "$BRD" ]; then # Preflight absent (an older wired project that has not synced). Fall back to the engine # directly — level 1 only, which is what this rung did before the grading layer existed. - run_launch "coverage (BRD leaves: UNCLAIMED/PHANTOM/DOUBLE)" "$OUTDIR/12-coverage.log" gate 300 -- \ + run_launch "coverage (BRD leaves: UNCLAIMED/PHANTOM/DOUBLE)" "$OUTDIR/12-coverage.log" gate "${VM_TMO_COVERAGE:-300}" -- \ "$COVERAGE_CHECK" --summary "$BRD" "$LEDGER" else fault "coverage (BRD leaves)" \ @@ -576,12 +578,12 @@ else fault "journeys" "no journey runner at ${JOURNEY_RUNNER#$ROOT/}" \ "Set JOURNEY_RUNNER, or see the journey-proof.md skill for the harness this expects." elif [ -f "$JOURNEY" ]; then - _exec "journeys (UI + ordered spans + data effects)" "$OUTDIR/20-journeys.log" gate 900 -- \ + _exec "journeys (UI + ordered spans + data effects)" "$OUTDIR/20-journeys.log" gate "${VM_TMO_JOURNEYS:-900}" -- \ node "$JOURNEY_RUNNER" "$JOURNEY" # Non-vacuity: a journey that cannot fail is not evidence. Skipped under --quick because it # re-walks every step. [ "$QUICK" -eq 1 ] || _exec "journeys (positive control — MUST detect a broken precondition)" \ - "$OUTDIR/21-journeys-control.log" gate 900 -- \ + "$OUTDIR/21-journeys-control.log" gate "${VM_TMO_JOURNEYS:-900}" -- \ node "$JOURNEY_RUNNER" "$JOURNEY" --positive-control else fault "journeys" "no ${JOURNEY#$ROOT/}" \