Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m

## Unreleased

- fix(progress-report): **`progress-report.py` no longer crashes with `TypeError: '<' not supported between instances of 'dict' and 'dict'` when two exec'd scripts share a leading number** (#513). `script_phases()` sorted `(number, phase dict)` pairs, so `10-data.mdl` and `10b-data-flows.mdl` (or one script logged under two paths), both matched to a plan phase, compared the dicts and every `exec.sh` run ended with `WARN: progress-report.html not updated`. It now sorts on (number, script name) only; an unmatched numbered script still takes the phase of the nearest lower-numbered matched one, ties broken by name. Fixture: `test-progress-report.sh` T17 (fails 3/3 on master). — jopterhorst (#513)
- new(canvas): **`project-bin/mf-canvas-facts.py` prints how a microflow or nanoflow lies on the Studio Pro canvas: labels on top of each other, lines through objects, note lines leaving the side that faces away, flows that run right-to-left or curl, captions wider than their shape, and decision captions that ask the opposite of their true branch (SENSE).** It prints facts, one line each, and no verdicts; read-only (it reads units through `mxpatch.py`), exit 2 when a flow could not be read. `verify-module.sh` runs it per module as an info rung (1c, log `14-canvas-facts.log`; a missing script, Python or `.mpr`, an exit 2 or a timeout is an INFO row reading NOT MEASURED, never a gate). Fixture `tests/wave2/test-mf-canvas-facts.sh` runs on a model mxcli v0.27.0 wrote (units and `.mpr` captured); `test-verify-module-446.sh` gains V8 for the rung. Calibration is from Studio Pro 10.24 screenshots, not verified on Studio Pro 11. Field evidence, measured 2026-10-21 on one Mendix 10.24 app: 1,588 flows read in one pass; on the 36 flows an mxcli-built branch added or changed in one module, OVERLAP 19, LINE 27, NOTE-SIDE 17, LEFTWARD 3, TURN 4, SENSE 9 before repair — saingge
- learn(preflight, teamserver-alignment): **a flow's return-type change and its callers' update go in one script (STOP row 33), and Studio Pro 10.24.18's "Merge feature branch" merges `origin/<branch>`, not the local branch.** On a copy of a Mendix 10.24.18 app with mxcli v0.27.0, the first script alone left `mx check` with CE0112 at a caller stored the way Studio Pro stores a call, while `check` and `exec` stayed silent; Studio Pro's own git log shows the merge of the remote branch. Text only; baseline-routed, +101 words. — saingge
- fix(doctor, preflight, platform-link): **a clean `fix property-sets --dry-run` on Mendix below 10.24.24 is no longer reported as "every unit has the property names Studio Pro writes".** mxcli's property table starts at 10.24.24, so on 10.24.18 (mxcli v0.27.0) the dry-run printed "Every unit already has the property names Studio Pro writes" while Mendix's `mx diff` exited 129 on a unit mxcli had written (mendixlabs/mxcli#1595). `doctor.sh --property-sets`, `--if-stale` and `--quick` now WARN "NOT PROOF" and name `mx diff <base>.mpr <mine>.mpr out.json` (exit 0) as the proof; the receipt records `unproven`; exit stays 0. `learned-detection-gaps.md` and `platform-link.md` said v0.26.0 closed the gap. Fixture P2b (11 cases). Baseline-routed, +18 words. — saingge
Expand Down
3 changes: 2 additions & 1 deletion project-bin/progress-report.py
Original file line number Diff line number Diff line change
Expand Up @@ -781,7 +781,8 @@ def script_phases(runs, phases):
direct[sc] = phase_for_script(sc, phases)
m = re.match(r"0*(\d+)", os.path.splitext(os.path.basename(sc.strip().split()[-1]) if sc.strip() else "")[0])
num[sc] = int(m.group(1)) if m else None
known = sorted((num[k], direct[k]) for k in direct if direct[k] and num[k] is not None)
# sort on (number, script name) only: two scripts can share a leading number (10-a, 10b-b) and dicts do not compare (#513)
known = [(n_, pp) for n_, _k, pp in sorted(((num[k], k, direct[k]) for k in direct if direct[k] and num[k] is not None), key=lambda t: (t[0], t[1]))]
out = {}
for k, p in direct.items():
if not p and num[k] is not None:
Expand Down
38 changes: 38 additions & 0 deletions tests/wave2/test-progress-report.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
# T13 context windows are 200k or 1M only; "window reached" only at 98% of the real window.
# T14 --session-log overrides discovery and is recorded in the footer; --help lists it and the rates file.
# T15 --open matches this project's exact file URL (osascript stubbed); a generator crash leaves one WARN.
# T17 two scripts sharing a leading number (10-data.mdl, 10b-data-flows.mdl), each matched to a phase:
# the page is still written, no TypeError (#513); the unmatched 11- script takes the later 10 phase.
#
# Usage: bash tests/wave2/test-progress-report.sh /path/to/build-plan-status.sh

Expand Down Expand Up @@ -314,6 +316,42 @@ CLAUDE_CONFIG_DIR="$CFG2" bash "$SCRIPT" "$P5" --html >/dev/null 2>&1
has "$P5/architecture/progress-report.html" "location.reload" "reload script present while active"
hasnt "$R2" "location.reload" "no reload script when idle"

echo "T17 scripts sharing a leading number (#513)"
# BUILD-LOG rows: the exec.sh row captured in fixtures/verify-446/BUILD-LOG.captured.md, time and script replaced.
CAP="$ROOT/tests/wave2/fixtures/verify-446/BUILD-LOG.captured.md"
P6="$WORK/p6"; mkdir -p "$P6/architecture" "$P6/docs"
cat > "$P6/architecture/build-plan.md" <<'MD'
# Build plan

### Phase 1 - Data

| # | Kind | Step | Produces / Proves | Depends on | Skills | State |
|---|---|---|---|---|---|---|
| 1 | DATA | Create entities: `mdlsource/10-data.mdl` | Order | none | none | built |

### Phase 2 - Flows

| # | Kind | Step | Produces / Proves | Depends on | Skills | State |
|---|---|---|---|---|---|---|
| 2 | LOGIC | Create flows: `mdlsource/10b-data-flows.mdl` | ACT_Order | 1 | none | built |
MD
{ sed -n '1,/^|---|/p' "$CAP"
for x in "2026-10-19T09:00:00+0000 10-data.mdl" "2026-10-19T10:00:00+0000 10b-data-flows.mdl" "2026-10-19T11:00:00+0000 11-misc.mdl"; do
set -- $x; grep '^| 20' "$CAP" | head -1 | sed -e "s/^| [^|]* | \`[^\`]*\` |/| $1 | \`$2\` |/"
done; } > "$P6/docs/BUILD-LOG.md"
out6="$(CLAUDE_CONFIG_DIR="$EMPTY" bash "$SCRIPT" "$P6" --html 2>&1)"
printf '%s' "$out6" | grep -q "generator failed\|not updated\|TypeError" && bad "generator does not fail on a shared leading number" || ok "generator does not fail on a shared leading number"
printf '%s' "$out6" | grep -q "wrote architecture/progress-report.html" && ok "page written with two scripts numbered 10" || bad "page written with two scripts numbered 10"
IFS= read -r -d '' SP_PY <<'PYEOF' || true
import sys, importlib.util
spec = importlib.util.spec_from_file_location("pr", sys.argv[1] + "/progress-report.py"); m = importlib.util.module_from_spec(spec); spec.loader.exec_module(m)
ph = [{"id": "1", "name": "Data", "steps": [{"step": "mdlsource/10-data.mdl"}]}, {"id": "2", "name": "Flows", "steps": [{"step": "mdlsource/10b-data-flows.mdl"}]}]
runs = [{"script": s} for s in ("10b-data-flows.mdl", "10-data.mdl", "11-misc.mdl")]
print(m.script_phases(runs, ph)["11-misc.mdl"]["name"])
PYEOF
SP="$("$PY" -c "$SP_PY" "$ROOT/project-bin" "$P6")"
[ "$SP" = "Flows" ] && ok "11- script takes the phase of the later-named 10 script (order by number, then name)" || bad "11- script takes the phase of the later-named 10 script (got: $SP)"

echo "T16 narrow-width CSS (phone)"
GEN="$ROOT/project-bin/progress-report.py"
grep -q "@media(max-width:520px){code,pre,.stage dd" "$GEN" && ok "narrow rules wrap code and values" || bad "narrow rules wrap code and values"
Expand Down
Loading