Conversation
…l locations - find_sp_app: newline-join listings, dedupe identical Program Files roots, accept only version-shaped dirs (gradle-8.5 was winning sort -V glued to the next entry) - check-scripts: project without bin/ is a WARN pointing at init-project - find_project_mxcli: mxcli.exe first on Git Bash; an ELF ./mxcli (the Dev Container's) is named, not chmod-ed; --install fetches the .exe beside it; exec.sh, lint-gate, review-module, conformance-check, fixture-manifest, page-scope resolve the same way - save-sp/restart-sp section is a note off macOS, not a WARN - toolkit.env (<project>/.claude/toolkit.env, ~/.mxcli-toolkit.env) loaded by _common.sh: MENDIX_APP, JAVA_HOME, MXBUILD_PATH, MXCLI_VERSION, PYTHON; Windows paths pasted as-is; doctor reports, self-gitignores, flags a JRE without javac; gate/verdict wording guides instead of alarms Rebased onto current master, which already carries Marco Keijsers' find_sp_app rewrite (532e359/737cbe3/368cd2e: a modeler/mxbuild.exe existence loop, native_path(), file-capture of mxbuild output). Conflict resolution in find_sp_app: dropped this commit's own glued-listing fix (newline-join workaround) and its trailing version-shaped-directory regex filter — both are superseded by master's existence loop, which appends one directory at a time (already newline-terminated, so nothing glues) and admits only a directory carrying modeler/mxbuild.exe (so gradle-8.5 can never be a candidate). Kept this commit's seen-based root de-duplication wrapped around master's loop: not redundant with it, since master's loop filters entries within one root's listing but never dedupes scanning the same physical folder twice when ProgramW6432 and PROGRAMFILES point at the same directory. The CHANGELOG's 'Fixture-proven here' claim is addressed in a follow-up commit (a real fixture is added, and the line is reworded to what it actually proves). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
… verdict wording corrected The Windows field run this instrument change needs is still owed; the PR stays draft until it is cited. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
project-bin/exec.sh hand-wrote the same sequence three times: run mxbuild with --write-errors, capture output to a file (never `$(...)` — Studio Pro 11's mxbuild.exe on Windows starts a helper deno.exe that inherits stdout and never closes it, so a command substitution waits forever for EOF that never comes), close stdin, and treat an empty errors file + exit 0 as a verified 0 (SP11 only writes --write-errors when the project already has errors). One copy for the pre-flight baseline, one for the main gate, one for the post-restore "whose error is it" check. Pulled the run+capture into project-bin/_common.sh's new mxtk_mxbuild_error_count(), so bin/doctor.sh's upcoming gate self-test can call the exact code a real exec run trusts, not a fourth copy that could quietly drift from it. It also adds a genuine new behaviour the old code never had: a portable timeout (background process + poll + kill, the same pattern as doctor.sh's docker_daemon_up — no timeout(1) is assumed, macOS ships none), overridable via MXTK_GATE_TIMEOUT, default 300s, generous enough that no real build is ever cut short by it. exec.sh's three call sites now call the shared function and keep their own downstream logic (err_count/err_codes/err_set, the delta-gate, the restore, the detailed error printing) unchanged — the function only replaces the "run it and get a file + exit code" mechanics, not the reading of codes or messages. Each call site adds `|| true` after the call: exec.sh runs under `set -e`, and the function's own return code (0 = count printed, 1 = unparseable, 2 = mxbuild/java not found, 3 = timed out) is not meant to abort the script — the existing file-presence/exit-code branching below each call site already decides the gate's verdict from $MXTK_MXBUILD_EXIT and the file's content, exactly as before. Behaviour is unchanged: tests/wave2/test-bug07-08.sh project-bin/exec.sh still passes all 28 assertions, including case G (mxbuild exits non-zero with no errors file -> gate fails, not "unverified") and case H (mxbuild absent -> gate skipped, exit 0) — the two cases most at risk of blurring together under the new function's own three-way return code. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
Every doctor.sh section up to this one answers "is mxbuild present and does it run" — none answers "if the model had a real error, would the gate see it". That gap is exactly how a wrong-architecture mxbuild once reported 0 errors for several commits before anyone noticed (merge desk, after Marco Keijsers' #59 and the July wrong-arch mxbuild incident). New "Gate self-test" section (full run only; skipped under --quick, forceable alone via `doctor.sh --gate-selftest [project-dir]`) runs the exact function exec.sh's own gate trusts — mxtk_mxbuild_error_count, project-bin/_common.sh, the mandatory chain step that produces every count this section reads — against a scratch copy of the real project model: 1. Baseline: the function must resolve a real integer off the untouched copy. "?" here means the gate cannot read mxbuild's own output — the original F-042-class defect. 2. Known-bad control: inject a deliberate CE0117-shape type mismatch via the project's own mxcli (throwaway module/microflow, quoted identifiers), then require the count to go from 0 to >=1. A gate that reports 0 on a model it just broke is worse than no gate: it is green on a broken build. The scratch directory is removed on every exit path via a RETURN trap, never touching the project's real .mpr/mprcontents. Bounded by DOCTOR_GATE_TIMEOUT (default 300s, same bound exec.sh's gate uses). NOT RUN (not FAIL) when there's no project/.mpr, no mxbuild/java, or no project mxcli resolved — this is a capability gap, not a defect. No real-mxbuild field run yet; fixture-proven with stubs only (next commit). Windows run still owed.
Stubs a fake project mxcli (marks a scratch model "bad" when it sees the self-test's injected MDL) and a fake mxbuild with four behaviours (MODE_GATE_STUB): healthy (0 then >=1 — the only PASS), no-file (never writes an errors file, exits non-zero — the original "?" defect), always-clean (always reports 0, even on the known-bad model — the gate-is-blind case), and slow (sleeps past DOCTOR_GATE_TIMEOUT). Covers: healthy -> PASS with scratch dir cleaned up and receipt recording it; no-file -> FAIL naming the unreadable error file; always-clean -> FAIL naming "gate is blind"; slow with DOCTOR_GATE_TIMEOUT=2 -> FAIL naming the timeout, doctor still returns promptly; no mxbuild resolvable (MXCLI_HOME redirected off this machine's real ~/.mxcli/mxbuild cache, since find_mxcli_cache doesn't go through MXBUILD_PATH/MENDIX_APP) -> NOT RUN, not FAIL; --quick alone omits the section; a full run includes it without the flag. bash tests/wave2/test-doctor-gate-selftest.sh bin/doctor.sh -> 16 passed, 0 failed.
Unit-tests mxtk_load_env, mxtk_is_elf and find_project_mxcli directly, each sourced fresh in its own subshell (PROJECT_ROOT/MXTK_ENV_LOADED are resolved once at source time, so re-sourcing in one long-lived shell would carry a previous case's environment forward). HOME is redirected per case so this machine's own ~/.mxcli-toolkit.env — absent here, but not guaranteed absent everywhere — can never leak in. Covers: a pre-set env var beats both files; the project file (.claude/toolkit.env) beats the user file (~/.mxcli-toolkit.env); the user file is used as the last resort and named in MXTK_ENV_LOADED; a Windows-form path (C:\...) is converted to Git Bash's /c/... form; mxtk_is_elf tells a real ELF binary from a shell script; and find_project_mxcli, on a stubbed Git Bash platform (OSTYPE=msys), prefers mxcli.exe over a same-directory ELF mxcli, refuses an ELF-only mxcli outright, while the identical ELF mxcli is accepted fine on a real Linux/container platform. bash tests/wave2/test-common-windows.sh project-bin/_common.sh -> 10 passed, 0 failed.
… line Two changes, both under 2026-09-16: 1. #25's original line claimed "Fixture-proven here (glue, precedence, .exe-over-ELF)" with no fixture behind it anywhere in that PR, and still described the find_sp_app "glue" fix this rebuild drops in favor of Marco Keijsers' #59 (already on master, same defect fixed a different way). Reworded to name what actually changed in this rebuild, to note the dropped glue fix and why, and to cite the new tests/wave2/test-common-windows.sh (10/10) for what it actually proves — precedence, path conversion, is_elf, and .exe-over-ELF on a stubbed Git Bash platform. Windows field run still owed; draft until cited here. 2. New line for the gate self-test (bin/doctor.sh, project-bin/exec.sh, project-bin/_common.sh): what it does, why (Marco Keijsers' #59 and the July wrong-arch-mxbuild incident), and that it is fixture-proven with stubs only — no real-mxbuild field run yet, Windows run owed, draft until cited here.
…ection is NOT RUN, not blind exec.sh's three mxbuild sites went through the new shared function with a 300s default bound. master had none: a large model's deploy build can run longer, and a timed-out gate reads as exit!=0 + no errors file = FAIL = auto-restore of work that was fine. exec.sh now passes 0 (unbounded) unless MXTK_GATE_TIMEOUT is set; doctor's scratch-copy self-test keeps 300s. If the project's mxcli refuses the known-bad injection, the copy is still clean and the old code reported the gate as blind. Now NOT RUN with mxcli's own message. Fixture case 8, 20/20. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
4 tasks
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.
What
Two parts, one branch, rebuilt on current master so it no longer conflicts with Marco Keijsers' Windows fixes (#59).
Part 1: #25's Windows onboarding work, minus what master already carries.
mxtk_posix_path,toolkit.envloader (MXTK_ENV_LOADED, env > project file > user file),mxtk_is_elf,find_project_mxcli(.exeover a same-dir ELF on Git Bash), doctor reporting which toolkit.env it read,--installfetchingmxcli.exebeside the Linux build, JRE-without-javac note, macOS-only sections demoted to notes off-macOS, self-gitignored/.claude/toolkit.env, sixproject-bin/*scripts routed throughfind_project_mxcli,check-scripts.shwarning instead of failing on a project with nobin/. Also doctor + _common: Windows onboarding fixes and toolkit.env — DRAFT until the Windows field run is cited #25'sseen-based Program Files de-dup, which solves a different problem than Marco's loop.find_sp_appglue fix and version-regex filter. Master already has Marco's fix for the identical defect.tests/wave2/test-common-windows.sh, 10/10, stubbedOSTYPE=msys.Part 2: doctor "Gate self-test".
Doctor probed whether mxbuild and Java were present. It never asked whether the gate could see an error. The wrong-arch mxbuild incident and #59 were both "gate reports green on a broken build". The new section (full run, or
--gate-selftestalone, skipped under--quick) copies the model into a scratch dir, reads a baseline count that must be a real integer, injects a CE0117-shape type mismatch via the project's own mxcli, and requires the count to move from 0 to at least 1. Bounded byDOCTOR_GATE_TIMEOUT(300s), scratch removed on every exit path. If mxcli refuses the injection the verdict is NOT RUN with mxcli's own message, never a false "blind". Receipt linegate-selftest: …lands in.claude/.doctor-receipt.Supporting refactor:
exec.sh's three inline mxbuild run-and-read blocks became one_common.shfunction,mxtk_mxbuild_error_count. Downstream branching untouched. The real gate stays unbounded by default (MXTK_GATE_TIMEOUTopt-in), because a timed-out gate would read as FAIL and auto-restore good work.Why draft
Neither part has a real field run yet:
.exe-over-ELF behaviour.mxcli execand must produce at least one mxbuild error. The stub fixtures prove the logic, not the assumption.Ready to flip when one of those runs is cited on this PR (Marco or Clinton are the obvious candidates). Per CLAUDE.md "field-proof before merge".
Checks
check-scripts.sh76/76 + 20/20,check-portability.shclean, leak guard clean,render-routing.sh --checkin sync,check-pr-discipline.shclean,tests/run-tests.sh19/19,test-bug07-08.sh28/28 (exec.sh gate discriminators unchanged),test-doctor-docker-probe.sh13/13,test-common-windows.sh10/10 (new),test-doctor-gate-selftest.sh20/20 (new).Supersedes #25.
🤖 Generated with Claude Code
https://claude.ai/code/session_01VJgWP5vEoAsNsJYqCDMGNw
Generated by Claude Code