Skip to content

Commit f676f60

Browse files
MendixMauclaude
andauthored
exec: ~60% fewer process starts per exec (Windows overhead, #590)
Per-run memos (model path, platform, Python, model dir, version), built-ins instead of date/dirname/basename, in-shell PROJECT.md/CLAUDE.local.md reads, one awk for lint parsing, wait instead of sleep polling, model-stamp asks git once, lint-gate receipt check skipped on an unchanged content signature, fork trimming in snapshot-mpr, look-ledger, script-owners, metrics-ledger, row-groups, build-plan-status, exec-approval and mdl-scan; MXTK_PROFILE=2. Field (Linux, purchase-requests app): forks 730 -> 335, programs started 360 -> 135 per exec, output identical. For #584/#585. Review: MERGE-AFTER-FIX — lint-receipt skip now keys on content (cp -p escape), T1b fixture fails on the old script, re-reviewed MERGE; Windows not measured yet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013jQvaonym9V1wKKfAEPmRr
1 parent a4d701a commit f676f60

15 files changed

Lines changed: 538 additions & 239 deletions

‎CHANGELOG.md‎

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

‎bin/doctor.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ if [ -n "$_perf_log" ] && [ -f "$_perf_log" ] && grep -q 'steps: ' "$_perf_log"
492492
warn "slow execs — $_pmsg"
493493
[ "$_pgate" -gt "${MXTK_PERF_GATE_WARN:-45}" ] && note "The gate (mxbuild) dominates: 'Gate mode: check' in PROJECT.md runs mx check per exec and the full build before push."
494494
[ -n "$_spawn_ms" ] && [ "$_spawn_ms" -gt "${MXTK_SPAWN_WARN_MS:-30}" ] && note "Process starts are slow too (above): that is the machine, not the model — see the advice there."
495-
note "Per-command profile of one exec: MXTK_PROFILE=1 ./bin/exec.sh <script> (prints the 15 slowest lines)."
495+
note "Per-command profile of one exec: MXTK_PROFILE=1 ./bin/exec.sh <script> (prints the 15 slowest lines; MXTK_PROFILE=2 traces the scripts it starts too)."
496496
else
497497
ok "$_pmsg"
498498
fi

‎bin/exec-approval.sh‎

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@
4848

4949
set -u
5050

51-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
52-
5351
PROJECT_DIR="${1:-}"
5452
ACTION="${2:-}"
5553

@@ -129,9 +127,14 @@ if [ -z "$MODE" ] && [ -f "$PROJECT_DIR/PROJECT.md" ]; then
129127
# first occurrence wins so an appended log entry cannot silently retune the project. The whole
130128
# rest of the line is the value, so any trailing note is invalid → `ask`. (interview-mode.sh
131129
# allows a note after `steering` only; this read deliberately stays exact.)
132-
FROM_MD=$(grep -iEm1 '^[[:space:]]*(-[[:space:]]*)?\**Exec approval\**[[:space:]]*:' "$PROJECT_DIR/PROJECT.md" 2>/dev/null \
133-
| sed -E 's/.*[Aa]pproval\**[[:space:]]*:[[:space:]]*//' \
134-
| tr '[:upper:]' '[:lower:]' | tr -d '[:space:]*`')
130+
# grep first, alone: most projects have no such line, and the sed | tr | tr behind it then
131+
# ran over empty input (three process starts to produce nothing).
132+
FROM_MD=""
133+
_EA_LINE=$(grep -iEm1 '^[[:space:]]*(-[[:space:]]*)?\**Exec approval\**[[:space:]]*:' "$PROJECT_DIR/PROJECT.md" 2>/dev/null || true)
134+
if [ -n "$_EA_LINE" ]; then
135+
FROM_MD=$(printf '%s\n' "$_EA_LINE" | sed -E 's/.*[Aa]pproval\**[[:space:]]*:[[:space:]]*//' \
136+
| tr '[:upper:]' '[:lower:]' | tr -d '[:space:]*`')
137+
fi
135138
if [ -n "$FROM_MD" ]; then
136139
if is_valid "$FROM_MD"; then
137140
MODE="$FROM_MD"; SOURCE="PROJECT.md"

‎bin/mdl-scan.sh‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,14 @@ done
5252
[ -f "$SCRIPT" ] && [ -r "$SCRIPT" ] || { echo "mdl-scan: cannot read script: $SCRIPT" >&2; exit 2; }
5353
if [ -n "$MPR" ] && [ ! -f "$MPR" ]; then echo "mdl-scan: -p: no such model: $MPR" >&2; exit 2; fi
5454

55-
RULES="${MDL_SCAN_RULES:-$(cd "$(dirname "$0")" && pwd)/lib/mdl-scan-rules.tsv}"
55+
# The script's own folder, as a string op when $0 is already a path (a cd | dirname | pwd was
56+
# three process starts per exec); an absolute path stays as it was, a relative one is anchored.
57+
if [ -n "${MDL_SCAN_RULES:-}" ]; then RULES="$MDL_SCAN_RULES"
58+
else
59+
_msd="${0%/*}"; [ "$_msd" != "$0" ] || _msd=.
60+
case "$_msd" in /*) ;; *) _msd="$(cd "$_msd" && pwd)" ;; esac
61+
RULES="$_msd/lib/mdl-scan-rules.tsv"
62+
fi
5663
[ -r "$RULES" ] || { echo "mdl-scan: rules file missing: $RULES" >&2; exit 2; }
5764

5865
awk -F'\t' -v file="$SCRIPT" '

‎project-bin/_common.sh‎

Lines changed: 116 additions & 61 deletions
Large diffs are not rendered by default.

‎project-bin/build-plan-status.sh‎

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,14 @@ MDLSOURCE="$ROOT/mdlsource"
8888
MODULES_DIR="$ROOT/architecture/modules"
8989
REGISTER="$ROOT/docs/improvement-register.md"
9090
BUILD_PLAN="$ROOT/architecture/build-plan.md"
91-
STAMP="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
91+
if [ -n "${EPOCHSECONDS:-}" ]; then TZ=UTC printf -v STAMP '%(%Y-%m-%dT%H:%M:%SZ)T' -1 # bash 5: no date process
92+
else STAMP="$(date -u +%Y-%m-%dT%H:%M:%SZ)"; fi
9293

9394
# PROJECT.md `Progress report: off | ask | auto` (default ask). off = this script never writes the
9495
# page; ask and auto only change what the agent does at a stage gate or module close (the skills
9596
# say: ask once, or open it), so the script treats them the same.
9697
report_name() { # the page name lives in progress-report.py (REPORT_FILE); asked once, here
97-
REPORT_FILE="$("${PY:-python3}" "$(dirname "${BASH_SOURCE[0]}")/progress-report.py" --print-name 2>/dev/null)" # portability-ok: PY is resolve_py output; python3 only if unset
98+
REPORT_FILE="$("${PY:-python3}" "${_bpd:-$(dirname "${BASH_SOURCE[0]}")}/progress-report.py" --print-name 2>/dev/null)" # portability-ok: PY is resolve_py output; python3 only if unset
9899
[ -n "$REPORT_FILE" ] || REPORT_FILE="progress-report.html"
99100
}
100101
progress_report_setting() {
@@ -116,12 +117,21 @@ progress_report_setting() {
116117
PHASE_ROWS=""
117118
PHASE_COUNT=0
118119
if [ -d "$MDLSOURCE" ]; then
120+
# Counted with globs: the find | wc | tr (and basename) per phase folder were five process
121+
# starts each. dotglob + the symlink test keep find -type f's answer.
122+
_dg=0; shopt -q dotglob && _dg=1
119123
for d in "$MDLSOURCE"/*/; do
120124
[ -d "$d" ] || continue
121-
phase="$(basename "$d")"
122-
total=$(find "$d" -maxdepth 1 -type f \( -name '*.mdl' -o -name '*.sql' \) | wc -l | tr -d ' ')
125+
_dn="${d%/}"; phase="${_dn##*/}"
126+
total=0; done_ct=0
127+
shopt -s dotglob # only for the file globs: the phase folders themselves stay non-hidden
128+
for _pf in "$d"*.mdl "$d"*.sql; do
129+
[ -f "$_pf" ] && [ ! -L "$_pf" ] || continue
130+
total=$((total + 1))
131+
case "${_pf##*/}" in done-*) done_ct=$((done_ct + 1)) ;; esac
132+
done
133+
[ "$_dg" = 1 ] || shopt -u dotglob
123134
[ "$total" -eq 0 ] && continue
124-
done_ct=$(find "$d" -maxdepth 1 -type f \( -name 'done-*.mdl' -o -name 'done-*.sql' \) | wc -l | tr -d ' ')
125135
pct=$(( total > 0 ? done_ct * 100 / total : 0 ))
126136
status="pending"
127137
[ "$done_ct" -gt 0 ] && status="in-progress"
@@ -142,7 +152,7 @@ REVIEWED_COUNT=0
142152
if [ -d "$MODULES_DIR" ]; then
143153
for d in "$MODULES_DIR"/*/; do
144154
[ -d "$d" ] || continue
145-
module="$(basename "$d")"
155+
_dn="${d%/}"; module="${_dn##*/}"
146156
briefed="no"
147157
if [ -f "$d/module-brief.md" ]; then
148158
briefed="yes"
@@ -170,14 +180,13 @@ if [ -d "$MODULES_DIR" ]; then
170180
reviewed="not yet"
171181
if [ -f "$summary" ]; then
172182
REVIEWED_COUNT=$((REVIEWED_COUNT+1))
173-
if grep -q $'\tFAULT\t' "$summary" 2>/dev/null; then
174-
reviewed="INCOMPLETE (instrument fault)"
175-
elif grep -q $'\tFINDING\t' "$summary" 2>/dev/null; then
176-
reviewed="FINDINGS"
177-
else
178-
reviewed="CLEAN"
179-
fi
180-
age_s=$(( $(date +%s) - $(date -r "$summary" +%s 2>/dev/null || echo 0) ))
183+
_sum=""; IFS= read -r -d '' _sum < "$summary" 2>/dev/null || true # two greps over it, in-shell
184+
case "$_sum" in
185+
*$'\tFAULT\t'*) reviewed="INCOMPLETE (instrument fault)" ;;
186+
*$'\tFINDING\t'*) reviewed="FINDINGS" ;;
187+
*) reviewed="CLEAN" ;;
188+
esac
189+
age_s=$(( ${EPOCHSECONDS:-$(date +%s)} - $(date -r "$summary" +%s 2>/dev/null || echo 0) ))
181190
age_d=$(( age_s / 86400 ))
182191
reviewed="$reviewed (${age_d}d ago)"
183192
fi
@@ -432,9 +441,10 @@ PYEOF
432441
}
433442

434443
if [ "$WRITE_JSON" -eq 1 ] || [ "$WRITE_HTML" -eq 1 ]; then
435-
if [ -f "$(dirname "${BASH_SOURCE[0]}")/_common.sh" ]; then
444+
_bpd="${BASH_SOURCE[0]%/*}"; [ "$_bpd" != "${BASH_SOURCE[0]}" ] || _bpd=. # dirname without a process
445+
if [ -f "$_bpd/_common.sh" ]; then
436446
# shellcheck disable=SC1091
437-
. "$(dirname "${BASH_SOURCE[0]}")/_common.sh"
447+
. "$_bpd/_common.sh"
438448
fi
439449
if ! type resolve_py >/dev/null 2>&1; then
440450
resolve_py() {
@@ -532,7 +542,7 @@ render_plan_section() { # stdout: the plan section's HTML
532542
echo "<h2>The plan</h2><p class=empty>Nothing to show yet: ${PLAN_MSG:-build-plan.md was not read}.</p>"
533543
return 0
534544
fi
535-
"$PY" - "$PLAN_JSON" "$MDLSOURCE" "${PHASE_DETAIL:-/dev/null}" "$ROOT" "$(dirname "${BASH_SOURCE[0]}")/progress-report.py" <<'PYEOF' || echo "<h2>The plan</h2><p class=empty>Could not render the plan section from build-plan.md.</p>"
545+
"$PY" - "$PLAN_JSON" "$MDLSOURCE" "${PHASE_DETAIL:-/dev/null}" "$ROOT" "${_bpd:-$(dirname "${BASH_SOURCE[0]}")}/progress-report.py" <<'PYEOF' || echo "<h2>The plan</h2><p class=empty>Could not render the plan section from build-plan.md.</p>"
536546
import fnmatch, html, json, os, re, sys
537547
538548
src, mdl, detail_out, proj, gen = sys.argv[1:6]
@@ -709,7 +719,7 @@ PYEOF
709719
# architecture/build-plan.html is left exactly where it is: not read, not rewritten, not deleted.
710720
if [ "$WRITE_HTML" -eq 1 ]; then
711721
SKIP_HTML=""
712-
GEN="$(dirname "${BASH_SOURCE[0]}")/progress-report.py"
722+
GEN="${_bpd:-$(dirname "${BASH_SOURCE[0]}")}/progress-report.py"
713723
report_name
714724
OUT="$ROOT/architecture/$REPORT_FILE"
715725
SETTING="$(progress_report_setting)"

0 commit comments

Comments
 (0)