Repository navigation
exec: ~60% fewer process starts per exec (Windows overhead, #584/#585) - #590
Merged
Merged
Conversation
…585) - Gate mode: check (PROJECT.md) runs `mx check` per exec instead of the full deploy build; the full build still runs on Java/theme changes, on drops/renames when the project has Java actions, every 5th exec, on --patch and before the first full build. - mxbuild path and model version are resolved once per run; the build-plan page refreshes in the background; a cold-start notice; MXTK_PROFILE=1 per-command trace; doctor measures process-start cost; a clear message when no lint baseline exists. Field run: purchase-requests app (Linux, Mendix 11.13.0). The gate took 20 s with a full build and 9-10 s with mx check; the 5th exec ran a full build. A dropped attribute was caught as 6 x CE1613 by a real mx check on the broken model. Fixture: tests/wave2/test-exec-gate-kind.sh (16/16), on captured mx check output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
… build in check mode E1 replay (purchase-requests app, 23 scripts): the drop/rename trigger fired on 3 ordinary re-runnable scripts. Fixture K6k. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…(Gate mode: check) Follows mxcli's own advice (mx check after every exec, mxbuild when packaging) and CI practice (one full build per push): - model-stamp records kind: check|full; check --full refuses a check-only stamp - new pre-push hook runs bin/verify-model.sh when the stamp is check-only, refuses on errors - module-close.sh runs the full build under Gate mode: check - verify-model.sh resets the check-only count; backstop MXTK_CHECK_MAX (10) replaces every 5th Field run (purchase-requests app, Linux, Mendix 11.13.0): an exec under Gate mode: check wrote kind: check; the following git push ran the full build (20 s) and re-stamped it full. Fixtures: test-exec-gate-kind.sh 28/28 (K7 stamp kind, K8 pre-push), test-model-stamp 35/35, test-module-close 7/7, test-exec-step-times 7/7, test-exec-gate-log 24/24. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…w projects Windows field run (ExpenseTracker, Windows 11, Git Bash, 103 ms per process start): check-only execs 90-103 s vs 138-139 s with the full build; gate 60 s -> 12-14 s. Doctor smoke: a BUILD-LOG with a 165 s gate row reports WARN with the gate lever; the gk project (Linux) reports ok, median 19 s. Fixtures: run-tests 33/33, test-doctor-stale-hooks 7/7, test-test-strategy-docs 15/15, test-affected-tests 138/138. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…frees the pipe, profile needs bash 4.1 - gate-kind.state is written only under Gate mode: check, so the pre-push hook and module-close full build never fire for projects that did not opt in - module-close builds only when the stamp says kind: check - background build-plan refresh sends stdout and stderr to .claude/loop/build-plan-refresh.warn: an inherited stderr kept `exec.sh 2>&1 | ...` open until the refresh finished - MXTK_PROFILE refuses on bash < 4.1 (no BASH_XTRACEFD) with one line - the per-run mxbuild memo is MXTK_MXBUILD_MEMO, not MXBUILD_PATH (explicit-override semantics no longer leak into child scripts) Fixtures: test-exec-gate-kind 28/28, test-module-close 7/7, test-exec-step-times 7/7, test-mxbuild-version-match. Field re-run on the purchase-requests app blocked by memory (mxbuild killed, exit 137, by orphaned deno helpers); to be repeated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…G entries Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
Maintainer decision 2026-10-29: nobody adds the PROJECT.md line, so the opt-in never reached the slow machines. The full build still runs before every push (pre-push hook), at module close, on Java/theme changes, on real drops/renames with Java actions, on the first exec in a clone and after 10 check-only passes. Fixture K6a/K6a2 (29/29). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…ojects; exit 2 only warns Review of #587: --check reported a missing pre-push as informational, and sync-project.sh installs hooks only when --check fails, so existing projects never got the full build before push. Missing pre-push now fails --check. The hook refuses a push only when the full build finds errors (verify-model.sh exit 1); exit 2 (mxbuild could not run) warns. Fixtures: test-exec-gate-kind 32/32 (K8d2, K8g, K8h), test-model-stamp 35/35, test-restatement-git-hooks 28/28, test-mx-metadata-note 40/40, test-doctor-stale-hooks 7/7. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…#585 follow-up) Field run: the "gk" PurchaseApp project (Purchasing + Approval modules, Mendix 11.13, Gate mode: check), copied to ab-581/ovh, `./bin/exec.sh mdlsource/9-gk/900-doc.mdl`, Linux, 3 runs before and 3 after. Counted with `strace -f -e trace=execve,clone,clone3,fork,vfork`: forks 733 / 742 / 730 -> 334 / 335 / 338 execs 350 / 375 / 350 -> 136 / 135 / 135 MXTK_PROFILE=1 traced commands (exec.sh's own process only) 1000 / 999 / 1000 -> 914 / 914 / 914 wall 18.2 / 18.3 / 18.5 s -> 16.6 / 16.6 / 17.1 s (9-10 s of it is mx check, 3 s mxcli lint, 3 s mxcli report: fixed costs, not process starts) Output, exit code (4, lint rose) and the BUILD-LOG row are byte-identical before and after; the model fingerprint is identical to the old script's. The 40% target holds for process starts, not for the exec.sh-only trace: that trace counts every statement exec.sh itself runs (conditionals, function bodies, loops), and a started script is ONE line in it however much it does. Process starts are what cost ~100 ms on Windows, so those were cut: - exec.sh: model path, platform, Python, model folder and version resolved once and exported (MXTK_MPR_MEMO, MXTK_MODEL_DIR_MEMO, MXTK_PLATFORM, MXTK_PY_MEMO, PROJECT_ROOT); EPOCHSECONDS / printf %(..)T / ${x##*/} instead of date, basename, dirname; PROJECT.md, CLAUDE.local.md and the gate-kind state read in-shell; lint-gate output parsed by one awk (was ~10 grep/sed/tr/sort/paste); script-owners greps skipped when it printed nothing. - _common.sh: unbounded gate waits with `wait`, not a `sleep 1` process per second; model version read with one Python start (was two); Studio Pro folder matching without basename/cut/sed/grep; find_mpr / find_model_dir / resolve_py honour the run memos; sha256 without cut. - model-stamp.sh: one git rev-parse (was 6), file list in an array (no mktemp, paste, rm), stamp read once, `clear` answers before any set-up. - snapshot-mpr, look-ledger, script-owners, metrics-ledger, row-groups, build-plan-status, lint-gate, exec-approval, mdl-scan: dirname / basename / date / ls|wc|tr / find|wc forks removed; script-owners record is one awk; lint-gate skips its rule-receipt Python while nothing it reads is newer than the last clean check. - MXTK_PROFILE=2 traces the scripts exec.sh starts too; profile lines name the file. Fixtures run (scoped, 59, all rc 0): every test-exec-*, test-model-stamp, test-restatement-guard/-git-hooks, test-look-*, test-lint-*, test-sec014-notice, test-metrics-ledger, test-row-groups, test-mdl-scan, test-common-*, test-find-java-version, test-mxbuild-version-match, test-shared-lock-takeover, test-describe-baseline, test-dryrun-writes-nothing, test-wrong-verdicts, test-build-plan-*, test-progress-report*, test-module-close, test-conformance-*, test-change-log, test-doctor-gate-selftest, test-stack-up-local and others. check-scripts.sh and check-portability.sh clean. Reported by mkr87. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
…rf/exec-overhead # Conflicts: # CHANGELOG.md # project-bin/exec.sh
…it the overhead entry Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
review) An overwrite that keeps an old mtime (cp -p, rsync -t, tar/unzip) let a re-seeded rule skip the receipt check. The skip marker now holds a cksum signature of the receipt, disabled and stock lists and every rule file. Fixture T1b in test-lint-receipt-revert.sh (82/82; the old script fails it, 81/1). test-lint-gate-accept 24/24, -new-findings 15/15, test-exec-lint-diff green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
… so it fails on the old skip Re-review of #590: strip_header renamed the file, which bumped the folder mtime and let the old mtime check pass T1b. Now 82/82 on the new script, T1b FAILs on 362b4d2^. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
# Conflicts: # CHANGELOG.md # bin/doctor.sh # project-bin/_common.sh # project-bin/exec.sh # project-bin/model-stamp.sh
This was referenced Oct 29, 2026
Open
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.
This PR is stacked on #587: its base is
perf/windows-exec-speed, and it will be retargeted to master once #587 merges.On Windows every process start costs about 100 ms. Before this change, one exec started about 730 forks and 360 programs, which is 60–70 s of overhead on a slow laptop (#584, #585, and a colleague's field run).
What changes
_common.shresolve once per run and hand the answers down as exported memos: the model path, platform, Python, model folder and model version.dirnameandbasenameno longer start processes. PROJECT.md and CLAUDE.local.md fields are read in-shell. Lint output is parsed by one awk instead of about ten tools.waitinstead of onesleep 1process per second.MXTK_PROFILE=2traces the scripts exec.sh starts as well.Evidence
Linux field run on a copy of the purchase-requests app, 3 runs each, counted with
strace -f:test-exec-*, model-stamp, look, lint, metrics-ledger, row-groups, mdl-scan, common, describe-baseline, build-plan, progress-report and conformance. They were re-run after merging the latest Exec speed: mx check gate by default, doctor performance check, Windows overhead fixes (#584, #585) #587: gate-kind 32/32, step-times 7/7, gate-log 24/24, lint-diff 9/9, gate-retry 52/52, crash-rollback 13/13, model-stamp 35/35, module-close 7/7.Risk
PROJECT_ROOTis now exported to the scripts exec.sh starts.Generated by Claude Code