Skip to content
Merged
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m

## Unreleased

- fix(exec): **a script restated from a stale DESCRIBE now WARNs instead of silently reverting an earlier exec** (#261). A script drafted from a DESCRIBE taken before an earlier script of the batch ran put four old messages back, with check, mxbuild and lint green. New `project-bin/describe-baseline.sh stamp` writes `-- baseline: <Doc> sha256=<hash>` (plus `-- baseline-mxcli: <version>`) from a DESCRIBE at draft time; `exec.sh` runs `verify` only for a script that carries the header, so other scripts cost one grep and no mxcli call. It reports DRIFT with the first lines of the diff, STALEHEADER, and RESTAMP after an mxcli upgrade (DESCRIBE text may change, so that is not called drift). A re-run by the script's own last recorded write (the #269 ledger) and a fresh model are not drift. Nothing is refused and the exit codes do not change. Preflight STOP 21 gains one clause (`-- supersedes:`, `stamp`, exec.sh only warns) and its trigger names `create or modify` (+24 words). Not-found DESCRIBE and `--version` output are captured from mxcli v0.26.0. Lands after the #269 PR; with it, supersedes draft #311. **Behaviour change to check in your project:** `exec.sh` output can carry `WARN: stale draft: …` lines, and the BUILD-LOG detail cell `WARN stale baseline: <docs>`; `MXTK_RESTATE_GUARD=off` skips the check. — AlvinnYeo (#261)
- fix(exec): **re-running an older `mdlsource/` script over a newer owner's live work now WARNs instead of passing silently** (#269). Three field apps had 99/579, 130/357 and 38/159 documents created by more than one script, and a replay of an older one reverted the newer with exit 0 and every gate green. New `project-bin/script-owners.sh` maps each microflow, nanoflow, page and snippet to the scripts that create or restate it, in run order (digit runs compared as numbers, so `2-core/` runs before `11-fixes/`; `done-` ignored), and reads `-- supersedes:` / `-- superseded-by:` headers. `exec.sh` records every kept write in a machine-local last-writer ledger (`.claude/loop/script-owners/`, self-gitignored, compacted per write); `restore-mpr.sh` marks it on a manual restore. A replay WARNs only when the newer owner's write is live: ledger first, else one DESCRIBE per document, at most 5 per exec (the rest print `CONFLICT (not checked)`). A new owner without a supersedes header gets one `NOTE:` line on its first run, kept out of BUILD-LOG. Nothing is refused and the exit codes do not change. With no co-owner, `exec.sh` runs one grep over `mdlsource/` and no mxcli call. `gate-check.sh` prints the co-owned count when it is above 0. Part of the rebuilt draft #311 (with the #261 PR). **Behaviour change to check in your project:** `exec.sh` output can carry `WARN: restatement: …` and `NOTE: new owner of …` lines; the BUILD-LOG detail cell can carry `WARN reverts: <docs>`. Set `MXTK_RESTATE_GUARD=off` to skip the check. — MendixMau (#269)
- fix(exec): **re-running an older `mdlsource/` script over a newer owner's live work now WARNs instead of passing silently** (#269). Three field apps had 99/579, 130/357 and 38/159 documents created by more than one script, and a replay of an older one reverted the newer with exit 0 and every gate green. New `project-bin/script-owners.sh` maps each microflow, nanoflow, page and snippet to the scripts that create or restate it, in run order (digit runs compared as numbers, so `2-core/` runs before `11-fixes/`; `done-` ignored), and reads `-- supersedes:` / `-- superseded-by:` headers. `exec.sh` records every kept write in a machine-local last-writer ledger (`.claude/loop/script-owners/`, self-gitignored, compacted per write); `restore-mpr.sh` marks it on a manual restore. A script counts as run when it has a ledger row, a `done-` name, or an applied `docs/BUILD-LOG.md` row, so a fresh clone or cloud session (empty ledger) still warns on a replay over committed newer work; a script nobody ran yet (draft-ahead) stays quiet. The ledger cannot see Studio Pro edits or a `git pull`/`checkout` of the `.mpr`. A replay WARNs only when the newer owner's write is live: ledger first, else one DESCRIBE per document, at most 5 per exec (the rest print `CONFLICT (not checked)`). A new owner without a supersedes header gets one `NOTE:` line on its first run, kept out of BUILD-LOG. Nothing is refused and the exit codes do not change. With no co-owner, `exec.sh` runs one grep over `mdlsource/` and no mxcli call. `gate-check.sh` prints the co-owned count when it is above 0. Part of the rebuilt draft #311 (with the #261 PR). **Behaviour change to check in your project:** `exec.sh` output can carry `WARN: restatement: …` and `NOTE: new owner of …` lines; the BUILD-LOG detail cell can carry `WARN reverts: <docs>`. Set `MXTK_RESTATE_GUARD=off` to skip the check. — MendixMau (#269)
- fix(exec): **re-running an older `mdlsource/` script over a newer owner's live work now WARNs instead of passing silently** (#269). Three field apps had 99/579, 130/357 and 38/159 documents created by more than one script, and a replay of an older one reverted the newer with exit 0 and every gate green. New `project-bin/script-owners.sh` maps each microflow, nanoflow, page and snippet to the scripts that create or restate it, in run order (digit runs compared as numbers, so `2-core/` runs before `11-fixes/`; `done-` ignored), and reads `-- supersedes:` / `-- superseded-by:` headers. `exec.sh` records every kept write in a machine-local last-writer ledger (`.claude/loop/script-owners/`, self-gitignored, compacted per write); `restore-mpr.sh` marks it on a manual restore. A script counts as run when it has a ledger row, a `done-` name, or an applied `docs/BUILD-LOG.md` row, so a fresh clone or cloud session (empty ledger) still warns on a replay over committed newer work; a script nobody ran yet (draft-ahead) stays quiet. The ledger cannot see Studio Pro edits or a `git pull`/`checkout` of the `.mpr`. A replay WARNs only when the newer owner's write is live: ledger first, else one DESCRIBE per document, at most 5 per exec (the rest print `CONFLICT (not checked)`). A new owner without a supersedes header gets one `NOTE:` line on its first run, kept out of BUILD-LOG. Nothing is refused and the exit codes do not change. With no co-owner, `exec.sh` runs one grep over `mdlsource/` and no mxcli call. `gate-check.sh` prints the co-owned count when it is above 0. Part of the rebuilt draft #311 (with the #261 PR). **Behaviour change to check in your project:** `exec.sh` output can carry `WARN: restatement: …` and `NOTE: new owner of …` lines; the BUILD-LOG detail cell can carry `WARN reverts: <docs>`. Set `MXTK_RESTATE_GUARD=off` to skip the check. — MendixMau (#269)
- fix(root): **the installed and toolkit copies of `_common.sh` now resolve the same project root from inside an app folder** (#489). With the cwd in `app/`, `app/javasource` or `apps/<X>/`, the installed copy (`<project>/bin/_common.sh`, tier 2) answered the project while the toolkit copy (tier 3) stopped at the folder holding the `.mpr`, so the same script wrote its look ledger, metrics ledger and BUILD-LOG to two roots depending on where it was run from. `mxtk_walk_root` now returns the project folder when the folder it stops at is `<p>/app` or `<p>/apps/<X>` and `<p>` is a marked project folder (an installed `bin/_common.sh`, or `.claude/` beside `PROJECT.md`); an unmarked app folder is still returned as itself, and so is an app folder that is a project of its own (its own install, or `.claude/` beside `PROJECT.md`); the folder names match in any letter case, and single-tree resolution is unchanged. Builtin tests only, no extra process. `find_mpr` now always prints an absolute path (a cwd-relative `MPR_FILE` broke once a caller did `cd "$PROJECT_ROOT"`), and with several apps and no `MPR_FILE`, sourcing `_common.sh` from inside one app's folder exports `MPR_FILE` as that app's model, so the pick survives exec.sh's `cd "$PROJECT_ROOT"` and reaches `snapshot-mpr.sh` (outside any one app nothing is picked and `find_mpr` still refuses; an explicit `MPR_FILE` or a root/`app/` model always wins; the pick is marked `MXTK_MPR_PICKED`, so a child script whose cwd is inside a different `apps/<X>/` re-derives instead of inheriting it, and `model-stamp.sh` says "(picked from your cwd)" when it refuses one). `lint-gate.sh` now honours `MPR_FILE` when `MPR` is unset and it resolves under the project root, so exec.sh run from inside one app no longer reaches its "several apps" refusal; an `MPR_FILE` that does not resolve there (cwd-relative, or absolute through a symlinked path) falls back to discovery as before, never to exit 2. An inherited pick from another project is dropped. **Behaviour change to check in your project:** a toolkit-copy script run from inside `app/` or `apps/<X>/` of a wired project now reads and writes state at the project root, as the installed copy already did; if `app/` (or `apps/<X>/`) holds `.mpr-snapshots/`, `docs/BUILD-LOG.md` or `.claude/loop/` from a toolkit-copy run, merge them into the project root. `find_mpr` with `MPR_FILE` set now prints an absolute path where it echoed a relative one. A project whose `bin/_common.sh` is hand-edited needs `sync-project.sh <project> --only-bin _common.sh --upgrade-bin _common.sh`, as for #420. `test-common-root-multiapp.sh` R8a, R9c-f, R13g, R17a-j and R18a-h (cwd in `app/`, `app/javasource`, `apps/A`, `apps/A/javasource`, a nested or wired app folder, `App/`, both copies; the cwd's app surviving a `cd` to the root and a child `snapshot-mpr.sh`; a child in another app re-deriving, R18h a child in another project): 67/67 with the fix; `test-lint-gate-accept.sh` T-MA (lint-gate with `MPR_FILE` in a multi-app folder) and T-MF (an unresolvable `MPR_FILE` falls back to discovery). — MendixMau (review 2026-10-20)
- fix(portability): **`bug-lookup.sh --index` and `test-routing-tier.sh` no longer depend on sed expanding `\t`, and `check-portability.sh` flags `\t` in a sed pattern or replacement outside a bracket** (#488). BSD sed (macOS) reads `\t` there as the letter `t`, so `sed -E 's/^([0-9]+):## /\1\t/'` fed `awk -F'\t'` no tab and `--index` printed 222 empty lines; the line-count check passed anyway. The index is now one awk (same 222 lines, byte-identical on GNU), the fixture builds its sed script with a real tab (`TAB=$'\t'`), and `test-bug-lookup.sh` runs `--index` under a sed shim that reads `\t` as `t` (fails on master: 0 non-empty lines). The lint also had a blind spot: its comment filter dropped any line holding `:#`, so the bug-lookup line was never checked; it is now anchored on the line number. New rule over the current tree: the two sites on master, 0 elsewhere. `test-sed-tab-bracket.sh` T4. Simulated on Linux only; one macOS run is still owed. — MendixMau (review 2026-10-20)
Expand Down
4 changes: 3 additions & 1 deletion bin/lib/install-manifest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,9 @@ MXTK_AGENTS_STAGE_BUILD="mdl-agent.md gate-agent.md test-agent.md review-agent.m
# anchors, a wireframe or a BRD, and gate-check.sh check_stage_3 fails a stale render.
# script-owners.sh joined on 2026-10-21 (#269): exec.sh runs it as its sibling before every MDL
# write (co-owned documents) and records each kept write in its ledger; restore-mpr.sh marks it.
MXTK_PROJECT_BIN="process-map.js process-map.template.html app-restart.sh test-scratch.sh script-owners.sh assemble-prototype.js prototype-route.js check-prototype-links.js wf-add-path-terminators.py wf-set-call-captions.py mxunit_bson.py mxpatch.py _common.sh app-facts.sh _claims.sh snapshot-mpr.sh restore-mpr.sh exec.sh affected-tests.sh look-ledger.sh save-sp.sh restart-sp.sh check-sp-health.sh verify-module.sh test-stack-up.sh fixture-manifest.sh check-root-clean.sh lint-gate.sh lint-trend.sh metrics-ledger.sh metrics-trend.sh close-task.sh conformance-check.sh coverage-preflight.sh graph-sweep.sh review-module.sh coherence-cadence.sh build-plan-status.sh progress-report.py done-drift-check.sh page-scope.sh render-improvement-register.sh check-design-portability.sh check-design-reaches-app.sh check-page-shell.sh page-fidelity.js model-stamp.sh verify-model.sh install-project-hooks.sh mx-metadata-note.py session-check.sh constants-audit.sh context-pack.sh check-staged-secrets.sh"
# describe-baseline.sh joined the same day (#261): exec.sh runs its verify for a script with a
# `-- baseline:` header, and it reads script-owners.sh's ledger as ITS sibling.
MXTK_PROJECT_BIN="process-map.js process-map.template.html app-restart.sh test-scratch.sh script-owners.sh describe-baseline.sh assemble-prototype.js prototype-route.js check-prototype-links.js wf-add-path-terminators.py wf-set-call-captions.py mxunit_bson.py mxpatch.py _common.sh app-facts.sh _claims.sh snapshot-mpr.sh restore-mpr.sh exec.sh affected-tests.sh look-ledger.sh save-sp.sh restart-sp.sh check-sp-health.sh verify-module.sh test-stack-up.sh fixture-manifest.sh check-root-clean.sh lint-gate.sh lint-trend.sh metrics-ledger.sh metrics-trend.sh close-task.sh conformance-check.sh coverage-preflight.sh graph-sweep.sh review-module.sh coherence-cadence.sh build-plan-status.sh progress-report.py done-drift-check.sh page-scope.sh render-improvement-register.sh check-design-portability.sh check-design-reaches-app.sh check-page-shell.sh page-fidelity.js model-stamp.sh verify-model.sh install-project-hooks.sh mx-metadata-note.py session-check.sh constants-audit.sh context-pack.sh check-staged-secrets.sh"

# Files in project-bin/ that are deliberately NOT installed into projects. The reverse check
# below flags anything named by NEITHER list, so a new file in project-bin/ has to be either
Expand Down
Loading
Loading