From 8ea49878ca80a38b2342b85ebdaa147e15f13c5f Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 22 Sep 2026 14:48:15 +0000 Subject: [PATCH] fix(doctor): keep the model's real basename in the gate self-test scratch dir gate_selftest() copied the project model to a hardcoded "$scratch/model.mpr" while copying mprcontents/ beside it verbatim. mprcontents/ carries an internal record of the model's real basename, so the renamed copy is a mismatched pair: mxbuild bails before writing any error file, mxtk_mxbuild_error_count returns "?", and the self-test prints gate self-test: gate cannot read mxbuild's error file (baseline run) GATE_SELFTEST_LINE="fail (unreadable error file)" which is the F-042-class string meaning "the gate itself is broken" - a false FAIL on a perfectly healthy gate, sending people hunting a nonexistent problem. The scratch copy now keeps basename "$MPR", threaded through all four later references (baseline count, the mxcli injection's -p, the known-bad count); scratch_mpr is declared in the existing bash 3.2-compatible local list. NOT FIELD-RUN. This environment has no .mpr, no mxbuild and no Studio Pro, so the fix is reasoned and inspected only. One run of `bin/doctor.sh --gate-selftest ` on a macOS machine with Studio Pro 11 against a real model is what would prove it; do not tell the team to pull until that run exists. Found by Yvann during Mac/sandbox onboarding, 2026-09-22. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_0187r9bQWkZAEppyEqrDevjK --- CHANGELOG.md | 1 + bin/doctor.sh | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 56c48812..81019991 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ three commits past it), and a bug report can name a release instead of a sha nob Sections dated before 2026-09-19 predate the cycle and stay as they are. ## Unreleased +- fix(bin/doctor.sh): **the gate self-test renamed the model in its scratch dir to `model.mpr` while copying `mprcontents/` verbatim beside it, so mxbuild bailed before writing any error file and the self-test reported `fail (unreadable error file)` — the F-042-class string that means "the gate itself is broken" — on a perfectly healthy gate.** `mprcontents/` carries an internal record of the model's real basename; the rename breaks the pair. The scratch copy now keeps the real basename (`$scratch/$(basename "$MPR")`), threaded through all four later references (baseline count, injection `exec -p`, known-bad count). **Not field-run** — reasoned and inspected only; needs one run of `doctor.sh --gate-selftest ` on a macOS machine with Studio Pro 11 and a real `.mpr` before the team is told to pull. Found by Yvann during Mac/sandbox onboarding — Yvann - docs(front door): **README and `toolkit-guide.html` now count five ways in, not three.** Both already listed migration, requirements-driven, greenfield and the à-la-carte no-pipeline route; only the headlines said "three", so sessions reading the headline reported three entry modes while the runbook and `CLAUDE.md` said three plus à-la-carte. Wording now: four pipeline entry modes plus one route with no pipeline — Maurits Visser - docs(testing): **Windows full test-run prompt.** `docs/windows-test-run.md` — a paste-able, unattended Claude Code prompt for a Git Bash machine: guards, both fixture suites, 27 Windows-relevant fixtures with their subjects, the committed inputs (`fixtures/app-analysis`, page-fidelity mocks, html-to-md capture) run directly, and a field run on a scratch copy of a real project incl. the two-tree and toolkit.env probes; one results file, facts only — Maurits Visser - learn(eval install run, UPSTREAM-PR.md): **the "could we change the CLI?" question answered with a built, tested, field-run PR rather than an estimate** — `marketplace install --file ` on a shallow clone of the upstream repo, following its own CONTRIBUTING and PR checklist (test first, verify at the symptom's layer, prove by revert, record a finding). Eight unit tests with the marketplace client factory fatal-if-called, one integration test against a real package, lint and the full test tree green. The field run with real packages found a **pre-existing bug**: with a relative `-p app.mpr` the install writer refused every bundled file as path traversal after the module was already transplanted — fixed as a separate commit, test shown failing first. Two integration-test failures were my own test bugs (temp HOME hiding the mxbuild cache; return operands read before the command ran), each misread as a product failure for one round. Not submitted (repo unreachable from this session); patches, PR body and submission recipe staged in the private repo. — Maurits Visser diff --git a/bin/doctor.sh b/bin/doctor.sh index bd3afa81..e8f863a5 100755 --- a/bin/doctor.sh +++ b/bin/doctor.sh @@ -889,7 +889,7 @@ if [ "$QUICK" != 1 ] || [ "$GATE_SELFTEST" = 1 ]; then head_ "Gate self-test (can the mxbuild gate actually see an error?)" gate_selftest() { - local scratch t0 t1 elapsed mdl model_dir base_count bad_count rc timeout_s + local scratch scratch_mpr t0 t1 elapsed mdl model_dir base_count bad_count rc timeout_s timeout_s="${DOCTOR_GATE_TIMEOUT:-300}" t0=$(date +%s) @@ -916,7 +916,12 @@ gate_selftest() { } trap 'rm -rf "$scratch" 2>/dev/null' RETURN - if ! cp "$MPR" "$scratch/model.mpr" 2>/dev/null; then + # Keep the model's REAL basename in the scratch dir: mprcontents/ (copied verbatim below) + # carries an internal record of it, and a renamed copy makes mxbuild bail BEFORE it writes + # any error file — which this self-test would then report as "gate cannot read mxbuild's + # error file", a false FAIL on a healthy gate. (Reported 2026-09-22 by Yvann.) + scratch_mpr="$scratch/$(basename "$MPR")" + if ! cp "$MPR" "$scratch_mpr" 2>/dev/null; then bad "gate self-test: could not copy the model into the scratch dir" GATE_SELFTEST_LINE="fail (copy failed)" return 0 @@ -926,7 +931,7 @@ gate_selftest() { # (a) Baseline: the gate must resolve SOME integer off this model, clean or not — "?" here # means the gate cannot read mxbuild's own output, which is the original F-042-class defect. - base_count=$(mxtk_mxbuild_error_count "$scratch/model.mpr" "$timeout_s") + base_count=$(mxtk_mxbuild_error_count "$scratch_mpr" "$timeout_s") rc=$? if [ "$rc" -eq 3 ]; then bad "gate self-test: mxbuild did not return within ${timeout_s}s (baseline run)" @@ -964,14 +969,14 @@ END; MDL # If mxcli refuses the injection (syntax rejected by a newer grammar, model locked, ...), # the copy is still clean and a 0 below would be a FALSE "blind" verdict — say NOT RUN. - if ! "$PMXCLI_PROBE" exec "$mdl" -p "$scratch/model.mpr" >"$scratch/inject.out" 2>&1; then + if ! "$PMXCLI_PROBE" exec "$mdl" -p "$scratch_mpr" >"$scratch/inject.out" 2>&1; then warn "gate self-test: NOT RUN — the project's mxcli refused the known-bad injection:" sed 's/^/ /' "$scratch/inject.out" | head -5 GATE_SELFTEST_LINE="not-run (injection refused)" return 0 fi - bad_count=$(mxtk_mxbuild_error_count "$scratch/model.mpr" "$timeout_s") + bad_count=$(mxtk_mxbuild_error_count "$scratch_mpr" "$timeout_s") rc=$? if [ "$rc" -eq 3 ]; then bad "gate self-test: mxbuild did not return within ${timeout_s}s (known-bad run)"