diff --git a/CHANGELOG.md b/CHANGELOG.md index ea25f688..85f9619b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,10 +20,10 @@ Sections dated before 2026-09-19 predate the cycle and stay as they are. Named m ## Unreleased - fix(build-plan-status): **every State the build-plan skill lists (built, partial, not built, blocked) and every spelling the phase card already counts (complete, verified, in progress, not needed and the like) is now read the same way by the plan header and the phase badge, so card, header and badge give one count; blocked counts as not built and is named in the header, genuinely unreadable values are still reported as unreadable; the later-stage placeholder FAIL is relabelled PENDING only while that stage is pending in PROJECT.md, with tests that a real FAIL stays FAIL and that FAIL stays when the current stage is unknown** — MendixMau +- docs(release): **`docs/releases/v1.0.md` rewritten to the maintainer's structure: performance first (testing at key moments with the measured numbers), the settings a project owner controls, context packs, everything else, how to update.** Docs only; no routed or always-loaded file touched. — MendixMau - fix(release-review): **the v1.0 release review: the multilingual skill loses its em and en dashes (wording only, content unchanged; its routing row keeps the trigger separator the agent stubs cut on), `doctor.sh` warns when a hook copy in `~/.claude/hooks` calls a toolkit script that no longer exists (it names the script and says to re-run `bin/install-claude-hooks.sh --full`; a warning, never a failure), and the `.gitignore` line for `.claude/progress-report-sessions.txt` now also reaches a project checked out as a git worktree (`.git` is a file there) in `doctor.sh` and `sync-project.sh`; `check-ignore --no-index` stops the line being appended again when the file is already tracked, and a `git rm --cached` hint is printed.** Tests: new `test-doctor-stale-hooks.sh`; worktree and tracked-file cases added to `test-progress-report-gitignore.sh`. CHANGELOG tidy (a stray blank line, one credit). — MendixMau - fix(progress-report): **round 6 of the review: the session cache is machine-local and tied to its project, the first cached run is not slower than a cold one, and the build ledger decides the Stage 4 to 5 switch.** (1) `.claude/progress-report-sessions.txt` holds absolute session-log paths, so `init-project.sh`, `doctor.sh` and `sync-project.sh` now put `/.claude/progress-report-sessions.txt` in the project's `.gitignore`, the way they do for the doctor receipt and `toolkit.env`. (2) The cache header records the project's real path and the attribution rules (25% of tool calls, 20 calls); a copied or moved project, or a changed threshold, reads it as cold, so a copy never lists the original's sessions. (3) Files skipped by the 300-file cap are recorded as `no`, so a cached run never reads more files than a cold one. (4) With rows in `metrics-ledger.tsv` (else BUILD-LOG) the switch comes from the ledger; an earlier exec.sh call or build skill in a session log is ignored, the timed sign-off rule stays, and the footer says how the switch is chosen. Tests: F15 to F17 in `test-progress-report-field-fixes.sh`, new `test-progress-report-gitignore.sh` — MendixMau -- fix(progress-report): **polish on a fresh and an updated demo project: a "done " plan row counts as built in the card, the plan header and the phase badge alike; a placeholder gate failure on a stage after the current one reads PENDING, not FAIL; the no-session-log notice is one calm line with the regenerate hint inside "How this was measured"; the test-moments table says unit tests run for the flows chosen at CAC-5, not "when switched on".** — field review of the #434 report -- fix(progress-report): **round 6 of the review: the session cache is machine-local and tied to its project, the first cached run is not slower than a cold one, and the build ledger decides the Stage 4 to 5 switch.** (1) `.claude/progress-report-sessions.txt` holds absolute session-log paths, so `init-project.sh`, `doctor.sh` and `sync-project.sh` now put `/.claude/progress-report-sessions.txt` in the project's `.gitignore`, the way they do for the doctor receipt and `toolkit.env`. (2) The cache header records the project's real path and the attribution rules (25% of tool calls, 20 calls); a copied or moved project, or a changed threshold, reads it as cold, so a copy never lists the original's sessions. (3) Files skipped by the 300-file cap are recorded as `no`, so a cached run never reads more files than a cold one. (4) With rows in `metrics-ledger.tsv` (else BUILD-LOG) the switch comes from the ledger; an earlier exec.sh call or build skill in a session log is ignored, the timed sign-off rule stays, and the footer says how the switch is chosen. Tests: F15 to F17 in `test-progress-report-field-fixes.sh`, new `test-progress-report-gitignore.sh` — review of PR #434 +- fix(progress-report): **polish on a fresh and an updated demo project: a "done " plan row counts as built in the card, the plan header and the phase badge alike; a placeholder gate failure on a stage after the current one reads PENDING, not FAIL; the no-session-log notice is one calm line with the regenerate hint inside "How this was measured"; the test-moments table says unit tests run for the flows chosen at CAC-5, not "when switched on".** — MendixMau - fix(progress-report): **round 5 of the field test: "building now" marks the phase of the last successful build step (its mdlsource folder, else the script name matched to the plan, else the highest active phase; blocked steps and earlier amber rows do not move it); discovery of sessions from other folders counts only tool calls that operate on the project (at least 25% of a session's calls and at least 20, gaps over 30 minutes cut, sessions that run progress-report.py excluded, text mentions never count) and lists the sessions used in a collapsed element; a Stage 4 sign-off row with a date but no time puts the Stage 5 switch at the first build activity on or after that date (marked inferred) instead of midnight; the exec log is now the primary source for build activity: `.claude/loop/metrics-ledger.tsv` (written by exec.sh, UTC shown as local time) gives the Stage 5 build facts with or without a session log (runs, applied, failed, blocked, restored, exec time, wall span, runs per phase, latest model score, share of exec time lost to failed or restored runs), the last build step, the building-now phase and the Stage 4 to 5 switch, with BUILD-LOG and then session activity as fallbacks; docs/progress/TIME-LEDGER.md is an optional hand-written extra and its reader maps columns by each table's header.** Tests F10 (existing-project fixture) and F11 (older toolkit, then sync-project.sh) added. — MendixMau - fix(progress-report): **field-test round on two real projects: one source of truth for stage state, a plan read from build-plan.md when the JSON is stale, wider log discovery with a ledger fallback, and a Build progress section.** (1) PROJECT.md (the stage line and the Decisions sign-off rows) beats a gate-check page that is older than it: the stage line's `· manual: 5` tail no longer swallows the last passed stage, the counter always equals the list it sits beside ("6 of 8" for P,0,1,2,3,4, plus "N waived"), and a passed stage the page does not list shows an amber "Gate-check page is N days old, re-run gate-check". (2) The report never lists itself as a stage artifact, nor any file outside the project folder. (3) `build-plan.json` older than `build-plan.md` or than the newest `docs/BUILD-LOG.md` row is no longer trusted: row state is read from the md State column by prefix (`not built` first; `built (...)` and `done ...` are built; `partial` and `in progress` are partial; `not needed` rows are not counted) and the page says "plan JSON was stale, counted from build-plan.md". (4) With no log in the project's own folder, discovery also scans other `~/.claude/projects/*` folders (30 days, newest 300 files): a log counts when its cwd is the project or when the project path appears in it at least 5 times, in which case only the stretch from the first to the last mention (padded 30 min) is counted, and the page says so; with no log at all, `docs/progress/TIME-LEDGER.md`, `docs/BUILD-LOG.md` and `.claude/loop/metrics-ledger.tsv` feed a labelled ledger card, and the banner says how to pass `--session-log`. (5) The Stage 4 to 5 switch for time and tokens is the earliest evidenced of the Stage 4 sign-off row in PROJECT.md, the first `exec.sh` call and the build skill, so a stale gate page no longer puts all build work in Stage 4. (6) The build detail section is now "Build progress", linked from the Stage 5 card: stacked built / partial / not built bars per phase, the headline "N of M rows built, K partial", the phase being built now marked, and the last build step with how long ago it ran. Test: `tests/wave2/test-progress-report-field-fixes.sh` (39 checks). — MendixMau - new(progress-report): **`architecture/progress-report.html` replaces `architecture/build-plan.html`, and adds time, token and tips views from the session log.** `build-plan-status.sh --html` now writes one self-contained page: every phase and the built versus proven views the old page had, stages P to 6 with artifact links, a progress bar and stage nav, and, when a Claude Code log for the project folder exists, time per stage, sub-agent use, context size, an estimated token cost (rates in an optional file, placeholder defaults, labelled as estimates), a Run health strip and a speed panel. Tips and tricks sit in a narrow side column (after the title, headline and stage cards on a phone), in one collapsed box per theme (Context, Tokens and cost, Speed, Health, Sub-agents), empty themes hidden. Only patterns with a concrete action in the project are shown, ranked by time or tokens lost, each with what was seen, why it matters and one fix. Severity is calm: red only for a key script (doctor, gate-check, exec, tests) failing every run with at least 3 runs, or a hang over 30 minutes; context is never red (a Context tip is amber when the window was reached or a compaction happened). Required gates and builds on the inherent list never produce a hang or slow tip and never change Run health; tips that lose under a minute are dropped; tips name real scripts or commands only. Costs that come from how the toolkit and mxcli work (build time, required gates and reviews, waiting on builds or the user, the mandated review model) are flagged inherent in the script and never shown. The context window is 1M only when the log records it (a `[1m]` model id or a context-1m beta); otherwise 200k, and a context above 200k with auto compactions caps the window at the compaction point and is labelled inferred. Never a percentage over 100. Every threshold sits in one block at the top of `project-bin/progress-report.py`, and the footer records the project folder and session log paths used. Only numbers, stage names, script names, file paths and sub-agent short descriptions are read from the log, never message text. Without a log the project sections render and the page says time and token data are unavailable. The page refreshes after every `exec.sh` slice and reloads itself every 30 s only while the build is active. PROJECT.md `Progress report: off | ask | auto` (default `ask`) controls it, and `--open` opens it. An existing `build-plan.html` is never deleted, and gate-check and status.sh still accept it. `--json` is unchanged. Skill words fell by about 100 (Step 10 and step 16 shortened). Tests: `tests/wave2/test-progress-report.sh`, `test-build-plan-json.sh`, `test-surface-column.sh`. — MendixMau diff --git a/docs/releases/v1.0.md b/docs/releases/v1.0.md index 46b7f75d..82f7855c 100644 --- a/docs/releases/v1.0.md +++ b/docs/releases/v1.0.md @@ -5,179 +5,402 @@ agent and [mxcli](https://github.com/mendixlabs/mxcli). It gives the agent a sta with recorded decisions (`PROJECT.md`), skills it loads only when a task calls for them, and mechanical gates (`bin/gate-check.sh`, lint, mxbuild, end-to-end journeys) that report what is actually in your project. It runs for migrations, requirements-driven builds, greenfield builds -and changes to a live app, or à la carte to audit and test an app you already have. - -1.0 is the first named milestone on top of the release train. It is not a rewrite: these notes -pick out what changed in the two weeks before it (2026-09-30 to 2026-10-14). Every line traces to -an entry in [`CHANGELOG.md`](../../CHANGELOG.md), which has the full detail and field evidence. -How milestones relate to the `vYYYY.MM.DD` tags: [`docs/RELEASE-PROCESS.md`](../RELEASE-PROCESS.md) -§8. - -1.0 is the first release-train tag published to GitHub, cut with `bin/cut-release.sh` when this -release is announced. Earlier `vYYYY.MM.DD` headings in CHANGELOG were never pushed as tags. - -Most PRs linked below landed together through -[#329](https://github.com/MendixMau/mxcli-project-toolkit/pull/329) and show as closed on GitHub; their -changes are on master. - -## Highlights - -### Every merge is reviewed by someone who did not write it - -A PR now gets an independent review (MERGE / MERGE-AFTER-FIX / HOLD, on value, regression risk -after sync, correctness and context cost) before it lands; green CI and the author's own report no -longer count as one. Nine PRs had merged on 2026-10-13 without one -([#316](https://github.com/MendixMau/mxcli-project-toolkit/pull/316)). Several fixes in this -release came out of those reviews (the exec lock race, the final-LOOK timing, the -`test-stack-up` exit codes). - -**For you:** what reaches your project on `git pull` has been read by a second reviewer, not just -tested by its author. - -### Less text in every session - -The always-loaded skill tier had reached 79,997 words against an 80,000-word cap. Incident stories -moved behind pointers into `process/baseline-incident-history.md` and the tier dropped to 76,259 -words with no rule removed ([#315](https://github.com/MendixMau/mxcli-project-toolkit/pull/315)). -New rule: room is made by moving text, never by deleting rules. `change-intake.md` became a -331-word core with an on-demand detail file -([#327](https://github.com/MendixMau/mxcli-project-toolkit/pull/327)), dispatch guidance moved to -its own small file ([#320](https://github.com/MendixMau/mxcli-project-toolkit/pull/320)), a -scaffolded `CLAUDE.local.md` is 17% shorter -([#292](https://github.com/MendixMau/mxcli-project-toolkit/pull/292)), routing in -`CLAUDE.local.md` carries triggers only -([#226](https://github.com/MendixMau/mxcli-project-toolkit/pull/226)), helper stubs read about 18% -less per dispatch ([#223](https://github.com/MendixMau/mxcli-project-toolkit/pull/223)), and a -build helper can get one context-pack file per build step instead of a reading list -([#198](https://github.com/MendixMau/mxcli-project-toolkit/pull/198)). - -**For you:** run `bin/sync-project.sh` and existing projects pick up the shorter wiring; sessions -start with less to read. - -### `exec.sh`: per-project lock, restart verdicts, safer restarts - -In a 20-task field run, 57 of 148 `exec.sh` runs applied nothing, and a machine-wide guard blocked -writes because a *different* project was writing. `exec.sh` now locks per project with a stale-lock -takeover, offers an opt-in `--commit-first`, and ends every applied script with a verdict: restart -needed, watch can apply this, or unknown -([#304](https://github.com/MendixMau/mxcli-project-toolkit/pull/304), -[#324](https://github.com/MendixMau/mxcli-project-toolkit/pull/324)). The review of #304 found the -takeover could let up to three contenders hold the lock; it is now serialised, and a fixture runs -10 rounds of 12 contenders and asserts at most one holder. New `bin/app-restart.sh` (#304) restarts only -this project's own `mxcli run --local`; since -[#322](https://github.com/MendixMau/mxcli-project-toolkit/pull/322) it also refuses over a leftover `mxcli test` injection. - -**For you:** two projects on one machine no longer block each other, and the agent is told when a -change needs an app restart instead of guessing. - -### Lint you can trust and tune - -UX001/002 plus Batches 1–4 landed: UX001/UX002, then ERR001/LOOP001, PERF001/002/004, -TXT001/TXT002/UI001, and Batch 4 with **SEC014** (an external role that can write status, audit or ownership members) and a -CONV009 that reads its `maxObjects` option -([#238](https://github.com/MendixMau/mxcli-project-toolkit/pull/238), -[#248](https://github.com/MendixMau/mxcli-project-toolkit/pull/248), -[#270](https://github.com/MendixMau/mxcli-project-toolkit/pull/270), -[#305](https://github.com/MendixMau/mxcli-project-toolkit/pull/305), -[#312](https://github.com/MendixMau/mxcli-project-toolkit/pull/312)). When `mxcli init` reverts -toolkit rules to stock, the lint gate now stops as **BLIND** instead of blaming the next script -for the jump, and sync restores them -([#308](https://github.com/MendixMau/mxcli-project-toolkit/pull/308)). Turning a rule off has one -supported route (`enabled: false` in `lint-config.yaml`, recorded in `PROJECT.md`). A metrics -ledger records outcome, speed, lint total and `mxcli report` score for every exec -([#265](https://github.com/MendixMau/mxcli-project-toolkit/pull/265)). - -**For you:** SEC014 asks one question (which roles are external) and prints a NOTE until you -answer it. - -### End-to-end proof that fails for the right reason - -The journey runner preflights the suite (a refused admin credential aborts before the first -journey) and journeys can declare `requires` / `leaves` / `consumes` -([#302](https://github.com/MendixMau/mxcli-project-toolkit/pull/302)). OQL rows are read by SELECT -alias, an app that dies mid-suite reads APP-DOWN rather than FAIL, and negative-only claims get a -liveness reference ([#310](https://github.com/MendixMau/mxcli-project-toolkit/pull/310)). -`test-stack-up.sh` identifies this project's own `run --local` by its command line -([#319](https://github.com/MendixMau/mxcli-project-toolkit/pull/319)). Re-runs are scoped to what -a change touched, UI-only changes get a light lane, and unit tests are off by default -([#290](https://github.com/MendixMau/mxcli-project-toolkit/pull/290)). The page-fidelity scorer -matches what a page displays, on whole words -([#318](https://github.com/MendixMau/mxcli-project-toolkit/pull/318)). - -**For you:** fewer false reds from the harness, and less time re-proving changes nobody touched. -**Check after upgrading:** `oqlScalar` now returns the first SELECT alias. - -### Stage 3 designs how users reach each page - -Stage 3 now writes `design/interaction-model.md` before the first wireframe: a home per role, an -inbox per user task, and for each page how it is reached and what it receives. Every wireframe -opens with a contract block ([#317](https://github.com/MendixMau/mxcli-project-toolkit/pull/317), -part 1 of [#291](https://github.com/MendixMau/mxcli-project-toolkit/issues/291)). Three apps had -passed every gate while one rooted 8 pages on a parameterless retrieve and gave all 6 roles one -home page. - -**For you:** navigation and page-parameter defects surface at design time, when they are cheap. - -### Changing an existing app: delivery rounds and mid-build changes - -In change-an-existing-app mode, `bin/status.sh` reports the delivery round from a `## Rounds` -table in `PROJECT.md`, drops noise that does not apply there, and counts targeted manual Studio -Pro steps written from `templates/manual-steps.md` -([#326](https://github.com/MendixMau/mxcli-project-toolkit/pull/326)). In every mode, feedback -typed mid-build is logged as a change-log row in `PROJECT.md` before any edit, and the -requirement or design is changed before the MDL -([#306](https://github.com/MendixMau/mxcli-project-toolkit/pull/306)). A final whole-app LOOK is -now owed at Stage 6 ([#303](https://github.com/MendixMau/mxcli-project-toolkit/pull/303), -[#321](https://github.com/MendixMau/mxcli-project-toolkit/pull/321)). - -**For you:** "where are we" has an answer in rounds, not a stage number that never moves. - -## Upgrading +and changes to a live app, or a la carte to audit and test an app you already have. + +1.0 is the first named milestone on top of the release train. Its cut is tagged `v2026.10.19`, +the first tag published to GitHub, and the GitHub Release on that tag is titled "1.0". Earlier +dated headings in the CHANGELOG were never pushed as tags. All 1.0 work merged into the +`release/v1.0` branch while master stayed frozen; that branch then merged to master, where the +cut and its tag were made. Every PR named below has merged, some through the integration batch +[#329](https://github.com/MendixMau/mxcli-project-toolkit/pull/329). Every line traces to an entry in +[`CHANGELOG.md`](../../CHANGELOG.md) or to a linked PR. How milestones relate to tags: +[`docs/RELEASE-PROCESS.md`](../RELEASE-PROCESS.md) §8. + +## 1. Performance improvements + +### Testing at key moments + +A twenty-task UX-fix retro measured what testing every change costs +([#274](https://github.com/MendixMau/mxcli-project-toolkit/issues/274)): UI-only changes were +re-proven 5 to 10 times (their own journey, the regression journeys of 4 to 5 other modules, +reviewer re-runs), a full `mxcli test` took about 6 minutes at every batch close, and 143 minutes +of unit tests found stale strings and credential problems, not logic bugs. +The toolkit now runs tests at fixed moments and keeps a change small. Per change, the build gate +plus what the change touched. The full run happens once when the build is complete and once +before every later deploy. Unit tests are off by default and switched on only where logic needs them +([#290](https://github.com/MendixMau/mxcli-project-toolkit/pull/290), +[#417](https://github.com/MendixMau/mxcli-project-toolkit/pull/417)). They are chosen per flow: a module brief lists the +`Unit flows:` worth a test, one line each with a reason, and `affected-tests.sh` runs only the +listed flows a change touched. That follows the maintainer's policy that unit-testing everything +is overkill: logic and integrations get unit tests, and UI journeys catch the rest +([#435](https://github.com/MendixMau/mxcli-project-toolkit/pull/435), [#436](https://github.com/MendixMau/mxcli-project-toolkit/pull/436)). + +| Moment | What runs | +|---|---| +| Every change (build and feedback) | The gate, plus what the change touched | +| Module done | That module's journeys, plus its listed unit flows | +| Build complete | Everything, once | +| Before every later deploy | Everything, once again | +| You ask | Everything | + +"What the change touched" comes from the script itself: `./bin/affected-tests.sh ` lists +the unit tests and journeys a change owes, from the elements the script writes and the flows +that call them +([#416](https://github.com/MendixMau/mxcli-project-toolkit/pull/416)). On three real change +scripts in a five-app project it selected 0 to 1 of 20 journey files and 0 to 1 unit test files +per change. It is advisory and exits 0. It also reports `journeys unmapped N of M` for journey +files that name-based selection cannot reach (12 of the 20 held no qualified name), so an empty +selection is never read as "nothing owed". `exec.sh` prints the `affected tests:` hint on every +MDL run. The first call takes about 19 seconds (it builds the mxcli catalog), later calls about 3 +seconds. + +### Other speed items + +- **Where an exec spends its time.** The run summary and `docs/BUILD-LOG.md` now carry per-step + seconds (`steps: guards Ns check Ns snapshot Ns baseline Ns exec Ns gate Ns lint Ns score Ns`), + and a run whose gate fails keeps its gate seconds. Those failed or rolled-back runs were 47 of + 238 rows in the measured project and its costliest 20%. The timing costs about 0.2 seconds per + exec, 0.5 to 0.7% of a 28 to 41 second exec + ([#413](https://github.com/MendixMau/mxcli-project-toolkit/pull/413)). +- **Fewer build rows.** A `BUILD` row is now one use case, and a script is the rollback unit. + Two Stage 4 runs on the same requirements had produced 137 and 246 rows (2.5 rows per use + case); build cost followed the row count, 11 versus 25 model calls per row and about 11 versus + about 40 hours. A Stage 4 A/B on two fixture modules (22 use cases) gave 1.05 rows per use case + with the new text and 2.27 to 2.45 with the old. +- **Stage 5 drafts in parallel.** Every build-plan row whose dependencies are applied, minus rows + that write the same document, is drafted at once, one helper per script. Applies stay one at a + time through `bin/exec.sh`, and the ready set is recomputed after each + ([#343](https://github.com/MendixMau/mxcli-project-toolkit/pull/343)). +- **Less to read at the start.** The always-loaded skill tier went from 79,997 to 76,259 words + with no rule removed + ([#315](https://github.com/MendixMau/mxcli-project-toolkit/pull/315)). A helper reads only the + baseline rows for its own role. The mdl helper at Stage 5 went from 56,236 to 43,599 words + (the runbook slice for its stage) and then to 30,647 (a routing row on demand for one role). + Routing tables are trigger lists, so a session no longer re-reads the whole runbook (about 24k + tokens) on every later call. +- **The app map refreshes only what changed.** On a 17,500-unit app the loop sweep re-described + every loop-containing microflow: 1,917 describes in 2 hours 45 minutes at 6 workers, while about + 80 units had changed between rounds. It now describes only changed units. On a synthetic + 2,000-unit app with 1% changed that is 20 describes instead of 2,000, and `bin/status.sh` shows + how stale the map is. No field run of the incremental sweep yet. +- **Context packs** cut helper tool calls and time; see section 3. + +## 2. You manage your own testing + +These are the settings a project owner controls: what runs and when, how much the agent +asks, and what it is allowed to touch. They survive `git pull` and `bin/sync-project.sh`. + +| What you want | The line or command | Where it lives | +|---|---|---| +| Unit tests across the project | `Unit tests default: no` (the default) or `yes` | `PROJECT.md`, intake Q13 | +| Unit tests for one module | Set the Unit row of the module brief's Test plan to `yes` and name why: `\| Unit (.test.mdl) \| yes \| \|` | `architecture/modules//module-brief.md`, `skills/module-brief.md` | +| What runs at each moment | `## Test strategy` table, offered at CAC-5 (architecture and offer, before the build). Status `CONFIRMED`, or `ASSUMED` in auto mode. Change any cell in your answer to the offer | `PROJECT.md`, `checkpoint-build.md` | +| Everything, now | Say "run everything". The full suite runs once on request | in chat | +| Which flows get a unit test | List them in the module brief as `Unit flows:`, one `- ACT_X: reason` line each. A list wins for its module even under `Unit tests default: yes` | `architecture/modules//module-brief.md` | +| Per-change test selection depth | `./bin/affected-tests.sh